Completed
Pull Request — master (#2185)
by Justin
06:08
created

WPSC_Payment_Gateway_Paypal_Express_Checkout   D

Complexity

Total Complexity 125

Size/Duplication

Total Lines 1103
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 6

Importance

Changes 0
Metric Value
dl 0
loc 1103
rs 4.4102
c 0
b 0
f 0
wmc 125
lcom 1
cbo 6

37 Methods

Rating   Name   Duplication   Size   Complexity  
A get_shortcut_url() 0 8 1
A callback_shortcut_process() 0 73 3
A review_order_url() 0 7 2
A review_order_callback() 0 9 1
A init() 0 6 1
A filter_unselect_default() 0 7 2
A get_mark_html() 0 5 1
B get_redirect_url() 0 27 3
A get_return_url() 0 13 1
A get_notify_url() 0 8 1
A set_purchase_log_for_callbacks() 0 16 3
C callback_ipn() 0 27 7
B pull_paypal_details() 0 29 4
D set_post_var() 0 46 17
A validate_var() 0 6 2
A callback_review_transaction() 0 13 2
A review_order_buyer_details() 0 9 1
A review_order_shipping_details() 0 12 1
A callback_confirm_transaction() 0 15 4
C do_transaction() 0 62 11
A callback_display_paypal_error() 0 3 1
A callback_display_generic_error() 0 3 1
C log_payer_details() 0 25 7
A log_protection_status() 0 12 2
B callback_process_confirmed_payment() 0 54 9
A filter_paypal_error_page() 0 17 2
A filter_generic_error_page() 0 9 1
B setup_form() 0 152 3
A is_currency_supported() 0 3 1
A get_currency_code() 0 9 2
A convert() 0 7 2
B process() 0 42 4
A log_error() 0 21 2
B __construct() 0 33 6
A incontext_load_scripts() 0 10 2
B add_ecs_button() 0 15 6
B process_refund() 0 41 6

How to fix   Complexity   

Complex Class

Complex classes like WPSC_Payment_Gateway_Paypal_Express_Checkout 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 WPSC_Payment_Gateway_Paypal_Express_Checkout, and based on these observations, apply Extract Interface, too.

1
<?php
2
/**
3
 * The PayPal Express Checkout Gateway class
4
 *
5
 */
6
7
class WPSC_Payment_Gateway_Paypal_Express_Checkout extends WPSC_Payment_Gateway {
8
	public $sandbox_url = 'https://www.sandbox.paypal.com/webscr';
9
	public $live_url    = 'https://www.paypal.com/cgi-bin/webscr';
10
	private $paypal_data;
11
	protected $gateway;
12
13
	/**
14
	 * Constructor of PayPal Express Checkout Gateway.
15
	 * The $child parameter should be set to true, if the constructor
16
	 * is called from a child class.
17
	 *
18
	 * @param array $options
19
	 * @param bool $child
20
	 *
21
	 * @since 3.9
22
	 */
23
	public function __construct( $options, $child = false ) {
24
		parent::__construct();
25
26
		require_once( 'php-merchant/gateways/paypal-express-checkout.php' );
27
		$this->gateway = new PHP_Merchant_Paypal_Express_Checkout( $options );
28
29
		if ( ! $child ) {
30
			$this->title = __( 'PayPal Express Checkout 3.0', 'wp-e-commerce' );
31
			$this->supports = array( 'refunds', 'partial-refunds' );
32
			$this->gateway->set_options( array(
33
				'api_username'     => $this->setting->get( 'api_username' ),
34
				'api_password'     => $this->setting->get( 'api_password' ),
35
				'api_signature'    => $this->setting->get( 'api_signature' ),
36
				'cancel_url'       => $this->get_shopping_cart_payment_url(),
37
				'currency'         => $this->get_currency_code(),
38
				'test'             => (bool) $this->setting->get( 'sandbox_mode' ),
39
				'address_override' => 1,
40
				'solution_type'    => 'mark',
41
				'cart_logo'        => $this->setting->get( 'cart_logo' ),
42
				'cart_border'      => $this->setting->get( 'cart_border' ),
43
				'incontext'        => (bool) $this->setting->get( 'incontext' ),
44
			) );
45
46
			// Express Checkout Button
47
			if ( (bool) $this->setting->get( 'shortcut' ) && ! (bool) $this->setting->get( 'incontext' ) ) {
48
				add_action( 'wpsc_cart_item_table_form_actions_left', array( $this, 'add_ecs_button' ), 2, 2 );
49
			}
50
			// Incontext Checkout Scripts
51
			if ( (bool) $this->setting->get( 'incontext' ) && ! (bool) $this->setting->get( 'shortcut' ) ) {
52
				add_action( 'wp_enqueue_scripts', array( $this, 'incontext_load_scripts' ) );
53
			}
54
		}
55
	}
56
57
	public function incontext_load_scripts() {
58
		wp_register_script( 'ec-incontext', WPSC_URL . '/wpsc-components/merchant-core-v3/gateways/ec-incontext.js', '', null, true );
59
		wp_localize_script( 'ec-incontext', 'wpec_ppic', array(
60
			'mid' => esc_attr( $this->setting->get( 'api_merchantid' ) ),
61
			'env' => (bool) $this->setting->get( 'sandbox_mode' ) === true ? 'sandbox' : 'production',
62
			)
63
		);
64
		wp_enqueue_script( 'ec-incontext' );
65
		wp_enqueue_script( 'ppincontext', 'https://www.paypalobjects.com/api/checkout.js', array(), null, true );
66
	}
67
68
	/**
69
	 * Insert the ExpessCheckout Shortcut Button
70
	 *
71
	 * @return void
72
	 */
73
	public function add_ecs_button( $cart_table, $context ) {
74
75
		if ( ! wpsc_uses_shipping() && wpsc_is_gateway_active( 'paypal-digital-goods' ) || ! wpsc_is_gateway_active( 'paypal-express-checkout' ) ) {
76
			return;
77
		}
78
79
		if ( 'bottom' == $context ) {
80
			return;
81
		}
82
83
		if ( _wpsc_get_current_controller_name() === 'cart' ) {
84
			$url = $this->get_shortcut_url();
85
			echo '<a class="express-checkout-button" href="'. esc_url( $url ) .'"><img src="https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-large.png" alt="' . __( 'Check out with PayPal', 'wp-e-commerce' ) . '" /></a>';
86
		}
87
	}
88
89
	/**
90
	 * Return the ExpressCheckout Shortcut redirection URL
91
	 *
92
	 * @return void
93
	 */
94
	public function get_shortcut_url() {
95
		$location = add_query_arg( array(
96
			'payment_gateway'          => 'paypal-express-checkout',
97
			'payment_gateway_callback' => 'shortcut_process',
98
		), home_url( 'index.php' ) );
99
100
		return apply_filters( 'wpsc_paypal_express_checkout_shortcut_url', $location );
101
	}
102
103
	/**
104
	 * ExpressCheckout Shortcut Callback
105
	 *
106
	 * @return int
107
	 */
108
	public function callback_shortcut_process() {
109
		if ( ! isset( $_GET['payment_gateway'] ) ) {
110
			return;
111
		}
112
		$payment_gateway = $_GET['payment_gateway'];
113
114
		global $wpsc_cart;
115
		//	Create a new PurchaseLog Object
116
		$purchase_log = new WPSC_Purchase_Log();
117
118
		// Create a Sessionid
119
		$sessionid = ( mt_rand( 100, 999 ) . time() );
120
		wpsc_update_customer_meta( 'checkout_session_id', $sessionid );
121
		$purchase_log->set( array(
122
			'user_ID'        => get_current_user_id(),
123
			'date'           => time(),
124
			'plugin_version' => WPSC_VERSION,
125
			'statusno'       => '0',
126
			'sessionid'      => $sessionid,
127
		) );
128
129
		if ( wpsc_is_tax_included() ) {
130
			$tax            = $wpsc_cart->calculate_total_tax();
131
			$tax_percentage = $wpsc_cart->tax_percentage;
132
		} else {
133
			$tax            = 0;
134
			$tax_percentage = 0;
135
		}
136
		$purchase_log->set( array(
137
			'wpec_taxes_total' => $tax,
138
			'wpec_taxes_rate'  => $tax_percentage,
139
		) );
140
141
		// Save the purchase_log object to generate it's id
142
		$purchase_log->save();
143
		$purchase_log_id = $purchase_log->get( 'id' );
144
145
		$wpsc_cart->log_id = $purchase_log_id;
146
		wpsc_update_customer_meta( 'current_purchase_log_id', $purchase_log_id );
147
148
		$purchase_log->set( array(
149
			'gateway'       => $payment_gateway,
150
			'base_shipping' => $wpsc_cart->calculate_base_shipping(),
151
			'totalprice'    => $wpsc_cart->calculate_total_price(),
152
		) );
153
154
		$purchase_log->save();
155
156
		$wpsc_cart->empty_db( $purchase_log_id );
157
		$wpsc_cart->save_to_db( $purchase_log_id );
158
		$wpsc_cart->submit_stock_claims( $purchase_log_id );
159
160
		// Save an empty Form
161
		$form   = WPSC_Checkout_Form::get();
162
		$fields = $form->get_fields();
163
		WPSC_Checkout_Form_Data::save_form( $purchase_log, $fields );
164
165
		// Return Customer to Review Order Page if there is Shipping
166
		add_filter( 'wpsc_paypal_express_checkout_transact_url', array( &$this, 'review_order_url' ) );
167
		add_filter( 'wpsc_paypal_express_checkout_return_url', array( &$this, 'review_order_callback' ) );
168
169
		// Set a Temporary Option for EC Shortcut
170
		wpsc_update_customer_meta( 'esc-' . $sessionid, true );
171
172
		// Apply Checkout Actions
173
		do_action( 'wpsc_submit_checkout', array(
174
			'purchase_log_id' => $purchase_log_id,
175
			'our_user_id'     => get_current_user_id(),
176
		) );
177
		do_action( 'wpsc_submit_checkout_gateway', $payment_gateway, $purchase_log );
178
179
		return $sessionid;
180
	}
181
182
	/**
183
	 * Return Customer to Review Order Page if there are Shipping Costs.
184
	 *
185
	 * @param string $url
186
	 * @return string
187
	 */
188
	public function review_order_url( $url ) {
189
		if ( wpsc_uses_shipping() ) {
190
		   $url = wpsc_get_checkout_url( 'review-order' );
191
		}
192
193
		return $url;
194
	}
195
196
	/**
197
	 * Sets the Review Callback for Review Order page.
198
	 *
199
	 * @param string $url
200
	 * @return string
201
	 */
202
	public function review_order_callback( $url ) {
203
		$args = array(
204
			'payment_gateway_callback' => 'review_transaction',
205
			'payment_gateway'          => 'paypal-express-checkout',
206
		);
207
		$url = add_query_arg( $args, $url );
208
209
		return esc_url( $url );
210
	}
211
212
	/**
213
	 * Run the gateway hooks
214
	 *
215
	 * @access public
216
	 * @since 4.0
217
	 *
218
	 * @return void
219
	 */
220
	public function init() {
221
		add_filter(
222
			'wpsc_payment_method_form_fields',
223
			array( 'WPSC_Payment_Gateway_Paypal_Express_Checkout', 'filter_unselect_default' ), 100 , 1
224
		);
225
	}
226
227
	/**
228
	 * No payment gateway is selected by default
229
	 *
230
	 * @access public
231
	 * @param array $fields
232
	 * @return array
233
	 *
234
	 * @since 3.9
235
	 */
236
	public static function filter_unselect_default( $fields ) {
237
		foreach ( $fields as $i => $field ) {
238
			$fields[ $i ][ 'checked' ] = false;
239
		}
240
241
		return $fields;
242
	}
243
244
	/**
245
	 * Returns the HTML of the logo of the payment gateway.
246
	 *
247
	 * @access public
248
	 * @return string
249
	 *
250
	 * @since 3.9
251
	 */
252
	public function get_mark_html() {
253
		$html = '<img src="https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg" border="0" alt="PayPal Logo">';
254
255
		return apply_filters( 'wpsc_paypal-ec_mark_html', $html );
256
	}
257
258
	/**
259
	 * Returns the PayPal redirect URL
260
	 *
261
	 * @param array $data Arguments to encode with the URL
262
	 * @return string
263
	 *
264
	 * @since 3.9
265
	 */
266
	public function get_redirect_url( $data = array() ) {
267
268
		// Select either the Sandbox or the Live URL
269
		if ( $this->setting->get( 'sandbox_mode' ) ) {
270
			$url = $this->sandbox_url;
271
		} else {
272
			$url = $this->live_url;
273
		}
274
275
		// Common Vars
276
		$common = array(
277
			'cmd'        => '_express-checkout',
278
			'useraction' => 'commit',
279
		);
280
281
		if ( wp_is_mobile() ) {
282
			$common['cmd'] = '_express-checkout-mobile';
283
		}
284
285
		// Merge the two arrays
286
		$data = array_merge( $data, $common );
287
288
		// Build the URL
289
		$url = add_query_arg( $data, $url );
290
291
		return $url;
292
	}
293
294
	/**
295
	 * Returns the URL of the Return Page after the PayPal Checkout
296
	 *
297
	 * @return string
298
	 */
299
	protected function get_return_url() {
300
		$transact_url = get_option( 'transact_url' );
301
		$transact_url = apply_filters( 'wpsc_paypal_express_checkout_transact_url', $transact_url );
302
303
		$location = add_query_arg( array(
304
			'sessionid'                => $this->purchase_log->get( 'sessionid' ),
305
			'payment_gateway'          => 'paypal-express-checkout',
306
			'payment_gateway_callback' => 'confirm_transaction',
307
		),
308
		$transact_url
309
	);
310
		return apply_filters( 'wpsc_paypal_express_checkout_return_url', $location, $this );
311
	}
312
313
	/**
314
	 * Returns the URL of the IPN Page
315
	 *
316
	 * @return string
317
	 */
318
	protected function get_notify_url() {
319
		$location = add_query_arg( array(
320
			'payment_gateway'          => 'paypal-express-checkout',
321
			'payment_gateway_callback' => 'ipn',
322
		), home_url( 'index.php' ) );
323
324
		return apply_filters( 'wpsc_paypal_express_checkout_notify_url', $location );
325
	}
326
327
	/**
328
	 * Creates a new Purchase Log entry and set it to the current object
329
	 *
330
	 * @return null
331
	 */
332
	protected function set_purchase_log_for_callbacks( $sessionid = false ) {
333
		// Define the sessionid if it's not passed
334
		if ( $sessionid === false ) {
335
			$sessionid = $_REQUEST['sessionid'];
336
		}
337
338
		// Create a new Purchase Log entry
339
		$purchase_log = new WPSC_Purchase_Log( $sessionid, 'sessionid' );
340
341
		if ( ! $purchase_log->exists() ) {
342
			return null;
343
		}
344
345
		// Set the Purchase Log for the gateway object
346
		$this->set_purchase_log( $purchase_log );
347
	}
348
349
	/**
350
	 * IPN Callback function
351
	 *
352
	 * @return void
353
	 */
354
	public function callback_ipn() {
355
		$ipn = new PHP_Merchant_Paypal_IPN( false, (bool) $this->setting->get( 'sandbox_mode', false ) );
356
357
		if ( $ipn->is_verified() ) {
358
			$sessionid = $ipn->get( 'invoice' );
359
			$this->set_purchase_log_for_callbacks( $sessionid );
360
361
			if ( $ipn->is_payment_denied() ) {
362
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::PAYMENT_DECLINED );
363
			} elseif ( $ipn->is_payment_refunded() ) {
364
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::REFUNDED );
365
			} elseif ( $ipn->is_payment_completed() ) {
366
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
367
			} elseif ( $ipn->is_payment_pending() ) {
368
				if ( $ipn->is_payment_refund_pending() ) {
369
					$this->purchase_log->set( 'processed', WPSC_Purchase_Log::REFUND_PENDING );
370
				} else {
371
					$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
372
				}
373
			}
374
375
			$this->purchase_log->save();
376
			transaction_results( $sessionid, false );
377
		}
378
379
		exit;
380
	}
381
382
	/**
383
	 * Pull and Record PayPal Details
384
	 *
385
	 * @return void
386
	 */
387
	public function pull_paypal_details() {
388
		$this->set_purchase_log_for_callbacks();
389
390
		// Pull the User Details from PayPal
391
		$this->paypal_data = $paypal = $this->gateway->get_details_for( $_GET['token'] );
392
		$payer = $paypal->get( 'payer' );
393
		$address = $paypal->get( 'shipping_address' );
394
395
		// PurchaseLog Update
396
		if ( isset( $address['country_code'] ) ) {
397
			$this->purchase_log->set( 'billing_country', $address['country_code'] );
398
			$this->purchase_log->set( 'shipping_country', $address['country_code'] );
399
		}
400
		if ( isset( $address['state'] ) ) {
401
			$this->purchase_log->set( 'billing_region', $address['state'] );
402
			$this->purchase_log->set( 'shipping_region', $address['state'] );
403
		}
404
405
		// Save Checkout Form Fields
406
		$form   = WPSC_Checkout_Form::get();
407
		$fields = $form->get_fields();
408
		$_POST['wpsc_checkout_details'] = array();
409
		foreach( $fields as $field ) {
410
			$this->set_post_var( $field, $payer, $address );
411
		}
412
413
		// Save details to the Forms Table
414
		WPSC_Checkout_Form_Data::save_form( $this->purchase_log, $fields );
415
	}
416
417
	/**
418
	 * To insert Data to the Form Table, we need to pass it
419
	 * to the global $_POST variable first
420
	 *
421
	 * @param object $payer
422
	 * @param object $field
423
	 * @param array $address
424
	 *
425
	 * @return void
426
	 */
427
	private function set_post_var( $field, $payer, $address ) {
428
		switch( $field->unique_name ) {
429
			// Shipping Details
430
		case 'shippingfirstname':
431
			$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['name'] );
432
			break;
433
		case 'shippinglastname':
434
			$_POST['wpsc_checkout_details'][$field->id] = '';
435
			break;
436
		case 'shippingaddress':
437
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['street'] );
438
			break;
439
		case 'shippingcity':
440
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['city'] );
441
			break;
442
		case 'shippingstate':
443
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['state'] );
444
			break;
445
		case 'shippingcountry':
446
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['country_code'] );
447
			break;
448
		case 'shippingpostcode':
449
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['zip'] );
450
			break;
451
			// Billing Details
452
		case 'billingfirstname':
453
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->first_name );
454
			break;
455
		case 'billinglastname':
456
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->last_name );
457
			break;
458
		case 'billingaddress':
459
		case 'billingcity':
460
		case 'billingstate':
461
		case 'billingpostcode':
462
		case 'billingphone':
463
			$_POST['wpsc_checkout_details'][$field->id] = '';
464
			break;
465
		case 'billingcountry':
466
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->country );
467
			break;
468
		case 'billingemail':
469
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->email );
470
			break;
471
		}
472
	}
473
474
	/**
475
	 * Verify that the variable isset and return it, otherwise return an empty
476
	 * string
477
	 *
478
	 * @param string $var
479
	 *
480
	 * @return string
481
	 */
482
	private function validate_var( $var ) {
483
		if ( isset( $var ) ) {
484
			return $var;
485
		}
486
		return '';
487
	}
488
489
	/**
490
	 * Review Transaction Callback
491
	 *
492
	 * @return void
493
	 */
494
	public function callback_review_transaction() {
495
		// Pull Customer Details from PayPal
496
		$this->pull_paypal_details();
497
498
		// If no Shipping is required, confirm the Transaction
499
		if ( !wpsc_uses_shipping() ) {
500
			$this->callback_confirm_transaction();
501
		}
502
503
		// Display Customer Details
504
		add_filter( 'wpsc_review_order_buyers_details', array( &$this, 'review_order_buyer_details' ) );
505
		add_filter( 'wpsc_review_order_shipping_details', array( &$this, 'review_order_shipping_details' ) );
506
	}
507
508
	/**
509
	 * Display Customer Details from PayPal
510
	 *
511
	 * @param string $output
512
	 * @return string
513
	 */
514
	public function review_order_buyer_details( $output ) {
515
		$payer = $this->paypal_data->get( 'payer' );
516
		$output .= '<ul>';
517
		$output .= '<li><strong>' . __( 'Email:', 'wp-e-commerce' ) . ' </strong>' . $payer->email . '</li>';
518
		$output .= '<li><strong>' . __( 'First Name:', 'wp-e-commerce' ) . ' </strong>' . $payer->first_name . '</li>';
519
		$output .= '<li><strong>' . __( 'Last Name:', 'wp-e-commerce' ) . ' </strong>' . $payer->last_name . '</li>';
520
		$output .= '</ul>';
521
		return $output;
522
	}
523
524
	/**
525
	 * Display Shipping Details from PayPal
526
	 *
527
	 * @param string $output
528
	 * @return string
529
	 */
530
	public function review_order_shipping_details( $output ) {
531
		$address = $this->paypal_data->get( 'shipping_address' );
532
		$output .= '<ul>';
533
		$output .= '<li>' . $address[ 'name' ] . '</li>';
534
		$output .= '<li>' . $address[ 'street' ] . '</li>';
535
		$output .= '<li>' . $address[ 'city' ] . '</li>';
536
		$output .= '<li>' . $address[ 'state' ] . '</li>';
537
		$output .= '<li>' . $address[ 'zip' ] . '</li>';
538
		$output .= '<li>' . $address[ 'country_code' ] . '</li>';
539
		$output .= '</ul>';
540
		return $output;
541
	}
542
543
	/**
544
	 * Confirm Transaction Callback
545
	 *
546
	 * @return bool
547
	 *
548
	 * @since 3.9
549
	 */
550
	public function callback_confirm_transaction() {
551
		if ( ! isset( $_REQUEST['sessionid'] ) || ! isset( $_REQUEST['token'] ) || ! isset( $_REQUEST['PayerID'] ) ) {
552
			return false;
553
		}
554
555
		// Set the Purchase Log
556
		$this->set_purchase_log_for_callbacks();
557
558
		// Display the Confirmation Page
559
		$this->do_transaction();
560
561
		// Remove Shortcut option if it exists
562
		$sessionid = $_REQUEST['sessionid'];
563
		wpsc_delete_customer_meta( 'esc-' . $sessionid );
564
	}
565
566
	/**
567
	 * Process the transaction through the PayPal APIs
568
	 *
569
	 * @since 3.9
570
	 */
571
	public function do_transaction() {
572
		$args = array_map( 'urldecode', $_GET );
573
		extract( $args, EXTR_SKIP );
0 ignored issues
show
introduced by
extract() usage is highly discouraged, due to the complexity and unintended issues it might cause.
Loading history...
574
575
		if ( ! isset( $sessionid ) || ! isset( $token ) || ! isset( $PayerID ) ) {
576
			return;
577
		}
578
579
		$this->set_purchase_log_for_callbacks();
580
581
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
582
		$options = array(
583
			'token'         => $token,
584
			'payer_id'      => $PayerID,
585
			'message_id'    => $this->purchase_log->get( 'id' ),
586
			'invoice'		=> $this->purchase_log->get( 'sessionid' ),
587
		);
588
		$options += $this->checkout_data->get_gateway_data();
589
		$options += $this->purchase_log->get_gateway_data( parent::get_currency_code(), $this->get_currency_code() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_currency_code() instead of do_transaction()). Are you sure this is correct? If so, you might want to change this to $this->get_currency_code().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
590
591
		if ( $this->setting->get( 'ipn', false ) ) {
592
			$options['notify_url'] = $this->get_notify_url();
593
		}
594
595
		// GetExpressCheckoutDetails
596
		$details = $this->gateway->get_details_for( $token );
597
		$this->log_payer_details( $details );
598
599
		$response = $this->gateway->purchase( $options );
600
		$this->log_protection_status( $response );
601
		$location = remove_query_arg( 'payment_gateway_callback' );
602
603
		if ( $response->has_errors() ) {
604
			$errors = $response->get_params();
605
606
			if ( isset( $errors['L_ERRORCODE0'] ) && '10486' == $errors['L_ERRORCODE0'] ) {
607
				wp_redirect( $this->get_redirect_url( array( 'token' => $token ) ) );
608
				exit;
609
			}
610
611
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
612
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_paypal_error' ) );
613
614
		} elseif ( $response->is_payment_completed() || $response->is_payment_pending() ) {
615
			$location = remove_query_arg( 'payment_gateway' );
616
617
			if ( $response->is_payment_completed() ) {
618
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
619
			} else {
620
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
621
			}
622
623
			$this->purchase_log->set( 'transactid', $response->get( 'transaction_id' ) )
624
				->set( 'date', time() )
625
				->save();
626
		} else {
627
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_generic_error' ) );
628
		}
629
630
		wp_redirect( esc_url_raw( $location ) );
631
		exit;
632
	}
633
634
	public function callback_display_paypal_error() {
635
		add_filter( 'wpsc_get_transaction_html_output', array( $this, 'filter_paypal_error_page' ) );
636
	}
637
638
	public function callback_display_generic_error() {
639
		add_filter( 'wpsc_get_transaction_html_output', array( $this, 'filter_generic_error_page' ) );
640
	}
641
642
	/**
643
	 * Records the Payer ID, Payer Status and Shipping Status to the Purchase
644
	 * Log on GetExpressCheckout Call
645
	 *
646
	 * @return void
647
	 */
648
	public function log_payer_details( $details ) {
649
		if ( isset( $details->get( 'payer' )->id ) && !empty( $details->get( 'payer' )->id ) ) {
650
			$payer_id = $details->get( 'payer' )->id;
651
		} else {
652
			$payer_id = 'not set';
653
		}
654
		if ( isset( $details->get( 'payer' )->status ) && !empty( $details->get( 'payer' )->status ) ) {
655
			$payer_status = $details->get( 'payer' )->status;
656
		} else {
657
			$payer_status = 'not set';
658
		}
659
		if ( isset( $details->get( 'payer' )->shipping_status ) && !empty( $details->get( 'payer' )->shipping_status ) ) {
660
			$payer_shipping_status = $details->get( 'payer' )->shipping_status;
661
		} else {
662
			$payer_shipping_status = 'not set';
663
		}
664
		$paypal_log = array(
665
			'payer_id'        => $payer_id,
666
			'payer_status'    => $payer_status,
667
			'shipping_status' => $payer_shipping_status,
668
			'protection'      => null,
669
		);
670
671
		wpsc_update_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details' , $paypal_log );
672
	}
673
674
	/**
675
	 * Records the Protection Eligibility status to the Purchase Log on
676
	 * DoExpressCheckout Call
677
	 *
678
	 * @return void
679
	 */
680
	public function log_protection_status( $response ) {
681
		$params = $response->get_params();
682
683
		if ( isset( $params['PAYMENTINFO_0_PROTECTIONELIGIBILITY'] ) ) {
684
			$elg                      = $params['PAYMENTINFO_0_PROTECTIONELIGIBILITY'];
685
		} else {
686
			$elg = false;
687
		}
688
		$paypal_log               = wpsc_get_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details', true );
689
		$paypal_log['protection'] = $elg;
690
		wpsc_update_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details' , $paypal_log );
691
	}
692
693
	public function callback_process_confirmed_payment() {
694
		$args = array_map( 'urldecode', $_GET );
695
		extract( $args, EXTR_SKIP );
0 ignored issues
show
introduced by
extract() usage is highly discouraged, due to the complexity and unintended issues it might cause.
Loading history...
696
697
		if ( ! isset( $sessionid ) || ! isset( $token ) || ! isset( $PayerID ) ) {
698
			return;
699
		}
700
701
		$this->set_purchase_log_for_callbacks();
702
703
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
704
		$options = array(
705
			'token'         => $token,
706
			'payer_id'      => $PayerID,
707
			'message_id'    => $this->purchase_log->get( 'id' ),
708
			'invoice'       => $this->purchase_log->get( 'sessionid' ),
709
		);
710
		$options += $this->checkout_data->get_gateway_data();
711
		$options += $this->purchase_log->get_gateway_data( parent::get_currency_code(), $this->get_currency_code() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_currency_code() instead of callback_process_confirmed_payment()). Are you sure this is correct? If so, you might want to change this to $this->get_currency_code().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
712
713
		if ( $this->setting->get( 'ipn', false ) ) {
714
			$options['notify_url'] = $this->get_notify_url();
715
		}
716
717
		// GetExpressCheckoutDetails
718
		$details = $this->gateway->get_details_for( $token );
719
		$this->log_payer_details( $details );
720
721
		$response = $this->gateway->purchase( $options );
722
		$this->log_protection_status( $response );
723
		$location = remove_query_arg( 'payment_gateway_callback' );
724
725
		if ( $response->has_errors() ) {
726
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
727
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_paypal_error' ) );
728
		} elseif ( $response->is_payment_completed() || $response->is_payment_pending() ) {
729
			$location = remove_query_arg( 'payment_gateway' );
730
731
			if ( $response->is_payment_completed() ) {
732
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
733
			} else {
734
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
735
			}
736
737
			$this->purchase_log->set( 'transactid', $response->get( 'transaction_id' ) )
738
				->set( 'date', time() )
739
				->save();
740
		} else {
741
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_generic_error' ) );
742
		}
743
744
		wp_redirect( esc_url_raw( $location ) );
745
		exit;
746
	}
747
748
	/**
749
	 * Error Page Template
750
	 *
751
	 * @since 3.9
752
	 */
753
	public function filter_paypal_error_page() {
754
		$errors = wpsc_get_customer_meta( 'paypal_express_checkout_errors' );
755
		ob_start();
756
?>
757
	<p>
758
	<?php _e( 'Sorry, your transaction could not be processed by PayPal. Please contact the site administrator. The following errors are returned:' , 'wp-e-commerce' ); ?>
759
		</p>
760
			<ul>
761
			<?php foreach ( $errors as $error ): ?>
762
			<li><?php echo esc_html( $error['details'] ) ?> (<?php echo esc_html( $error['code'] ); ?>)</li>
763
			<?php endforeach; ?>
764
		</ul>
765
			<p><a href="<?php echo esc_url( $this->get_shopping_cart_payment_url() ); ?>"><?php ( 'Click here to go back to the checkout page.') ?></a></p>
766
<?php
767
		$output = apply_filters( 'wpsc_paypal_express_checkout_gateway_error_message', ob_get_clean(), $errors );
768
		return $output;
769
	}
770
771
	/**
772
	 * Generic Error Page Template
773
	 *
774
	 * @since 3.9
775
	 */
776
	public function filter_generic_error_page() {
777
		ob_start();
778
?>
779
<p><?php _e( 'Sorry, but your transaction could not be processed by PayPal for some reason. Please contact the site administrator.' , 'wp-e-commerce' ); ?></p>
780
<p><a href="<?php echo esc_attr( $this->get_shopping_cart_payment_url() ); ?>"><?php _e( 'Click here to go back to the checkout page.', 'wp-e-commerce' ) ?></a></p>
781
<?php
782
		$output = apply_filters( 'wpsc_paypal_express_checkout_generic_error_message', ob_get_clean() );
783
		return $output;
784
	}
785
786
	/**
787
	 * Settings Form Template
788
	 *
789
	 * @since 3.9
790
	 */
791
	public function setup_form() {
792
		$paypal_currency = $this->get_currency_code();
793
?>
794
795
<!-- Account Credentials -->
796
<tr>
797
	<td colspan="2">
798
		<h4><?php _e( 'Account Credentials', 'wp-e-commerce' ); ?></h4>
799
	</td>
800
</tr>
801
<tr>
802
	<td>
803
		<label for="wpsc-paypal-express-api-username"><?php _e( 'API Username', 'wp-e-commerce' ); ?></label>
804
	</td>
805
	<td>
806
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'api_username' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'api_username' ) ); ?>" id="wpsc-paypal-express-api-username" />
807
	</td>
808
</tr>
809
<tr>
810
	<td>
811
		<label for="wpsc-paypal-express-api-password"><?php _e( 'API Password', 'wp-e-commerce' ); ?></label>
812
	</td>
813
	<td>
814
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'api_password' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'api_password' ) ); ?>" id="wpsc-paypal-express-api-password" />
815
	</td>
816
</tr>
817
<tr>
818
	<td>
819
		<label for="wpsc-paypal-express-api-signature"><?php _e( 'API Signature', 'wp-e-commerce' ); ?></label>
820
	</td>
821
	<td>
822
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'api_signature' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'api_signature' ) ); ?>" id="wpsc-paypal-express-api-signature" />
823
	</td>
824
</tr>
825
<tr>
826
	<td>
827
		<label for="wpsc-paypal-express-api-username"><?php _e( 'Merchant ID', 'wp-e-commerce' ); ?></label>
828
	</td>
829
	<td>
830
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'api_merchantid' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'api_merchantid' ) ); ?>" id="wpsc-paypal-express-api-username" />
831
	</td>
832
</tr>
833
<tr>
834
	<td>
835
		<label><?php _e( 'Sandbox Mode', 'wp-e-commerce' ); ?></label>
836
	</td>
837
	<td>
838
		<label><input <?php checked( $this->setting->get( 'sandbox_mode' ) ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'sandbox_mode' ) ); ?>" value="1" /> <?php _e( 'Yes', 'wp-e-commerce' ); ?></label>&nbsp;&nbsp;&nbsp;
839
		<label><input <?php checked( (bool) $this->setting->get( 'sandbox_mode' ), false ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'sandbox_mode' ) ); ?>" value="0" /> <?php _e( 'No', 'wp-e-commerce' ); ?></label>
840
	</td>
841
</tr>
842
<tr>
843
	<td>
844
		<label><?php _e( 'IPN', 'wp-e-commerce' ); ?></label>
845
	</td>
846
	<td>
847
		<label><input <?php checked( $this->setting->get( 'ipn' ) ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'ipn' ) ); ?>" value="1" /> <?php _e( 'Yes', 'wp-e-commerce' ); ?></label>&nbsp;&nbsp;&nbsp;
848
		<label><input <?php checked( (bool) $this->setting->get( 'ipn' ), false ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'ipn' ) ); ?>" value="0" /> <?php _e( 'No', 'wp-e-commerce' ); ?></label>
849
	</td>
850
</tr>
851
852
<!-- Cart Customization -->
853
<tr>
854
	<td colspan="2">
855
		<label><h4><?php _e( 'Cart Customization', 'wp-e-commerce'); ?></h4></label>
856
	</td>
857
</tr>
858
<tr>
859
	<td>
860
		<label for="wpsc-paypal-express-cart-logo"><?php _e( 'Merchant Logo', 'wp-e-commerce' ); ?></label>
861
	</td>
862
	<td>
863
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'cart_logo' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'cart_logo' ) ); ?>" id="wpsc-paypal-express-cart-logo" /><br><span class="small description"><?php _e( 'The image must be stored in a HTTPS Server. Limit the image to 190 pixels wide by 60 pixels high.', 'wp-e-commerce' ); ?></span>
864
	</td>
865
</tr>
866
<tr>
867
	<td>
868
		<label for="wpsc-paypal-express-cart-border"><?php _e( 'Cart Border Color', 'wp-e-commerce' ); ?></label>
869
	</td>
870
	<td>
871
		<input type="text" name="<?php echo esc_attr( $this->setting->get_field_name( 'cart_border' ) ); ?>" value="<?php echo esc_attr( $this->setting->get( 'cart_border' ) ); ?>" id="wpsc-paypal-express-cart-border" />
872
	</td>
873
</tr>
874
<tr>
875
	<td>
876
		<label for="wpsc-paypal-express-cart-border"><?php _e( 'Enable In-Context Checkout', 'wp-e-commerce' ); ?></label>
877
	</td>
878
	<td>
879
		<label><input <?php checked( $this->setting->get( 'incontext' ) ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'incontext' ) ); ?>" value="1" /> <?php _e( 'Yes', 'wp-e-commerce' ); ?></label>&nbsp;&nbsp;&nbsp;
880
		<label><input <?php checked( (bool) $this->setting->get( 'incontext' ), false ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'incontext' ) ); ?>" value="0" /> <?php _e( 'No', 'wp-e-commerce' ); ?></label>
881
	</td>
882
</tr>
883
884
<!-- Currency Conversion -->
885
<?php if ( ! $this->is_currency_supported() ) : ?>
886
<tr>
887
	<td colspan="2">
888
		<h4><?php _e( 'Currency Conversion', 'wp-e-commerce' ); ?></h4>
889
	</td>
890
</tr>
891
<tr>
892
	<td colspan="2">
893
		<p><?php _e( "Your base currency is currently not accepted by PayPal. As a result, before a payment request is sent to PayPal, WP eCommerce has to convert the amounts into one of PayPal's supported currencies. Please select your preferred currency below.", 'wp-e-commerce' ); ?></p>
894
	</td>
895
</tr>
896
<tr>
897
	<td>
898
		<label for "wpsc-paypal-express-currency"><?php _e( 'PayPal Currency', 'wp-e-commerce' ); ?></label>
899
	</td>
900
	<td>
901
		<select name="<?php echo esc_attr( $this->setting->get_field_name( 'currency' ) ); ?>" id="wpsc-paypal-express-currency">
902
			<?php foreach ( $this->gateway->get_supported_currencies() as $currency ) : ?>
903
			<option <?php selected( $currency, $paypal_currency ); ?> value="<?php echo esc_attr( $currency ); ?>"><?php echo esc_html( $currency ); ?></option>
904
			<?php endforeach ?>
905
		</select>
906
	</td>
907
</tr>
908
<?php endif ?>
909
910
<!-- Checkout Shortcut -->
911
<tr>
912
	<td colspan="2">
913
		<h4><?php _e( 'Express Checkout Shortcut', 'wp-e-commerce' ); ?></h4>
914
	</td>
915
</tr>
916
<tr>
917
	<td>
918
		<label><?php _e( 'Enable Shortcut', 'wp-e-commerce' ); ?></label>
919
	</td>
920
	<td>
921
		<label><input <?php checked( $this->setting->get( 'shortcut' ) ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'shortcut' ) ); ?>" value="1" /> <?php _e( 'Yes', 'wp-e-commerce' ); ?></label>&nbsp;&nbsp;&nbsp;
922
		<label><input <?php checked( (bool) $this->setting->get( 'shortcut' ), false ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'shortcut' ) ); ?>" value="0" /> <?php _e( 'No', 'wp-e-commerce' ); ?></label>
923
	</td>
924
</tr>
925
926
<!-- Error Logging -->
927
<tr>
928
	<td colspan="2">
929
		<h4><?php _e( 'Error Logging', 'wp-e-commerce' ); ?></h4>
930
	</td>
931
</tr>
932
<tr>
933
	<td>
934
		<label><?php _e( 'Enable Debugging', 'wp-e-commerce' ); ?></label>
935
	</td>
936
	<td>
937
		<label><input <?php checked( $this->setting->get( 'debugging' ) ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'debugging' ) ); ?>" value="1" /> <?php _e( 'Yes', 'wp-e-commerce' ); ?></label>&nbsp;&nbsp;&nbsp;
938
		<label><input <?php checked( (bool) $this->setting->get( 'debugging' ), false ); ?> type="radio" name="<?php echo esc_attr( $this->setting->get_field_name( 'debugging' ) ); ?>" value="0" /> <?php _e( 'No', 'wp-e-commerce' ); ?></label>
939
	</td>
940
</tr>
941
<?php
942
	}
943
944
	/**
945
	 * Check if the selected currency is supported by the gateway
946
	 *
947
	 * @return bool
948
	 *
949
	 * @since 3.9
950
	 */
951
	protected function is_currency_supported() {
952
		return in_array( parent::get_currency_code(), $this->gateway->get_supported_currencies() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_currency_code() instead of is_currency_supported()). Are you sure this is correct? If so, you might want to change this to $this->get_currency_code().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
953
	}
954
955
	/**
956
	 * Return the Currency ISO code
957
	 *
958
	 * @return string
959
	 *
960
	 * @since 3.9
961
	 */
962
	public function get_currency_code() {
963
		$code = parent::get_currency_code();
964
965
		if ( ! in_array( $code, $this->gateway->get_supported_currencies() ) ) {
966
			$code = $this->setting->get( 'currency', 'USD' );
967
		}
968
969
		return $code;
970
	}
971
972
	/**
973
	 * Convert an amount (integer) to the supported currency
974
	 * @param integer $amt
975
	 *
976
	 * @return integer
977
	 *
978
	 * @since 3.9
979
	 */
980
	protected function convert( $amt ) {
981
		if ( $this->is_currency_supported() ) {
982
			return $amt;
983
		}
984
985
		return wpsc_convert_currency( $amt, parent::get_currency_code(), $this->get_currency_code() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_currency_code() instead of convert()). Are you sure this is correct? If so, you might want to change this to $this->get_currency_code().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
986
	}
987
988
	/**
989
	 * Process the SetExpressCheckout API Call
990
	 *
991
	 * @return void
992
	 *
993
	 * @since 3.9
994
	 */
995
	public function process() {
996
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
997
		$options = array(
998
			'return_url'       => $this->get_return_url(),
999
			'message_id'       => $this->purchase_log->get( 'id' ),
1000
			'invoice'          => $this->purchase_log->get( 'sessionid' ),
1001
			'address_override' => 1,
1002
		);
1003
1004
		$options += $this->checkout_data->get_gateway_data();
1005
		$options += $this->purchase_log->get_gateway_data( parent::get_currency_code(), $this->get_currency_code() );
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (get_currency_code() instead of process()). Are you sure this is correct? If so, you might want to change this to $this->get_currency_code().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
1006
1007
		if ( $this->setting->get( 'ipn', false ) ) {
1008
			$options['notify_url'] = $this->get_notify_url();
1009
		}
1010
1011
		// SetExpressCheckout
1012
		$response = $this->gateway->setup_purchase( $options );
1013
1014
		if ( $response->is_successful() ) {
1015
			$params = $response->get_params();
1016
			if ( $params['ACK'] == 'SuccessWithWarning' ) {
1017
				$this->log_error( $response );
1018
				wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
1019
			}
1020
			// Successful redirect
1021
			$url = $this->get_redirect_url( array( 'token' => $response->get( 'token' ) ) );
1022
		} else {
1023
1024
			// SetExpressCheckout Failure
1025
			$this->log_error( $response );
1026
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
1027
1028
			$url = add_query_arg( array(
1029
				'payment_gateway'          => 'paypal-express-checkout',
1030
				'payment_gateway_callback' => 'display_paypal_error',
1031
			), $this->get_return_url() );
1032
		}
1033
1034
		wp_redirect( $url );
1035
		exit;
1036
	}
1037
1038
	/**
1039
	 * Log an error message
1040
	 *
1041
	 * @param PHP_Merchant_Paypal_Express_Checkout_Response $response
1042
	 * @return void
1043
	 *
1044
	 * @since 3.9
1045
	 */
1046
	public function log_error( $response ) {
1047
		if ( $this->setting->get( 'debugging' ) ) {
1048
1049
			add_filter( 'wpsc_logging_post_type_args', 'WPSC_Logging::force_ui' );
1050
			add_filter( 'wpsc_logging_taxonomy_args ', 'WPSC_Logging::force_ui' );
1051
1052
			$log_data = array(
1053
				'post_title'    => 'PayPal ExpressCheckout Operation Failure',
1054
				'post_content'  =>  'There was an error processing the payment. Find details in the log entry meta fields.',
0 ignored issues
show
introduced by
Expected 1 space after "=>"; 2 found
Loading history...
1055
				'log_type'      => 'error'
1056
			);
1057
1058
			$log_meta = array(
1059
				'correlation_id'   => $response->get( 'correlation_id' ),
1060
				'time' => $response->get( 'datetime' ),
1061
				'errors' => $response->get_errors(),
1062
			);
1063
1064
			$log_entry = WPSC_Logging::insert_log( $log_data, $log_meta );
1065
		}
1066
	}
1067
1068
	public function process_refund( $order_id, $amount = 0.00, $reason = '' ) {
1069
1070
		if ( 0.00 == $amount ) {
1071
			return new WP_Error( 'paypal_refund_error', __( 'Refund Error: You need to specify a refund amount.', 'wp-e-commerce' ) );
1072
		}
1073
1074
		$log        = new WPSC_Purchase_Log( $order_id );
1075
		$refundType = 'Full';
1076
1077
		// If refund is full amount is not needed
1078
		// add refund params
1079
		$options = array(
1080
			'transaction_id' => $log->get( 'transactid' ),
1081
			'invoice'        => $log->get( 'sessionid' ),
1082
			'refund_type'    => $refundType,
1083
			'note'           => $reason,
1084
		);
1085
1086
		// do API call
1087
		$response = $this->gateway->credit( $options );
1088
1089
		// look at ACK to see if success or failure
1090
		if ( $response->has_errors() ) {
1091
			// WE could use $response->get_errors() and return the errors in an alert message ?
1092
			return false;
1093
		}
1094
1095
		if ( $response->is_successful() ) {
1096
			$params = $response->get_params();
1097
			if ( 'Success' == $params['ACK'] || 'SuccessWithWarning' == $params['ACK'] ) {
1098
				$this->log_error( $response );
1099
				// Set a log meta entry
1100
				$log->set( 'total_order_refunded' , $amount )->save();
1101
				wpsc_purchlogs_update_notes( absint( $order_id ), sprintf( __( 'Refunded %s - Refund ID: %s', 'woocommerce' ), $params['GROSSREFUNDAMT'], $params['REFUNDTRANSACTIONID'] ) );
1102
1103
				return true;
1104
			}
1105
		} else {
1106
			return false;
1107
		}
1108
	}
1109
}
1110