Test Failed
Pull Request — master (#658)
by
unknown
02:48
created

API::refund()   A

Complexity

Conditions 3
Paths 4

Size

Total Lines 21
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 7
CRAP Score 3

Importance

Changes 0
Metric Value
cc 3
eloc 17
nc 4
nop 7
dl 0
loc 21
ccs 7
cts 7
cp 1
crap 3
rs 9.3142
c 0
b 0
f 0
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
 * API.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\AbstractAPI;
25
use EasyWeChat\Support\Collection;
26
use EasyWeChat\Support\XML;
27
use Psr\Http\Message\ResponseInterface;
28
29
/**
30
 * Class API.
31
 */
32
class API extends AbstractAPI
33
{
34
    /**
35
     * Merchant instance.
36
     *
37
     * @var Merchant
38
     */
39
    protected $merchant;
40
41
    /**
42
     * Sandbox box mode.
43
     *
44
     * @var string
45
     */
46
    protected $prefix = '';
47
48
    const API_ENDPOINT = 'https://api.mch.weixin.qq.com';
49
50
    // api
51
    const API_PAY_ORDER = '/pay/micropay';
52
    const API_PREPARE_ORDER = '/pay/unifiedorder';
53
    const API_QUERY = '/pay/orderquery';
54
    const API_CLOSE = '/pay/closeorder';
55
    const API_REVERSE = '/secapi/pay/reverse';
56
    const API_REFUND = '/secapi/pay/refund';
57
    const API_QUERY_REFUND = '/pay/refundquery';
58
    const API_DOWNLOAD_BILL = '/pay/downloadbill';
59
    const API_REPORT = '/payitil/report';
60
    const API_URL_SHORTEN = '/tools/shorturl';
61
    const API_AUTH_CODE_TO_OPENID = '/tools/authcodetoopenid';
62
63
    // order id types.
64
    const TRANSACTION_ID = 'transaction_id';
65
    const OUT_TRADE_NO = 'out_trade_no';
66
    const OUT_REFUND_NO = 'out_refund_no';
67
    const REFUND_ID = 'refund_id';
68
69
    // bill types.
70
    const BILL_TYPE_ALL = 'ALL';
71 12
    const BILL_TYPE_SUCCESS = 'SUCCESS';
72
    const BILL_TYPE_REFUND = 'REFUND';
73 12
    const BILL_TYPE_REVOKED = 'REVOKED';
74 12
75
    /**
76
     * API constructor.
77
     *
78
     * @param \EasyWeChat\Payment\Merchant $merchant
79
     */
80
    public function __construct(Merchant $merchant, $isSandboxMode = false)
81
    {
82
        $this->merchant = $merchant;
83 1
        if ($isSandboxMode) {
84
            $this->prefix = '/sandbox';
85 1
        }
86
    }
87
88
    /**
89
     * Pay the order.
90
     *
91
     * @param Order $order
92
     *
93
     * @return \EasyWeChat\Support\Collection
94
     */
95 1
    public function pay(Order $order)
96
    {
97 1
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_PAY_ORDER, $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API..._ORDER, $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 97 which is incompatible with the return type documented by EasyWeChat\Payment\API::pay of type EasyWeChat\Support\Collection.
Loading history...
98 1
    }
99 1
100 1
    /**
101
     * Prepare order to pay.
102 1
     *
103
     * @param Order $order
104
     *
105
     * @return \EasyWeChat\Support\Collection
106
     */
107
    public function prepare(Order $order)
108
    {
109
        $order->notify_url = $order->get('notify_url', $this->merchant->notify_url);
0 ignored issues
show
Documentation introduced by
The property notify_url does not exist on object<EasyWeChat\Payment\Merchant>. Since you implemented __get, maybe consider adding a @property annotation.

Since your code implements the magic getter _get, this function will be called for any read access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

If the property has read access only, you can use the @property-read annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
110
        if (is_null($order->spbill_create_ip)) {
111
            $order->spbill_create_ip = ($order->trade_type === Order::NATIVE) ? get_server_ip() : get_client_ip();
112
        }
113 1
114
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_PREPARE_ORDER, $order->all());
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API..._ORDER, $order->all()); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 114 which is incompatible with the return type documented by EasyWeChat\Payment\API::prepare of type EasyWeChat\Support\Collection.
Loading history...
115
    }
116 1
117 1
    /**
118
     * Query order.
119 1
     *
120
     * @param string $orderNo
121
     * @param string $type
122
     *
123
     * @return \EasyWeChat\Support\Collection
124
     */
125 View Code Duplication
    public function query($orderNo, $type = self::OUT_TRADE_NO)
126
    {
127
        $params = [
128
            $type => $orderNo,
129 1
        ];
130
131 1
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_QUERY, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...f::API_QUERY, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 131 which is incompatible with the return type documented by EasyWeChat\Payment\API::query of type EasyWeChat\Support\Collection.
Loading history...
132
    }
133
134
    /**
135
     * Query order by transaction_id.
136
     *
137
     * @param string $transactionId
138
     *
139
     * @return \EasyWeChat\Support\Collection
140
     */
141 1
    public function queryByTransactionId($transactionId)
142
    {
143
        return $this->query($transactionId, self::TRANSACTION_ID);
144 1
    }
145 1
146
    /**
147 1
     * Close order by out_trade_no.
148
     *
149
     * @param $tradeNo
150
     *
151
     * @return \EasyWeChat\Support\Collection
152
     */
153
    public function close($tradeNo)
154
    {
155
        $params = [
156
            'out_trade_no' => $tradeNo,
157
        ];
158 1
159
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_CLOSE, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...f::API_CLOSE, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 159 which is incompatible with the return type documented by EasyWeChat\Payment\API::close of type EasyWeChat\Support\Collection.
Loading history...
160
    }
161 1
162 1
    /**
163
     * Reverse order.
164 1
     *
165
     * @param string $orderNo
166
     * @param string $type
167
     *
168
     * @return \EasyWeChat\Support\Collection
169
     */
170
    public function reverse($orderNo, $type = self::OUT_TRADE_NO)
171
    {
172
        $params = [
173
            $type => $orderNo,
174
        ];
175
176
        return $this->safeRequest(self::API_ENDPOINT . $this->prefix . self::API_REVERSE, $params);
177
    }
178
179
    /**
180
     * Reverse order by transaction_id.
181
     *
182
     * @param int $transactionId
183
     *
184
     * @return \EasyWeChat\Support\Collection
185
     */
186
    public function reverseByTransactionId($transactionId)
187
    {
188
        return $this->reverse($transactionId, self::TRANSACTION_ID);
189
    }
190
191 1
    /**
192
     * Make a refund request.
193
     *
194
     * @param string $orderNo
195
     * @param float  $totalFee
196
     * @param float  $refundFee
197
     * @param string $opUserId
198
     * @param string $type
199
     * @param string $refundAccount
200
     *
201 1
     * @return \EasyWeChat\Support\Collection
202 1
     */
203 1
    public function refund(
204 1
        $orderNo,
205 1
        $refundNo,
206 1
        $totalFee,
207 1
        $refundFee = null,
208 1
        $opUserId = null,
209
        $type = self::OUT_TRADE_NO,
210 1
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
211
        ) {
212
        $params = [
213
            $type => $orderNo,
214
            'out_refund_no' => $refundNo,
215
            'total_fee' => $totalFee,
216
            'refund_fee' => $refundFee ?: $totalFee,
217
            'refund_fee_type' => $this->merchant->fee_type,
218
            'refund_account' => $refundAccount,
219
            'op_user_id' => $opUserId ?: $this->merchant->merchant_id,
220
        ];
221
222
        return $this->safeRequest(self::API_ENDPOINT.$this->prefix.self::API_REFUND, $params);
223
    }
224
225
    /**
226
     * Refund by transaction id.
227
     *
228
     * @param string $orderNo
229
     * @param float  $totalFee
230
     * @param float  $refundFee
231
     * @param string $opUserId
232
     * @param string $refundAccount
233
     *
234
     * @return \EasyWeChat\Support\Collection
235
     */
236
    public function refundByTransactionId(
237
        $orderNo,
238
        $refundNo,
239
        $totalFee,
240
        $refundFee = null,
241
        $opUserId = null,
242
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
243 1
        ) {
244
        return $this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, self::TRANSACTION_ID, $refundAccount);
245
    }
246 1
247 1
    /**
248
     * Query refund status.
249 1
     *
250
     * @param string $orderNo
251
     * @param string $type
252
     *
253
     * @return \EasyWeChat\Support\Collection
254
     */
255 View Code Duplication
    public function queryRefund($orderNo, $type = self::OUT_TRADE_NO)
256
    {
257
        $params = [
258
            $type => $orderNo,
259
        ];
260
261
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_QUERY_REFUND, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...QUERY_REFUND, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 261 which is incompatible with the return type documented by EasyWeChat\Payment\API::queryRefund of type EasyWeChat\Support\Collection.
Loading history...
262
    }
263
264
    /**
265
     * Query refund status by out_refund_no.
266
     *
267
     * @param string $refundNo
268
     *
269
     * @return \EasyWeChat\Support\Collection
270
     */
271
    public function queryRefundByRefundNo($refundNo)
272
    {
273
        return $this->queryRefund($refundNo, self::OUT_REFUND_NO);
274
    }
275
276
    /**
277
     * Query refund status by transaction_id.
278
     *
279
     * @param string $transactionId
280
     *
281
     * @return \EasyWeChat\Support\Collection
282
     */
283
    public function queryRefundByTransactionId($transactionId)
284
    {
285
        return $this->queryRefund($transactionId, self::TRANSACTION_ID);
286
    }
287
288
    /**
289
     * Query refund status by refund_id.
290
     *
291
     * @param string $refundId
292
     *
293
     * @return \EasyWeChat\Support\Collection
294
     */
295
    public function queryRefundByRefundId($refundId)
296 1
    {
297
        return $this->queryRefund($refundId, self::REFUND_ID);
298
    }
299 1
300 1
    /**
301 1
     * Download bill history as a table file.
302
     *
303 1
     * @param string $date
304
     * @param string $type
305
     *
306
     * @return \Psr\Http\Message\ResponseInterface
307
     */
308
    public function downloadBill($date, $type = self::BILL_TYPE_ALL)
309
    {
310
        $params = [
311
            'bill_date' => $date,
312
            'bill_type' => $type,
313 1
        ];
314
315 1
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_DOWNLOAD_BILL, $params, 'post', [\GuzzleHttp\RequestOptions::STREAM => true], true)->getBody();
0 ignored issues
show
Bug introduced by
The method getBody does only exist in Psr\Http\Message\ResponseInterface, but not in EasyWeChat\Support\Collection.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
316
    }
317
318
    /**
319
     * Convert long url to short url.
320
     *
321
     * @param string $url
322
     *
323
     * @return \EasyWeChat\Support\Collection
324
     */
325
    public function urlShorten($url)
326
    {
327
        return $this->request(self::API_URL_SHORTEN, ['long_url' => $url]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...y('long_url' => $url)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 327 which is incompatible with the return type documented by EasyWeChat\Payment\API::urlShorten of type EasyWeChat\Support\Collection.
Loading history...
328
    }
329
330
    /**
331
     * Report API status to WeChat.
332
     *
333
     * @param string $api
334
     * @param int    $timeConsuming
335
     * @param string $resultCode
336
     * @param string $returnCode
337
     * @param array  $other         ex: err_code,err_code_des,out_trade_no,user_ip...
338
     *
339
     * @return \EasyWeChat\Support\Collection
340
     */
341
    public function report($api, $timeConsuming, $resultCode, $returnCode, array $other = [])
342
    {
343
        $params = array_merge([
344
            'interface_url' => $api,
345
            'execute_time_' => $timeConsuming,
346
            'return_code' => $returnCode,
347
            'return_msg' => null,
348
            'result_code' => $resultCode,
349
            'user_ip' => get_client_ip(),
350
            'time' => time(),
351 1
        ], $other);
352
353 1
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_REPORT, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...::API_REPORT, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 353 which is incompatible with the return type documented by EasyWeChat\Payment\API::report of type EasyWeChat\Support\Collection.
Loading history...
354
    }
355
356
    /**
357
     * Get openid by auth code.
358
     *
359
     * @param string $authCode
360
     *
361
     * @return \EasyWeChat\Support\Collection
362
     */
363 1
    public function authCodeToOpenId($authCode)
364
    {
365 1
        return $this->request(self::API_ENDPOINT.$this->prefix.self::API_AUTH_CODE_TO_OPENID, ['auth_code' => $authCode]);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API...h_code' => $authCode)); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 365 which is incompatible with the return type documented by EasyWeChat\Payment\API::authCodeToOpenId of type EasyWeChat\Support\Collection.
Loading history...
366 1
    }
367
368
    /**
369
     * Merchant setter.
370
     *
371
     * @param Merchant $merchant
372
     *
373 1
     * @return $this
374
     */
375 1
    public function setMerchant(Merchant $merchant)
376
    {
377
        $this->merchant = $merchant;
378
    }
379
380
    /**
381
     * Merchant getter.
382
     *
383
     * @return Merchant
384
     */
385
    public function getMerchant()
386
    {
387
        return $this->merchant;
388
    }
389 10
390
    /**
391 10
     * Make a API request.
392
     *
393 10
     * @param string $api
394 10
     * @param array  $params
395 10
     * @param string $method
396 10
     * @param array  $options
397 10
     * @param bool   $returnResponse
398 10
     *
399
     * @return \EasyWeChat\Support\Collection|\Psr\Http\Message\ResponseInterface
400 10
     */
401 10
    protected function request($api, array $params, $method = 'post', array $options = [], $returnResponse = false)
402 10
    {
403
        $params = array_merge($params, $this->merchant->only(['sub_appid', 'sub_mch_id']));
404 10
405
        $params['appid'] = $this->merchant->app_id;
406 10
        $params['mch_id'] = $this->merchant->merchant_id;
407
        $params['device_info'] = $this->merchant->device_info;
408
        $params['nonce_str'] = uniqid();
409
        $params = array_filter($params);
410
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
411
412
        $options = array_merge([
413
            'body' => XML::build($params),
414
        ], $options);
415
416
        $response = $this->getHttp()->request($api, $method, $options);
417
418 2
        return $returnResponse ? $response : $this->parseResponse($response);
419
    }
420
421 2
    /**
422 2
     * Request with SSL.
423 2
     *
424
     * @param string $api
425 2
     * @param array  $params
426
     * @param string $method
427
     *
428
     * @return \EasyWeChat\Support\Collection
429
     */
430
    protected function safeRequest($api, array $params, $method = 'post')
431
    {
432
        $options = [
433
            'cert' => $this->merchant->get('cert_path'),
434
            'ssl_key' => $this->merchant->get('key_path'),
435 9
        ];
436
437 9
        return $this->request($api, $params, $method, $options);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request($api, $params, $method, $options); of type Psr\Http\Message\Respons...Chat\Support\Collection adds the type Psr\Http\Message\ResponseInterface to the return on line 437 which is incompatible with the return type documented by EasyWeChat\Payment\API::safeRequest of type EasyWeChat\Support\Collection.
Loading history...
438
    }
439
440
    /**
441 9
     * Parse Response XML to array.
442
     *
443
     * @param ResponseInterface $response
444
     *
445
     * @return \EasyWeChat\Support\Collection
446
     */
447
    protected function parseResponse($response)
448
    {
449
        if ($response instanceof ResponseInterface) {
450
            $response = $response->getBody();
451
        }
452
453
        return new Collection((array) XML::parse($response));
454
    }
455
456
    /**
457
     * Set sandbox mode
458
     *
459
     * @param bool $mode
460
     */
461
    public function enableSandbox($mode)
462
    {
463
        if ($mode) {
464
            $this->prefix = '/sandbox';
465
        } else {
466
            $this->prefix = '';
467
        }
468
    }
469
}
470