Completed
Push — master ( 9ecbd8...e429fc )
by Raza
02:03
created

PayPalRequest::searchTransactions()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
cc 1
eloc 3
nc 1
nop 1
dl 0
loc 6
rs 9.4285
c 2
b 0
f 0
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
        $this->setRequestData();
112
    }
113
114
    /**
115
     * Function to initialize Http Client.
116
     *
117
     * @return HttpClient
118
     */
119
    protected function setClient()
120
    {
121
        return new HttpClient([
122
            'curl' => [
123
                CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1_2,
124
            ],
125
        ]);
126
    }
127
128
    /**
129
     * Set PayPal API Credentials.
130
     *
131
     * @param array $credentials
132
     *
133
     * @throws \Exception
134
     *
135
     * @return void
136
     */
137
    public function setApiCredentials($credentials)
138
    {
139
        // Setting Default PayPal Mode If not set
140
        $this->setApiEnvironment($credentials);
141
142
        // Set API configuration for the PayPal provider
143
        $this->setApiProviderConfiguration($credentials);
144
145
        // Set default currency.
146
        $this->setCurrency($credentials['currency']);
147
148
        // Set default payment action.
149
        $this->paymentAction = !empty($this->config['payment_action']) ? $this->config['payment_action'] : 'Sale';
150
151
        // Set default locale.
152
        $this->locale = !empty($this->config['locale']) ? $this->config['locale'] : 'en_US';
153
154
        // Set PayPal API Endpoint.
155
        $this->apiUrl = $this->config['api_url'];
156
157
        // Set PayPal IPN Notification URL
158
        $this->notifyUrl = $credentials['notify_url'];
159
    }
160
161
    /**
162
     * Set API environment to be used by PayPal.
163
     *
164
     * @param array $credentials
165
     *
166
     * @return void
167
     */
168
    private function setApiEnvironment($credentials)
169
    {
170
        if (empty($credentials['mode']) || !in_array($credentials['mode'], ['sandbox', 'live'])) {
171
            $this->mode = 'live';
172
        } else {
173
            $this->mode = $credentials['mode'];
174
        }
175
    }
176
177
    /**
178
     * Set configuration details for the provider.
179
     *
180
     * @param array $credentials
181
     *
182
     * @throws \Exception
183
     *
184
     * @return void
185
     */
186
    private function setApiProviderConfiguration($credentials)
187
    {
188
        // Setting PayPal API Credentials
189
        collect($credentials[$this->mode])->map(function ($value, $key) {
190
            $this->config[$key] = $value;
191
        });
192
193
        // Setup PayPal API Signature value to use.
194
        $this->config['signature'] = empty($this->config['certificate']) ?
195
            $this->config['secret'] : file_get_contents($this->config['certificate']);
196
197
        if ($this instanceof \Srmklive\PayPal\Services\AdaptivePayments) {
198
            $this->setAdaptivePaymentsOptions();
199
        } elseif ($this instanceof \Srmklive\PayPal\Services\ExpressCheckout) {
200
            $this->setExpressCheckoutOptions($credentials);
201
        } else {
202
            throw new \Exception('Invalid api credentials provided for PayPal!. Please provide the right api credentials.');
203
        }
204
    }
205
206
    /**
207
     * Setup request data to be sent to PayPal.
208
     *
209
     * @param array $data
210
     *
211
     * @return \Illuminate\Support\Collection
212
     */
213
    protected function setRequestData(array $data = [])
214
    {
215
        if (($this->post instanceof Collection) && (!$this->post->isEmpty())) {
216
            unset($this->post);
217
        }
218
219
        $this->post = new Collection($data);
220
221
        return $this->post;
222
    }
223
224
    /**
225
     * Set other/override PayPal API parameters.
226
     *
227
     * @param array $options
228
     *
229
     * @return $this
230
     */
231
    public function addOptions(array $options)
232
    {
233
        $this->options = $options;
234
235
        return $this;
236
    }
237
238
    /**
239
     * Function to set currency.
240
     *
241
     * @param string $currency
242
     *
243
     * @throws \Exception
244
     *
245
     * @return $this
246
     */
247
    public function setCurrency($currency = 'USD')
248
    {
249
        $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'];
250
251
        // Check if provided currency is valid.
252
        if (!in_array($currency, $allowedCurrencies)) {
253
            throw new \Exception('Currency is not supported by PayPal.');
254
        }
255
256
        $this->currency = $currency;
257
258
        return $this;
259
    }
260
261
    /**
262
     * Retrieve PayPal IPN Response.
263
     *
264
     * @param array $post
265
     *
266
     * @return array
267
     */
268
    public function verifyIPN($post)
269
    {
270
        $this->setRequestData($post);
271
272
        $this->apiUrl = $this->config['gateway_url'].'/cgi-bin/webscr';
273
274
        return $this->doPayPalRequest('verifyipn');
275
    }
276
277
    /**
278
     * Refund PayPal Transaction.
279
     *
280
     * @param string $transaction
281
     * @param float  $amount
282
     *
283
     * @return array
284
     */
285
    public function refundTransaction($transaction, $amount = 0.00)
286
    {
287
        $this->setRequestData([
288
            'TRANSACTIONID' => $transaction,
289
        ]);
290
291
        if ($amount > 0) {
292
            $this->post->merge([
293
                'REFUNDTYPE' => 'Partial',
294
                'AMT'        => $amount,
295
            ]);
296
        }
297
298
        return $this->doPayPalRequest('RefundTransaction');
299
    }
300
301
    /**
302
     * Search Transactions On PayPal.
303
     *
304
     * @param array $post
305
     *
306
     * @return array
307
     */
308
    public function searchTransactions($post)
309
    {
310
        $this->setRequestData($post);
311
312
        return $this->doPayPalRequest('TransactionSearch');
313
    }
314
315
    /**
316
     * Create request payload to be sent to PayPal.
317
     *
318
     * @param string $method
319
     */
320
    private function createRequestPayload($method)
321
    {
322
        $config = array_merge([
323
            'USER'      => $this->config['username'],
324
            'PWD'       => $this->config['password'],
325
            'SIGNATURE' => $this->config['signature'],
326
            'VERSION'   => 123,
327
            'METHOD'    => $method,
328
        ], $this->options);
329
330
        $this->post = $this->post->merge($config)
331
            ->filter(function ($value, $key) use ($method) {
332
                return (($method === 'verifyipn') && ($key === 'METHOD')) ?: $value;
333
            });
334
    }
335
336
    /**
337
     * Perform PayPal API request & return response.
338
     *
339
     * @throws \Exception
340
     *
341
     * @return \Psr\Http\Message\StreamInterface
342
     */
343
    private function makeHttpRequest()
344
    {
345
        try {
346
            return $this->client->post($this->apiUrl, [
347
                $this->httpBodyParam => $this->post->toArray(),
348
            ])->getBody();
349
        } catch (HttpClientException $e) {
350
            throw new \Exception($e->getRequest().' '.$e->getResponse());
351
        } catch (HttpServerException $e) {
352
            throw new \Exception($e->getRequest().' '.$e->getResponse());
353
        } catch (HttpBadResponseException $e) {
354
            throw new \Exception($e->getRequest().' '.$e->getResponse());
355
        }
356
    }
357
358
    /**
359
     * Function To Perform PayPal API Request.
360
     *
361
     * @param string $method
362
     *
363
     * @throws \Exception
364
     *
365
     * @return array|\Psr\Http\Message\StreamInterface
366
     */
367
    private function doPayPalRequest($method)
368
    {
369
        // Setup PayPal API Request Payload
370
        $this->createRequestPayload($method);
371
372
        try {
373
            // Perform PayPal HTTP API request.
374
            $response = $this->makeHttpRequest();
375
376
            return $this->retrieveData($method, $response);
377
        } catch (\Exception $e) {
378
            $message = collect($e->getTrace())->implode('\n');
379
        }
380
381
        return [
382
            'type'      => 'error',
383
            'message'   => $message,
384
        ];
385
    }
386
387
    /**
388
     * Parse PayPal NVP Response.
389
     *
390
     * @param string                                  $method
391
     * @param array|\Psr\Http\Message\StreamInterface $response
392
     *
393
     * @return array
394
     */
395
    private function retrieveData($method, $response)
396
    {
397
        if ($method === 'verifyipn') {
398
            return $response;
399
        }
400
401
        parse_str($response, $output);
402
403
        return $output;
404
    }
405
}
406