Completed
Push — master ( 30b9a3...a81e2b )
by Justin
11:10 queued 05:29
created

process_refund()   C

Complexity

Conditions 13
Paths 12

Size

Total Lines 68
Code Lines 36

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 13
eloc 36
nc 12
nop 4
dl 0
loc 68
rs 5.761
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

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
		if( wpsc_is_checkout() ) {
59
			wp_register_script( 'ec-incontext', WPSC_URL . '/wpsc-components/merchant-core-v3/gateways/ec-incontext.js', '', null, true );
60
			wp_localize_script( 'ec-incontext', 'wpec_ppic', array(
61
				'mid' => esc_attr( $this->setting->get( 'api_merchantid' ) ),
62
				'env' => (bool) $this->setting->get( 'sandbox_mode' ) === true ? 'sandbox' : 'production',
63
				)
64
			);
65
			wp_enqueue_script( 'ec-incontext' );
66
			wp_enqueue_script( 'ppincontext', 'https://www.paypalobjects.com/api/checkout.js', array(), null, true );
67
		}
68
	}
69
70
	/**
71
	 * Insert the ExpessCheckout Shortcut Button
72
	 *
73
	 * @return void
74
	 */
75
	public function add_ecs_button( $cart_table, $context ) {
76
77
		if ( ! wpsc_uses_shipping() && wpsc_is_gateway_active( 'paypal-digital-goods' ) || ! wpsc_is_gateway_active( 'paypal-express-checkout' ) ) {
78
			return;
79
		}
80
81
		if ( 'bottom' == $context ) {
82
			return;
83
		}
84
85
		if ( _wpsc_get_current_controller_name() === 'cart' ) {
86
			$url = $this->get_shortcut_url();
87
			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>';
88
		}
89
	}
90
91
	/**
92
	 * Return the ExpressCheckout Shortcut redirection URL
93
	 *
94
	 * @return void
95
	 */
96
	public function get_shortcut_url() {
97
		$location = add_query_arg( array(
98
			'payment_gateway'          => 'paypal-express-checkout',
99
			'payment_gateway_callback' => 'shortcut_process',
100
		), home_url( 'index.php' ) );
101
102
		return apply_filters( 'wpsc_paypal_express_checkout_shortcut_url', $location );
103
	}
104
105
	/**
106
	 * ExpressCheckout Shortcut Callback
107
	 *
108
	 * @return int
109
	 */
110
	public function callback_shortcut_process() {
111
		if ( ! isset( $_GET['payment_gateway'] ) ) {
112
			return;
113
		}
114
		$payment_gateway = $_GET['payment_gateway'];
115
116
		global $wpsc_cart;
117
		//	Create a new PurchaseLog Object
118
		$purchase_log = new WPSC_Purchase_Log();
119
120
		// Create a Sessionid
121
		$sessionid = ( mt_rand( 100, 999 ) . time() );
122
		wpsc_update_customer_meta( 'checkout_session_id', $sessionid );
123
		$purchase_log->set( array(
124
			'user_ID'        => get_current_user_id(),
125
			'date'           => time(),
126
			'plugin_version' => WPSC_VERSION,
127
			'statusno'       => '0',
128
			'sessionid'      => $sessionid,
129
		) );
130
131
		if ( wpsc_is_tax_included() ) {
132
			$tax            = $wpsc_cart->calculate_total_tax();
133
			$tax_percentage = $wpsc_cart->tax_percentage;
134
		} else {
135
			$tax            = 0;
136
			$tax_percentage = 0;
137
		}
138
		$purchase_log->set( array(
139
			'wpec_taxes_total' => $tax,
140
			'wpec_taxes_rate'  => $tax_percentage,
141
		) );
142
143
		// Save the purchase_log object to generate it's id
144
		$purchase_log->save();
145
		$purchase_log_id = $purchase_log->get( 'id' );
146
147
		$wpsc_cart->log_id = $purchase_log_id;
148
		wpsc_update_customer_meta( 'current_purchase_log_id', $purchase_log_id );
149
150
		$purchase_log->set( array(
151
			'gateway'       => $payment_gateway,
152
			'base_shipping' => $wpsc_cart->calculate_base_shipping(),
153
			'totalprice'    => $wpsc_cart->calculate_total_price(),
154
		) );
155
156
		$purchase_log->save();
157
158
		$wpsc_cart->empty_db( $purchase_log_id );
159
		$wpsc_cart->save_to_db( $purchase_log_id );
160
		$wpsc_cart->submit_stock_claims( $purchase_log_id );
161
162
		// Save an empty Form
163
		$form   = WPSC_Checkout_Form::get();
164
		$fields = $form->get_fields();
165
		WPSC_Checkout_Form_Data::save_form( $purchase_log, $fields );
166
167
		// Return Customer to Review Order Page if there is Shipping
168
		add_filter( 'wpsc_paypal_express_checkout_transact_url', array( &$this, 'review_order_url' ) );
169
		add_filter( 'wpsc_paypal_express_checkout_return_url', array( &$this, 'review_order_callback' ) );
170
171
		// Set a Temporary Option for EC Shortcut
172
		wpsc_update_customer_meta( 'esc-' . $sessionid, true );
173
174
		// Apply Checkout Actions
175
		do_action( 'wpsc_submit_checkout', array(
176
			'purchase_log_id' => $purchase_log_id,
177
			'our_user_id'     => get_current_user_id(),
178
		) );
179
		do_action( 'wpsc_submit_checkout_gateway', $payment_gateway, $purchase_log );
180
181
		return $sessionid;
182
	}
183
184
	/**
185
	 * Return Customer to Review Order Page if there are Shipping Costs.
186
	 *
187
	 * @param string $url
188
	 * @return string
189
	 */
190
	public function review_order_url( $url ) {
191
		if ( wpsc_uses_shipping() ) {
192
		   $url = wpsc_get_checkout_url( 'review-order' );
193
		}
194
195
		return $url;
196
	}
197
198
	/**
199
	 * Sets the Review Callback for Review Order page.
200
	 *
201
	 * @param string $url
202
	 * @return string
203
	 */
204
	public function review_order_callback( $url ) {
205
		$args = array(
206
			'payment_gateway_callback' => 'review_transaction',
207
			'payment_gateway'          => 'paypal-express-checkout',
208
		);
209
		$url = add_query_arg( $args, $url );
210
211
		return esc_url( $url );
212
	}
213
214
	/**
215
	 * Run the gateway hooks
216
	 *
217
	 * @access public
218
	 * @since 4.0
219
	 *
220
	 * @return void
221
	 */
222
	public function init() {
223
		add_filter(
224
			'wpsc_payment_method_form_fields',
225
			array( 'WPSC_Payment_Gateway_Paypal_Express_Checkout', 'filter_unselect_default' ), 100 , 1
226
		);
227
	}
228
229
	/**
230
	 * No payment gateway is selected by default
231
	 *
232
	 * @access public
233
	 * @param array $fields
234
	 * @return array
235
	 *
236
	 * @since 3.9
237
	 */
238
	public static function filter_unselect_default( $fields ) {
239
		foreach ( $fields as $i => $field ) {
240
			$fields[ $i ][ 'checked' ] = false;
241
		}
242
243
		return $fields;
244
	}
245
246
	/**
247
	 * Returns the HTML of the logo of the payment gateway.
248
	 *
249
	 * @access public
250
	 * @return string
251
	 *
252
	 * @since 3.9
253
	 */
254
	public function get_mark_html() {
255
		$html = '<img src="https://www.paypalobjects.com/webstatic/mktg/logo/pp_cc_mark_37x23.jpg" border="0" alt="PayPal Logo">';
256
257
		return apply_filters( 'wpsc_paypal-ec_mark_html', $html );
258
	}
259
260
	/**
261
	 * Returns the PayPal redirect URL
262
	 *
263
	 * @param array $data Arguments to encode with the URL
264
	 * @return string
265
	 *
266
	 * @since 3.9
267
	 */
268
	public function get_redirect_url( $data = array() ) {
269
270
		// Select either the Sandbox or the Live URL
271
		if ( $this->setting->get( 'sandbox_mode' ) ) {
272
			$url = $this->sandbox_url;
273
		} else {
274
			$url = $this->live_url;
275
		}
276
277
		// Common Vars
278
		$common = array(
279
			'cmd'        => '_express-checkout',
280
			'useraction' => 'commit',
281
		);
282
283
		if ( wp_is_mobile() ) {
284
			$common['cmd'] = '_express-checkout-mobile';
285
		}
286
287
		// Merge the two arrays
288
		$data = array_merge( $data, $common );
289
290
		// Build the URL
291
		$url = add_query_arg( $data, $url );
292
293
		return $url;
294
	}
295
296
	/**
297
	 * Returns the URL of the Return Page after the PayPal Checkout
298
	 *
299
	 * @return string
300
	 */
301
	protected function get_return_url() {
302
		$transact_url = get_option( 'transact_url' );
303
		$transact_url = apply_filters( 'wpsc_paypal_express_checkout_transact_url', $transact_url );
304
305
		$location = add_query_arg( array(
306
			'sessionid'                => $this->purchase_log->get( 'sessionid' ),
307
			'payment_gateway'          => 'paypal-express-checkout',
308
			'payment_gateway_callback' => 'confirm_transaction',
309
		),
310
		$transact_url
311
	);
312
		return apply_filters( 'wpsc_paypal_express_checkout_return_url', $location, $this );
313
	}
314
315
	/**
316
	 * Returns the URL of the IPN Page
317
	 *
318
	 * @return string
319
	 */
320
	protected function get_notify_url() {
321
		$location = add_query_arg( array(
322
			'payment_gateway'          => 'paypal-express-checkout',
323
			'payment_gateway_callback' => 'ipn',
324
		), home_url( 'index.php' ) );
325
326
		return apply_filters( 'wpsc_paypal_express_checkout_notify_url', $location );
327
	}
328
329
	/**
330
	 * Creates a new Purchase Log entry and set it to the current object
331
	 *
332
	 * @return null
333
	 */
334
	protected function set_purchase_log_for_callbacks( $sessionid = false ) {
335
		// Define the sessionid if it's not passed
336
		if ( $sessionid === false ) {
337
			$sessionid = $_REQUEST['sessionid'];
338
		}
339
340
		// Create a new Purchase Log entry
341
		$purchase_log = new WPSC_Purchase_Log( $sessionid, 'sessionid' );
342
343
		if ( ! $purchase_log->exists() ) {
344
			return null;
345
		}
346
347
		// Set the Purchase Log for the gateway object
348
		$this->set_purchase_log( $purchase_log );
349
	}
350
351
	/**
352
	 * IPN Callback function
353
	 *
354
	 * @return void
355
	 */
356
	public function callback_ipn() {
357
		$ipn = new PHP_Merchant_Paypal_IPN( false, (bool) $this->setting->get( 'sandbox_mode', false ) );
358
359
		if ( $ipn->is_verified() ) {
360
			$sessionid = $ipn->get( 'invoice' );
361
			$this->set_purchase_log_for_callbacks( $sessionid );
362
363
			if ( $ipn->is_payment_denied() ) {
364
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::PAYMENT_DECLINED );
365
			} elseif ( $ipn->is_payment_refunded() ) {
366
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::REFUNDED );
367
			} elseif ( $ipn->is_payment_completed() ) {
368
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
369
			} elseif ( $ipn->is_payment_pending() ) {
370
				if ( $ipn->is_payment_refund_pending() ) {
371
					$this->purchase_log->set( 'processed', WPSC_Purchase_Log::REFUND_PENDING );
372
				} else {
373
					$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
374
				}
375
			}
376
377
			$this->purchase_log->save();
378
			transaction_results( $sessionid, false );
379
		}
380
381
		exit;
382
	}
383
384
	/**
385
	 * Pull and Record PayPal Details
386
	 *
387
	 * @return void
388
	 */
389
	public function pull_paypal_details() {
390
		$this->set_purchase_log_for_callbacks();
391
392
		// Pull the User Details from PayPal
393
		$this->paypal_data = $paypal = $this->gateway->get_details_for( $_GET['token'] );
394
		$payer = $paypal->get( 'payer' );
395
		$address = $paypal->get( 'shipping_address' );
396
397
		// PurchaseLog Update
398
		if ( isset( $address['country_code'] ) ) {
399
			$this->purchase_log->set( 'billing_country', $address['country_code'] );
400
			$this->purchase_log->set( 'shipping_country', $address['country_code'] );
401
		}
402
		if ( isset( $address['state'] ) ) {
403
			$this->purchase_log->set( 'billing_region', $address['state'] );
404
			$this->purchase_log->set( 'shipping_region', $address['state'] );
405
		}
406
407
		// Save Checkout Form Fields
408
		$form   = WPSC_Checkout_Form::get();
409
		$fields = $form->get_fields();
410
		$_POST['wpsc_checkout_details'] = array();
411
		foreach( $fields as $field ) {
412
			$this->set_post_var( $field, $payer, $address );
413
		}
414
415
		// Save details to the Forms Table
416
		WPSC_Checkout_Form_Data::save_form( $this->purchase_log, $fields );
417
	}
418
419
	/**
420
	 * To insert Data to the Form Table, we need to pass it
421
	 * to the global $_POST variable first
422
	 *
423
	 * @param object $payer
424
	 * @param object $field
425
	 * @param array $address
426
	 *
427
	 * @return void
428
	 */
429
	private function set_post_var( $field, $payer, $address ) {
430
		switch( $field->unique_name ) {
431
			// Shipping Details
432
		case 'shippingfirstname':
433
			$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['name'] );
434
			break;
435
		case 'shippinglastname':
436
			$_POST['wpsc_checkout_details'][$field->id] = '';
437
			break;
438
		case 'shippingaddress':
439
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['street'] );
440
			break;
441
		case 'shippingcity':
442
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['city'] );
443
			break;
444
		case 'shippingstate':
445
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['state'] );
446
			break;
447
		case 'shippingcountry':
448
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['country_code'] );
449
			break;
450
		case 'shippingpostcode':
451
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $address['zip'] );
452
			break;
453
			// Billing Details
454
		case 'billingfirstname':
455
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->first_name );
456
			break;
457
		case 'billinglastname':
458
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->last_name );
459
			break;
460
		case 'billingaddress':
461
		case 'billingcity':
462
		case 'billingstate':
463
		case 'billingpostcode':
464
		case 'billingphone':
465
			$_POST['wpsc_checkout_details'][$field->id] = '';
466
			break;
467
		case 'billingcountry':
468
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->country );
469
			break;
470
		case 'billingemail':
471
				$_POST['wpsc_checkout_details'][$field->id] = $this->validate_var( $payer->email );
472
			break;
473
		}
474
	}
475
476
	/**
477
	 * Verify that the variable isset and return it, otherwise return an empty
478
	 * string
479
	 *
480
	 * @param string $var
481
	 *
482
	 * @return string
483
	 */
484
	private function validate_var( $var ) {
485
		if ( isset( $var ) ) {
486
			return $var;
487
		}
488
		return '';
489
	}
490
491
	/**
492
	 * Review Transaction Callback
493
	 *
494
	 * @return void
495
	 */
496
	public function callback_review_transaction() {
497
		// Pull Customer Details from PayPal
498
		$this->pull_paypal_details();
499
500
		// If no Shipping is required, confirm the Transaction
501
		if ( !wpsc_uses_shipping() ) {
502
			$this->callback_confirm_transaction();
503
		}
504
505
		// Display Customer Details
506
		add_filter( 'wpsc_review_order_buyers_details', array( &$this, 'review_order_buyer_details' ) );
507
		add_filter( 'wpsc_review_order_shipping_details', array( &$this, 'review_order_shipping_details' ) );
508
	}
509
510
	/**
511
	 * Display Customer Details from PayPal
512
	 *
513
	 * @param string $output
514
	 * @return string
515
	 */
516
	public function review_order_buyer_details( $output ) {
517
		$payer = $this->paypal_data->get( 'payer' );
518
		$output .= '<ul>';
519
		$output .= '<li><strong>' . __( 'Email:', 'wp-e-commerce' ) . ' </strong>' . $payer->email . '</li>';
520
		$output .= '<li><strong>' . __( 'First Name:', 'wp-e-commerce' ) . ' </strong>' . $payer->first_name . '</li>';
521
		$output .= '<li><strong>' . __( 'Last Name:', 'wp-e-commerce' ) . ' </strong>' . $payer->last_name . '</li>';
522
		$output .= '</ul>';
523
		return $output;
524
	}
525
526
	/**
527
	 * Display Shipping Details from PayPal
528
	 *
529
	 * @param string $output
530
	 * @return string
531
	 */
532
	public function review_order_shipping_details( $output ) {
533
		$address = $this->paypal_data->get( 'shipping_address' );
534
		$output .= '<ul>';
535
		$output .= '<li>' . $address[ 'name' ] . '</li>';
536
		$output .= '<li>' . $address[ 'street' ] . '</li>';
537
		$output .= '<li>' . $address[ 'city' ] . '</li>';
538
		$output .= '<li>' . $address[ 'state' ] . '</li>';
539
		$output .= '<li>' . $address[ 'zip' ] . '</li>';
540
		$output .= '<li>' . $address[ 'country_code' ] . '</li>';
541
		$output .= '</ul>';
542
		return $output;
543
	}
544
545
	/**
546
	 * Confirm Transaction Callback
547
	 *
548
	 * @return bool
549
	 *
550
	 * @since 3.9
551
	 */
552
	public function callback_confirm_transaction() {
553
		if ( ! isset( $_REQUEST['sessionid'] ) || ! isset( $_REQUEST['token'] ) || ! isset( $_REQUEST['PayerID'] ) ) {
554
			return false;
555
		}
556
557
		// Set the Purchase Log
558
		$this->set_purchase_log_for_callbacks();
559
560
		// Display the Confirmation Page
561
		$this->do_transaction();
562
563
		// Remove Shortcut option if it exists
564
		$sessionid = $_REQUEST['sessionid'];
565
		wpsc_delete_customer_meta( 'esc-' . $sessionid );
566
	}
567
568
	/**
569
	 * Process the transaction through the PayPal APIs
570
	 *
571
	 * @since 3.9
572
	 */
573
	public function do_transaction() {
574
		$args = array_map( 'urldecode', $_GET );
575
		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...
576
577
		if ( ! isset( $sessionid ) || ! isset( $token ) || ! isset( $PayerID ) ) {
578
			return;
579
		}
580
581
		$this->set_purchase_log_for_callbacks();
582
583
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
584
		$options = array(
585
			'token'         => $token,
586
			'payer_id'      => $PayerID,
587
			'message_id'    => $this->purchase_log->get( 'id' ),
588
			'invoice'		=> $this->purchase_log->get( 'sessionid' ),
589
		);
590
		$options += $this->checkout_data->get_gateway_data();
591
		$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...
592
593
		if ( $this->setting->get( 'ipn', false ) ) {
594
			$options['notify_url'] = $this->get_notify_url();
595
		}
596
597
		// GetExpressCheckoutDetails
598
		$details = $this->gateway->get_details_for( $token );
599
		$this->log_payer_details( $details );
600
601
		$response = $this->gateway->purchase( $options );
602
		$this->log_protection_status( $response );
603
		$location = remove_query_arg( 'payment_gateway_callback' );
604
605
		if ( $response->has_errors() ) {
606
			$errors = $response->get_params();
607
608
			if ( isset( $errors['L_ERRORCODE0'] ) && '10486' == $errors['L_ERRORCODE0'] ) {
609
				wp_redirect( $this->get_redirect_url( array( 'token' => $token ) ) );
610
				exit;
611
			}
612
613
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
614
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_paypal_error' ) );
615
616
		} elseif ( $response->is_payment_completed() || $response->is_payment_pending() ) {
617
			$location = remove_query_arg( 'payment_gateway' );
618
619
			if ( $response->is_payment_completed() ) {
620
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
621
			} else {
622
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
623
			}
624
625
			$this->purchase_log->set( 'transactid', $response->get( 'transaction_id' ) )
626
				->set( 'date', time() )
627
				->save();
628
		} else {
629
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_generic_error' ) );
630
		}
631
632
		wp_redirect( esc_url_raw( $location ) );
633
		exit;
634
	}
635
636
	public function callback_display_paypal_error() {
637
		add_filter( 'wpsc_get_transaction_html_output', array( $this, 'filter_paypal_error_page' ) );
638
	}
639
640
	public function callback_display_generic_error() {
641
		add_filter( 'wpsc_get_transaction_html_output', array( $this, 'filter_generic_error_page' ) );
642
	}
643
644
	/**
645
	 * Records the Payer ID, Payer Status and Shipping Status to the Purchase
646
	 * Log on GetExpressCheckout Call
647
	 *
648
	 * @return void
649
	 */
650
	public function log_payer_details( $details ) {
651
		if ( isset( $details->get( 'payer' )->id ) && !empty( $details->get( 'payer' )->id ) ) {
652
			$payer_id = $details->get( 'payer' )->id;
653
		} else {
654
			$payer_id = 'not set';
655
		}
656
		if ( isset( $details->get( 'payer' )->status ) && !empty( $details->get( 'payer' )->status ) ) {
657
			$payer_status = $details->get( 'payer' )->status;
658
		} else {
659
			$payer_status = 'not set';
660
		}
661
		if ( isset( $details->get( 'payer' )->shipping_status ) && !empty( $details->get( 'payer' )->shipping_status ) ) {
662
			$payer_shipping_status = $details->get( 'payer' )->shipping_status;
663
		} else {
664
			$payer_shipping_status = 'not set';
665
		}
666
		$paypal_log = array(
667
			'payer_id'        => $payer_id,
668
			'payer_status'    => $payer_status,
669
			'shipping_status' => $payer_shipping_status,
670
			'protection'      => null,
671
		);
672
673
		wpsc_update_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details' , $paypal_log );
674
	}
675
676
	/**
677
	 * Records the Protection Eligibility status to the Purchase Log on
678
	 * DoExpressCheckout Call
679
	 *
680
	 * @return void
681
	 */
682
	public function log_protection_status( $response ) {
683
		$params = $response->get_params();
684
685
		if ( isset( $params['PAYMENTINFO_0_PROTECTIONELIGIBILITY'] ) ) {
686
			$elg                      = $params['PAYMENTINFO_0_PROTECTIONELIGIBILITY'];
687
		} else {
688
			$elg = false;
689
		}
690
		$paypal_log               = wpsc_get_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details', true );
691
		$paypal_log['protection'] = $elg;
692
		wpsc_update_purchase_meta( $this->purchase_log->get( 'id' ), 'paypal_ec_details' , $paypal_log );
693
	}
694
695
	public function callback_process_confirmed_payment() {
696
		$args = array_map( 'urldecode', $_GET );
697
		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...
698
699
		if ( ! isset( $sessionid ) || ! isset( $token ) || ! isset( $PayerID ) ) {
700
			return;
701
		}
702
703
		$this->set_purchase_log_for_callbacks();
704
705
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
706
		$options = array(
707
			'token'         => $token,
708
			'payer_id'      => $PayerID,
709
			'message_id'    => $this->purchase_log->get( 'id' ),
710
			'invoice'       => $this->purchase_log->get( 'sessionid' ),
711
		);
712
		$options += $this->checkout_data->get_gateway_data();
713
		$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...
714
715
		if ( $this->setting->get( 'ipn', false ) ) {
716
			$options['notify_url'] = $this->get_notify_url();
717
		}
718
719
		// GetExpressCheckoutDetails
720
		$details = $this->gateway->get_details_for( $token );
721
		$this->log_payer_details( $details );
722
723
		$response = $this->gateway->purchase( $options );
724
		$this->log_protection_status( $response );
725
		$location = remove_query_arg( 'payment_gateway_callback' );
726
727
		if ( $response->has_errors() ) {
728
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
729
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_paypal_error' ) );
730
		} elseif ( $response->is_payment_completed() || $response->is_payment_pending() ) {
731
			$location = remove_query_arg( 'payment_gateway' );
732
733
			if ( $response->is_payment_completed() ) {
734
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ACCEPTED_PAYMENT );
735
			} else {
736
				$this->purchase_log->set( 'processed', WPSC_Purchase_Log::ORDER_RECEIVED );
737
			}
738
739
			$this->purchase_log->set( 'transactid', $response->get( 'transaction_id' ) )
740
				->set( 'date', time() )
741
				->save();
742
		} else {
743
			$location = add_query_arg( array( 'payment_gateway_callback' => 'display_generic_error' ) );
744
		}
745
746
		wp_redirect( esc_url_raw( $location ) );
747
		exit;
748
	}
749
750
	/**
751
	 * Error Page Template
752
	 *
753
	 * @since 3.9
754
	 */
755
	public function filter_paypal_error_page() {
756
		$errors = wpsc_get_customer_meta( 'paypal_express_checkout_errors' );
757
		ob_start();
758
?>
759
	<p>
760
	<?php _e( 'Sorry, your transaction could not be processed by PayPal. Please contact the site administrator. The following errors are returned:' , 'wp-e-commerce' ); ?>
761
		</p>
762
			<ul>
763
			<?php foreach ( $errors as $error ): ?>
764
			<li><?php echo esc_html( $error['details'] ) ?> (<?php echo esc_html( $error['code'] ); ?>)</li>
765
			<?php endforeach; ?>
766
		</ul>
767
			<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>
768
<?php
769
		$output = apply_filters( 'wpsc_paypal_express_checkout_gateway_error_message', ob_get_clean(), $errors );
770
		return $output;
771
	}
772
773
	/**
774
	 * Generic Error Page Template
775
	 *
776
	 * @since 3.9
777
	 */
778
	public function filter_generic_error_page() {
779
		ob_start();
780
?>
781
<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>
782
<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>
783
<?php
784
		$output = apply_filters( 'wpsc_paypal_express_checkout_generic_error_message', ob_get_clean() );
785
		return $output;
786
	}
787
788
	/**
789
	 * Settings Form Template
790
	 *
791
	 * @since 3.9
792
	 */
793
	public function setup_form() {
794
		$paypal_currency = $this->get_currency_code();
795
?>
796
797
<!-- Account Credentials -->
798
<tr>
799
	<td colspan="2">
800
		<h4><?php _e( 'Account Credentials', 'wp-e-commerce' ); ?></h4>
801
	</td>
802
</tr>
803
<tr>
804
	<td>
805
		<label for="wpsc-paypal-express-api-username"><?php _e( 'API Username', 'wp-e-commerce' ); ?></label>
806
	</td>
807
	<td>
808
		<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" />
809
	</td>
810
</tr>
811
<tr>
812
	<td>
813
		<label for="wpsc-paypal-express-api-password"><?php _e( 'API Password', 'wp-e-commerce' ); ?></label>
814
	</td>
815
	<td>
816
		<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" />
817
	</td>
818
</tr>
819
<tr>
820
	<td>
821
		<label for="wpsc-paypal-express-api-signature"><?php _e( 'API Signature', 'wp-e-commerce' ); ?></label>
822
	</td>
823
	<td>
824
		<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" />
825
	</td>
826
</tr>
827
<tr>
828
	<td>
829
		<label for="wpsc-paypal-express-api-username"><?php _e( 'Merchant ID', 'wp-e-commerce' ); ?></label>
830
	</td>
831
	<td>
832
		<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" />
833
	</td>
834
</tr>
835
<tr>
836
	<td>
837
		<label><?php _e( 'Sandbox Mode', 'wp-e-commerce' ); ?></label>
838
	</td>
839
	<td>
840
		<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;
841
		<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>
842
	</td>
843
</tr>
844
<tr>
845
	<td>
846
		<label><?php _e( 'IPN', 'wp-e-commerce' ); ?></label>
847
	</td>
848
	<td>
849
		<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;
850
		<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>
851
	</td>
852
</tr>
853
854
<!-- Cart Customization -->
855
<tr>
856
	<td colspan="2">
857
		<label><h4><?php _e( 'Cart Customization', 'wp-e-commerce'); ?></h4></label>
858
	</td>
859
</tr>
860
<tr>
861
	<td>
862
		<label for="wpsc-paypal-express-cart-logo"><?php _e( 'Merchant Logo', 'wp-e-commerce' ); ?></label>
863
	</td>
864
	<td>
865
		<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>
866
	</td>
867
</tr>
868
<tr>
869
	<td>
870
		<label for="wpsc-paypal-express-cart-border"><?php _e( 'Cart Border Color', 'wp-e-commerce' ); ?></label>
871
	</td>
872
	<td>
873
		<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" />
874
	</td>
875
</tr>
876
<tr>
877
	<td>
878
		<label for="wpsc-paypal-express-cart-border"><?php _e( 'Enable In-Context Checkout', 'wp-e-commerce' ); ?></label>
879
	</td>
880
	<td>
881
		<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;
882
		<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>
883
	</td>
884
</tr>
885
886
<!-- Currency Conversion -->
887
<?php if ( ! $this->is_currency_supported() ) : ?>
888
<tr>
889
	<td colspan="2">
890
		<h4><?php _e( 'Currency Conversion', 'wp-e-commerce' ); ?></h4>
891
	</td>
892
</tr>
893
<tr>
894
	<td colspan="2">
895
		<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>
896
	</td>
897
</tr>
898
<tr>
899
	<td>
900
		<label for "wpsc-paypal-express-currency"><?php _e( 'PayPal Currency', 'wp-e-commerce' ); ?></label>
901
	</td>
902
	<td>
903
		<select name="<?php echo esc_attr( $this->setting->get_field_name( 'currency' ) ); ?>" id="wpsc-paypal-express-currency">
904
			<?php foreach ( $this->gateway->get_supported_currencies() as $currency ) : ?>
905
			<option <?php selected( $currency, $paypal_currency ); ?> value="<?php echo esc_attr( $currency ); ?>"><?php echo esc_html( $currency ); ?></option>
906
			<?php endforeach ?>
907
		</select>
908
	</td>
909
</tr>
910
<?php endif ?>
911
912
<!-- Checkout Shortcut -->
913
<tr>
914
	<td colspan="2">
915
		<h4><?php _e( 'Express Checkout Shortcut', 'wp-e-commerce' ); ?></h4>
916
	</td>
917
</tr>
918
<tr>
919
	<td>
920
		<label><?php _e( 'Enable Shortcut', 'wp-e-commerce' ); ?></label>
921
	</td>
922
	<td>
923
		<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;
924
		<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>
925
	</td>
926
</tr>
927
928
<!-- Error Logging -->
929
<tr>
930
	<td colspan="2">
931
		<h4><?php _e( 'Error Logging', 'wp-e-commerce' ); ?></h4>
932
	</td>
933
</tr>
934
<tr>
935
	<td>
936
		<label><?php _e( 'Enable Debugging', 'wp-e-commerce' ); ?></label>
937
	</td>
938
	<td>
939
		<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;
940
		<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>
941
	</td>
942
</tr>
943
<?php
944
	}
945
946
	/**
947
	 * Check if the selected currency is supported by the gateway
948
	 *
949
	 * @return bool
950
	 *
951
	 * @since 3.9
952
	 */
953
	protected function is_currency_supported() {
954
		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...
955
	}
956
957
	/**
958
	 * Return the Currency ISO code
959
	 *
960
	 * @return string
961
	 *
962
	 * @since 3.9
963
	 */
964
	public function get_currency_code() {
965
		$code = parent::get_currency_code();
966
967
		if ( ! in_array( $code, $this->gateway->get_supported_currencies() ) ) {
968
			$code = $this->setting->get( 'currency', 'USD' );
969
		}
970
971
		return $code;
972
	}
973
974
	/**
975
	 * Convert an amount (integer) to the supported currency
976
	 * @param integer $amt
977
	 *
978
	 * @return integer
979
	 *
980
	 * @since 3.9
981
	 */
982
	protected function convert( $amt ) {
983
		if ( $this->is_currency_supported() ) {
984
			return $amt;
985
		}
986
987
		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...
988
	}
989
990
	/**
991
	 * Process the SetExpressCheckout API Call
992
	 *
993
	 * @return void
994
	 *
995
	 * @since 3.9
996
	 */
997
	public function process() {
998
		$total = $this->convert( $this->purchase_log->get( 'totalprice' ) );
999
		$options = array(
1000
			'return_url'       => $this->get_return_url(),
1001
			'message_id'       => $this->purchase_log->get( 'id' ),
1002
			'invoice'          => $this->purchase_log->get( 'sessionid' ),
1003
			'address_override' => 1,
1004
		);
1005
1006
		$options += $this->checkout_data->get_gateway_data();
1007
		$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...
1008
1009
		if ( $this->setting->get( 'ipn', false ) ) {
1010
			$options['notify_url'] = $this->get_notify_url();
1011
		}
1012
1013
		// SetExpressCheckout
1014
		$response = $this->gateway->setup_purchase( $options );
1015
1016
		if ( $response->is_successful() ) {
1017
			$params = $response->get_params();
1018
			if ( $params['ACK'] == 'SuccessWithWarning' ) {
1019
				$this->log_error( $response );
1020
				wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
1021
			}
1022
			// Successful redirect
1023
			$url = $this->get_redirect_url( array( 'token' => $response->get( 'token' ) ) );
1024
		} else {
1025
1026
			// SetExpressCheckout Failure
1027
			$this->log_error( $response );
1028
			wpsc_update_customer_meta( 'paypal_express_checkout_errors', $response->get_errors() );
1029
1030
			$url = add_query_arg( array(
1031
				'payment_gateway'          => 'paypal-express-checkout',
1032
				'payment_gateway_callback' => 'display_paypal_error',
1033
			), $this->get_return_url() );
1034
		}
1035
1036
		wp_redirect( $url );
1037
		exit;
1038
	}
1039
1040
	/**
1041
	 * Log an error message
1042
	 *
1043
	 * @param PHP_Merchant_Paypal_Express_Checkout_Response $response
1044
	 * @return void
1045
	 *
1046
	 * @since 3.9
1047
	 */
1048
	public function log_error( $response ) {
1049
		if ( $this->setting->get( 'debugging' ) ) {
1050
1051
			add_filter( 'wpsc_logging_post_type_args', 'WPSC_Logging::force_ui' );
1052
			add_filter( 'wpsc_logging_taxonomy_args ', 'WPSC_Logging::force_ui' );
1053
1054
			$log_data = array(
1055
				'post_title'    => 'PayPal ExpressCheckout Operation Failure',
1056
				'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...
1057
				'log_type'      => 'error'
1058
			);
1059
1060
			$log_meta = array(
1061
				'correlation_id'   => $response->get( 'correlation_id' ),
1062
				'time' => $response->get( 'datetime' ),
1063
				'errors' => $response->get_errors(),
1064
			);
1065
1066
			$log_entry = WPSC_Logging::insert_log( $log_data, $log_meta );
1067
		}
1068
	}
1069
1070
	public function process_refund( $order_id, $amount = 0.00, $reason = '', $manual = false ) {
1071
1072
		if ( 0.00 == $amount ) {
1073
			return new WP_Error( 'paypal_refund_error', __( 'Refund Error: You need to specify a refund amount.', 'wp-e-commerce' ) );
1074
		}
1075
1076
		$log = new WPSC_Purchase_Log( $order_id );
1077
1078
		if ( ! $log->get( 'transactid' ) ) {
1079
			return new WP_Error( 'error', __( 'Refund Failed: No transaction ID', 'wp-e-commerce' ) );
1080
		}
1081
1082
		$max_refund  = $log->get( 'totalprice' ) - $log->get_total_refunded();
1083
1084
		if ( $amount && $max_refund < $amount || 0 > $amount ) {
1085
			throw new Exception( __( 'Invalid refund amount', 'wp-e-commerce' ) );
1086
		}
1087
1088
		if ( $manual ) {
1089
			$current_refund = $log->get_total_refunded();
1090
			$log->set( 'total_order_refunded' , $amount + $current_refund )->save();
1091
1092
			wpsc_purchlogs_update_notes( absint( $order_id ), sprintf( __( 'Refunded %s via Manual Refund', 'wp-e-commerce' ), $amount ) );
1093
1094
			return true;
1095
		}
1096
1097
		// If refund is full amount is not needed
1098
		// add refund params
1099
		$options = array(
1100
			'transaction_id' => $log->get( 'transactid' ),
1101
			'invoice'        => $log->get( 'sessionid' ),
1102
			'note'           => $reason,
1103
		);
1104
1105
		if( $amount && $amount <= $log->get_remaining_refund() ) {
1106
			$options['refund_type'] = 'Partial';
1107
			$options['amount']      = $amount;
1108
		} else {
1109
			$options['refund_type'] = 'Full';
1110
		}
1111
1112
		// do API call
1113
		$response = $this->gateway->credit( $options );
1114
1115
		// look at ACK to see if success or failure
1116
		if ( $response->has_errors() ) {
1117
			// WE could use $response->get_errors() and return the errors in an alert message ?
1118
			return false;
1119
		}
1120
1121
		if ( $response->is_successful() ) {
1122
			$params = $response->get_params();
1123
			if ( 'Success' == $params['ACK'] || 'SuccessWithWarning' == $params['ACK'] ) {
1124
1125
				$this->log_error( $response );
1126
				// Set a log meta entry
1127
				$current_refund = $log->get_total_refunded();
1128
				$log->set( 'total_order_refunded' , $amount + $current_refund )->save();
1129
1130
				wpsc_purchlogs_update_notes( absint( $order_id ), sprintf( __( 'Refunded %s - Refund ID: %s', 'wp-e-commerce' ), $params['GROSSREFUNDAMT'], $params['REFUNDTRANSACTIONID'] ) );
1131
1132
				return true;
1133
			}
1134
		} else {
1135
			return false;
1136
		}
1137
	}
1138
}
1139