Completed
Push — master ( 8b1c68...7c567b )
by Raza
02:11
created

PayPalRequest::verifyIPN()   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
     * Http Client class object.
15
     *
16
     * @var HttpClient
17
     */
18
    private $client;
19
20
    /**
21
     * PayPal API mode to be used.
22
     *
23
     * @var string
24
     */
25
    public $mode;
26
27
    /**
28
     * Request data to be sent to PayPal.
29
     *
30
     * @var \Illuminate\Support\Collection
31
     */
32
    protected $post;
33
34
    /**
35
     * PayPal API configuration.
36
     *
37
     * @var array
38
     */
39
    private $config;
40
41
    /**
42
     * Default currency for PayPal.
43
     *
44
     * @var string
45
     */
46
    private $currency;
47
48
    /**
49
     * Additional options for PayPal API request.
50
     *
51
     * @var array
52
     */
53
    private $options;
54
55
    /**
56
     * Default payment action for PayPal.
57
     *
58
     * @var string
59
     */
60
    private $paymentAction;
61
62
    /**
63
     * Default locale for PayPal.
64
     *
65
     * @var string
66
     */
67
    private $locale;
68
69
    /**
70
     * PayPal API Endpoint.
71
     *
72
     * @var string
73
     */
74
    private $apiUrl;
75
76
    /**
77
     * IPN notification url for PayPal.
78
     *
79
     * @var string
80
     */
81
    private $notifyUrl;
82
83
    /**
84
     * Http Client request body parameter name.
85
     *
86
     * @var string
87
     */
88
    private $httpBodyParam;
89
90
    /**
91
     * Function To Set PayPal API Configuration.
92
     *
93
     * @param array $config
94
     *
95
     * @return void
96
     */
97
    private function setConfig(array $config = [])
98
    {
99
        // Setting Http Client
100
        $this->client = $this->setClient();
101
102
        // Set Api Credentials
103
        if (function_exists('config')) {
104
            $this->setApiCredentials(
105
                config('paypal')
106
            );
107
        } elseif (!empty($config)) {
108
            $this->setApiCredentials($config);
109
        }
110
111
        // Set options to be empty.
112
        $this->options = [];
113
114
        $this->setRequestData();
115
    }
116
117
    /**
118
     * Function to initialize Http Client.
119
     *
120
     * @return HttpClient
121
     */
122
    protected function setClient()
123
    {
124
        return new HttpClient([
125
            'curl' => [
126
                CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
127
            ],
128
        ]);
129
    }
130
131
    /**
132
     * Set PayPal API Credentials.
133
     *
134
     * @param array $credentials
135
     *
136
     * @throws \Exception
137
     *
138
     * @return void
139
     */
140
    public function setApiCredentials($credentials)
141
    {
142
        // Setting Default PayPal Mode If not set
143
        $this->setApiEnvironment($credentials);
144
145
        // Set API configuration for the PayPal provider
146
        $this->setApiProviderConfiguration($credentials);
147
148
        // Set default currency.
149
        $this->setCurrency($credentials['currency']);
150
151
        // Set default payment action.
152
        $this->paymentAction = $this->config['payment_action'];
153
154
        // Set default locale.
155
        $this->locale = $this->config['locale'];
156
157
        // Set PayPal API Endpoint.
158
        $this->apiUrl = $this->config['api_url'];
159
160
        // Set PayPal IPN Notification URL
161
        $this->notifyUrl = $credentials['notify_url'];
162
    }
163
164
    /**
165
     * Set API environment to be used by PayPal.
166
     *
167
     * @param array $credentials
168
     *
169
     * @return void
170
     */
171
    private function setApiEnvironment($credentials)
172
    {
173
        if (empty($credentials['mode']) || !in_array($credentials['mode'], ['sandbox', 'live'])) {
174
            $this->mode = 'live';
175
        } else {
176
            $this->mode = $credentials['mode'];
177
        }
178
    }
179
180
    /**
181
     * Set configuration details for the provider.
182
     *
183
     * @param array $credentials
184
     *
185
     * @throws \Exception
186
     *
187
     * @return void
188
     */
189
    private function setApiProviderConfiguration($credentials)
190
    {
191
        // Setting PayPal API Credentials
192
        collect($credentials[$this->mode])->map(function ($value, $key) {
193
            $this->config[$key] = $value;
194
        });
195
196
        // Setup PayPal API Signature value to use.
197
        $this->config['signature'] = empty($this->config['certificate']) ?
198
            $this->config['secret'] : file_get_contents($this->config['certificate']);
199
200
        if ($this instanceof \Srmklive\PayPal\Services\AdaptivePayments) {
201
            $this->setAdaptivePaymentsOptions();
202
        } elseif ($this instanceof \Srmklive\PayPal\Services\ExpressCheckout) {
203
            $this->setExpressCheckoutOptions($credentials);
0 ignored issues
show
Unused Code introduced by
The call to ExpressCheckout::setExpressCheckoutOptions() has too many arguments starting with $credentials.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
204
        } else {
205
            throw new \Exception('Invalid api credentials provided for PayPal!. Please provide the right api credentials.');
206
        }
207
208
        if (empty($credentials['payment_action'])) {
209
            $credentials['payment_action'] = 'Sale';
210
        }
211
212
        if (empty($credentials['locale'])) {
213
            $credentials['locale'] = 'en_US';
214
        }
215
216
        // Adding params outside sandbox / live array
217
        $this->config['payment_action'] = $credentials['payment_action'];
218
        $this->config['notify_url'] = $credentials['notify_url'];
219
        $this->config['locale'] = $credentials['locale'];
220
    }
221
222
    /**
223
     * Setup request data to be sent to PayPal.
224
     *
225
     * @param array $data
226
     *
227
     * @return \Illuminate\Support\Collection
228
     */
229
    protected function setRequestData(array $data = [])
230
    {
231
        if (($this->post instanceof Collection) && ($this->post->isNotEmpty())) {
232
            unset($this->post);
233
        }
234
235
        $this->post = new Collection($data);
236
237
        return $this->post;
238
    }
239
240
    /**
241
     * Set other/override PayPal API parameters.
242
     *
243
     * @param array $options
244
     *
245
     * @return $this
246
     */
247
    public function addOptions(array $options)
248
    {
249
        $this->options = $options;
250
251
        return $this;
252
    }
253
254
    /**
255
     * Function to set currency.
256
     *
257
     * @param string $currency
258
     *
259
     * @throws \Exception
260
     *
261
     * @return $this
262
     */
263
    public function setCurrency($currency = 'USD')
264
    {
265
        $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'];
266
267
        // Check if provided currency is valid.
268
        if (!in_array($currency, $allowedCurrencies)) {
269
            throw new \Exception('Currency is not supported by PayPal.');
270
        }
271
272
        $this->currency = $currency;
273
274
        return $this;
275
    }
276
277
    /**
278
     * Retrieve PayPal IPN Response.
279
     *
280
     * @param array $post
281
     *
282
     * @return array
283
     */
284
    public function verifyIPN($post)
285
    {
286
        $this->setRequestData($post);
287
288
        $this->apiUrl = $this->config['gateway_url'].'/cgi-bin/webscr';
289
290
        return $this->doPayPalRequest('verifyipn');
291
    }
292
293
    /**
294
     * Refund PayPal Transaction.
295
     *
296
     * @param string $transaction
297
     * @param float  $amount
298
     *
299
     * @return array
300
     */
301
    public function refundTransaction($transaction, $amount = 0.00)
302
    {
303
        $this->setRequestData([
304
            'TRANSACTIONID' => $transaction,
305
        ]);
306
307
        if ($amount > 0) {
308
            $this->post->merge([
309
                'REFUNDTYPE' => 'Partial',
310
                'AMT'        => $amount,
311
            ]);
312
        }
313
314
        return $this->doPayPalRequest('RefundTransaction');
315
    }
316
317
    /**
318
     * Search Transactions On PayPal.
319
     *
320
     * @param array $post
321
     *
322
     * @return array
323
     */
324
    public function searchTransactions($post)
325
    {
326
        $this->setRequestData($post);
327
328
        return $this->doPayPalRequest('TransactionSearch');
329
    }
330
331
    /**
332
     * Create request payload to be sent to PayPal.
333
     *
334
     * @param string $method
335
     */
336
    private function createRequestPayload($method)
337
    {
338
        $config = array_merge([
339
            'USER'      => $this->config['username'],
340
            'PWD'       => $this->config['password'],
341
            'SIGNATURE' => $this->config['signature'],
342
            'VERSION'   => 123,
343
            'METHOD'    => $method,
344
        ], $this->options);
345
346
        $this->post = $this->post->merge($config)
347
            ->filter(function ($value, $key) use ($method) {
348
                return (($method === 'verifyipn') && ($key === 'METHOD')) ?: $value;
349
            });
350
    }
351
352
    /**
353
     * Perform PayPal API request & return response.
354
     *
355
     * @throws \Exception
356
     *
357
     * @return \Psr\Http\Message\StreamInterface
358
     */
359
    private function makeHttpRequest()
360
    {
361
        try {
362
            return $this->client->post($this->apiUrl, [
363
                $this->httpBodyParam => $this->post->toArray(),
364
            ])->getBody();
365
        } catch (HttpClientException $e) {
366
            throw new \Exception($e->getRequest().' '.$e->getResponse());
367
        } catch (HttpServerException $e) {
368
            throw new \Exception($e->getRequest().' '.$e->getResponse());
369
        } catch (HttpBadResponseException $e) {
370
            throw new \Exception($e->getRequest().' '.$e->getResponse());
371
        }
372
    }
373
374
    /**
375
     * Function To Perform PayPal API Request.
376
     *
377
     * @param string $method
378
     *
379
     * @throws \Exception
380
     *
381
     * @return array|\Psr\Http\Message\StreamInterface
382
     */
383
    private function doPayPalRequest($method)
384
    {
385
        // Setup PayPal API Request Payload
386
        $this->createRequestPayload($method);
387
388
        try {
389
            // Perform PayPal HTTP API request.
390
            $response = $this->makeHttpRequest();
391
392
            return $this->retrieveData($method, $response);
393
        } catch (\Exception $e) {
394
            $message = collect($e->getTrace())->implode('\n');
395
        }
396
397
        return [
398
            'type'      => 'error',
399
            'message'   => $message,
400
        ];
401
    }
402
403
    /**
404
     * Parse PayPal NVP Response.
405
     *
406
     * @param string $method
407
     * @param mixed  $response
408
     *
409
     * @return array
410
     */
411
    private function retrieveData($method, $response)
412
    {
413
        if ($method === 'verifyipn') {
414
            return $response;
415
        }
416
417
        parse_str($response, $output);
418
419
        return $output;
420
    }
421
}
422