Completed
Push — master ( 0319e5...35d520 )
by Raza
03:46
created

src/Services/ExpressCheckout.php (1 issue)

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
3
namespace Srmklive\PayPal\Services;
4
5
use Illuminate\Support\Collection;
6
use Srmklive\PayPal\Traits\PayPalRequest as PayPalAPIRequest;
7
use Srmklive\PayPal\Traits\PayPalTransactions;
8
use Srmklive\PayPal\Traits\RecurringProfiles;
9
10
class ExpressCheckout
11
{
12
    // Integrate PayPal Request trait
13
    use PayPalAPIRequest, PayPalTransactions, RecurringProfiles;
14
15
    /**
16
     * ExpressCheckout constructor.
17
     *
18
     * @param array $config
19
     *
20
     * @throws \Exception
21
     */
22
    public function __construct(array $config = [])
23
    {
24
        // Setting PayPal API Credentials
25
        $this->setConfig($config);
26
27
        $this->httpBodyParam = 'form_params';
28
29
        $this->options = [];
30
    }
31
32
    /**
33
     * Set ExpressCheckout API endpoints & options.
34
     *
35
     * @param array $credentials
36
     *
37
     * @return void
38
     */
39
    public function setExpressCheckoutOptions($credentials)
40
    {
41
        // Setting API Endpoints
42
        if ($this->mode === 'sandbox') {
43
            $this->config['api_url'] = !empty($this->config['secret']) ?
44
                'https://api-3t.sandbox.paypal.com/nvp' : 'https://api.sandbox.paypal.com/nvp';
45
46
            $this->config['gateway_url'] = 'https://www.sandbox.paypal.com';
47
            $this->config['ipn_url'] = 'https://ipnpb.sandbox.paypal.com/cgi-bin/webscr';
48 View Code Duplication
        } else {
0 ignored issues
show
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
49
            $this->config['api_url'] = !empty($this->config['secret']) ?
50
                'https://api-3t.paypal.com/nvp' : 'https://api.paypal.com/nvp';
51
52
            $this->config['gateway_url'] = 'https://www.paypal.com';
53
            $this->config['ipn_url'] = 'https://ipnpb.paypal.com/cgi-bin/webscr';
54
        }
55
56
        // Adding params outside sandbox / live array
57
        $this->config['payment_action'] = $credentials['payment_action'];
58
        $this->config['notify_url'] = $credentials['notify_url'];
59
        $this->config['locale'] = $credentials['locale'];
60
    }
61
62
    /**
63
     * Set cart item details for PayPal.
64
     *
65
     * @param array $items
66
     *
67
     * @return \Illuminate\Support\Collection
68
     */
69
    protected function setCartItems($items)
70
    {
71
        return (new Collection($items))->map(function ($item, $num) {
72
            return [
73
                'L_PAYMENTREQUEST_0_NAME'.$num => $item['name'],
74
                'L_PAYMENTREQUEST_0_AMT'.$num  => $item['price'],
75
                'L_PAYMENTREQUEST_0_QTY'.$num  => isset($item['qty']) ? $item['qty'] : 1,
76
            ];
77
        })->flatMap(function ($value) {
78
            return $value;
79
        });
80
    }
81
82
    /**
83
     * Set Recurring payments details for SetExpressCheckout API call.
84
     *
85
     * @param array $data
86
     * @param bool  $subscription
87
     */
88
    protected function setExpressCheckoutRecurringPaymentConfig($data, $subscription = false)
89
    {
90
        $billingType = $this->billingType;
91
92
        // Overwrite billing type if $subscription flag is enabled
93
        if ($subscription) {
94
            $billingType = 'RecurringPayments';
95
        }
96
97
        // Send L_BILLINGTYPE0 and L_BILLINGAGREEMENTDESCRIPTION0 only if there is billing type
98
        if (isset($billingType)) {
99
            $this->post = $this->post->merge([
100
                'L_BILLINGTYPE0'                 => $billingType,
101
                'L_BILLINGAGREEMENTDESCRIPTION0' => !empty($data['subscription_desc']) ?
102
                    $data['subscription_desc'] : $data['invoice_description'],
103
            ]);
104
        }
105
    }
106
107
    /**
108
     * Set item subtotal if available.
109
     *
110
     * @param array $data
111
     */
112
    protected function setItemSubTotal($data)
113
    {
114
        $this->subtotal = isset($data['subtotal']) ? $data['subtotal'] : $data['total'];
115
    }
116
117
    /**
118
     * Set shipping amount if available.
119
     *
120
     * @param array $data
121
     */
122
    protected function setShippingAmount($data)
123
    {
124
        if (isset($data['shipping'])) {
125
            $this->post = $this->post->merge([
126
                'PAYMENTREQUEST_0_SHIPPINGAMT' => $data['shipping'],
127
            ]);
128
        }
129
    }
130
131
    /**
132
     * Set shipping discount if available.
133
     *
134
     * @param array $data
135
     */
136
    protected function setShippingDiscount($data)
137
    {
138
        if (isset($data['shipping_discount'])) {
139
            if ($data['shipping_discount'] > 0) {
140
                $data['shipping_discount'] *= -1;
141
            }
142
143
            $this->post = $this->post->merge([
144
                'PAYMENTREQUEST_0_SHIPDISCAMT' => $data['shipping_discount'],
145
                'PAYMENTREQUEST_0_AMT'         => round($data['total'] + $data['shipping_discount'], 2),
146
            ]);
147
        }
148
    }
149
150
    /**
151
     * Perform a SetExpressCheckout API call on PayPal.
152
     *
153
     * @param array $data
154
     * @param bool  $subscription
155
     *
156
     * @throws \Exception
157
     *
158
     * @return array|\Psr\Http\Message\StreamInterface
159
     */
160
    public function setExpressCheckout($data, $subscription = false)
161
    {
162
        $this->setItemSubTotal($data);
163
164
        $this->post = $this->setCartItems($data['items'])->merge([
165
            'PAYMENTREQUEST_0_ITEMAMT'       => $this->subtotal,
166
            'PAYMENTREQUEST_0_AMT'           => $data['total'],
167
            'PAYMENTREQUEST_0_PAYMENTACTION' => $this->paymentAction,
168
            'PAYMENTREQUEST_0_CURRENCYCODE'  => $this->currency,
169
            'PAYMENTREQUEST_0_DESC'          => $data['invoice_description'],
170
            'PAYMENTREQUEST_0_INVNUM'        => $data['invoice_id'],
171
            'NOSHIPPING'                     => 1,
172
            'RETURNURL'                      => $data['return_url'],
173
            'CANCELURL'                      => $data['cancel_url'],
174
            'LOCALE'                         => $this->locale,
175
        ]);
176
177
        $this->setShippingAmount($data);
178
179
        $this->setShippingDiscount($data);
180
181
        $this->setExpressCheckoutRecurringPaymentConfig($data, $subscription);
182
183
        $response = $this->doPayPalRequest('SetExpressCheckout');
184
185
        return collect($response)->merge([
186
            'paypal_link' => !empty($response['TOKEN']) ? $this->config['gateway_url'].'/webscr?cmd=_express-checkout&token='.$response['TOKEN'] : null,
187
        ])->toArray();
188
    }
189
190
    /**
191
     * Perform a GetExpressCheckoutDetails API call on PayPal.
192
     *
193
     * @param string $token
194
     *
195
     * @throws \Exception
196
     *
197
     * @return array|\Psr\Http\Message\StreamInterface
198
     */
199
    public function getExpressCheckoutDetails($token)
200
    {
201
        $this->setRequestData([
202
            'TOKEN' => $token,
203
        ]);
204
205
        return $this->doPayPalRequest('GetExpressCheckoutDetails');
206
    }
207
208
    /**
209
     * Perform DoExpressCheckoutPayment API call on PayPal.
210
     *
211
     * @param array  $data
212
     * @param string $token
213
     * @param string $payerid
214
     *
215
     * @throws \Exception
216
     *
217
     * @return array|\Psr\Http\Message\StreamInterface
218
     */
219
    public function doExpressCheckoutPayment($data, $token, $payerid)
220
    {
221
        $this->setItemSubTotal($data);
222
223
        $this->post = $this->setCartItems($data['items'])->merge([
224
            'TOKEN'                          => $token,
225
            'PAYERID'                        => $payerid,
226
            'PAYMENTREQUEST_0_ITEMAMT'       => $this->subtotal,
227
            'PAYMENTREQUEST_0_AMT'           => $data['total'],
228
            'PAYMENTREQUEST_0_PAYMENTACTION' => !empty($this->config['payment_action']) ? $this->config['payment_action'] : 'Sale',
229
            'PAYMENTREQUEST_0_CURRENCYCODE'  => $this->currency,
230
            'PAYMENTREQUEST_0_DESC'          => $data['invoice_description'],
231
            'PAYMENTREQUEST_0_INVNUM'        => $data['invoice_id'],
232
            'PAYMENTREQUEST_0_NOTIFYURL'     => $this->notifyUrl,
233
        ]);
234
235
        $this->setShippingAmount($data);
236
237
        return $this->doPayPalRequest('DoExpressCheckoutPayment');
238
    }
239
240
    /**
241
     * Perform a DoAuthorization API call on PayPal.
242
     *
243
     * @param string $authorization_id Transaction ID
244
     * @param float  $amount           Amount to capture
245
     * @param array  $data             Optional request fields
246
     *
247
     * @throws \Exception
248
     *
249
     * @return array|\Psr\Http\Message\StreamInterface
250
     */
251
    public function doAuthorization($authorization_id, $amount, $data = [])
252
    {
253
        $this->setRequestData(
254
            array_merge($data, [
255
                'AUTHORIZATIONID' => $authorization_id,
256
                'AMT'             => $amount,
257
            ])
258
        );
259
260
        return $this->doPayPalRequest('DoAuthorization');
261
    }
262
263
    /**
264
     * Perform a DoCapture API call on PayPal.
265
     *
266
     * @param string $authorization_id Transaction ID
267
     * @param float  $amount           Amount to capture
268
     * @param string $complete         Indicates whether or not this is the last capture.
269
     * @param array  $data             Optional request fields
270
     *
271
     * @throws \Exception
272
     *
273
     * @return array|\Psr\Http\Message\StreamInterface
274
     */
275
    public function doCapture($authorization_id, $amount, $complete = 'Complete', $data = [])
276
    {
277
        $this->setRequestData(
278
            array_merge($data, [
279
                'AUTHORIZATIONID' => $authorization_id,
280
                'AMT'             => $amount,
281
                'COMPLETETYPE'    => $complete,
282
                'CURRENCYCODE'    => $this->currency,
283
            ])
284
        );
285
286
        return $this->doPayPalRequest('DoCapture');
287
    }
288
289
    /**
290
     * Perform a DoReauthorization API call on PayPal to reauthorize an existing authorization transaction.
291
     *
292
     * @param string $authorization_id
293
     * @param float  $amount
294
     * @param array  $data
295
     *
296
     * @throws \Exception
297
     *
298
     * @return array|\Psr\Http\Message\StreamInterface
299
     */
300
    public function doReAuthorization($authorization_id, $amount, $data = [])
301
    {
302
        $this->setRequestData(
303
            array_merge($data, [
304
                'AUTHORIZATIONID' => $authorization_id,
305
                'AMOUNT'          => $amount,
306
            ])
307
        );
308
309
        return $this->doPayPalRequest('DoReauthorization');
310
    }
311
312
    /**
313
     * Perform a DoVoid API call on PayPal.
314
     *
315
     * @param string $authorization_id Transaction ID
316
     * @param array  $data             Optional request fields
317
     *
318
     * @throws \Exception
319
     *
320
     * @return array|\Psr\Http\Message\StreamInterface
321
     */
322
    public function doVoid($authorization_id, $data = [])
323
    {
324
        $this->setRequestData(
325
            array_merge($data, [
326
                'AUTHORIZATIONID' => $authorization_id,
327
            ])
328
        );
329
330
        return $this->doPayPalRequest('DoVoid');
331
    }
332
333
    /**
334
     * Perform a CreateBillingAgreement API call on PayPal.
335
     *
336
     * @param string $token
337
     *
338
     * @throws \Exception
339
     *
340
     * @return array|\Psr\Http\Message\StreamInterface
341
     */
342
    public function createBillingAgreement($token)
343
    {
344
        $this->setRequestData([
345
            'TOKEN' => $token,
346
        ]);
347
348
        return $this->doPayPalRequest('CreateBillingAgreement');
349
    }
350
351
    /**
352
     * Perform a CreateRecurringPaymentsProfile API call on PayPal.
353
     *
354
     * @param array  $data
355
     * @param string $token
356
     *
357
     * @throws \Exception
358
     *
359
     * @return array|\Psr\Http\Message\StreamInterface
360
     */
361
    public function createRecurringPaymentsProfile($data, $token)
362
    {
363
        $this->post = $this->setRequestData($data)->merge([
364
            'TOKEN' => $token,
365
        ]);
366
367
        return $this->doPayPalRequest('CreateRecurringPaymentsProfile');
368
    }
369
370
    /**
371
     * Perform a GetRecurringPaymentsProfileDetails API call on PayPal.
372
     *
373
     * @param string $id
374
     *
375
     * @throws \Exception
376
     *
377
     * @return array|\Psr\Http\Message\StreamInterface
378
     */
379
    public function getRecurringPaymentsProfileDetails($id)
380
    {
381
        $this->setRequestData([
382
            'PROFILEID' => $id,
383
        ]);
384
385
        return $this->doPayPalRequest('GetRecurringPaymentsProfileDetails');
386
    }
387
388
    /**
389
     * Perform a UpdateRecurringPaymentsProfile API call on PayPal.
390
     *
391
     * @param array  $data
392
     * @param string $id
393
     *
394
     * @throws \Exception
395
     *
396
     * @return array|\Psr\Http\Message\StreamInterface
397
     */
398
    public function updateRecurringPaymentsProfile($data, $id)
399
    {
400
        $this->post = $this->setRequestData($data)->merge([
401
            'PROFILEID' => $id,
402
        ]);
403
404
        return $this->doPayPalRequest('UpdateRecurringPaymentsProfile');
405
    }
406
407
    /**
408
     * Change Recurring payment profile status on PayPal.
409
     *
410
     * @param string $id
411
     * @param string $status
412
     *
413
     * @throws \Exception
414
     *
415
     * @return array|\Psr\Http\Message\StreamInterface
416
     */
417
    protected function manageRecurringPaymentsProfileStatus($id, $status)
418
    {
419
        $this->setRequestData([
420
            'PROFILEID' => $id,
421
            'ACTION'    => $status,
422
        ]);
423
424
        return $this->doPayPalRequest('ManageRecurringPaymentsProfileStatus');
425
    }
426
427
    /**
428
     * Perform a ManageRecurringPaymentsProfileStatus API call on PayPal to cancel a RecurringPaymentsProfile.
429
     *
430
     * @param string $id
431
     *
432
     * @throws \Exception
433
     *
434
     * @return array|\Psr\Http\Message\StreamInterface
435
     */
436
    public function cancelRecurringPaymentsProfile($id)
437
    {
438
        return $this->manageRecurringPaymentsProfileStatus($id, 'Cancel');
439
    }
440
441
    /**
442
     * Perform a ManageRecurringPaymentsProfileStatus API call on PayPal to suspend a RecurringPaymentsProfile.
443
     *
444
     * @param string $id
445
     *
446
     * @throws \Exception
447
     *
448
     * @return array|\Psr\Http\Message\StreamInterface
449
     */
450
    public function suspendRecurringPaymentsProfile($id)
451
    {
452
        return $this->manageRecurringPaymentsProfileStatus($id, 'Suspend');
453
    }
454
455
    /**
456
     * Perform a ManageRecurringPaymentsProfileStatus API call on PayPal to reactivate a RecurringPaymentsProfile.
457
     *
458
     * @param string $id
459
     *
460
     * @throws \Exception
461
     *
462
     * @return array|\Psr\Http\Message\StreamInterface
463
     */
464
    public function reactivateRecurringPaymentsProfile($id)
465
    {
466
        return $this->manageRecurringPaymentsProfileStatus($id, 'Reactivate');
467
    }
468
}
469