Completed
Branch BUG-11108-ticket-reserved-coun... (74c229)
by
unknown
11:53 queued 12s
created

EEG_Paypal_Express   D

Complexity

Total Complexity 68

Size/Duplication

Total Lines 661
Duplicated Lines 12.1 %

Coupling/Cohesion

Components 1
Dependencies 11

Importance

Changes 0
Metric Value
dl 80
loc 661
rs 4.2451
c 0
b 0
f 0
wmc 68
lcom 1
cbo 11

9 Methods

Rating   Name   Duplication   Size   Complexity  
B __construct() 0 31 1
A set_settings() 0 8 2
D set_redirection_info() 34 111 13
D handle_payment_update() 46 130 18
D itemize_list() 0 155 15
B _ppExpress_request() 0 26 1
D _ppExpress_check_response() 0 26 10
A _log_clean_request() 0 6 1
C _get_errors() 0 34 7

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complex Class

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like EEG_Paypal_Express often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use EEG_Paypal_Express, and based on these observations, apply Extract Interface, too.

1
<?php if (! defined('EVENT_ESPRESSO_VERSION')) {
2
    exit('NO direct script access allowed');
3
}
4
5
6
7
/**
8
 * ----------------------------------------------
9
 * Class  EEG_Paypal_Express
10
 *
11
 * @package            Event Espresso
12
 * @subpackage         eea-paypal-express
13
 * @author             Event Espresso
14
 * @version            $VID:$
15
 * ----------------------------------------------
16
 */
17
//Quickfix to address https://events.codebasehq.com/projects/event-espresso/tickets/11089 ASAP
18
if (! function_exists('mb_strcut')) {
19
    /**
20
     * Very simple mimic of mb_substr (which WP ensures exists in wp-includes/compat.php). Still has all the problems of mb_substr
21
     * (namely, that we might send too many characters to PayPal; however in this case they just issue a warning but nothing breaks)
22
     * @param $string
23
     * @param $start
24
     * @param $length
25
     * @return bool|string
26
     */
27
    function mb_strcut($string, $start, $length = null)
28
    {
29
        return mb_substr($string, $start, $length);
30
    }
31
}
32
class EEG_Paypal_Express extends EE_Offsite_Gateway
33
{
34
35
    /**
36
     * Merchant API Username.
37
     *
38
     * @var string
39
     */
40
    protected $_api_username;
41
42
    /**
43
     * Merchant API Password.
44
     *
45
     * @var string
46
     */
47
    protected $_api_password;
48
49
    /**
50
     * API Signature.
51
     *
52
     * @var string
53
     */
54
    protected $_api_signature;
55
56
    /**
57
     * Request Shipping address on PP checkout page.
58
     *
59
     * @var string
60
     */
61
    protected $_request_shipping_addr;
62
63
    /**
64
     * Business/personal logo.
65
     *
66
     * @var string
67
     */
68
    protected $_image_url;
69
70
    /**
71
     * gateway URL variable
72
     *
73
     * @var string
74
     */
75
    protected $_base_gateway_url = '';
76
77
78
79
    /**
80
     * EEG_Paypal_Express constructor.
81
     */
82
    public function __construct()
83
    {
84
        $this->_currencies_supported = array(
85
            'USD',
86
            'AUD',
87
            'BRL',
88
            'CAD',
89
            'CZK',
90
            'DKK',
91
            'EUR',
92
            'HKD',
93
            'HUF',
94
            'ILS',
95
            'JPY',
96
            'MYR',
97
            'MXN',
98
            'NOK',
99
            'NZD',
100
            'PHP',
101
            'PLN',
102
            'GBP',
103
            'RUB',
104
            'SGD',
105
            'SEK',
106
            'CHF',
107
            'TWD',
108
            'THB',
109
            'TRY',
110
        );
111
        parent::__construct();
112
    }
113
114
115
116
    /**
117
     * Sets the gateway URL variable based on whether debug mode is enabled or not.
118
     *
119
     * @param array $settings_array
120
     */
121
    public function set_settings($settings_array)
122
    {
123
        parent::set_settings($settings_array);
124
        // Redirect URL.
125
        $this->_base_gateway_url = $this->_debug_mode
126
            ? 'https://api-3t.sandbox.paypal.com/nvp'
127
            : 'https://api-3t.paypal.com/nvp';
128
    }
129
130
131
132
    /**
133
     * @param EEI_Payment $payment
134
     * @param array       $billing_info
135
     * @param string      $return_url
136
     * @param string      $notify_url
137
     * @param string      $cancel_url
138
     * @return \EE_Payment|\EEI_Payment
139
     * @throws \EE_Error
140
     */
141
    public function set_redirection_info(
142
        $payment,
143
        $billing_info = array(),
144
        $return_url = null,
145
        $notify_url = null,
146
        $cancel_url = null
147
    ) {
148 View Code Duplication
        if (! $payment instanceof EEI_Payment) {
149
            $payment->set_gateway_response(
150
                esc_html__(
151
                    'Error. No associated payment was found.',
152
                    'event_espresso'
153
                )
154
            );
155
            $payment->set_status($this->_pay_model->failed_status());
156
            return $payment;
157
        }
158
        $transaction = $payment->transaction();
159 View Code Duplication
        if (! $transaction instanceof EEI_Transaction) {
160
            $payment->set_gateway_response(
161
                esc_html__(
162
                    'Could not process this payment because it has no associated transaction.',
163
                    'event_espresso'
164
                )
165
            );
166
            $payment->set_status($this->_pay_model->failed_status());
167
            return $payment;
168
        }
169
        $order_description = mb_strcut($this->_format_order_description($payment), 0, 127);
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::_format_order_description() has been deprecated with message: since 4.9.31 instead use $this->_get_gateway_formatter()->formatOrderDescription($payment)

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
170
        $primary_registration = $transaction->primary_registration();
171
        $primary_attendee = $primary_registration instanceof EE_Registration
172
            ? $primary_registration->attendee()
173
            : false;
174
        $locale = explode('-', get_bloginfo('language'));
175
        // Gather request parameters.
176
        $token_request_dtls = array(
177
            'METHOD'                         => 'SetExpressCheckout',
178
            'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
179
            'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
180
            'PAYMENTREQUEST_0_DESC'          => $order_description,
181
            'RETURNURL'                      => $return_url,
182
            'CANCELURL'                      => $cancel_url,
183
            'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
184
            // Buyer does not need to create a PayPal account to check out.
185
            // This is referred to as PayPal Account Optional.
186
            'SOLUTIONTYPE'                   => 'Sole',
187
            //EE will blow up if you change this
188
            'BUTTONSOURCE'                   => 'EventEspresso_SP',
189
            // Locale of the pages displayed by PayPal during Express Checkout.
190
            'LOCALECODE'                     => $locale[1]
191
        );
192
        // Show itemized list.
193
        $itemized_list = $this->itemize_list($payment, $transaction);
194
        $token_request_dtls = array_merge($token_request_dtls, $itemized_list);
195
        // Automatically filling out shipping and contact information.
196
        if ($this->_request_shipping_addr && $primary_attendee instanceof EEI_Attendee) {
197
            // If you do not pass the shipping address, PayPal obtains it from the buyer's account profile.
198
            $token_request_dtls['NOSHIPPING'] = '2';
199
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET'] = $primary_attendee->address();
200
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTREET2'] = $primary_attendee->address2();
201
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCITY'] = $primary_attendee->city();
202
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOSTATE'] = $primary_attendee->state_abbrev();
203
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOCOUNTRYCODE'] = $primary_attendee->country_ID();
204
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOZIP'] = $primary_attendee->zip();
205
            $token_request_dtls['PAYMENTREQUEST_0_EMAIL'] = $primary_attendee->email();
206
            $token_request_dtls['PAYMENTREQUEST_0_SHIPTOPHONENUM'] = $primary_attendee->phone();
207
        } elseif (! $this->_request_shipping_addr) {
208
            // Do not request shipping details on the PP Checkout page.
209
            $token_request_dtls['NOSHIPPING'] = '1';
210
            $token_request_dtls['REQCONFIRMSHIPPING'] = '0';
211
        }
212
        // Used a business/personal logo on the PayPal page.
213
        if (! empty($this->_image_url)) {
214
            $token_request_dtls['LOGOIMG'] = $this->_image_url;
215
        }
216
        $token_request_dtls = apply_filters(
217
            'FHEE__EEG_Paypal_Express__set_redirection_info__arguments',
218
            $token_request_dtls,
219
            $this
220
        );
221
        // Request PayPal token.
222
        $token_request_response = $this->_ppExpress_request($token_request_dtls, 'Payment Token', $payment);
223
        $token_rstatus = $this->_ppExpress_check_response($token_request_response);
224
        $response_args = (isset($token_rstatus['args']) && is_array($token_rstatus['args']))
225
            ? $token_rstatus['args']
226
            : array();
227
        if ($token_rstatus['status']) {
228
            // We got the Token so we may continue with the payment and redirect the client.
229
            $payment->set_details($response_args);
230
            $gateway_url = $this->_debug_mode ? 'https://www.sandbox.paypal.com' : 'https://www.paypal.com';
231
            $payment->set_redirect_url(
232
                $gateway_url
233
                . '/checkoutnow?useraction=commit&cmd=_express-checkout&token='
234
                . $response_args['TOKEN']
235
            );
236 View Code Duplication
        } else {
237
            if (isset($response_args['L_ERRORCODE'])) {
238
                $payment->set_gateway_response($response_args['L_ERRORCODE'] . '; ' . $response_args['L_SHORTMESSAGE']);
239
            } else {
240
                $payment->set_gateway_response(
241
                    esc_html__(
242
                        'Error occurred while trying to setup the Express Checkout.',
243
                        'event_espresso'
244
                    )
245
                );
246
            }
247
            $payment->set_details($response_args);
248
            $payment->set_status($this->_pay_model->failed_status());
249
        }
250
        return $payment;
251
    }
252
253
254
255
    /**
256
     * @param array           $update_info {
257
     * @type string           $gateway_txn_id
258
     * @type string status an EEMI_Payment status
259
     *                                     }
260
     * @param EEI_Transaction $transaction
261
     * @return EEI_Payment
262
     */
263
    public function handle_payment_update($update_info, $transaction)
264
    {
265
        $payment = $transaction instanceof EEI_Transaction ? $transaction->last_payment() : null;
266
        if ($payment instanceof EEI_Payment) {
267
            $this->log(array('Return from Authorization' => $update_info), $payment);
268
            $transaction = $payment->transaction();
269 View Code Duplication
            if (! $transaction instanceof EEI_Transaction) {
270
                $payment->set_gateway_response(
271
                    esc_html__(
272
                        'Could not process this payment because it has no associated transaction.',
273
                        'event_espresso'
274
                    )
275
                );
276
                $payment->set_status($this->_pay_model->failed_status());
277
                return $payment;
278
            }
279
            $primary_registrant = $transaction->primary_registration();
280
            $payment_details = $payment->details();
281
            // Check if we still have the token.
282
            if (! isset($payment_details['TOKEN']) || empty($payment_details['TOKEN'])) {
283
                $payment->set_status($this->_pay_model->failed_status());
284
                return $payment;
285
            }
286
            $cdetails_request_dtls = array(
287
                'METHOD' => 'GetExpressCheckoutDetails',
288
                'TOKEN'  => $payment_details['TOKEN'],
289
            );
290
            // Request Customer Details.
291
            $cdetails_request_response = $this->_ppExpress_request(
292
                $cdetails_request_dtls,
293
                'Customer Details',
294
                $payment
295
            );
296
            $cdetails_rstatus = $this->_ppExpress_check_response($cdetails_request_response);
297
            $cdata_response_args = (isset($cdetails_rstatus['args']) && is_array($cdetails_rstatus['args']))
298
                ? $cdetails_rstatus['args']
299
                : array();
300
            if ($cdetails_rstatus['status']) {
301
                // We got the PayerID so now we can Complete the transaction.
302
                $docheckout_request_dtls = array(
303
                    'METHOD'                         => 'DoExpressCheckoutPayment',
304
                    'PAYERID'                        => $cdata_response_args['PAYERID'],
305
                    'TOKEN'                          => $payment_details['TOKEN'],
306
                    'PAYMENTREQUEST_0_PAYMENTACTION' => 'Sale',
307
                    'PAYMENTREQUEST_0_AMT'           => $payment->amount(),
308
                    'PAYMENTREQUEST_0_CURRENCYCODE'  => $payment->currency_code(),
309
                    //EE will blow up if you change this
310
                    'BUTTONSOURCE'                   => 'EventEspresso_SP',
311
                );
312
                 // Include itemized list.
313
                $itemized_list = $this->itemize_list(
314
                    $payment,
315
                    $transaction,
316
                    $cdata_response_args
317
                );
318
                $docheckout_request_dtls = array_merge($docheckout_request_dtls, $itemized_list);
319
                // Payment Checkout/Capture.
320
                $docheckout_request_response = $this->_ppExpress_request(
321
                    $docheckout_request_dtls,
322
                    'Do Payment',
323
                    $payment
324
                );
325
                $docheckout_rstatus = $this->_ppExpress_check_response($docheckout_request_response);
326
                $docheckout_response_args = (isset($docheckout_rstatus['args']) && is_array($docheckout_rstatus['args']))
327
                    ? $docheckout_rstatus['args']
328
                    : array();
329
                if ($docheckout_rstatus['status']) {
330
                    // All is well, payment approved.
331
                    $primary_registration_code = $primary_registrant instanceof EE_Registration ?
332
                        $primary_registrant->reg_code()
333
                        : '';
334
                    $payment->set_extra_accntng($primary_registration_code);
335
                    $payment->set_amount(isset($docheckout_response_args['PAYMENTINFO_0_AMT'])
336
                        ? (float)$docheckout_response_args['PAYMENTINFO_0_AMT']
337
                        : 0);
338
                    $payment->set_txn_id_chq_nmbr(isset($docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID'])
339
                        ? $docheckout_response_args['PAYMENTINFO_0_TRANSACTIONID']
340
                        : null);
341
                    $payment->set_details($cdata_response_args);
342
                    $payment->set_gateway_response(isset($docheckout_response_args['PAYMENTINFO_0_ACK'])
343
                        ? $docheckout_response_args['PAYMENTINFO_0_ACK']
344
                        : '');
345
                    $payment->set_status($this->_pay_model->approved_status());
346 View Code Duplication
                } else {
347
                    if (isset($docheckout_response_args['L_ERRORCODE'])) {
348
                        $payment->set_gateway_response(
349
                            $docheckout_response_args['L_ERRORCODE']
350
                            . '; '
351
                            . $docheckout_response_args['L_SHORTMESSAGE']
352
                        );
353
                    } else {
354
                        $payment->set_gateway_response(
355
                            esc_html__(
356
                                'Error occurred while trying to Capture the funds.',
357
                                'event_espresso'
358
                            )
359
                        );
360
                    }
361
                    $payment->set_details($docheckout_response_args);
362
                    $payment->set_status($this->_pay_model->declined_status());
363
                }
364 View Code Duplication
            } else {
365
                if (isset($cdata_response_args['L_ERRORCODE'])) {
366
                    $payment->set_gateway_response(
367
                        $cdata_response_args['L_ERRORCODE']
368
                        . '; '
369
                        . $cdata_response_args['L_SHORTMESSAGE']
370
                    );
371
                } else {
372
                    $payment->set_gateway_response(
373
                        esc_html__(
374
                            'Error occurred while trying to get payment Details from PayPal.',
375
                            'event_espresso'
376
                        )
377
                    );
378
                }
379
                $payment->set_details($cdata_response_args);
380
                $payment->set_status($this->_pay_model->failed_status());
381
            }
382
        } else {
383
            $payment->set_gateway_response(
384
                esc_html__(
385
                    'Error occurred while trying to process the payment.',
386
                    'event_espresso'
387
                )
388
            );
389
            $payment->set_status($this->_pay_model->failed_status());
390
        }
391
        return $payment;
392
    }
393
394
395
396
    /**
397
     *  Make a list of items that are in the giver transaction.
398
     *
399
     * @param EEI_Payment     $payment
400
     * @param EEI_Transaction $transaction
401
     * @param array           $request_response_args Data from a previous communication with PP.
402
     * @return array
403
     */
404
    public function itemize_list(EEI_Payment $payment, EEI_Transaction $transaction, $request_response_args = array())
405
    {
406
        $itemized_list = array();
407
        // If we have data from a previous communication with PP (on this transaction) we may use that for our list...
408
        if (
409
            ! empty($request_response_args)
410
            && array_key_exists('L_PAYMENTREQUEST_0_AMT0', $request_response_args)
411
            && array_key_exists('PAYMENTREQUEST_0_ITEMAMT', $request_response_args)
412
        ) {
413
            foreach ($request_response_args as $arg_key => $arg_val) {
414
                if (
415
                    strpos($arg_key, 'PAYMENTREQUEST_') !== false
416
                    && strpos($arg_key, 'NOTIFYURL') === false
417
                ) {
418
                    $itemized_list[$arg_key] = $arg_val;
419
                }
420
            }
421
            // If we got only a few Items then something is not right.
422
            if (count($itemized_list) > 2) {
423
                return $itemized_list;
424
            } else {
425
                if (WP_DEBUG) {
426
                    throw new EE_Error(
427
                        sprintf(
428
                            esc_html__(
429
                                // @codingStandardsIgnoreStart
430
                                'Unable to continue with the checkout because a proper purchase list could not be generated. The purchased list we could have sent was %1$s',
431
                                // @codingStandardsIgnoreEnd
432
                                'event_espresso'
433
                            ),
434
                            wp_json_encode($itemized_list)
435
                        )
436
                    );
437
                }
438
                // Reset the list and log an error, maybe allow to try and generate a new list (below).
439
                $itemized_list = array();
440
                $this->log(
441
                    array(
442
                        esc_html__(
443
                            'Could not generate a proper item list with:',
444
                            'event_espresso'
445
                        ) => $request_response_args
446
                    ),
447
                    $payment
448
                );
449
            }
450
        }
451
        // ...otherwise we generate a new list for this transaction.
452
        if ($this->_money->compare_floats($payment->amount(), $transaction->total(), '==')) {
453
            $item_num = 0;
454
            $itemized_sum = 0;
455
            $total_line_items = $transaction->total_line_item();
456
            // Go through each item in the list.
457
            foreach ($total_line_items->get_items() as $line_item) {
458
                if ($line_item instanceof EE_Line_Item) {
459
                    // PayPal doesn't like line items with 0.00 amount, so we may skip those.
460
                    if (EEH_Money::compare_floats($line_item->total(), '0.00', '==')) {
461
                        continue;
462
                    }
463
                    $unit_price = $line_item->unit_price();
464
                    $line_item_quantity = $line_item->quantity();
465
                    // This is a discount.
466
                    if ($line_item->is_percent()) {
467
                        $unit_price = $line_item->total();
468
                        $line_item_quantity = 1;
469
                    }
470
                    // Item Name.
471
                    $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
472
                        $this->_format_line_item_name($line_item, $payment),
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::_format_line_item_name() has been deprecated with message: since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemName($line_item,$payment)

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
473
                        0,
474
                        127
475
                    );
476
                    // Item description.
477
                    $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = mb_strcut(
478
                        $this->_format_line_item_desc($line_item, $payment),
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::_format_line_item_desc() has been deprecated with message: since 4.9.31 instead use $this->_get_gateway_formatter()->formatLineItemDesc($line_item, $payment))

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
479
                        0,
480
                        127
481
                    );
482
                    // Cost of individual item.
483
                    $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $this->format_currency($unit_price);
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::format_currency() has been deprecated with message: since 4.9.31 insetad use EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
484
                    // Item Number.
485
                    $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
486
                    // Item quantity.
487
                    $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = $line_item_quantity;
488
                    // Digital item is sold.
489
                    $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
490
                    $itemized_sum += $line_item->total();
491
                    ++$item_num;
492
                }
493
            }
494
            // Item's sales S/H and tax amount.
495
            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $total_line_items->get_items_total();
496
            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = $total_line_items->get_total_tax();
497
            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
498
            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
499
            $itemized_sum_diff_from_txn_total = round(
500
                $transaction->total() - $itemized_sum - $total_line_items->get_total_tax(),
501
                2
502
            );
503
            // If we were not able to recognize some item like promotion, surcharge or cancellation,
504
            // add the difference as an extra line item.
505
            if ($this->_money->compare_floats($itemized_sum_diff_from_txn_total, 0, '!=')) {
506
                // Item Name.
507
                $itemized_list['L_PAYMENTREQUEST_0_NAME' . $item_num] = mb_strcut(
508
                    esc_html__(
509
                        'Other (promotion/surcharge/cancellation)',
510
                        'event_espresso'
511
                    ),
512
                    0,
513
                    127
514
                );
515
                // Item description.
516
                $itemized_list['L_PAYMENTREQUEST_0_DESC' . $item_num] = '';
517
                // Cost of individual item.
518
                $itemized_list['L_PAYMENTREQUEST_0_AMT' . $item_num] = $this->format_currency(
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::format_currency() has been deprecated with message: since 4.9.31 insetad use EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
519
                    $itemized_sum_diff_from_txn_total
520
                );
521
                // Item Number.
522
                $itemized_list['L_PAYMENTREQUEST_0_NUMBER' . $item_num] = $item_num + 1;
523
                // Item quantity.
524
                $itemized_list['L_PAYMENTREQUEST_0_QTY' . $item_num] = 1;
525
                // Digital item is sold.
526
                $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY' . $item_num] = 'Physical';
527
                $item_num++;
528
            }
529
        } else {
530
            // Just one Item.
531
            // Item Name.
532
            $itemized_list['L_PAYMENTREQUEST_0_NAME0'] = mb_strcut(
533
                $this->_format_partial_payment_line_item_name($payment),
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::_format_part...ayment_line_item_name() has been deprecated with message: since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemName($payment)

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
534
                0,
535
                127
536
            );
537
            // Item description.
538
            $itemized_list['L_PAYMENTREQUEST_0_DESC0'] = mb_strcut(
539
                $this->_format_partial_payment_line_item_desc($payment),
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::_format_part...ayment_line_item_desc() has been deprecated with message: since 4.9.31 instead use $this->_get_gateway_formatter()->formatPartialPaymentLineItemDesc()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
540
                0,
541
                127
542
            );
543
            // Cost of individual item.
544
            $itemized_list['L_PAYMENTREQUEST_0_AMT0'] = $this->format_currency($payment->amount());
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::format_currency() has been deprecated with message: since 4.9.31 insetad use EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
545
            // Item Number.
546
            $itemized_list['L_PAYMENTREQUEST_0_NUMBER0'] = 1;
547
            // Item quantity.
548
            $itemized_list['L_PAYMENTREQUEST_0_QTY0'] = 1;
549
            // Digital item is sold.
550
            $itemized_list['L_PAYMENTREQUEST_0_ITEMCATEGORY0'] = 'Physical';
551
            // Item's sales S/H and tax amount.
552
            $itemized_list['PAYMENTREQUEST_0_ITEMAMT'] = $this->format_currency($payment->amount());
0 ignored issues
show
Deprecated Code introduced by
The method EE_Gateway::format_currency() has been deprecated with message: since 4.9.31 insetad use EventEspresso\core\services\payment_methods\gateways\GatewayDataFormatter::format_currency()

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
553
            $itemized_list['PAYMENTREQUEST_0_TAXAMT'] = '0';
554
            $itemized_list['PAYMENTREQUEST_0_SHIPPINGAMT'] = '0';
555
            $itemized_list['PAYMENTREQUEST_0_HANDLINGAMT'] = '0';
556
        }
557
        return $itemized_list;
558
    }
559
560
561
562
    /**
563
     *  Make the Express checkout request.
564
     *
565
     * @param array       $request_params
566
     * @param string      $request_text
567
     * @param EEI_Payment $payment
568
     * @return mixed
569
     */
570
    public function _ppExpress_request($request_params, $request_text, $payment)
571
    {
572
        $request_dtls = array(
573
            'VERSION'   => '204.0',
574
            'USER'      => urlencode($this->_api_username),
575
            'PWD'       => urlencode($this->_api_password),
576
            'SIGNATURE' => urlencode($this->_api_signature),
577
        );
578
        $dtls = array_merge($request_dtls, $request_params);
579
        $this->_log_clean_request($dtls, $payment, $request_text . ' Request');
580
        // Request Customer Details.
581
        $request_response = wp_remote_post(
582
            $this->_base_gateway_url,
583
            array(
584
                'method'      => 'POST',
585
                'timeout'     => 45,
586
                'httpversion' => '1.1',
587
                'cookies'     => array(),
588
                'headers'     => array(),
589
                'body'        => http_build_query($dtls),
590
            )
591
        );
592
        // Log the response.
593
        $this->log(array($request_text . ' Response' => $request_response), $payment);
594
        return $request_response;
595
    }
596
597
598
599
    /**
600
     *  Check the response status.
601
     *
602
     * @param mixed $request_response
603
     * @return array
604
     */
605
    public function _ppExpress_check_response($request_response)
606
    {
607
        if (is_wp_error($request_response) || empty($request_response['body'])) {
608
            // If we got here then there was an error in this request.
609
            return array('status' => false, 'args' => $request_response);
610
        }
611
        $response_args = array();
612
        parse_str(urldecode($request_response['body']), $response_args);
613
        if (! isset($response_args['ACK'])) {
614
            return array('status' => false, 'args' => $request_response);
615
        }
616
        if (
617
            (
618
                isset($response_args['PAYERID'])
619
                || isset($response_args['TOKEN'])
620
                || isset($response_args['PAYMENTINFO_0_TRANSACTIONID'])
621
                || (isset($response_args['PAYMENTSTATUS']) && $response_args['PAYMENTSTATUS'] === 'Completed')
622
            )
623
            && in_array($response_args['ACK'], array('Success', 'SuccessWithWarning'), true)
624
        ) {
625
            // Response status OK, return response parameters for further processing.
626
            return array('status' => true, 'args' => $response_args);
627
        }
628
        $errors = $this->_get_errors($response_args);
629
        return array('status' => false, 'args' => $errors);
630
    }
631
632
633
634
    /**
635
     *  Log a "Cleared" request.
636
     *
637
     * @param array       $request
638
     * @param EEI_Payment $payment
639
     * @param string      $info
640
     * @return void
641
     */
642
    private function _log_clean_request($request, $payment, $info)
643
    {
644
        $cleaned_request_data = $request;
645
        unset($cleaned_request_data['PWD'], $cleaned_request_data['USER'], $cleaned_request_data['SIGNATURE']);
646
        $this->log(array($info => $cleaned_request_data), $payment);
647
    }
648
649
650
651
    /**
652
     *  Get error from the response data.
653
     *
654
     * @param array $data_array
655
     * @return array
656
     */
657
    private function _get_errors($data_array)
658
    {
659
        $errors = array();
660
        $n = 0;
661
        while (isset($data_array["L_ERRORCODE{$n}"])) {
662
            $l_error_code = isset($data_array["L_ERRORCODE{$n}"])
663
                ? $data_array["L_ERRORCODE{$n}"]
664
                : '';
665
            $l_severity_code = isset($data_array["L_SEVERITYCODE{$n}"])
666
                ? $data_array["L_SEVERITYCODE{$n}"]
667
                : '';
668
            $l_short_message = isset($data_array["L_SHORTMESSAGE{$n}"])
669
                ? $data_array["L_SHORTMESSAGE{$n}"]
670
                : '';
671
            $l_long_message = isset($data_array["L_LONGMESSAGE{$n}"])
672
                ? $data_array["L_LONGMESSAGE{$n}"]
673
                : '';
674
            if ($n === 0) {
675
                $errors = array(
676
                    'L_ERRORCODE'    => $l_error_code,
677
                    'L_SHORTMESSAGE' => $l_short_message,
678
                    'L_LONGMESSAGE'  => $l_long_message,
679
                    'L_SEVERITYCODE' => $l_severity_code,
680
                );
681
            } else {
682
                $errors['L_ERRORCODE'] .= ', ' . $l_error_code;
683
                $errors['L_SHORTMESSAGE'] .= ', ' . $l_short_message;
684
                $errors['L_LONGMESSAGE'] .= ', ' . $l_long_message;
685
                $errors['L_SEVERITYCODE'] .= ', ' . $l_severity_code;
686
            }
687
            $n++;
688
        }
689
        return $errors;
690
    }
691
692
}
693
// End of file EEG_Paypal_Express.gateway.php
694