Completed
Push — master ( 923933...545f71 )
by Carlos
03:11
created

API::queryByTransactionId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 2
cts 2
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 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
 * API.php.
14
 *
15
 * @author    overtrue <[email protected]>
16
 * @copyright 2015 overtrue <[email protected]>
17
 *
18
 * @link      https://github.com/overtrue
19
 * @link      http://overtrue.me
20
 */
21
namespace EasyWeChat\Payment;
22
23
use EasyWeChat\Core\AbstractAPI;
24
use EasyWeChat\Support\Collection;
25
use EasyWeChat\Support\XML;
26
use Psr\Http\Message\ResponseInterface;
27
28
/**
29
 * Class API.
30
 */
31
class API extends AbstractAPI
32
{
33
    /**
34
     * Merchant instance.
35
     *
36
     * @var Merchant
37
     */
38
    protected $merchant;
39
40
    // api
41
    const API_PAY_ORDER = 'https://api.mch.weixin.qq.com/pay/micropay';
42
    const API_PREPARE_ORDER = 'https://api.mch.weixin.qq.com/pay/unifiedorder';
43
    const API_QUERY = 'https://api.mch.weixin.qq.com/pay/orderquery';
44
    const API_CLOSE = 'https://api.mch.weixin.qq.com/pay/closeorder';
45
    const API_REVERSE = 'https://api.mch.weixin.qq.com/secapi/pay/reverse';
46
    const API_REFUND = 'https://api.mch.weixin.qq.com/secapi/pay/refund';
47
    const API_QUERY_REFUND = 'https://api.mch.weixin.qq.com/pay/refundquery';
48
    const API_DOWNLOAD_BILL = 'https://api.mch.weixin.qq.com/pay/downloadbill';
49
    const API_REPORT = 'https://api.mch.weixin.qq.com/payitil/report';
50
    const API_URL_SHORTEN = 'https://api.mch.weixin.qq.com/tools/shorturl';
51
    const API_AUTH_CODE_TO_OPENID = 'https://api.mch.weixin.qq.com/tools/authcodetoopenid';
52
53
    // order id types.
54
    const TRANSACTION_ID = 'transaction_id';
55
    const OUT_TRADE_NO = 'out_trade_no';
56
    const OUT_REFUND_NO = 'out_refund_no';
57
    const REFUND_ID = 'refund_id';
58
59
    // bill types.
60
    const BILL_TYPE_ALL = 'ALL';
61
    const BILL_TYPE_SUCCESS = 'SUCCESS';
62
    const BILL_TYPE_REFUND = 'REFUND';
63
    const BILL_TYPE_REVOKED = 'REVOKED';
64
65
    /**
66
     * API constructor.
67
     *
68
     * @param \EasyWeChat\Payment\Merchant $merchant
69
     */
70 12
    public function __construct(Merchant $merchant)
71
    {
72 12
        $this->merchant = $merchant;
73 12
    }
74
75
    /**
76
     * Pay the order.
77
     *
78
     * @param Order $order
79
     *
80
     * @return \EasyWeChat\Support\Collection
81
     */
82 1
    public function pay(Order $order)
83
    {
84 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 84 which is incompatible with the return type documented by EasyWeChat\Payment\API::pay of type EasyWeChat\Support\Collection.
Loading history...
85
    }
86
87
    /**
88
     * Prepare order to pay.
89
     *
90
     * @param Order $order
91
     *
92
     * @return \EasyWeChat\Support\Collection
93
     */
94 1
    public function prepare(Order $order)
95
    {
96 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\Order>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
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...
97 1
        $order->spbill_create_ip = ($order->trade_type == Order::NATIVE) ? get_server_ip() : get_client_ip();
0 ignored issues
show
Documentation introduced by
The property spbill_create_ip does not exist on object<EasyWeChat\Payment\Order>. Since you implemented __set, maybe consider adding a @property annotation.

Since your code implements the magic setter _set, this function will be called for any write 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.");
        }
    }

}

Since the property has write access only, you can use the @property-write 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...
Documentation introduced by
The property trade_type does not exist on object<EasyWeChat\Payment\Order>. 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
99 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 99 which is incompatible with the return type documented by EasyWeChat\Payment\API::prepare of type EasyWeChat\Support\Collection.
Loading history...
100
    }
101
102
    /**
103
     * Query order.
104
     *
105
     * @param string $orderNo
106
     * @param string $type
107
     *
108
     * @return \EasyWeChat\Support\Collection
109
     */
110 1
    public function query($orderNo, $type = self::OUT_TRADE_NO)
111
    {
112
        $params = [
113 1
            $type => $orderNo,
114 1
        ];
115
116 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 116 which is incompatible with the return type documented by EasyWeChat\Payment\API::query of type EasyWeChat\Support\Collection.
Loading history...
117
    }
118
119
    /**
120
     * Query order by transaction_id.
121
     *
122
     * @param string $transactionId
123
     *
124
     * @return \EasyWeChat\Support\Collection
125
     */
126 1
    public function queryByTransactionId($transactionId)
127
    {
128 1
        return $this->query($transactionId, self::TRANSACTION_ID);
129
    }
130
131
    /**
132
     * Close order by out_trade_no.
133
     *
134
     * @param $tradeNo
135
     *
136
     * @return \EasyWeChat\Support\Collection
137
     */
138 1
    public function close($tradeNo)
139
    {
140
        $params = [
141 1
            'out_trade_no' => $tradeNo,
142 1
        ];
143
144 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 144 which is incompatible with the return type documented by EasyWeChat\Payment\API::close of type EasyWeChat\Support\Collection.
Loading history...
145
    }
146
147
    /**
148
     * Reverse order.
149
     *
150
     * @param string $orderNo
151
     * @param string $type
152
     *
153
     * @return \EasyWeChat\Support\Collection
154
     */
155 1
    public function reverse($orderNo, $type = self::OUT_TRADE_NO)
156
    {
157
        $params = [
158 1
            $type => $orderNo,
159 1
        ];
160
161 1
        return $this->safeRequest(self::API_REVERSE, $params);
162
    }
163
164
    /**
165
     * Reverse order by transaction_id.
166
     *
167
     * @param int $transactionId
168
     *
169
     * @return \EasyWeChat\Support\Collection
170
     */
171
    public function reverseByTransactionId($transactionId)
172
    {
173
        return $this->reverse($transactionId, self::TRANSACTION_ID);
174
    }
175
176
    /**
177
     * Make a refund request.
178
     *
179
     * @param string $orderNo
180
     * @param float  $totalFee
181
     * @param float  $refundFee
182
     * @param string $opUserId
183
     * @param string $type
184
     *
185
     * @return \EasyWeChat\Support\Collection
186
     */
187 1
    public function refund(
188
        $orderNo,
189
        $refundNo,
190
        $totalFee,
191
        $refundFee = null,
192
        $opUserId = null,
193
        $type = self::OUT_TRADE_NO
194
        ) {
195
        $params = [
196 1
            $type => $orderNo,
197 1
            'out_refund_no' => $refundNo,
198 1
            'total_fee' => $totalFee,
199 1
            'refund_fee' => $refundFee ?: $totalFee,
200 1
            'refund_fee_type' => $this->merchant->fee_type,
201 1
            'op_user_id' => $opUserId ?: $this->merchant->merchant_id,
202 1
        ];
203
204 1
        return $this->safeRequest(self::API_REFUND, $params);
205
    }
206
207
    /**
208
     * Refund by transaction id.
209
     *
210
     * @param string $orderNo
211
     * @param float  $totalFee
212
     * @param float  $refundFee
213
     * @param string $opUserId
214
     *
215
     * @return \EasyWeChat\Support\Collection
216
     */
217
    public function refundByTransactionId(
218
        $orderNo,
219
        $refundNo,
220
        $totalFee,
221
        $refundFee = null,
222
        $opUserId = null
223
        ) {
224
        return $this->refund($orderNo, $refundNo, $totalFee, $refundFee, $opUserId, self::TRANSACTION_ID);
225
    }
226
227
    /**
228
     * Query refund status.
229
     *
230
     * @param string $orderNo
231
     * @param string $type
232
     *
233
     * @return \EasyWeChat\Support\Collection
234
     */
235 1
    public function queryRefund($orderNo, $type = self::OUT_TRADE_NO)
236
    {
237
        $params = [
238 1
            $type => $orderNo,
239 1
        ];
240
241 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 241 which is incompatible with the return type documented by EasyWeChat\Payment\API::queryRefund of type EasyWeChat\Support\Collection.
Loading history...
242
    }
243
244
    /**
245
     * Query refund status by out_refund_no.
246
     *
247
     * @param string $refundNo
248
     *
249
     * @return \EasyWeChat\Support\Collection
250
     */
251
    public function queryRefundByRefundNo($refundNo)
252
    {
253
        return $this->queryRefund($refundNo, self::OUT_REFUND_NO);
254
    }
255
256
    /**
257
     * Query refund status by transaction_id.
258
     *
259
     * @param string $transactionId
260
     *
261
     * @return \EasyWeChat\Support\Collection
262
     */
263
    public function queryRefundByTransactionId($transactionId)
264
    {
265
        return $this->queryRefund($transactionId, self::TRANSACTION_ID);
266
    }
267
268
    /**
269
     * Query refund status by refund_id.
270
     *
271
     * @param string $refundId
272
     *
273
     * @return \EasyWeChat\Support\Collection
274
     */
275
    public function queryRefundByRefundId($refundId)
276
    {
277
        return $this->queryRefund($refundId, self::REFUND_ID);
278
    }
279
280
    /**
281
     * Download bill history as a table file.
282
     *
283
     * @param string $date
284
     * @param string $type
285
     *
286
     * @return \Psr\Http\Message\ResponseInterface
287
     */
288 1
    public function downloadBill($date, $type = self::BILL_TYPE_ALL)
289
    {
290
        $params = [
291 1
            'bill_date' => $date,
292 1
            'bill_type' => $type,
293 1
        ];
294
295 1
        return $this->request(self::API_DOWNLOAD_BILL, $params, 'post', [], 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...
296
    }
297
298
    /**
299
     * Convert long url to short url.
300
     *
301
     * @param string $url
302
     *
303
     * @return \EasyWeChat\Support\Collection
304
     */
305 1
    public function urlShorten($url)
306
    {
307 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 307 which is incompatible with the return type documented by EasyWeChat\Payment\API::urlShorten of type EasyWeChat\Support\Collection.
Loading history...
308
    }
309
310
    /**
311
     * Report API status to WeChat.
312
     *
313
     * @param string $api
314
     * @param int    $timeConsuming
315
     * @param string $resultCode
316
     * @param string $returnCode
317
     * @param array  $other         ex: err_code,err_code_des,out_trade_no,user_ip...
318
     *
319
     * @return \EasyWeChat\Support\Collection
320
     */
321
    public function report($api, $timeConsuming, $resultCode, $returnCode, array $other = [])
322
    {
323
        $params = array_merge([
324
            'interface_url' => $api,
325
            'execute_time_' => $timeConsuming,
326
            'return_code' => $returnCode,
327
            'return_msg' => null,
328
            'result_code' => $resultCode,
329
            'user_ip' => get_client_ip(),
330
            'time' => time(),
331
        ], $other);
332
333
        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 333 which is incompatible with the return type documented by EasyWeChat\Payment\API::report of type EasyWeChat\Support\Collection.
Loading history...
334
    }
335
336
    /**
337
     * Get openid by auth code.
338
     *
339
     * @param string $authCode
340
     *
341
     * @return \EasyWeChat\Support\Collection
342
     */
343 1
    public function authCodeToOpenId($authCode)
344
    {
345 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 345 which is incompatible with the return type documented by EasyWeChat\Payment\API::authCodeToOpenId of type EasyWeChat\Support\Collection.
Loading history...
346
    }
347
348
    /**
349
     * Merchant setter.
350
     *
351
     * @param Merchant $merchant
352
     *
353
     * @return $this
354
     */
355 1
    public function setMerchant(Merchant $merchant)
356
    {
357 1
        $this->merchant = $merchant;
358 1
    }
359
360
    /**
361
     * Merchant getter.
362
     *
363
     * @return Merchant
364
     */
365 1
    public function getMerchant()
366
    {
367 1
        return $this->merchant;
368
    }
369
370
    /**
371
     * Make a API request.
372
     *
373
     * @param string $api
374
     * @param array  $params
375
     * @param string $method
376
     * @param array  $options
377
     * @param bool   $returnResponse
378
     *
379
     * @return \EasyWeChat\Support\Collection|\Psr\Http\Message\ResponseInterface
380
     */
381 10
    protected function request($api, array $params, $method = 'post', array $options = [], $returnResponse = false)
382
    {
383 10
        $params = array_merge($params, $this->merchant->only(['sub_appid', 'sub_mch_id']));
384
385 10
        $params['appid'] = $this->merchant->app_id;
386 10
        $params['mch_id'] = $this->merchant->merchant_id;
387 10
        $params['device_info'] = $this->merchant->device_info;
388 10
        $params['nonce_str'] = uniqid();
389 10
        $params = array_filter($params);
390 10
        $params['sign'] = generate_sign($params, $this->merchant->key, 'md5');
391
392 10
        $options = array_merge([
393 10
            'body' => XML::build($params),
394 10
        ], $options);
395
396 10
        $response = $this->getHttp()->request($api, $method, $options);
397
398 10
        return $returnResponse ? $response : $this->parseResponse($response);
399
    }
400
401
    /**
402
     * Request with SSL.
403
     *
404
     * @param string $api
405
     * @param array  $params
406
     * @param string $method
407
     *
408
     * @return \EasyWeChat\Support\Collection
409
     */
410 2
    protected function safeRequest($api, array $params, $method = 'post')
411
    {
412
        $options = [
413 2
            'cert' => $this->merchant->get('cert_path'),
414 2
            'ssl_key' => $this->merchant->get('key_path'),
415 2
        ];
416
417 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 417 which is incompatible with the return type documented by EasyWeChat\Payment\API::safeRequest of type EasyWeChat\Support\Collection.
Loading history...
418
    }
419
420
    /**
421
     * Parse Response XML to array.
422
     *
423
     * @param string|\Psr\Http\Message\ResponseInterface $response
424
     *
425
     * @return \EasyWeChat\Support\Collection
426
     */
427 9
    protected function parseResponse($response)
428
    {
429 9
        if ($response instanceof ResponseInterface) {
430
            $response = $response->getBody();
431
        }
432
433 9
        return new Collection((array) XML::parse($response));
434
    }
435
}
436