Completed
Push — master ( 81d11d...aa48ec )
by Carlos
02:49
created

API::close()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 4
nc 1
nop 1
dl 0
loc 8
ccs 4
cts 4
cp 1
crap 1
rs 9.4285
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
    // api
42
    const API_PAY_ORDER = 'https://api.mch.weixin.qq.com/pay/micropay';
43
    const API_PREPARE_ORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
44
    const API_QUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';
45
    const API_CLOSE = 'https://api.mch.weixin.qq.com/pay/closeorder';
46
    const API_REVERSE = 'https://api.mch.weixin.qq.com/secapi/pay/reverse';
47
    const API_REFUND = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
48
    const API_QUERY_REFUND = 'https://api.mch.weixin.qq.com/pay/refundquery';
49
    const API_DOWNLOAD_BILL = 'https://api.mch.weixin.qq.com/pay/downloadbill';
50
    const API_REPORT = 'https://api.mch.weixin.qq.com/payitil/report';
51
    const API_URL_SHORTEN = 'https://api.mch.weixin.qq.com/tools/shorturl';
52
    const API_AUTH_CODE_TO_OPENID = 'https://api.mch.weixin.qq.com/tools/authcodetoopenid';
53
54
    // order id types.
55
    const TRANSACTION_ID = 'transaction_id';
56
    const OUT_TRADE_NO = 'out_trade_no';
57
    const OUT_REFUND_NO = 'out_refund_no';
58
    const REFUND_ID = 'refund_id';
59
60
    // bill types.
61
    const BILL_TYPE_ALL = 'ALL';
62
    const BILL_TYPE_SUCCESS = 'SUCCESS';
63
    const BILL_TYPE_REFUND = 'REFUND';
64
    const BILL_TYPE_REVOKED = 'REVOKED';
65
66
    /**
67
     * API constructor.
68
     *
69
     * @param \EasyWeChat\Payment\Merchant $merchant
70
     */
71 12
    public function __construct(Merchant $merchant)
72
    {
73 12
        $this->merchant = $merchant;
74 12
    }
75
76
    /**
77
     * Pay the order.
78
     *
79
     * @param Order $order
80
     *
81
     * @return \EasyWeChat\Support\Collection
82
     */
83 1
    public function pay(Order $order)
84
    {
85 1
        return $this->request(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 85 which is incompatible with the return type documented by EasyWeChat\Payment\API::pay of type EasyWeChat\Support\Collection.
Loading history...
86
    }
87
88
    /**
89
     * Prepare order to pay.
90
     *
91
     * @param Order $order
92
     *
93
     * @return \EasyWeChat\Support\Collection
94
     */
95 1
    public function prepare(Order $order)
96
    {
97 1
        $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...
98 1
        if (is_null($order->spbill_create_ip)) {
99 1
            $order->spbill_create_ip = ($order->trade_type === Order::NATIVE) ? get_server_ip() : get_client_ip();
100 1
        }
101
        
102 1
        return $this->request(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 102 which is incompatible with the return type documented by EasyWeChat\Payment\API::prepare of type EasyWeChat\Support\Collection.
Loading history...
103
    }
104
105
    /**
106
     * Query order.
107
     *
108
     * @param string $orderNo
109
     * @param string $type
110
     *
111
     * @return \EasyWeChat\Support\Collection
112
     */
113 1
    public function query($orderNo, $type = self::OUT_TRADE_NO)
114
    {
115
        $params = [
116 1
            $type => $orderNo,
117 1
        ];
118
119 1
        return $this->request(self::API_QUERY, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API_QUERY, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 119 which is incompatible with the return type documented by EasyWeChat\Payment\API::query of type EasyWeChat\Support\Collection.
Loading history...
120
    }
121
122
    /**
123
     * Query order by transaction_id.
124
     *
125
     * @param string $transactionId
126
     *
127
     * @return \EasyWeChat\Support\Collection
128
     */
129 1
    public function queryByTransactionId($transactionId)
130
    {
131 1
        return $this->query($transactionId, self::TRANSACTION_ID);
132
    }
133
134
    /**
135
     * Close order by out_trade_no.
136
     *
137
     * @param $tradeNo
138
     *
139
     * @return \EasyWeChat\Support\Collection
140
     */
141 1
    public function close($tradeNo)
142
    {
143
        $params = [
144 1
            'out_trade_no' => $tradeNo,
145 1
        ];
146
147 1
        return $this->request(self::API_CLOSE, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API_CLOSE, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 147 which is incompatible with the return type documented by EasyWeChat\Payment\API::close of type EasyWeChat\Support\Collection.
Loading history...
148
    }
149
150
    /**
151
     * Reverse order.
152
     *
153
     * @param string $orderNo
154
     * @param string $type
155
     *
156
     * @return \EasyWeChat\Support\Collection
157
     */
158 1
    public function reverse($orderNo, $type = self::OUT_TRADE_NO)
159
    {
160
        $params = [
161 1
            $type => $orderNo,
162 1
        ];
163
164 1
        return $this->safeRequest(self::API_REVERSE, $params);
165
    }
166
167
    /**
168
     * Reverse order by transaction_id.
169
     *
170
     * @param int $transactionId
171
     *
172
     * @return \EasyWeChat\Support\Collection
173
     */
174
    public function reverseByTransactionId($transactionId)
175
    {
176
        return $this->reverse($transactionId, self::TRANSACTION_ID);
177
    }
178
179
    /**
180
     * Make a refund request.
181
     *
182
     * @param string $orderNo
183
     * @param float  $totalFee
184
     * @param float  $refundFee
185
     * @param string $opUserId
186
     * @param string $type
187
     * @param string $refundAccount
188
     *
189
     * @return \EasyWeChat\Support\Collection
190
     */
191 1
    public function refund(
192
        $orderNo,
193
        $refundNo,
194
        $totalFee,
195
        $refundFee = null,
196
        $opUserId = null,
197
        $type = self::OUT_TRADE_NO,
198
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
199
        ) {
200
        $params = [
201 1
            $type => $orderNo,
202 1
            'out_refund_no' => $refundNo,
203 1
            'total_fee' => $totalFee,
204 1
            'refund_fee' => $refundFee ?: $totalFee,
205 1
            'refund_fee_type' => $this->merchant->fee_type,
206 1
            'refund_account' => $refundAccount,
207 1
            'op_user_id' => $opUserId ?: $this->merchant->merchant_id,
208 1
        ];
209
210 1
        return $this->safeRequest(self::API_REFUND, $params);
211
    }
212
213
    /**
214
     * Refund by transaction id.
215
     *
216
     * @param string $orderNo
217
     * @param float  $totalFee
218
     * @param float  $refundFee
219
     * @param string $opUserId
220
     * @param string $refundAccount
221
     *
222
     * @return \EasyWeChat\Support\Collection
223
     */
224
    public function refundByTransactionId(
225
        $orderNo,
226
        $refundNo,
227
        $totalFee,
228
        $refundFee = null,
229
        $opUserId = null,
230
        $refundAccount = 'REFUND_SOURCE_UNSETTLED_FUNDS'
231
        ) {
232
        return $this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, self::TRANSACTION_ID, $refundAccount);
233
    }
234
235
    /**
236
     * Query refund status.
237
     *
238
     * @param string $orderNo
239
     * @param string $type
240
     *
241
     * @return \EasyWeChat\Support\Collection
242
     */
243 1
    public function queryRefund($orderNo, $type = self::OUT_TRADE_NO)
244
    {
245
        $params = [
246 1
            $type => $orderNo,
247 1
        ];
248
249 1
        return $this->request(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 249 which is incompatible with the return type documented by EasyWeChat\Payment\API::queryRefund of type EasyWeChat\Support\Collection.
Loading history...
250
    }
251
252
    /**
253
     * Query refund status by out_refund_no.
254
     *
255
     * @param string $refundNo
256
     *
257
     * @return \EasyWeChat\Support\Collection
258
     */
259
    public function queryRefundByRefundNo($refundNo)
260
    {
261
        return $this->queryRefund($refundNo, self::OUT_REFUND_NO);
262
    }
263
264
    /**
265
     * Query refund status by transaction_id.
266
     *
267
     * @param string $transactionId
268
     *
269
     * @return \EasyWeChat\Support\Collection
270
     */
271
    public function queryRefundByTransactionId($transactionId)
272
    {
273
        return $this->queryRefund($transactionId, self::TRANSACTION_ID);
274
    }
275
276
    /**
277
     * Query refund status by refund_id.
278
     *
279
     * @param string $refundId
280
     *
281
     * @return \EasyWeChat\Support\Collection
282
     */
283
    public function queryRefundByRefundId($refundId)
284
    {
285
        return $this->queryRefund($refundId, self::REFUND_ID);
286
    }
287
288
    /**
289
     * Download bill history as a table file.
290
     *
291
     * @param string $date
292
     * @param string $type
293
     *
294
     * @return \Psr\Http\Message\ResponseInterface
295
     */
296 1
    public function downloadBill($date, $type = self::BILL_TYPE_ALL)
297
    {
298
        $params = [
299 1
            'bill_date' => $date,
300 1
            'bill_type' => $type,
301 1
        ];
302
303 1
        return $this->request(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...
304
    }
305
306
    /**
307
     * Convert long url to short url.
308
     *
309
     * @param string $url
310
     *
311
     * @return \EasyWeChat\Support\Collection
312
     */
313 1
    public function urlShorten($url)
314
    {
315 1
        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 315 which is incompatible with the return type documented by EasyWeChat\Payment\API::urlShorten of type EasyWeChat\Support\Collection.
Loading history...
316
    }
317
318
    /**
319
     * Report API status to WeChat.
320
     *
321
     * @param string $api
322
     * @param int    $timeConsuming
323
     * @param string $resultCode
324
     * @param string $returnCode
325
     * @param array  $other         ex: err_code,err_code_des,out_trade_no,user_ip...
326
     *
327
     * @return \EasyWeChat\Support\Collection
328
     */
329
    public function report($api, $timeConsuming, $resultCode, $returnCode, array $other = [])
330
    {
331
        $params = array_merge([
332
            'interface_url' => $api,
333
            'execute_time_' => $timeConsuming,
334
            'return_code' => $returnCode,
335
            'return_msg' => null,
336
            'result_code' => $resultCode,
337
            'user_ip' => get_client_ip(),
338
            'time' => time(),
339
        ], $other);
340
341
        return $this->request(self::API_REPORT, $params);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->request(self::API_REPORT, $params); of type EasyWeChat\Support\Colle...ssage\ResponseInterface adds the type Psr\Http\Message\ResponseInterface to the return on line 341 which is incompatible with the return type documented by EasyWeChat\Payment\API::report of type EasyWeChat\Support\Collection.
Loading history...
342
    }
343
344
    /**
345
     * Get openid by auth code.
346
     *
347
     * @param string $authCode
348
     *
349
     * @return \EasyWeChat\Support\Collection
350
     */
351 1
    public function authCodeToOpenId($authCode)
352
    {
353 1
        return $this->request(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 353 which is incompatible with the return type documented by EasyWeChat\Payment\API::authCodeToOpenId of type EasyWeChat\Support\Collection.
Loading history...
354
    }
355
356
    /**
357
     * Merchant setter.
358
     *
359
     * @param Merchant $merchant
360
     *
361
     * @return $this
362
     */
363 1
    public function setMerchant(Merchant $merchant)
364
    {
365 1
        $this->merchant = $merchant;
366 1
    }
367
368
    /**
369
     * Merchant getter.
370
     *
371
     * @return Merchant
372
     */
373 1
    public function getMerchant()
374
    {
375 1
        return $this->merchant;
376
    }
377
378
    /**
379
     * Make a API request.
380
     *
381
     * @param string $api
382
     * @param array  $params
383
     * @param string $method
384
     * @param array  $options
385
     * @param bool   $returnResponse
386
     *
387
     * @return \EasyWeChat\Support\Collection|\Psr\Http\Message\ResponseInterface
388
     */
389 10
    protected function request($api, array $params, $method = 'post', array $options = [], $returnResponse = false)
390
    {
391 10
        $params = array_merge($params, $this->merchant->only(['sub_appid', 'sub_mch_id']));
392
393 10
        $params['appid'] = $this->merchant->app_id;
394 10
        $params['mch_id'] = $this->merchant->merchant_id;
395 10
        $params['device_info'] = $this->merchant->device_info;
396 10
        $params['nonce_str'] = uniqid();
397 10
        $params = array_filter($params);
398 10
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
399
400 10
        $options = array_merge([
401 10
            'body' => XML::build($params),
402 10
        ], $options);
403
404 10
        $response = $this->getHttp()->request($api, $method, $options);
405
406 10
        return $returnResponse ? $response : $this->parseResponse($response);
407
    }
408
409
    /**
410
     * Request with SSL.
411
     *
412
     * @param string $api
413
     * @param array  $params
414
     * @param string $method
415
     *
416
     * @return \EasyWeChat\Support\Collection
417
     */
418 2
    protected function safeRequest($api, array $params, $method = 'post')
419
    {
420
        $options = [
421 2
            'cert' => $this->merchant->get('cert_path'),
422 2
            'ssl_key' => $this->merchant->get('key_path'),
423 2
        ];
424
425 2
        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 425 which is incompatible with the return type documented by EasyWeChat\Payment\API::safeRequest of type EasyWeChat\Support\Collection.
Loading history...
426
    }
427
428
    /**
429
     * Parse Response XML to array.
430
     *
431
     * @param ResponseInterface $response
432
     *
433
     * @return \EasyWeChat\Support\Collection
434
     */
435 9
    protected function parseResponse($response)
436
    {
437 9
        if ($response instanceof ResponseInterface) {
438
            $response = $response->getBody();
439
        }
440
441 9
        return new Collection((array) XML::parse($response));
442
    }
443
}
444