Completed
Push — master ( 50fa90...02ff86 )
by Raza
02:18
created

PayPalRequest::setRequestData()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 10
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 3
eloc 5
c 0
b 0
f 0
nc 2
nop 1
dl 0
loc 10
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
    private $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
        // Setting PayPal API Credentials
146
        collect($credentials[$this->mode])->map(function ($value, $key) {
147
            $this->config[$key] = $value;
148
        });
149
150
        // Setup PayPal API Signature value to use.
151
        $this->config['signature'] = empty($this->config['certificate']) ?
152
            $this->config['secret'] : file_get_contents($this->config['certificate']);
153
154
        // Set API configuration for the PayPal provider
155
        $this->setApiProviderConfiguration($credentials);
156
157
        // Set default currency.
158
        $this->setCurrency($credentials['currency']);
159
160
        // Set default payment action.
161
        $this->paymentAction = !empty($this->config['payment_action']) ?
162
            $this->config['payment_action'] : 'Sale';
163
164
        // Set default locale.
165
        $this->locale = !empty($this->config['locale']) ?
166
            $this->config['locale'] : 'en_US';
167
168
        // Set PayPal API Endpoint.
169
        $this->apiUrl = $this->config['api_url'];
170
171
        // Set PayPal IPN Notification URL
172
        $this->notifyUrl = $credentials['notify_url'];
173
    }
174
175
    /**
176
     * Set API environment to be used by PayPal.
177
     *
178
     * @param array $credentials
179
     *
180
     * @return void
181
     */
182
    private function setApiEnvironment($credentials)
183
    {
184
        if (empty($credentials['mode']) || !in_array($credentials['mode'], ['sandbox', 'live'])) {
185
            $this->mode = 'live';
186
        } else {
187
            $this->mode = $credentials['mode'];
188
        }
189
    }
190
191
    /**
192
     * Set configuration details for the provider.
193
     *
194
     * @param array $credentials
195
     *
196
     * @throws \Exception
197
     *
198
     * @return void
199
     */
200
    private function setApiProviderConfiguration($credentials)
201
    {
202
        if ($this instanceof \Srmklive\PayPal\Services\AdaptivePayments) {
203
            $this->setAdaptivePaymentsOptions($this->mode);
0 ignored issues
show
Bug introduced by
The property mode cannot be accessed from this context as it is declared private in class Srmklive\PayPal\Traits\PayPalRequest.

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

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

Loading history...
204
        } elseif ($this instanceof \Srmklive\PayPal\Services\ExpressCheckout) {
205
            $this->setExpressCheckoutOptions($credentials, $this->mode);
0 ignored issues
show
Bug introduced by
The property mode cannot be accessed from this context as it is declared private in class Srmklive\PayPal\Traits\PayPalRequest.

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

If you need to make a property accessible to another context you can either raise its visibility level or provide an accessible getter in the defining class.

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