Completed
Push — master ( c4ee50...5b2a30 )
by Carlos
06:26 queued 03:11
created

API::refundByTransactionId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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