Completed
Push — master ( 80f8c6...3cf7ad )
by Raza
01:59
created

PayPalRequest::refundTransaction()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 4
c 2
b 0
f 0
nc 1
nop 1
dl 0
loc 8
rs 9.4285
1
<?php
2
3
namespace Srmklive\PayPal\Traits;
4
5
use GuzzleHttp\Client as HttpClient;
6
use GuzzleHttp\Exception\BadResponseException as HttpBadResponseException;
7
use GuzzleHttp\Exception\ClientException as HttpClientException;
8
use GuzzleHttp\Exception\ServerException as HttpServerException;
9
use Illuminate\Support\Collection;
10
11
trait PayPalRequest
12
{
13
    /**
14
     * @var HttpClient
15
     */
16
    private $client;
17
18
    /**
19
     * @var \Illuminate\Support\Collection
20
     */
21
    protected $post;
22
23
    /**
24
     * @var array
25
     */
26
    private $config;
27
28
    /**
29
     * @var string
30
     */
31
    private $currency;
32
33
    /**
34
     * @var array
35
     */
36
    private $options;
37
38
    /**
39
     * @var string
40
     */
41
    private $paymentAction;
42
43
    /**
44
     * @var string
45
     */
46
    private $locale;
47
48
    /**
49
     * Function To Set PayPal API Configuration.
50
     *
51
     * @return void
52
     */
53
    private function setConfig()
54
    {
55
        // Setting Http Client
56
        $this->client = $this->setClient();
57
58
        // Set Api Credentials
59
        if (function_exists('config')) {
60
            $this->setApiCredentials(
61
                config('paypal')
62
            );
63
        }
64
65
        $this->post = $this->setRequestData();
0 ignored issues
show
Documentation Bug introduced by
It seems like $this->setRequestData() of type this<Srmklive\PayPal\Traits\PayPalRequest> is incompatible with the declared type object<Illuminate\Support\Collection> of property $post.

Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.

Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..

Loading history...
66
    }
67
68
    /**
69
     * Function to initialize Http Client.
70
     *
71
     * @return HttpClient
72
     */
73
    protected function setClient()
74
    {
75
        return new HttpClient([
76
            'curl' => [
77
                CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
78
            ],
79
        ]);
80
    }
81
82
    /**
83
     * Set PayPal API Credentials.
84
     *
85
     * @param array  $credentials
86
     * @param string $mode
87
     *
88
     * @return void
89
     */
90
    public function setApiCredentials($credentials, $mode = '')
91
    {
92
        // Setting Default PayPal Mode If not set
93
        if (empty($credentials['mode']) ||
94
            (!in_array($credentials['mode'], ['sandbox', 'live']))
95
        ) {
96
            $credentials['mode'] = 'live';
97
        }
98
99
        // Setting default mode.
100
        if (empty($mode)) {
101
            $mode = $credentials['mode'];
102
        }
103
104
        // Setting PayPal API Credentials
105
        foreach ($credentials[$mode] as $key => $value) {
106
            $this->config[$key] = $value;
107
        }
108
109
        // Setup PayPal API Signature value to use.
110
        if (!empty($this->config['secret'])) {
111
            $this->config['signature'] = $this->config['secret'];
112
        } else {
113
            $this->config['signature'] = file_get_contents($this->config['certificate']);
114
        }
115
116
        if ($this instanceof \Srmklive\PayPal\Services\AdaptivePayments) {
117
            $this->setAdaptivePaymentsOptions($mode);
0 ignored issues
show
Bug introduced by
The method setAdaptivePaymentsOptions() cannot be called from this context as it is declared protected in class Srmklive\PayPal\Traits\PayPalRequest.

This check looks for access to methods that are not accessible from the current context.

If you need to make a method accessible to another context you can raise its visibility level in the defining class.

Loading history...
118
        } else {
119
            $this->setExpressCheckoutOptions($credentials, $mode);
120
        }
121
122
        // Set default currency.
123
        $this->setCurrency($credentials['currency']);
124
125
        // Set default payment action.
126
        $this->paymentAction = !empty($this->config['payment_action']) ?
127
            $this->config['payment_action'] : 'Sale';
128
129
        // Set default locale.
130
        $this->locale = !empty($this->config['locale']) ?
131
            $this->config['locale'] : 'en_US';
132
    }
133
134
    /**
135
     * Setup request data to be sent to PayPal.
136
     *
137
     * @param array $data
138
     * @return $this
139
     */
140
    protected function setRequestData(array $data = [])
141
    {
142
        if (($this->post instanceof Collection) && ($this->post->isNotEmpty())) {
143
            unset($this->post);
144
        }
145
146
        $this->post = new Collection($data);
147
148
        return $this;
149
    }
150
151
    /**
152
     * Set other/override PayPal API parameters.
153
     *
154
     * @param array $options
155
     *
156
     * @return $this
157
     */
158
    public function addOptions(array $options)
159
    {
160
        $this->options = $options;
161
162
        return $this;
163
    }
164
165
    /**
166
     * Set ExpressCheckout API endpoints & options.
167
     *
168
     * @param array  $credentials
169
     * @param string $mode
170
     *
171
     * @return void
172
     */
173
    protected function setExpressCheckoutOptions($credentials, $mode)
174
    {
175
        // Setting API Endpoints
176
        if ($mode == 'sandbox') {
177
            $this->config['api_url'] = !empty($this->config['secret']) ?
178
                'https://api-3t.sandbox.paypal.com/nvp' : 'https://api.sandbox.paypal.com/nvp';
179
180
            $this->config['gateway_url'] = 'https://www.sandbox.paypal.com';
181
        } else {
182
            $this->config['api_url'] = !empty($this->config['secret']) ?
183
                'https://api-3t.paypal.com/nvp' : 'https://api.paypal.com/nvp';
184
185
            $this->config['gateway_url'] = 'https://www.paypal.com';
186
        }
187
188
        // Adding params outside sandbox / live array
189
        $this->config['payment_action'] = $credentials['payment_action'];
190
        $this->config['notify_url'] = $credentials['notify_url'];
191
        $this->config['locale'] = $credentials['locale'];
192
    }
193
194
    /**
195
     * Set AdaptivePayments API endpoints & options.
196
     *
197
     * @param string $mode
198
     *
199
     * @return void
200
     */
201
    protected function setAdaptivePaymentsOptions($mode)
202
    {
203
        if ($mode == 'sandbox') {
204
            $this->config['api_url'] = 'https://svcs.sandbox.paypal.com/AdaptivePayments';
205
            $this->config['gateway_url'] = 'https://www.sandbox.paypal.com/cgi-bin/webscr';
206
        } else {
207
            $this->config['api_url'] = 'https://svcs.paypal.com/AdaptivePayments';
208
            $this->config['gateway_url'] = 'https://www.paypal.com/cgi-bin/webscr';
209
        }
210
    }
211
212
    /**
213
     * Function to set currency.
214
     *
215
     * @param string $currency
216
     *
217
     * @throws \Exception
218
     *
219
     * @return $this
220
     */
221
    public function setCurrency($currency = 'USD')
222
    {
223
        $allowedCurrencies = ['AUD', 'BRL', 'CAD', 'CZK', 'DKK', 'EUR', 'HKD', 'HUF', 'ILS', 'JPY', 'MYR', 'MXN', 'NOK', 'NZD', 'PHP', 'PLN', 'GBP', 'SGD', 'SEK', 'CHF', 'TWD', 'THB', 'USD', 'RUB'];
224
225
        // Check if provided currency is valid.
226
        if (!in_array($currency, $allowedCurrencies)) {
227
            throw new \Exception('Currency is not supported by PayPal.');
228
        }
229
230
        $this->currency = $currency;
231
232
        return $this;
233
    }
234
235
    /**
236
     * Retrieve PayPal IPN Response.
237
     *
238
     * @param array $post
239
     *
240
     * @return array
241
     */
242
    public function verifyIPN($post)
243
    {
244
        $this->setRequestData($post);
245
246
        return $this->doPayPalRequest('verifyipn');
247
    }
248
249
    /**
250
     * Refund PayPal Transaction.
251
     *
252
     * @param string $transaction
253
     *
254
     * @return array
255
     */
256
    public function refundTransaction($transaction)
257
    {
258
        $this->setRequestData([
259
            'TRANSACTIONID' => $transaction,
260
        ]);
261
262
        return $this->doPayPalRequest('RefundTransaction');
263
    }
264
265
    /**
266
     * Search Transactions On PayPal.
267
     *
268
     * @param array $post
269
     *
270
     * @return array
271
     */
272
    public function searchTransactions($post)
273
    {
274
        $this->setRequestData($post);
275
276
        return $this->doPayPalRequest('TransactionSearch');
277
    }
278
279
    /**
280
     * Function To Perform PayPal API Request.
281
     *
282
     * @param string $method
283
     *
284
     * @throws \Exception
285
     *
286
     * @return array|\Psr\Http\Message\StreamInterface
287
     */
288
    private function doPayPalRequest($method)
289
    {
290
        // Check configuration settings. Reset them if empty.
291
        if (empty($this->config)) {
292
            self::setConfig();
293
        }
294
295
        // Throw exception if configuration is still not set.
296
        if (empty($this->config)) {
297
            throw new \Exception('PayPal api settings not found.');
298
        }
299
300
        // Setting API Credentials, Version & Method
301
        $this->post->merge([
302
            'USER'      => $this->config['username'],
303
            'PWD'       => $this->config['password'],
304
            'SIGNATURE' => $this->config['signature'],
305
            'VERSION'   => 123,
306
            'METHOD'    => $method,
307
        ]);
308
309
        // Checking Whether The Request Is PayPal IPN Response
310
        if ($method == 'verifyipn') {
311
            $this->post = $this->post->filter(function($value, $key) {
312
                if ($key !== 'METHOD') {
313
                    return $value;
314
                }
315
            });
316
317
            $post_url = $this->config['gateway_url'].'/cgi-bin/webscr';
318
        } else {
319
            $post_url = $this->config['api_url'];
320
        }
321
322
        // Merge $options array if set.
323
        if (!empty($this->options)) {
324
            $this->post->merge($this->options);
325
        }
326
327
        try {
328
            $request = $this->client->post($post_url, [
329
                'form_params' => $this->post->toArray(),
330
            ]);
331
332
            $response = $request->getBody(true);
333
334
            return ($method == 'verifyipn') ? $response : $this->retrieveData($response);
335
        } catch (HttpClientException $e) {
336
            throw new \Exception($e->getRequest().' '.$e->getResponse());
337
        } catch (HttpServerException $e) {
338
            throw new \Exception($e->getRequest().' '.$e->getResponse());
339
        } catch (HttpBadResponseException $e) {
340
            throw new \Exception($e->getRequest().' '.$e->getResponse());
341
        } catch (\Exception $e) {
342
            $message = $e->getMessage();
343
        }
344
345
        return [
346
            'type'      => 'error',
347
            'message'   => $message,
348
        ];
349
    }
350
351
    /**
352
     * Parse PayPal NVP Response.
353
     *
354
     * @param string $request
355
     * @param array  $response
356
     *
357
     * @return array
358
     */
359
    private function retrieveData($request, array $response = null)
360
    {
361
        parse_str($request, $response);
362
363
        return $response;
364
    }
365
}
366