Completed
Push — master ( d3fec9...d4f8f7 )
by Raza
02:12
created

PayPalRequest::createRequestPayload()   A

Complexity

Conditions 3
Paths 1

Size

Total Lines 15
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

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