WooCommerce PayPal Express Checkout Payment Gateway - Version 1.1.0

Version Description

  • Improved flow after express checkout by removing billing and shipping fields and simply allowing shipping method selection.
  • Fix - Fixed in-context checkout to work after ajax cart reload.
  • Fix - Added missing 'large' button size.
  • Fix - Prevent double stock reduction when payment complete.
  • Fix - Allow PPE from pay page and don't use in-context checkout for PayPal Mark on checkout.
  • Fix - Increase timeout to 30 to prevent error #3.
  • Tweak - If the store owner decides to enable PayPal standard, respect that decision and remove EC from checkout screen.
  • Tweak - Change place order button to "continue to payment".
  • Tweak - Moved default button location to woocommerce_proceed_to_checkout hook.
  • Tweak - Improved button appearance and look alongside regular checkout button.
Download this release

Release Info

Developer akeda
Plugin Icon 128x128 WooCommerce PayPal Express Checkout Payment Gateway
Version 1.1.0
Comparing to
See all releases

Code changes from version 1.0.4 to 1.1.0

assets/css/wc-gateway-ppec-frontend-cart.css CHANGED
@@ -1,22 +1,29 @@
1
- .woo_pp_cart_buttons_div {
2
- margin-top: -20px;
 
 
3
  }
4
- .woo_pp_cart_buttons_div:after {
5
- visibility: hidden;
6
  display: block;
7
- font-size: 0;
8
- content: " ";
9
- clear: both;
10
- height: 0;
11
  }
12
-
13
- .paypal-button-hidden {
14
- visibility: hidden;
 
 
 
 
15
  }
16
-
17
  .paypal-button-widget .paypal-button,
18
  .paypal-button-widget .paypal-button:hover {
19
  background: transparent;
20
  box-shadow: none;
21
  border: none;
22
  }
 
 
 
 
 
1
+ .wcppec-checkout-buttons {
2
+ text-align: center;
3
+ margin: 1em 0;
4
+ overflow: hidden;
5
  }
6
+ .wcppec-checkout-buttons__separator {
 
7
  display: block;
8
+ opacity: .5;
9
+ margin: 0 0 1em;
 
 
10
  }
11
+ .wcppec-checkout-buttons__button {
12
+ display: block;
13
+ text-decoration: none !important;
14
+ border: 0 !important;
15
+ }
16
+ .wcppec-checkout-buttons__button img {
17
+ margin: 0 auto;
18
  }
 
19
  .paypal-button-widget .paypal-button,
20
  .paypal-button-widget .paypal-button:hover {
21
  background: transparent;
22
  box-shadow: none;
23
  border: none;
24
  }
25
+ .wcppec-cart-widget-button {
26
+ display: inline-block;
27
+ text-decoration: none !important;
28
+ border: 0 !important;
29
+ }
assets/js/wc-gateway-ppec-frontend-in-context-checkout.js ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ;(function ( $, window, document ) {
2
+
3
+ window.paypalCheckoutReady = function() {
4
+ paypal.checkout.setup(
5
+ wc_ppec_context.payer_id,
6
+ {
7
+ environment: wc_ppec_context.environment,
8
+ button: 'woo_pp_ec_button',
9
+ locale: wc_ppec_context.locale,
10
+ }
11
+ );
12
+ }
13
+
14
+ $( document ).on( 'click', '#woo_pp_ec_button', function( event ) {
15
+ event.preventDefault();
16
+ paypal.checkout.initXO();
17
+ paypal.checkout.startFlow( wc_ppec_context.start_flow );
18
+ } );
19
+
20
+ })( jQuery, window, document );
includes/abstracts/abstract-wc-gateway-ppec-client-credential.php CHANGED
@@ -27,13 +27,6 @@ abstract class WC_Gateway_PPEC_Client_Credential {
27
  */
28
  protected $_subject;
29
 
30
- /**
31
- * Payer ID.
32
- *
33
- * @var string
34
- */
35
- protected $_payer_id;
36
-
37
  /**
38
  * Get API username.
39
  *
@@ -61,24 +54,6 @@ abstract class WC_Gateway_PPEC_Client_Credential {
61
  return $this->_subject;
62
  }
63
 
64
- /**
65
- * Get payer ID.
66
- *
67
- * @return string Payer ID
68
- */
69
- public function get_payer_id() {
70
- return $this->_payer_id;
71
- }
72
-
73
- /**
74
- * Set payer ID.
75
- *
76
- * @param string $payer_id Payer ID
77
- */
78
- public function set_payer_id( $payer_id ) {
79
- $this->_payer_id = $payer_id;
80
- }
81
-
82
  /**
83
  * Retrieves the subdomain of the endpoint which should be used for this type
84
  * of credentials.
27
  */
28
  protected $_subject;
29
 
 
 
 
 
 
 
 
30
  /**
31
  * Get API username.
32
  *
54
  return $this->_subject;
55
  }
56
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
57
  /**
58
  * Retrieves the subdomain of the endpoint which should be used for this type
59
  * of credentials.
includes/abstracts/abstract-wc-gateway-ppec.php CHANGED
@@ -4,212 +4,155 @@ if ( ! defined( 'ABSPATH' ) ) {
4
  exit; // Exit if accessed directly
5
  }
6
 
 
 
 
7
  abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
8
 
9
- private static $process_admin_options_already_run = false;
10
- private static $process_admin_options_validation_error = false;
11
-
12
- protected $buyer_email = false;
13
- public static $use_buyer_email = true;
14
-
15
  public function __construct() {
16
-
17
- $this->has_fields = false;
18
- $this->icon = false;
19
- $this->title = '';
20
- $this->description = '';
21
- $this->supports[] = 'refunds';
22
-
23
  $this->method_title = __( 'PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' );
24
- $this->method_description = __( 'Process payments quickly and securely with PayPal.', 'woocommerce-gateway-paypal-express-checkout' );
 
 
 
 
25
 
26
  wc_gateway_ppec()->ips->maybe_received_credentials();
27
 
28
  $this->init_form_fields();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
 
30
- $settings = wc_gateway_ppec()->settings->loadSettings();
31
-
 
 
 
 
 
32
 
33
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
34
 
35
- // Do we need to auto-select this payment method?
36
- // TODO: Move this out to particular handler instead of gateway
37
  if ( ! is_admin() ) {
38
- $session = WC()->session->get( 'paypal' );
39
- if ( null != $session && is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) && $session->checkout_completed && $session->expiry_time >= time() && $session->payerID ) {
40
- if ( $session->checkout_details && is_a( $session->checkout_details, 'PayPal_Checkout_Details' ) && ( is_checkout() || is_ajax() ) && self::$use_buyer_email ) {
41
- $this->buyer_email = $session->checkout_details->payer_details->email;
42
- $this->title .= ' - ' . esc_html( $this->buyer_email );
43
- }
44
-
45
- $posted = array(
46
- 'billing_first_name' => $session->checkout_details->payer_details->first_name,
47
- 'billing_last_name' => $session->checkout_details->payer_details->last_name,
48
- 'billing_email' => $session->checkout_details->payer_details->email,
49
- 'billing_phone' => $session->checkout_details->payer_details->phone_number,
50
- 'billing_country' => $session->checkout_details->payer_details->country
51
- );
52
 
53
- if ( $session->shipping_required ) {
54
- if ( false === strpos( $session->checkout_details->payments[0]->shipping_address->getName(), ' ' ) ) {
55
- $posted['shipping_first_name'] = $session->checkout_details->payer_details->first_name;
56
- $posted['shipping_last_name'] = $session->checkout_details->payer_details->last_name;
57
- $posted['shipping_company'] = $session->checkout_details->payments[0]->shipping_address->getName();
58
- } else {
59
- $name = explode( ' ', $session->checkout_details->payments[0]->shipping_address->getName() );
60
- $posted['shipping_first_name'] = $name[0];
61
- array_shift( $name );
62
- $posted['shipping_last_name'] = implode( ' ', $name );
63
- }
64
-
65
- $posted = array_merge( $posted, array(
66
- 'shipping_company' => $session->checkout_details->payer_details->business_name,
67
- 'shipping_address_1' => $session->checkout_details->payments[0]->shipping_address->getStreet1(),
68
- 'shipping_address_2' => $session->checkout_details->payments[0]->shipping_address->getStreet2(),
69
- 'shipping_city' => $session->checkout_details->payments[0]->shipping_address->getCity(),
70
- 'shipping_state' => $session->checkout_details->payments[0]->shipping_address->getState(),
71
- 'shipping_postcode' => $session->checkout_details->payments[0]->shipping_address->getZip(),
72
- 'shipping_country' => $session->checkout_details->payments[0]->shipping_address->getCountry(),
73
- 'ship_to_different_address' => true
74
- ) );
75
-
76
- } else {
77
- $posted['ship_to_different_address'] = false;
78
- }
79
-
80
- $_POST = array_merge( $_POST, $posted );
81
-
82
- // Make sure the proper option is selected based on what the buyer picked
83
- if ( ! ( $session->using_ppc xor is_a( $this, 'WC_Gateway_PPEC_With_PayPal_Credit' ) ) ) {
84
- $this->chosen = true;
85
- } else {
86
- $this->chosen = false;
87
- }
88
  }
89
  }
90
  }
91
 
92
- public function before_checkout_billing_form( $checkout ) {
93
- $checkout->checkout_fields['billing'] = array(
94
- 'billing_first_name' => $checkout->checkout_fields['billing']['billing_first_name'],
95
- 'billing_last_name' => $checkout->checkout_fields['billing']['billing_last_name'],
96
- 'billing_country' => $checkout->checkout_fields['billing']['billing_country'],
97
- 'billing_email' => $checkout->checkout_fields['billing']['billing_email'],
98
- 'billing_phone' => $checkout->checkout_fields['billing']['billing_phone']
99
- );
100
- }
101
-
102
  public function init_form_fields() {
103
- $this->form_fields = array();
104
  }
105
 
 
 
 
106
  public function process_payment( $order_id ) {
107
-
108
  $checkout = wc_gateway_ppec()->checkout;
 
 
109
 
110
- // Check the session. Are we going to just complete an existing payment, or are we going to
111
- // send the user over PayPal to pay?
112
-
113
- $session = WC()->session->get( 'paypal' );
114
- if ( ! $session || ! is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) ||
115
- ! $session->checkout_completed || $session->expiry_time < time() ||
116
- ! $session->payerID ) {
117
- // Redirect them over to PayPal.
118
  try {
119
- $redirect_url = $checkout->start_checkout_from_checkout( $order_id, 'ppec_paypal_credit' === $this->id );
120
- $settings = wc_gateway_ppec()->settings->loadSettings();
121
- if ( $settings->enableInContextCheckout && $settings->getActiveApiCredentials()->get_payer_id() ) {
122
- $redirect_url = 'javascript:woo_pp_checkout_callback("' . urlencode( $redirect_url ) . '");';
123
- }
124
  return array(
125
- 'result' => 'success',
126
- 'redirect' => $redirect_url
127
  );
128
  } catch( PayPal_API_Exception $e ) {
129
- $final_output = '<ul>';
130
- foreach ( $e->errors as $error ) {
131
- $final_output .= '<li>' . $error->maptoBuyerFriendlyError() . '</li>';
132
- }
133
- $final_output .= '</ul>';
134
- wc_add_notice( 'Payment error:' . $final_output, 'error' );
135
  }
136
  } else {
137
- // We have a token we can work with. Just complete the payment now.
138
  try {
139
- $payment_details = $checkout->completePayment( $order_id, $session->token, $session->payerID );
140
- $transaction_id = $payment_details->payments[0]->transaction_id;
141
- $payment_status = $payment_details->payments[0]->payment_status;
142
- $pending_reason = $payment_details->payments[0]->pending_reason;
143
- $order = wc_get_order( $order_id );
144
 
145
- if ( 'Pending' === $payment_status && 'authorization' === $pending_reason ) {
146
- update_post_meta( $order->id, '_ppec_charge_captured', 'no' );
147
- add_post_meta( $order->id, '_transaction_id', $transaction_id, true );
148
 
149
- // Mark as on-hold
150
- $order->update_status( 'on-hold', sprintf( __( 'PayPal Express Checkout charge authorized (Charge ID: %s). Process order to take payment, or cancel to remove the pre-authorization.', 'woocommerce-gateway-paypal-express-checkout' ), $transaction_id ) );
151
 
152
- $order->reduce_order_stock();
153
-
154
- } else {
155
- // TODO: Handle things like eChecks, giropay, etc.
156
- $order->payment_complete( $transaction_id );
157
- $order->add_order_note( sprintf( __( 'PayPal Express Checkout transaction completed; transaction ID = %s', 'woocommerce-gateway-paypal-express-checkout' ), $transaction_id ) );
158
-
159
- update_post_meta( $order->id, '_ppec_charge_captured', 'yes' );
160
- }
161
-
162
- unset( WC()->session->paypal );
163
 
164
  return array(
165
- 'result' => 'success',
166
  'redirect' => $this->get_return_url( $order )
167
  );
168
  } catch( PayPal_Missing_Session_Exception $e ) {
169
- // For some reason, our session data is missing. Generally, if we've made it this far, this shouldn't happen.
170
- wc_add_notice( __( 'Sorry, an error occurred while trying to process your payment. Please try again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
171
  } catch( PayPal_API_Exception $e ) {
172
  // Did we get a 10486 or 10422 back from PayPal? If so, this means we need to send the buyer back over to
173
  // PayPal to have them pick out a new funding method.
174
- $need_to_redirect_back = false;
175
- foreach ( $e->errors as $error ) {
176
- if ( '10486' == $error->error_code || '10422' == $error->error_code ) {
177
- $need_to_redirect_back = true;
178
- }
179
- }
180
-
181
- if ( $need_to_redirect_back ) {
182
- // We're explicitly not loading settings here because we don't want in-context checkout
183
- // shown when we're redirecting back to PP for a funding source error.
184
- $settings = wc_gateway_ppec()->settings->loadSettings();
185
 
 
186
  $session->checkout_completed = false;
187
- $session->leftFrom = 'order';
188
- $session->order_id = $order_id;
189
- WC()->session->paypal = $session;
 
190
  return array(
191
- 'result' => 'success',
192
- 'redirect' => $settings->getPayPalRedirectUrl( $session->token, true )
193
  );
194
  } else {
195
- $final_output = '<ul>';
196
- foreach ( $e->errors as $error ) {
197
- $final_output .= '<li>' . $error->maptoBuyerFriendlyError() . '</li>';
198
- }
199
- $final_output .= '</ul>';
200
- wc_add_notice( __( 'Payment error:', 'woocommerce-gateway-paypal-express-checkout' ) . $final_output, 'error' );
201
- return;
202
  }
203
  }
204
  }
205
  }
206
 
 
 
 
 
 
207
  private function get_certificate_info( $cert_string ) {
208
  if ( ! strlen( $cert_string ) ) {
209
  return __( 'No API certificate on file.', 'woocommerce-gateway-paypal-express-checkout' );
210
  }
211
 
212
- $cert = openssl_x509_read( $cert_string );
 
 
213
  if ( false !== $cert ) {
214
  $certinfo = openssl_x509_parse( $cert );
215
  if ( false !== $certinfo ) {
@@ -230,485 +173,148 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
230
  } else {
231
  $out = __( 'The certificate on file is not valid.', 'woocommerce-gateway-paypal-express-checkout' );
232
  }
233
- } else {
234
- $out = __( 'The certificate on file is not valid.', 'woocommerce-gateway-paypal-express-checkout' );
235
  }
236
 
237
  return $out;
238
  }
239
 
240
- // We want to be able to do some magic JavaScript stuff that WooCommerce's settings API won't let us do, so we're just going
241
- // to override how WooCommerce tells us it should be done.
242
- public function admin_options() {
243
- $enable_ips = wc_gateway_ppec()->ips->is_supported();
244
-
245
- $error_msgs = get_option( 'woo_pp_admin_error' );
246
- if ( $error_msgs ) {
247
- foreach ( $error_msgs as $error_msg ) {
248
- foreach ( $error_msg as $type => $message ) {
249
- if ( 'error' == $type ) {
250
- WC_Admin_Settings::add_error( 'Error: ' . $message );
251
- } elseif ( 'warning' == $type ) {
252
- $this->display_warning( $message );
253
- } elseif ( 'success' == $type ) {
254
- WC_Admin_Settings::add_message( $message );
255
- }
256
- }
257
- }
258
 
259
- WC_Admin_Settings::show_messages();
260
- delete_option( 'woo_pp_admin_error' );
 
261
  }
262
 
263
- $settings = wc_gateway_ppec()->settings->loadSettings();
264
-
265
- $enabled = false;
266
- $logging_enabled = false;
267
- $ppc_enabled = false;
268
- $icc_enabled = false;
269
-
270
- $live_api_username = '';
271
- $sb_api_username = '';
272
- $live_api_pass = '';
273
- $live_api_sig = '';
274
- $sb_api_pass = '';
275
- $sb_api_sig = '';
276
- $live_subject = '';
277
- $sb_subject = '';
278
-
279
- $live_style = 'signature';
280
- $sb_style = 'signature';
281
-
282
- $live_cert = false;
283
- $sb_cert = false;
284
-
285
- $live_cert_info = __( 'No API certificate on file', 'woocommerce-gateway-paypal-express-checkout' );
286
- $sb_cert_info = __( 'No API certificate on file', 'woocommerce-gateway-paypal-express-checkout' );
287
- $environment = 'sandbox';
288
-
289
- // If we're re-rending the page after a validation error, make sure that we show the data the user entered instead of just reverting
290
- // to what is stored in the database.
291
- if ( self::$process_admin_options_validation_error ) {
292
- // TODO: We should probably encrypt the cert in some manner instead of just Base64-encoding it
293
- if ( ! empty( $_POST['woo_pp_enabled'] ) && 'true' == $_POST['woo_pp_enabled'] ) {
294
- $enabled = true;
295
- }
296
-
297
- if ( ! empty( $_POST['woo_pp_ppc_enabled'] ) && 'true' == $_POST['woo_pp_ppc_enabled'] ) {
298
- $ppc_enabled = true;
299
- }
300
-
301
- if ( ! empty( $_POST['woo_pp_icc_enabled'] ) && 'true' == $_POST['woo_pp_icc_enabled'] ) {
302
- $icc_enabled = true;
303
- }
304
-
305
- if ( ! empty( $_POST['woo_pp_logging_enabled'] ) && 'true' == $_POST['woo_pp_logging_enabled'] ) {
306
- $logging_enabled = true;
307
- }
308
-
309
- if ( array_key_exists( 'woo_pp_environment', $_POST ) ) {
310
- if ( 'live' == $_POST['woo_pp_environment'] || 'sandbox' == $_POST['woo_pp_environment'] ) {
311
- $environment = $_POST['woo_pp_environment'];
312
- }
313
- }
314
-
315
- // Grab the live credentials.
316
- $live_api_username = $_POST['woo_pp_live_api_username'];
317
- $live_api_pass = $_POST['woo_pp_live_api_password'];
318
- $live_subject = $_POST['woo_pp_live_subject' ];
319
-
320
- if ( array_key_exists( 'woo_pp_live_api_style', $_POST ) ) {
321
- if ( 'signature' == $_POST['woo_pp_live_api_style'] || 'certificate' == $_POST['woo_pp_live_api_style'] ) {
322
- $live_style = $_POST['woo_pp_live_api_style'];
323
- }
324
- }
325
-
326
- if ( 'signature' == $live_style ) {
327
- $live_api_sig = $_POST['woo_pp_live_api_signature'];
328
- } else {
329
- if ( array_key_exists( 'woo_pp_live_api_certificate', $_FILES ) && array_key_exists( 'tmp_name', $_FILES['woo_pp_live_api_certificate'] )
330
- && array_key_exists( 'size', $_FILES['woo_pp_live_api_certificate'] ) && $_FILES['woo_pp_live_api_certificate']['size'] ) {
331
- $live_cert = file_get_contents( $_FILES['woo_pp_live_api_certificate']['tmp_name'] );
332
- $live_cert_info = $this->get_certificate_info( $live_cert );
333
- } elseif ( array_key_exists( 'woo_pp_live_api_cert_string', $_POST ) ) {
334
- $live_cert = base64_decode( $_POST['woo_pp_live_api_cert_string'] );
335
- $live_cert_info = $this->get_certificate_info( $live_cert );
336
- }
337
- }
338
-
339
- // Grab the sandbox credentials.
340
- $sb_api_username = $_POST['woo_pp_sandbox_api_username'];
341
- $sb_api_pass = $_POST['woo_pp_sandbox_api_password'];
342
- $sb_subject = $_POST['woo_pp_sandbox_subject' ];
343
-
344
- if ( array_key_exists( 'woo_pp_sandbox_api_style', $_POST ) ) {
345
- if ( 'signature' == $_POST['woo_pp_sandbox_api_style'] || 'certificate' == $_POST['woo_pp_sandbox_api_style'] ) {
346
- $sb_style = $_POST['woo_pp_sandbox_api_style'];
347
- }
348
- }
349
-
350
- if ( 'signature' == $sb_style ) {
351
- $sb_api_sig = $_POST['woo_pp_sandbox_api_signature'];
352
- } else {
353
- if ( array_key_exists( 'woo_pp_sandbox_api_certificate', $_FILES ) && array_key_exists( 'tmp_name', $_FILES['woo_pp_sandbox_api_certificate'] )
354
- && array_key_exists( 'size', $_FILES['woo_pp_sandbox_api_certificate'] ) && $_FILES['woo_pp_sandbox_api_certificate']['size'] ) {
355
- $sb_cert = file_get_contents( $_FILES['woo_pp_sandbox_api_certificate']['tmp_name'] );
356
- $sb_cert_info = $this->get_certificate_info( $sb_cert );
357
- } elseif ( array_key_exists( 'woo_pp_sandbox_api_cert_string', $_POST ) ) {
358
- $sb_cert = base64_decode( $_POST['woo_pp_sandbox_api_cert_string'] );
359
- $sb_cert_info = $this->get_certificate_info( $sb_cert );
360
- }
361
- }
362
-
363
- if ( ! empty( $_POST['woo_pp_allow_guest_checkout'] ) && 'true' == $_POST['woo_pp_allow_guest_checkout'] ) {
364
- $allow_guest_checkout = true;
365
- } else {
366
- $allow_guest_checkout = false;
367
- }
368
-
369
- if ( ! empty( $_POST['woo_pp_block_echecks'] ) && 'true' == $_POST['woo_pp_block_echecks'] ) {
370
- $block_echecks = true;
371
- } else {
372
- $block_echecks = false;
373
- }
374
-
375
- if ( ! empty( $_POST['woo_pp_req_billing_address'] ) && 'true' == $_POST['woo_pp_req_billing_address'] ) {
376
- $require_billing_address = true;
377
- } else {
378
- $require_billing_address = false;
379
- }
380
 
381
- $button_size = $_POST['woo_pp_button_size' ];
382
- $mark_size = $_POST['woo_pp_mark_size' ];
383
- $logo_image_url = $_POST['woo_pp_logo_image_url' ];
384
- $payment_action = $_POST['woo_pp_payment_action' ];
385
- $zero_subtotal_behavior = $_POST['woo_pp_zero_subtotal_behavior' ];
386
- $subtotal_mismatch_behavior = $_POST['woo_pp_subtotal_mismatch_behavior'];
387
  } else {
 
 
388
 
389
- if ( is_object( $settings->liveApiCredentials ) && is_a( $settings->liveApiCredentials, 'WC_Gateway_PPEC_Client_Credential' ) ) {
390
- $live_api_username = $settings->liveApiCredentials->get_username();
391
- $live_subject = $settings->liveApiCredentials->get_subject();
392
- $live_api_pass = $settings->liveApiCredentials->get_password();
393
-
394
- if ( is_a( $settings->liveApiCredentials, 'WC_Gateway_PPEC_Client_Credential_Signature' ) && $settings->liveApiCredentials->get_signature() ) {
395
- $live_api_sig = $settings->liveApiCredentials->get_signature();
396
- }
397
- if ( is_a( $settings->liveApiCredentials, 'WC_Gateway_PPEC_Client_Credential_Certificate' ) && $settings->liveApiCredentials->get_certificate() ) {
398
- $live_cert_info = $this->get_certificate_info( $settings->liveApiCredentials->get_certificate() );
399
- $live_style = 'certificate';
400
- }
401
- }
402
-
403
- if ( is_object( $settings->sandboxApiCredentials ) && is_a( $settings->sandboxApiCredentials, 'WC_Gateway_PPEC_Client_Credential' ) ) {
404
- $sb_api_username = $settings->sandboxApiCredentials->get_username();
405
- $sb_subject = $settings->sandboxApiCredentials->get_subject();
406
- $sb_api_pass = $settings->sandboxApiCredentials->get_password();
407
 
408
- if ( is_a( $settings->sandboxApiCredentials, 'WC_Gateway_PPEC_Client_Credential_Signature' ) && $settings->sandboxApiCredentials->get_signature() ) {
409
- $sb_api_sig = $settings->sandboxApiCredentials->get_signature();
410
- }
411
- if ( is_a ( $settings->sandboxApiCredentials, 'WC_Gateway_PPEC_Client_Credential_Certificate' ) && $settings->sandboxApiCredentials->get_certificate() ) {
412
- $sb_style = 'certificate';
413
- $sb_cert_info = $this->get_certificate_info( $settings->sandboxApiCredentials->get_certificate() );
414
- }
415
- }
416
-
417
- $enabled = $settings->enabled;
418
- $logging_enabled = $settings->logging_enabled;
419
- $ppc_enabled = $settings->ppcEnabled;
420
- $icc_enabled = $settings->enableInContextCheckout;
421
- $environment = $settings->environment;
422
- $button_size = $settings->buttonSize;
423
- $mark_size = $settings->markSize;
424
- $logo_image_url = $settings->logoImageUrl;
425
- $payment_action = $settings->paymentAction;
426
- $allow_guest_checkout = $settings->allowGuestCheckout;
427
- $block_echecks = $settings->blockEChecks;
428
- $require_billing_address = $settings->requireBillingAddress;
429
- $zero_subtotal_behavior = $settings->zeroSubtotalBehavior;
430
- $subtotal_mismatch_behavior = $settings->subtotalMismatchBehavior;
431
  }
432
 
433
- $help_image_url = WC()->plugin_url() . '/assets/images/help.png';
434
- $ips_url = admin_url( 'admin.php?page=wc-settings&tab=checkout&section=wc_gateway_ppec_with_paypal&ips-signup=true' );
435
- add_thickbox();
436
 
437
- require_once( wc_gateway_ppec()->includes_path . 'views/admin-settings.php' );
 
438
  }
439
 
440
  /**
441
- * This function fills in the $credentials variable with the credentials
442
- * the user filled in on the page, and returns true or false to indicate
443
- * a success or error, respectively.
444
- *
445
- * Why not just return the credentials or false on failure? Because the user
446
- * might not fill in the credentials at all, which isn't an error. This way
447
- * allows us to do it without returning an error because the user didn't fill
448
- * in the credentials.
449
- *
450
- * @param string $environment Environment. Either 'live' or 'sandbox'
451
- *
452
- * @return WC_Gateway_PPEC_Client_Credential Credential object
453
  */
454
- private function validate_credentials( $environment ) {
455
- $settings = wc_gateway_ppec()->settings->loadSettings();
456
- if ( 'sandbox' == $environment ) {
457
- $creds = $settings->sandboxApiCredentials;
458
- } else {
459
- $creds = $settings->liveApiCredentials;
460
- }
461
 
462
- $api_user = trim( $_POST[ 'woo_pp_' . $environment . '_api_username' ] );
463
- $api_pass = trim( $_POST[ 'woo_pp_' . $environment . '_api_password' ] );
464
- $api_style = trim( $_POST[ 'woo_pp_' . $environment . '_api_style' ] );
465
 
466
- $subject = trim( $_POST[ 'woo_pp_' . $environment . '_subject' ] );
467
- if ( empty( $subject ) ) {
468
- $subject = false;
469
- }
470
-
471
- $credential = false;
472
- if ( 'signature' === $api_style ) {
473
- $api_sig = trim( $_POST[ 'woo_pp_' . $environment . '_api_signature' ] );
474
- } elseif ( 'certificate' === $api_style ) {
475
- if ( array_key_exists( 'woo_pp_' . $environment . '_api_certificate', $_FILES )
476
- && array_key_exists( 'tmp_name', $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ] )
477
- && array_key_exists( 'size', $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ] )
478
- && $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ]['size'] ) {
479
- $api_cert = file_get_contents( $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ]['tmp_name'] );
480
- $_POST[ 'woo_pp_' . $environment . '_api_cert_string' ] = base64_encode( $api_cert );
481
- unlink( $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ]['tmp_name'] );
482
- unset( $_FILES[ 'woo_pp_' . $environment . '_api_certificate' ] );
483
- } elseif ( array_key_exists( 'woo_pp_' . $environment . '_api_cert_string', $_POST ) && ! empty( $_POST[ 'woo_pp_' . $environment . '_api_cert_string' ] ) ) {
484
- $api_cert = base64_decode( $_POST[ 'woo_pp_' . $environment . '_api_cert_string' ] );
485
- }
486
- } else {
487
- WC_Admin_Settings::add_error( sprintf( __( 'Error: You selected an invalid credential type for your %s API credentials.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
488
- return false;
489
- }
490
-
491
- if ( ! empty( $api_user ) ) {
492
- if ( empty( $api_pass ) ) {
493
- WC_Admin_Settings::add_error( sprintf( __( 'Error: You must enter a %s API password.' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
494
  return false;
495
  }
496
 
497
- if ( 'signature' === $api_style ) {
498
- if ( ! empty( $api_sig ) ) {
499
-
500
- // Ok, test them out.
501
- $api_credentials = new WC_Gateway_PPEC_Client_Credential_Signature( $api_user, $api_pass, $api_sig, $subject );
502
- try {
503
- $payer_id = wc_gateway_ppec()->client->test_api_credentials( $api_credentials, $environment );
504
- if ( ! $payer_id ) {
505
- WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s credentials you provided are not valid. Please double-check that you entered them correctly and try again.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
506
- return false;
507
- }
508
- $api_credentials->set_payer_id( $payer_id );
509
- } catch( PayPal_API_Exception $ex ) {
510
- $this->display_warning( sprintf( __( 'An error occurred while trying to validate your %s API credentials. Unable to verify that your API credentials are correct.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
511
- }
512
-
513
- $credential = $api_credentials;
514
 
515
- } else {
516
- WC_Admin_Settings::add_error( sprintf( __( 'Error: You must provide a %s API signature.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
517
- return false;
518
- }
519
-
520
- } else {
521
- if ( ! empty( $api_cert ) ) {
522
- $cert = openssl_x509_read( $api_cert );
523
- if ( false === $cert ) {
524
- WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s API certificate is not valid.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
525
- self::$process_admin_options_validation_error = true;
526
- return false;
527
- }
528
-
529
- $cert_info = openssl_x509_parse( $cert );
530
- $valid_until = $cert_info['validTo_time_t'];
531
- if ( $valid_until < time() ) {
532
- WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s API certificate has expired.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
533
- return false;
534
- }
535
 
536
- if ( $cert_info['subject']['CN'] != $api_user ) {
537
- WC_Admin_Settings::add_error( __( 'Error: The API username does not match the name in the API certificate. Make sure that you have the correct API certificate.', 'woocommerce-gateway-paypal-express-checkout' ) );
538
- return false;
539
- }
540
- } else {
541
- // If we already have a cert on file, don't require one.
542
- if ( $creds && is_a( $creds, 'WC_Gateway_PPEC_Client_Credential_Certificate' ) ) {
543
- if ( ! $creds->get_certificate() ) {
544
- WC_Admin_Settings::add_error( sprintf( __( 'Error: You must provide a %s API certificate.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
545
- return false;
546
- }
547
- $api_cert = $creds->get_certificate();
548
- } else {
549
- WC_Admin_Settings::add_error( sprintf( __( 'Error: You must provide a %s API certificate.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
550
- return false;
551
- }
552
- }
553
 
554
- $api_credentials = new WC_Gateway_PPEC_Client_Credential_Certificate( $api_user, $api_pass, $api_cert, $subject );
555
- try {
556
- $payer_id = wc_gateway_ppec()->client->test_api_credentials( $api_credentials, $environment );
557
  if ( ! $payer_id ) {
558
- WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s credentials you provided are not valid. Please double-check that you entered them correctly and try again.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
559
  return false;
560
  }
561
- $api_credentials->set_payer_id( $payer_id );
562
  } catch( PayPal_API_Exception $ex ) {
563
- $this->display_warning( sprintf( __( 'An error occurred while trying to validate your %s API credentials. Unable to verify that your API credentials are correct.', 'woocommerce-gateway-paypal-express-checkout' ), __( $environment, 'woocommerce-gateway-paypal-express-checkout' ) ) );
564
  }
565
 
566
- $credential = $api_credentials;
567
- }
568
- }
569
-
570
- return $credential;
571
- }
572
-
573
- public function process_admin_options() {
574
- // For some reason, this function is being fired twice, so this bit of code is here to prevent that from happening.
575
- if ( self::$process_admin_options_already_run ) {
576
- return false;
577
- }
578
-
579
- self::$process_admin_options_already_run = true;
580
-
581
- $settings = wc_gateway_ppec()->settings->loadSettings();
582
 
583
- $environment = $_POST['woo_pp_environment'];
584
 
585
- if ( ! in_array( $environment, array( 'live', 'sandbox' ) ) ) {
586
- WC_Admin_Settings::add_error( __( 'Error: The environment you selected is not valid.', 'woocommerce-gateway-paypal-express-checkout' ) );
587
- return false;
588
- }
589
-
590
- $credential = $this->validate_credentials( $environment );
591
- if ( ! is_a( $credential, 'WC_Gateway_PPEC_Client_Credential' ) ) {
592
- if ( array_key_exists( 'woo_pp_sandbox_api_certificate', $_FILES )
593
- && array_key_exists( 'tmp_name', $_FILES['woo_pp_sandbox_api_certificate'] )
594
- && array_key_exists( 'size', $_FILES['woo_pp_sandbox_api_certificate'] )
595
- && $_FILES['woo_pp_sandbox_api_certificate']['size'] ) {
596
-
597
- $_POST['woo_pp_sandbox_api_cert_string'] = base64_encode( file_get_contents( $_FILES['woo_pp_sandbox_api_certificate']['tmp_name'] ) );
598
- unlink( $_FILES['woo_pp_sandbox_api_certificate']['tmp_name'] );
599
- unset( $_FILES['woo_pp_sandbox_api_certificate'] );
600
 
601
- }
 
602
 
603
- WC_Admin_Settings::add_error( __( 'Error: You must supply a valid set of credentials before enabling the plugin.', 'woocommerce-gateway-paypal-express-checkout' ) );
604
- self::$process_admin_options_validation_error = true;
605
- return false;
606
- }
607
 
608
- // Validate the URL.
609
- $logo_image_url = trim( $_POST['woo_pp_logo_image_url'] );
610
- if ( ! empty( $logo_image_url ) && ! preg_match( '/https?:\/\/[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9](\/[a-zA-Z0-9.\/?&%#]*)?/', $logo_image_url ) ) {
611
- WC_Admin_Settings::add_error( __( 'Error: The logo image URL you provided is not valid.', 'woocommerce-gateway-paypal-express-checkout' ) );
612
- self::$process_admin_options_validation_error = true;
613
- return false;
614
- }
615
 
616
- if ( empty( $logo_image_url ) ) {
617
- $logo_image_url = false;
618
- }
619
 
620
- $enabled = false;
621
- $logging_enabled = false;
622
- $ppc_enabled = false;
623
- $icc_enabled = false;
624
- $allow_guest_checkout = false;
625
- $block_echecks = false;
626
- $require_billing_address = false;
627
- $live_account_enabled_for_billing_address = false;
628
- $sb_account_enabled_for_billing_address = false;
629
-
630
- if ( isset( $_POST['woo_pp_enabled'] ) && 'true' == $_POST['woo_pp_enabled'] ) {
631
- $enabled = true;
632
- }
633
 
634
- if ( isset( $_POST['woo_pp_ppc_enabled'] ) && 'true' == $_POST['woo_pp_ppc_enabled'] ) {
635
- $ppc_enabled = true;
636
- }
 
637
 
638
- if ( isset( $_POST['woo_pp_allow_guest_checkout'] ) && 'true' == $_POST['woo_pp_allow_guest_checkout'] ) {
639
- $allow_guest_checkout = true;
640
- }
641
 
642
- if ( isset( $_POST['woo_pp_block_echecks'] ) && 'true' == $_POST['woo_pp_block_echecks'] ) {
643
- $block_echecks = true;
644
- }
645
 
646
- if ( isset( $_POST['woo_pp_req_billing_address'] ) && 'true' == $_POST['woo_pp_req_billing_address'] ) {
647
- $require_billing_address = true;
648
- }
649
 
650
- if ( isset( $_POST['woo_pp_icc_enabled'] ) && 'true' == $_POST['woo_pp_icc_enabled'] ) {
651
- $icc_enabled = true;
652
- }
653
 
654
- if ( isset( $_POST['woo_pp_logging_enabled'] ) && 'true' == $_POST['woo_pp_logging_enabled'] ) {
655
- $logging_enabled = true;
656
- }
657
 
658
- $is_account_enabled_for_billing_address = false;
659
- try {
660
- $is_account_enabled_for_billing_address = wc_gateway_ppec()->client->test_for_billing_address_enabled( $credential, $environment );
661
- } catch( PayPal_API_Exception $ex ) {
662
- $this->display_warning( __( 'An error occurred while trying to determine which features are enabled on your live account. You may not have access to all of the settings allowed by your PayPal account. Please click "Save Changes" to try again.', 'woocommerce-gateway-paypal-express-checkout' ) );
663
- }
664
 
665
- switch ( $environment ) {
666
- case 'live':
667
- $live_account_enabled_for_billing_address = $is_account_enabled_for_billing_address;
668
- break;
669
- case 'sandbox':
670
- $sb_account_enabled_for_billing_address = $is_account_enabled_for_billing_address;
671
- break;
672
  }
673
-
674
- // WC_Gateway_PPEC_Settings already has sanitizers for these values, so we don't need to check them.
675
- $button_size = $_POST['woo_pp_button_size'];
676
- $mark_size = $_POST['woo_pp_mark_size'];
677
- $payment_action = $_POST['woo_pp_payment_action'];
678
- $zero_subtotal_behavior = $_POST['woo_pp_zero_subtotal_behavior'];
679
- $subtotal_mismatch_behavior = $_POST['woo_pp_subtotal_mismatch_behavior'];
680
-
681
- // Go ahead and save everything.
682
- $settings->enabled = $enabled;
683
- $settings->logging_enabled = $logging_enabled;
684
- $settings->ppcEnabled = $ppc_enabled;
685
- $settings->enableInContextCheckout = $icc_enabled;
686
- $settings->buttonSize = $button_size;
687
- $settings->logoImageUrl = $logo_image_url;
688
- $settings->markSize = $mark_size;
689
- $settings->environment = $environment;
690
- $settings->liveApiCredentials = 'live' === $environment ? $credential : false;
691
- $settings->sandboxApiCredentials = 'sandbox' === $environment ? $credential : false;
692
- $settings->allowGuestCheckout = $allow_guest_checkout;
693
- $settings->blockEChecks = $block_echecks;
694
- $settings->requireBillingAddress = $require_billing_address;
695
- $settings->paymentAction = $payment_action;
696
- $settings->zeroSubtotalBehavior = $zero_subtotal_behavior;
697
- $settings->subtotalMismatchBehavior = $subtotal_mismatch_behavior;
698
- $settings->liveAccountIsEnabledForBillingAddress = $live_account_enabled_for_billing_address;
699
- $settings->sbAccountIsEnabledForBillingAddress = $sb_account_enabled_for_billing_address;
700
-
701
- $settings->saveSettings();
702
- }
703
-
704
- public function display_warning( $message ) {
705
- echo '<div class="error"><p>Warning: ' . $message . '</p></div>';
706
  }
707
 
 
 
 
708
  public function process_refund( $order_id, $amount = null, $reason = '' ) {
709
-
710
- $settings = wc_gateway_ppec()->settings->loadSettings();
711
-
712
  $order = wc_get_order( $order_id );
713
 
714
  if ( 0 == $amount || null == $amount ) {
@@ -725,7 +331,6 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
725
  foreach ( $txnData['refundable_txns'] as $key => $value ) {
726
  $refundableAmount = $value['amount'] - $value['refunded_amount'];
727
 
728
-
729
  if ( $amount == $refundableAmount ) {
730
  if ( 0 == $value['refunded_amount'] ) {
731
  $refundType = 'Full';
@@ -736,7 +341,7 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
736
  try {
737
  $refundTxnID = WC_Gateway_PPEC_Refund::refund_order( $order, $amount, $refundType, $reason, $order->get_order_currency() );
738
  $txnData['refundable_txns'][ $key ]['refunded_amount'] += $amount;
739
- $order->add_order_note( sprintf( $refundTxnID, __( 'PayPal refund completed; transaction ID = %s', 'woocommerce-gateway-paypal-express-checkout' ), $refundTxnID ) );
740
  update_post_meta( $order_id, '_woo_pp_txnData', $txnData );
741
 
742
  return true;
@@ -748,12 +353,9 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
748
 
749
  return new WP_Error( 'paypal_refund_error', $final_output );
750
  }
751
-
752
  }
753
-
754
  }
755
 
756
-
757
  foreach ( $txnData['refundable_txns'] as $key => $value ) {
758
  $refundableAmount = $value['amount'] - $value['refunded_amount'];
759
 
@@ -836,13 +438,11 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
836
  * @return string
837
  */
838
  public function get_transaction_url( $order ) {
839
- $settings = wc_gateway_ppec()->settings->loadSettings();
840
- if ( 'sandbox' === $settings->environment ) {
841
  $this->view_transaction_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
842
  } else {
843
  $this->view_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
844
  }
845
-
846
  return parent::get_transaction_url( $order );
847
  }
848
 
@@ -852,17 +452,9 @@ abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
852
  * @return bool
853
  */
854
  public function is_available() {
855
- $settings = wc_gateway_ppec()->settings->loadSettings();
856
- if ( ! $settings->enabled ) {
857
- return false;
858
- }
859
-
860
- $api_credentials = $settings->getActiveApiCredentials();
861
- if ( ! is_callable( array( $api_credentials, 'get_payer_id' ) ) ) {
862
  return false;
863
  }
864
-
865
  return true;
866
  }
867
-
868
  }
4
  exit; // Exit if accessed directly
5
  }
6
 
7
+ /**
8
+ * WC_Gateway_PPEC
9
+ */
10
  abstract class WC_Gateway_PPEC extends WC_Payment_Gateway {
11
 
12
+ /**
13
+ * Constructor.
14
+ */
 
 
 
15
  public function __construct() {
16
+ $this->has_fields = false;
17
+ $this->icon = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-small.png';
18
+ $this->supports[] = 'refunds';
 
 
 
 
19
  $this->method_title = __( 'PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' );
20
+ $this->method_description = __( 'Allow customers to conveniently checkout directly with PayPal.', 'woocommerce-gateway-paypal-express-checkout' );
21
+
22
+ if ( empty( $_GET['woo-paypal-return'] ) ) {
23
+ $this->order_button_text = __( 'Continue to payment', 'woocommerce-gateway-paypal-express-checkout' );
24
+ }
25
 
26
  wc_gateway_ppec()->ips->maybe_received_credentials();
27
 
28
  $this->init_form_fields();
29
+ $this->init_settings();
30
+
31
+ $this->title = $this->method_title;
32
+ $this->description = '';
33
+ $this->enabled = $this->get_option( 'enabled', 'yes' );
34
+ $this->button_size = $this->get_option( 'button_size', 'large' );
35
+ $this->environment = $this->get_option( 'environment', 'live' );
36
+ $this->mark_enabled = 'yes' === $this->get_option( 'mark_enabled', 'no' );
37
+
38
+ if ( 'live' === $this->environment ) {
39
+ $this->api_username = $this->get_option( 'api_username' );
40
+ $this->api_password = $this->get_option( 'api_password' );
41
+ $this->api_signature = $this->get_option( 'api_signature' );
42
+ $this->api_certificate = $this->get_option( 'api_certificate' );
43
+ $this->api_subject = $this->get_option( 'api_subject' );
44
+ } else {
45
+ $this->api_username = $this->get_option( 'sandbox_api_username' );
46
+ $this->api_password = $this->get_option( 'sandbox_api_password' );
47
+ $this->api_signature = $this->get_option( 'sandbox_api_signature' );
48
+ $this->api_certificate = $this->get_option( 'sandbox_api_certificate' );
49
+ $this->api_subject = $this->get_option( 'sandbox_api_subject' );
50
+ }
51
 
52
+ $this->debug = 'yes' === $this->get_option( 'debug', 'no' );
53
+ $this->invoice_prefix = $this->get_option( 'invoice_prefix', 'WC-' );
54
+ $this->instant_payments = 'yes' === $this->get_option( 'instant_payments', 'no' );
55
+ $this->require_billing = 'yes' === $this->get_option( 'require_billing', 'no' );
56
+ $this->paymentaction = $this->get_option( 'paymentaction', 'sale' );
57
+ $this->logo_image_url = $this->get_option( 'logo_image_url' );
58
+ $this->subtotal_mismatch_behavior = $this->get_option( 'subtotal_mismatch_behavior', 'add' );
59
 
60
  add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
61
 
62
+ // Change gateway name if session is active
 
63
  if ( ! is_admin() ) {
64
+ $session = WC()->session->get( 'paypal' );
65
+ $checkout = wc_gateway_ppec()->checkout;
 
 
 
 
 
 
 
 
 
 
 
 
66
 
67
+ if ( ! $checkout->has_active_session() || ! $session->checkout_completed ) {
68
+ $this->title = $this->get_option( 'title' );
69
+ $this->description = $this->get_option( 'description' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
70
  }
71
  }
72
  }
73
 
74
+ /**
75
+ * Initialise Gateway Settings Form Fields.
76
+ */
 
 
 
 
 
 
 
77
  public function init_form_fields() {
78
+ $this->form_fields = include( dirname( dirname( __FILE__ ) ) . '/settings/settings-ppec.php' );
79
  }
80
 
81
+ /**
82
+ * Process payments
83
+ */
84
  public function process_payment( $order_id ) {
 
85
  $checkout = wc_gateway_ppec()->checkout;
86
+ $order = wc_get_order( $order_id );
87
+ $session = WC()->session->get( 'paypal' );
88
 
89
+ // Redirect them over to PayPal if they have no current session (this is for PayPal Mark).
90
+ if ( ! $checkout->has_active_session() || ! $session->checkout_completed ) {
 
 
 
 
 
 
91
  try {
 
 
 
 
 
92
  return array(
93
+ 'result' => 'success',
94
+ 'redirect' => $checkout->start_checkout_from_checkout( $order_id ),
95
  );
96
  } catch( PayPal_API_Exception $e ) {
97
+ wc_gateway_ppec_format_paypal_api_exception( $e->errors );
 
 
 
 
 
98
  }
99
  } else {
 
100
  try {
101
+ // Get details
102
+ $checkout_details = $checkout->getCheckoutDetails( $session->token );
 
 
 
103
 
104
+ // Store addresses given by PayPal
105
+ $order->set_address( $checkout->get_mapped_billing_address( $checkout_details ), 'billing' );
106
+ $order->set_address( $checkout->get_mapped_shipping_address( $checkout_details ), 'shipping' );
107
 
108
+ // Complete the payment now.
109
+ $checkout->do_payment( $order, $session->token, $session->payerID );
110
 
111
+ // Clear Cart
112
+ WC()->cart->empty_cart();
 
 
 
 
 
 
 
 
 
113
 
114
  return array(
115
+ 'result' => 'success',
116
  'redirect' => $this->get_return_url( $order )
117
  );
118
  } catch( PayPal_Missing_Session_Exception $e ) {
119
+ // For some reason, our session data is missing. Generally, if we've made it this far, this shouldn't happen.
120
+ wc_add_notice( __( 'Sorry, an error occurred while trying to process your payment. Please try again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
121
  } catch( PayPal_API_Exception $e ) {
122
  // Did we get a 10486 or 10422 back from PayPal? If so, this means we need to send the buyer back over to
123
  // PayPal to have them pick out a new funding method.
124
+ $error_codes = wp_list_pluck( $e->errors, 'error_code' );
 
 
 
 
 
 
 
 
 
 
125
 
126
+ if ( in_array( '10486', $error_codes ) || in_array( '10422', $error_codes ) ) {
127
  $session->checkout_completed = false;
128
+ $session->source = 'order';
129
+ $session->order_id = $order_id;
130
+ WC()->session->set( 'paypal', $session );
131
+
132
  return array(
133
+ 'result' => 'success',
134
+ 'redirect' => wc_gateway_ppec()->settings->get_paypal_redirect_url( $session->token, true )
135
  );
136
  } else {
137
+ wc_gateway_ppec_format_paypal_api_exception( $e->errors );
 
 
 
 
 
 
138
  }
139
  }
140
  }
141
  }
142
 
143
+ /**
144
+ * Get info about uploaded certificate.
145
+ * @param string $cert_string
146
+ * @return string
147
+ */
148
  private function get_certificate_info( $cert_string ) {
149
  if ( ! strlen( $cert_string ) ) {
150
  return __( 'No API certificate on file.', 'woocommerce-gateway-paypal-express-checkout' );
151
  }
152
 
153
+ $cert = @openssl_x509_read( $cert_string );
154
+ $out = '';
155
+
156
  if ( false !== $cert ) {
157
  $certinfo = openssl_x509_parse( $cert );
158
  if ( false !== $certinfo ) {
173
  } else {
174
  $out = __( 'The certificate on file is not valid.', 'woocommerce-gateway-paypal-express-checkout' );
175
  }
 
 
176
  }
177
 
178
  return $out;
179
  }
180
 
181
+ /**
182
+ * Do some additonal validation before saving options via the API.
183
+ */
184
+ public function process_admin_options() {
185
+ // Validate logo
186
+ $logo_image_url = wc_clean( $_POST['woocommerce_ppec_paypal_logo_image_url'] );
 
 
 
 
 
 
 
 
 
 
 
 
187
 
188
+ if ( ! empty( $logo_image_url ) && ! preg_match( '/https?:\/\/[a-zA-Z0-9][a-zA-Z0-9.-]+[a-zA-Z0-9](\/[a-zA-Z0-9.\/?&%#]*)?/', $logo_image_url ) ) {
189
+ WC_Admin_Settings::add_error( __( 'Error: The logo image URL you provided is not valid and cannot be used.', 'woocommerce-gateway-paypal-express-checkout' ) );
190
+ unset( $_POST['woocommerce_ppec_paypal_logo_image_url'] );
191
  }
192
 
193
+ // If a certificate has been uploaded, read the contents and save that string instead.
194
+ if ( array_key_exists( 'woocommerce_ppec_paypal_api_certificate', $_FILES )
195
+ && array_key_exists( 'tmp_name', $_FILES['woocommerce_ppec_paypal_api_certificate'] )
196
+ && array_key_exists( 'size', $_FILES['woocommerce_ppec_paypal_api_certificate'] )
197
+ && $_FILES['woocommerce_ppec_paypal_api_certificate']['size'] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
198
 
199
+ $_POST['woocommerce_ppec_paypal_api_certificate'] = base64_encode( file_get_contents( $_FILES['woocommerce_ppec_paypal_api_certificate']['tmp_name'] ) );
200
+ unlink( $_FILES['woocommerce_ppec_paypal_api_certificate']['tmp_name'] );
201
+ unset( $_FILES['woocommerce_ppec_paypal_api_certificate'] );
 
 
 
202
  } else {
203
+ $_POST['woocommerce_ppec_paypal_api_certificate'] = $this->get_option( 'api_certificate' );
204
+ }
205
 
206
+ if ( array_key_exists( 'woocommerce_ppec_paypal_sandbox_api_certificate', $_FILES )
207
+ && array_key_exists( 'tmp_name', $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate'] )
208
+ && array_key_exists( 'size', $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate'] )
209
+ && $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate']['size'] ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
210
 
211
+ $_POST['woocommerce_ppec_paypal_sandbox_api_certificate'] = base64_encode( file_get_contents( $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate']['tmp_name'] ) );
212
+ unlink( $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate']['tmp_name'] );
213
+ unset( $_FILES['woocommerce_ppec_paypal_sandbox_api_certificate'] );
214
+ } else {
215
+ $_POST['woocommerce_ppec_paypal_sandbox_api_certificate'] = $this->get_option( 'sandbox_api_certificate' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
216
  }
217
 
218
+ parent::process_admin_options();
 
 
219
 
220
+ // Validate credentials
221
+ $this->validate_active_credentials();
222
  }
223
 
224
  /**
225
+ * Validate the provided credentials.
 
 
 
 
 
 
 
 
 
 
 
226
  */
227
+ protected function validate_active_credentials() {
228
+ $settings = wc_gateway_ppec()->settings->load_settings( true );
229
+ $creds = $settings->get_active_api_credentials();
 
 
 
 
230
 
231
+ if ( ! empty( $creds->get_username() ) ) {
 
 
232
 
233
+ if ( empty( $creds->get_password() ) ) {
234
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: You must enter a %s API password.' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  return false;
236
  }
237
 
238
+ if ( is_a( $creds, 'WC_Gateway_PPEC_Client_Credential_Signature' ) && ! empty( $creds->get_signature() ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
239
 
240
+ try {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
241
 
242
+ $payer_id = wc_gateway_ppec()->client->test_api_credentials( $creds, $settings->get_environment() );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
243
 
 
 
 
244
  if ( ! $payer_id ) {
245
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s credentials you provided are not valid. Please double-check that you entered them correctly and try again.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
246
  return false;
247
  }
248
+
249
  } catch( PayPal_API_Exception $ex ) {
250
+ WC_Admin_Settings::add_error( sprintf( __( 'An error occurred while trying to validate your %s API credentials. Unable to verify that your API credentials are correct.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
251
  }
252
 
253
+ } elseif ( is_a( $creds, 'WC_Gateway_PPEC_Client_Credential_Certificate' ) && ! empty( $creds->get_certificate() ) ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
254
 
255
+ $cert = @openssl_x509_read( $creds->get_certificate() );
256
 
257
+ if ( false === $cert ) {
258
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s API certificate is not valid.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
259
+ return false;
260
+ }
 
 
 
 
 
 
 
 
 
 
 
261
 
262
+ $cert_info = openssl_x509_parse( $cert );
263
+ $valid_until = $cert_info['validTo_time_t'];
264
 
265
+ if ( $valid_until < time() ) {
266
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s API certificate has expired.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
267
+ return false;
268
+ }
269
 
270
+ if ( $cert_info['subject']['CN'] != $creds->get_username() ) {
271
+ WC_Admin_Settings::add_error( __( 'Error: The API username does not match the name in the API certificate. Make sure that you have the correct API certificate.', 'woocommerce-gateway-paypal-express-checkout' ) );
272
+ return false;
273
+ }
 
 
 
274
 
275
+ try {
 
 
276
 
277
+ $payer_id = wc_gateway_ppec()->client->test_api_credentials( $creds, $settings->get_environment() );
 
 
 
 
 
 
 
 
 
 
 
 
278
 
279
+ if ( ! $payer_id ) {
280
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: The %s credentials you provided are not valid. Please double-check that you entered them correctly and try again.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
281
+ return false;
282
+ }
283
 
284
+ } catch( PayPal_API_Exception $ex ) {
285
+ WC_Admin_Settings::add_error( sprintf( __( 'An error occurred while trying to validate your %s API credentials. Unable to verify that your API credentials are correct.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
286
+ }
287
 
288
+ } else {
 
 
289
 
290
+ WC_Admin_Settings::add_error( sprintf( __( 'Error: You must provide a %s API signature or certificate.', 'woocommerce-gateway-paypal-express-checkout' ), __( $settings->get_environment(), 'woocommerce-gateway-paypal-express-checkout' ) ) );
291
+ return false;
292
+ }
293
 
294
+ $settings_array = (array) get_option( 'woocommerce_ppec_paypal_settings', array() );
 
 
295
 
296
+ if ( 'yes' === $settings_array['require_billing'] ) {
297
+ $is_account_enabled_for_billing_address = false;
 
298
 
299
+ try {
300
+ $is_account_enabled_for_billing_address = wc_gateway_ppec()->client->test_for_billing_address_enabled( $creds, $settings->get_environment() );
301
+ } catch( PayPal_API_Exception $ex ) {
302
+ $is_account_enabled_for_billing_address = false;
303
+ }
 
304
 
305
+ if ( ! $is_account_enabled_for_billing_address ) {
306
+ $settings_array['require_billing'] = 'no';
307
+ update_option( 'woocommerce_ppec_paypal_settings', $settings_array );
308
+ WC_Admin_Settings::add_error( __( 'The "require billing address" option is not enabled by your account and has been disabled.', 'woocommerce-gateway-paypal-express-checkout' ) );
309
+ }
310
+ }
 
311
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
312
  }
313
 
314
+ /**
315
+ * Refunds.
316
+ */
317
  public function process_refund( $order_id, $amount = null, $reason = '' ) {
 
 
 
318
  $order = wc_get_order( $order_id );
319
 
320
  if ( 0 == $amount || null == $amount ) {
331
  foreach ( $txnData['refundable_txns'] as $key => $value ) {
332
  $refundableAmount = $value['amount'] - $value['refunded_amount'];
333
 
 
334
  if ( $amount == $refundableAmount ) {
335
  if ( 0 == $value['refunded_amount'] ) {
336
  $refundType = 'Full';
341
  try {
342
  $refundTxnID = WC_Gateway_PPEC_Refund::refund_order( $order, $amount, $refundType, $reason, $order->get_order_currency() );
343
  $txnData['refundable_txns'][ $key ]['refunded_amount'] += $amount;
344
+ $order->add_order_note( sprintf( __( 'PayPal refund completed; transaction ID = %s', 'woocommerce-gateway-paypal-express-checkout' ), $refundTxnID ) );
345
  update_post_meta( $order_id, '_woo_pp_txnData', $txnData );
346
 
347
  return true;
353
 
354
  return new WP_Error( 'paypal_refund_error', $final_output );
355
  }
 
356
  }
 
357
  }
358
 
 
359
  foreach ( $txnData['refundable_txns'] as $key => $value ) {
360
  $refundableAmount = $value['amount'] - $value['refunded_amount'];
361
 
438
  * @return string
439
  */
440
  public function get_transaction_url( $order ) {
441
+ if ( 'sandbox' === $this->environment ) {
 
442
  $this->view_transaction_url = 'https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
443
  } else {
444
  $this->view_transaction_url = 'https://www.paypal.com/cgi-bin/webscr?cmd=_view-a-trans&id=%s';
445
  }
 
446
  return parent::get_transaction_url( $order );
447
  }
448
 
452
  * @return bool
453
  */
454
  public function is_available() {
455
+ if ( 'yes' !== $this->enabled ) {
 
 
 
 
 
 
456
  return false;
457
  }
 
458
  return true;
459
  }
 
460
  }
includes/class-wc-gateway-ppec-admin-handler.php CHANGED
@@ -28,8 +28,6 @@ class WC_Gateway_PPEC_Admin_Handler {
28
  add_action( 'woocommerce_order_action_ppec_capture_charge', array( $this, 'maybe_capture_charge' ) );
29
 
30
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_redirect_to_ppec_settings' ) );
31
-
32
- add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
33
  }
34
 
35
  public function add_capture_charge_order_action( $actions ) {
@@ -40,11 +38,7 @@ class WC_Gateway_PPEC_Admin_Handler {
40
  $order = wc_get_order( $_REQUEST['post'] );
41
 
42
  // bail if the order wasn't paid for with this gateway
43
- if ( 'ppec_paypal' !== $order->payment_method ) {
44
- return $actions;
45
- }
46
-
47
- if ( 'yes' === get_post_meta( $order->id, '_ppec_charge_captured', true ) ) {
48
  return $actions;
49
  }
50
 
@@ -162,8 +156,6 @@ class WC_Gateway_PPEC_Admin_Handler {
162
  $order->add_order_note( __( 'Unable to capture charge!', 'woocommerce-gateway-paypal-express-checkout' ) . ' ' . $result->get_error_message() );
163
  } else {
164
  $order->add_order_note( sprintf( __( 'PayPal Express Checkout charge complete (Charge ID: %s)', 'woocommerce-gateway-paypal-express-checkout' ), $trans_id ) );
165
-
166
- update_post_meta( $order->id, '_ppec_charge_captured', 'yes' );
167
  }
168
  }
169
  }
@@ -205,7 +197,6 @@ class WC_Gateway_PPEC_Admin_Handler {
205
  $order->add_order_note( __( 'Unable to void charge!', 'woocommerce-gateway-paypal-express-checkout' ) . ' ' . $result->get_error_message() );
206
  } else {
207
  $order->add_order_note( sprintf( __( 'PayPal Express Checkout charge voided (Charge ID: %s)', 'woocommerce-gateway-paypal-express-checkout' ), $trans_id) );
208
- delete_post_meta( $order->id, '_ppec_charge_captured' );
209
  }
210
  }
211
  }
@@ -231,7 +222,7 @@ class WC_Gateway_PPEC_Admin_Handler {
231
  * @return void
232
  */
233
  public function maybe_redirect_to_ppec_settings() {
234
- if ( ! wc_gateway_ppec()->settings->loadSettings()->enabled ) {
235
  return;
236
  }
237
 
@@ -244,18 +235,4 @@ class WC_Gateway_PPEC_Admin_Handler {
244
  wp_safe_redirect( $redirect );
245
  }
246
  }
247
-
248
- /**
249
- * Enqueue script related to admin.
250
- *
251
- * @return void
252
- */
253
- public function enqueue_scripts() {
254
- $settings = wc_gateway_ppec()->settings->loadSettings();
255
-
256
- wp_enqueue_script( 'wc-gateway-ppec-admin', wc_gateway_ppec()->plugin_url . 'assets/js/wc-gateway-ppec-admin.js', array( 'jquery' ), wc_gateway_ppec()->version, true );
257
- wp_localize_script( 'wc-gateway-ppec-admin', 'wc_ppec_settings', array(
258
- 'enabled' => $settings->enabled,
259
- ) );
260
- }
261
  }
28
  add_action( 'woocommerce_order_action_ppec_capture_charge', array( $this, 'maybe_capture_charge' ) );
29
 
30
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_redirect_to_ppec_settings' ) );
 
 
31
  }
32
 
33
  public function add_capture_charge_order_action( $actions ) {
38
  $order = wc_get_order( $_REQUEST['post'] );
39
 
40
  // bail if the order wasn't paid for with this gateway
41
+ if ( 'ppec_paypal' !== $order->payment_method || 'pending' !== get_post_meta( $order->id, '_paypal_status', true ) ) {
 
 
 
 
42
  return $actions;
43
  }
44
 
156
  $order->add_order_note( __( 'Unable to capture charge!', 'woocommerce-gateway-paypal-express-checkout' ) . ' ' . $result->get_error_message() );
157
  } else {
158
  $order->add_order_note( sprintf( __( 'PayPal Express Checkout charge complete (Charge ID: %s)', 'woocommerce-gateway-paypal-express-checkout' ), $trans_id ) );
 
 
159
  }
160
  }
161
  }
197
  $order->add_order_note( __( 'Unable to void charge!', 'woocommerce-gateway-paypal-express-checkout' ) . ' ' . $result->get_error_message() );
198
  } else {
199
  $order->add_order_note( sprintf( __( 'PayPal Express Checkout charge voided (Charge ID: %s)', 'woocommerce-gateway-paypal-express-checkout' ), $trans_id) );
 
200
  }
201
  }
202
  }
222
  * @return void
223
  */
224
  public function maybe_redirect_to_ppec_settings() {
225
+ if ( ! wc_gateway_ppec()->settings->enabled ) {
226
  return;
227
  }
228
 
235
  wp_safe_redirect( $redirect );
236
  }
237
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  }
includes/class-wc-gateway-ppec-api-error.php CHANGED
@@ -19,39 +19,40 @@ class PayPal_API_Error {
19
 
20
  public function mapToBuyerFriendlyError() {
21
  switch ( $this->error_code ) {
22
- case '-1': return 'Unable to communicate with PayPal. Please try your payment again.';
23
- case '10407': return 'PayPal rejected your email address because it is not valid. Please double-check your email address and try again.';
24
  case '10409':
25
  case '10421':
26
- case '10410': return 'Your PayPal checkout session is invalid. Please check out again.';
27
- case '10411': return 'Your PayPal checkout session has expired. Please check out again.';
28
  case '11607':
29
- case '10415': return 'Your PayPal payment has already been completed. Please contact the store owner for more information.';
30
- case '10416': return 'Your PayPal payment could not be processed. Please check out again or contact PayPal for assistance.';
31
- case '10417': return 'Your PayPal payment could not be processed. Please select an alternative method of payment or contact PayPal for assistance.';
32
  case '10486':
33
- case '10422': return 'Your PayPal payment could not be processed. Please return to PayPal and select a new method of payment.';
34
  case '10485':
35
- case '10435': return 'You have not approved this transaction on the PayPal website. Please check out again and be sure to complete all steps of the PayPal checkout process.';
36
- case '10474': return 'Your shipping address may not be in a different country than your country of residence. Please double-check your shipping address and try again.';
37
- case '10537': return 'This store does not accept transactions from buyers in your country. Please contact the store owner for assistance.';
38
- case '10538': return 'The transaction is over the threshold allowed by this store. Please contact the store owner for assistance.';
39
  case '11611':
40
- case '10539': return 'Your transaction was declined. Please contact the store owner for assistance.';
41
- case '10725': return 'The country in your shipping address is not valid. Please double-check your shipping address and try again.';
42
- case '10727': return 'The street address in your shipping address is not valid. Please double-check your shipping address and try again.';
43
- case '10728': return 'The city in your shipping address is not valid. Please double-check your shipping address and try again.';
44
- case '10729': return 'The state in your shipping address is not valid. Please double-check your shipping address and try again.';
45
- case '10730': return 'The ZIP code or postal code in your shipping address is not valid. Please double-check your shipping address and try again.';
46
- case '10736': return 'PayPal rejected your shipping address because the city, state, and/or ZIP code are incorrect. Please double-check that they are all spelled correctly and try again.';
 
47
  case '13113':
48
- case '11084': return 'Your PayPal payment could not be processed. Please contact PayPal for assistance.';
49
  case '12126':
50
- case '12125': return 'The redemption code(s) you entered on PayPal cannot be used at this time. Please return to PayPal and remove them.';
51
  case '17203':
52
  case '17204':
53
- case '17200': return 'Your funding instrument is invalid. Please check out again and select a new funding source.';
54
- default: return 'An error occurred while processing your PayPal payment. Please contact the store owner for assistance.';
55
  }
56
  }
57
  }
19
 
20
  public function mapToBuyerFriendlyError() {
21
  switch ( $this->error_code ) {
22
+ case '-1': return __( 'Unable to communicate with PayPal. Please try your payment again.', 'woocommerce-gateway-paypal-express-checkout' );
23
+ case '10407': return __( 'PayPal rejected your email address because it is not valid. Please double-check your email address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
24
  case '10409':
25
  case '10421':
26
+ case '10410': return __( 'Your PayPal checkout session is invalid. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' );
27
+ case '10411': return __( 'Your PayPal checkout session has expired. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' );
28
  case '11607':
29
+ case '10415': return __( 'Your PayPal payment has already been completed. Please contact the store owner for more information.', 'woocommerce-gateway-paypal-express-checkout' );
30
+ case '10416': return __( 'Your PayPal payment could not be processed. Please check out again or contact PayPal for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
31
+ case '10417': return __( 'Your PayPal payment could not be processed. Please select an alternative method of payment or contact PayPal for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
32
  case '10486':
33
+ case '10422': return __( 'Your PayPal payment could not be processed. Please return to PayPal and select a new method of payment.', 'woocommerce-gateway-paypal-express-checkout' );
34
  case '10485':
35
+ case '10435': return __( 'You have not approved this transaction on the PayPal website. Please check out again and be sure to complete all steps of the PayPal checkout process.', 'woocommerce-gateway-paypal-express-checkout' );
36
+ case '10474': return __( 'Your shipping address may not be in a different country than your country of residence. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
37
+ case '10537': return __( 'This store does not accept transactions from buyers in your country. Please contact the store owner for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
38
+ case '10538': return __( 'The transaction is over the threshold allowed by this store. Please contact the store owner for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
39
  case '11611':
40
+ case '10539': return __( 'Your transaction was declined. Please contact the store owner for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
41
+ case '10725': return __( 'The country in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
42
+ case '10727': return __( 'The street address in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
43
+ case '10728': return __( 'The city in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
44
+ case '10729': return __( 'The state in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
45
+ case '10730': return __( 'The ZIP code or postal code in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
46
+ case '10731': return __( 'The country in your shipping address is not valid. Please double-check your shipping address and try again.', 'woocommerce-gateway-paypal-express-checkout' );
47
+ case '10736': return __( 'PayPal rejected your shipping address because the city, state, and/or ZIP code are incorrect. Please double-check that they are all spelled correctly and try again.', 'woocommerce-gateway-paypal-express-checkout' );
48
  case '13113':
49
+ case '11084': return __( 'Your PayPal payment could not be processed. Please contact PayPal for assistance.', 'woocommerce-gateway-paypal-express-checkout' );
50
  case '12126':
51
+ case '12125': return __( 'The redemption code(s) you entered on PayPal cannot be used at this time. Please return to PayPal and remove them.', 'woocommerce-gateway-paypal-express-checkout' );
52
  case '17203':
53
  case '17204':
54
+ case '17200': return __( 'Your funding instrument is invalid. Please check out again and select a new funding source.', 'woocommerce-gateway-paypal-express-checkout' );
55
+ default: return sprintf( __( 'An error (%s) occurred while processing your PayPal payment. Please contact the store owner for assistance.', 'woocommerce-gateway-paypal-express-checkout' ), $this->error_code );
56
  }
57
  }
58
  }
includes/class-wc-gateway-ppec-cart-handler.php CHANGED
@@ -2,11 +2,13 @@
2
  /**
3
  * Cart handler.
4
  */
5
-
6
  if ( ! defined( 'ABSPATH' ) ) {
7
- exit; // Exit if accessed directly
8
  }
9
 
 
 
 
10
  class WC_Gateway_PPEC_Cart_Handler {
11
 
12
  /**
@@ -35,14 +37,13 @@ class WC_Gateway_PPEC_Cart_Handler {
35
  * Constructor.
36
  */
37
  public function __construct() {
38
- add_action( 'woocommerce_before_cart_totals', array( $this, 'before_cart_totals' ) );
39
-
40
- if ( version_compare( WC()->version, '2.3', '>=' ) ) {
41
- add_action( 'woocommerce_after_cart_totals', array( $this, 'display_paypal_button' ) );
42
- } else {
43
- add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_paypal_button' ) );
44
  }
45
 
 
 
 
46
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
47
  }
48
 
@@ -55,100 +56,73 @@ class WC_Gateway_PPEC_Cart_Handler {
55
  }
56
  }
57
 
 
 
 
58
  public function display_paypal_button() {
59
- $settings = wc_gateway_ppec()->settings->loadSettings();
60
- if( ! $settings->enabled ) {
61
- return;
62
- }
63
 
64
- $api_credentials = $settings->getActiveApiCredentials();
65
- if ( ! is_callable( array( $api_credentials, 'get_payer_id' ) ) ) {
66
  return;
67
  }
68
-
69
- if ( version_compare( WC()->version, '2.3', '>' ) ) {
70
- $class = 'woo_pp_cart_buttons_div';
71
- } else {
72
- $class = 'woo_pp_checkout_buttons_div';
73
- }
74
-
75
- if ( $settings->enableInContextCheckout ) {
76
- $class .= ' paypal-button-hidden';
77
- }
78
-
79
- $redirect_arg = array( 'startcheckout' => 'true' );
80
- $redirect = add_query_arg( $redirect_arg );
81
-
82
- $checkout_logo = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-' . $settings->buttonSize . '.png';
83
- $credit_logo = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/ppcredit-logo-' . $settings->buttonSize . '.png';
84
  ?>
85
- <div class="<?php echo esc_attr( $class ); ?>">
86
- <span style="float: right;">
87
- <a href="<?php echo esc_url( $redirect ); ?>" id="woo_pp_ec_button">
88
- <?php if ( ! $settings->enableInContextCheckout ) : ?>
89
- <img src="<?php echo esc_url( $checkout_logo ); ?>" alt="<?php _e( 'Check out with PayPal', 'woocommerce-gateway-paypal-express-checkout' ); ?>" style="width: auto; height: auto;">
90
- <?php endif; ?>
91
- </a>
92
- </span>
93
-
94
- <? /* defer ppc for next release.
95
- <?php if ( $settings->ppcEnabled && 'US' === WC()->countries->get_base_country() ) : ?>
96
- <?php
97
- $redirect = add_query_arg( array( 'use-ppc' => 'true' ), $redirect );
98
- ?>
99
- <span style="float: right; padding-right: 5px;">
100
-
101
- <a href="<?php echo esc_url( $redirect ); ?>" id="woo_pp_ppc_button">
102
- <img src="<?php echo esc_url( $credit_logo ); ?>" alt="<?php _e( 'Pay with PayPal Credit', 'woocommerce-gateway-paypal-express-checkout' ); ?>" style="width: auto; height: auto;">
103
- </a>
104
- </span>
105
  <?php endif; ?>
106
- */ ?>
107
- </div>
108
 
 
 
 
 
109
  <?php
110
- if ( $settings->enableInContextCheckout ) {
111
- $payer_id = $api_credentials->get_payer_id();
112
- $setup_args = array(
113
- // 'button' => array( 'woo_pp_ec_button', 'woo_pp_ppc_button' ),
114
- 'buttons' => array(
115
- array(
116
- 'container' => 'woo_pp_ec_button',
117
- 'size' => $settings->buttonSize,
118
- 'shape' => 'rect',
119
- )
120
- ),
121
- 'locale' => $settings->get_paypal_locale(),
122
- );
123
- ?>
124
- <script type="text/javascript">
125
- window.paypalCheckoutReady = function() {
126
- paypal.checkout.setup( <?php echo json_encode( $payer_id ); ?>, <?php echo json_encode( $setup_args ); ?> );
127
- }
128
- </script>
129
- <?php
130
- }
131
  }
132
 
133
- public function enqueue_scripts() {
134
- if ( ! is_cart() ) {
135
- return;
136
- }
 
 
137
 
138
- $settings = wc_gateway_ppec()->settings->loadSettings();
139
- if ( ! $settings->enabled ) {
140
  return;
141
  }
 
 
 
 
 
 
142
 
143
- $api_credentials = $settings->getActiveApiCredentials();
144
- if ( ! is_callable( array( $api_credentials, 'get_payer_id' ) ) ) {
 
 
 
 
 
 
145
  return;
146
  }
147
 
148
  wp_enqueue_style( 'wc-gateway-ppec-frontend-cart', wc_gateway_ppec()->plugin_url . 'assets/css/wc-gateway-ppec-frontend-cart.css' );
149
 
150
- if ( $settings->enableInContextCheckout ) {
151
- wp_enqueue_script( 'paypal-checkout-js', 'https://www.paypalobjects.com/api/checkout.js', array(), null, true );
 
 
 
 
 
 
 
 
 
152
  }
153
  }
154
 
@@ -194,10 +168,7 @@ class WC_Gateway_PPEC_Cart_Handler {
194
  // if they do not match, check to see what the merchant would like to do
195
  // options are to remove line items or add a line item to adjust for the difference
196
  if ( $this->totalItemAmount != $roundedPayPalTotal ) {
197
- $settings = wc_gateway_ppec()->settings->loadSettings();
198
- $subtotalBehavior = $settings->subtotalMismatchBehavior;
199
-
200
- if ( WC_Gateway_PPEC_Settings::subtotalMismatchBehaviorAddLineItem == $subtotalBehavior ) {
201
  // ...
202
  // Add line item to make up different between WooCommerce calculations and PayPal calculations
203
  $cartItemAmountDifference = $this->totalItemAmount - $roundedPayPalTotal;
@@ -213,7 +184,7 @@ class WC_Gateway_PPEC_Cart_Handler {
213
  $this->totalItemAmount += $modifyLineItem[ 'amount' ];
214
  $this->orderTotal += $modifyLineItem[ 'amount' ];
215
 
216
- } elseif ( WC_Gateway_PPEC_Settings::subtotalMismatchBehaviorDropLineItems == $subtotalBehavior ) {
217
  // ...
218
  // Omit line items altogether
219
  unset($this->items);
@@ -223,55 +194,12 @@ class WC_Gateway_PPEC_Cart_Handler {
223
 
224
  // enter discount shenanigans. item total cannot be 0 so make modifications accordingly
225
  if ( $this->totalItemAmount == $discounts ) {
226
- $settings = wc_gateway_ppec()->settings->loadSettings();
227
- $behavior = $settings->zeroSubtotalBehavior;
228
-
229
- if ( WC_Gateway_PPEC_Settings::zeroSubtotalBehaviorModifyItems == $behavior ) {
230
- // ...
231
- // Go ahead and pass the discounts with the cart, but then add in a 0.01 line
232
- // item and add a 0.01 shipping discount.
233
- $discountLineItem = array(
234
- 'name' => 'Discount',
235
- 'description' => 'Discount Amount',
236
- 'quantity' => 1,
237
- 'amount' => -$discounts
238
- );
239
-
240
- $this->items[] = $discountLineItem;
241
-
242
- if ( $is_zdp_currency ) {
243
- $discount = 1;
244
- } else {
245
- $discount = 0.01;
246
- }
247
-
248
- $modifyLineItem = array(
249
- 'name' => 'Discount Offset',
250
- 'description' => 'Amount Discounted in Shipping',
251
- 'quantity' => 1,
252
- 'amount' => $discount
253
- );
254
-
255
- $this->items[] = $modifyLineItem;
256
- $this->shipDiscountAmount = -$discount;
257
- $this->totalItemAmount = $this->totalItemAmount - $discounts + $discount;
258
- $this->orderTotal -= $discounts;
259
-
260
- } elseif ( WC_Gateway_PPEC_Settings::zeroSubtotalBehaviorOmitLineItems == $behavior ) {
261
- // ...
262
- // Omit line items altogether
263
- unset($this->items);
264
- $this->shipDiscountAmount = 0;
265
- $this->totalItemAmount -= $discounts;
266
- $this->orderTotal -= $discounts;
267
-
268
- } else {
269
- // ...
270
- // Increase SHIPDISCAMT by the amount of all the coupons in the cart
271
- $this->shipDiscountAmount = -$discounts;
272
- $this->orderTotal -= $discounts;
273
-
274
- }
275
  } else {
276
  // Build PayPal_Cart object as normal
277
  if ( $discounts > 0 ) {
@@ -289,7 +217,7 @@ class WC_Gateway_PPEC_Cart_Handler {
289
  $this->totalItemAmount -= $discounts;
290
  $this->orderTotal -= $discounts;
291
  }
292
-
293
  // If the totals don't line up, adjust the tax to make it work (cause it's probably a tax mismatch).
294
  $wooOrderTotal = round( WC()->cart->total, $decimals );
295
  if( $wooOrderTotal != $this->orderTotal ) {
@@ -306,9 +234,9 @@ class WC_Gateway_PPEC_Cart_Handler {
306
  $this->custom = '';
307
  $this->invoiceNumber = '';
308
 
309
- if ( ! is_numeric( $this->shipping ) )
310
  $this->shipping = 0;
311
-
312
  }
313
 
314
  public function loadOrderDetails( $order_id ) {
@@ -337,7 +265,7 @@ class WC_Gateway_PPEC_Cart_Handler {
337
  );
338
 
339
  $this->items[] = $item;
340
-
341
  $roundedPayPalTotal += round( $amount * $values['qty'], $decimals );
342
  }
343
 
@@ -353,10 +281,7 @@ class WC_Gateway_PPEC_Cart_Handler {
353
  // if they do not match, check to see what the merchant would like to do
354
  // options are to remove line items or add a line item to adjust for the difference
355
  if ( $this->totalItemAmount != $roundedPayPalTotal ) {
356
- $settings = wc_gateway_ppec()->settings->loadSettings();
357
- $subtotalBehavior = $settings->subtotalMismatchBehavior;
358
-
359
- if ( WC_Gateway_PPEC_Settings::subtotalMismatchBehaviorAddLineItem == $subtotalBehavior ) {
360
  // ...
361
  // Add line item to make up different between WooCommerce calculations and PayPal calculations
362
  $cartItemAmountDifference = $this->totalItemAmount - $roundedPayPalTotal;
@@ -370,7 +295,7 @@ class WC_Gateway_PPEC_Cart_Handler {
370
 
371
  $this->items[] = $modifyLineItem;
372
 
373
- } elseif ( WC_Gateway_PPEC_Settings::subtotalMismatchBehaviorDropLineItems == $subtotalBehavior ) {
374
  // ...
375
  // Omit line items altogether
376
  unset($this->items);
@@ -380,54 +305,11 @@ class WC_Gateway_PPEC_Cart_Handler {
380
 
381
  // enter discount shenanigans. item total cannot be 0 so make modifications accordingly
382
  if ( $this->totalItemAmount == $discounts ) {
383
- $settings = wc_gateway_ppec()->settings->loadSettings();
384
- $behavior = $settings->zeroSubtotalBehavior;
385
-
386
- if ( WC_Gateway_PPEC_Settings::zeroSubtotalBehaviorModifyItems == $behavior ) {
387
- // ...
388
- // Go ahead and pass the discounts with the cart, but then add in a 0.01 line
389
- // item and add a 0.01 shipping discount.
390
- $discountLineItem = array(
391
- 'name' => 'Discount',
392
- 'description' => 'Discount Amount',
393
- 'quantity' => 1,
394
- 'amount' => -$discounts
395
- );
396
-
397
- $this->items[] = $discountLineItem;
398
-
399
- if ( $is_zdp_currency ) {
400
- $discount = 1;
401
- } else {
402
- $discount = 0.01;
403
- }
404
-
405
- $modifyLineItem = array(
406
- 'name' => 'Discount Offset',
407
- 'description' => 'Amount Discounted in Shipping',
408
- 'quantity' => 1,
409
- 'amount' => $discount
410
- );
411
-
412
- $this->items[] = $modifyLineItem;
413
- $this->shipDiscountAmount = -$discount;
414
- $this->totalItemAmount = $this->totalItemAmount - $discounts + $discount;
415
- $this->orderTotal -= $discounts;
416
-
417
- } elseif ( WC_Gateway_PPEC_Settings::zeroSubtotalBehaviorOmitLineItems == $behavior ) {
418
- // ...
419
- // Omit line items altogether
420
- unset($this->items);
421
- $this->shipDiscountAmount = 0;
422
- $this->totalItemAmount -= $discounts;
423
- $this->orderTotal -= $discounts;
424
-
425
- } else {
426
- // ...
427
- // Increase SHIPDISCAMT by the amount of all the coupons in the cart
428
- $this->shipDiscountAmount = -$discounts;
429
- $this->orderTotal -= $discounts;
430
- }
431
  } else {
432
  // Build PayPal_Cart object as normal
433
  if ( $discounts > 0 ) {
@@ -445,7 +327,7 @@ class WC_Gateway_PPEC_Cart_Handler {
445
 
446
  $this->shipDiscountAmount = 0;
447
  }
448
-
449
  // If the totals don't line up, adjust the tax to make it work (cause it's probably a tax mismatch).
450
  $wooOrderTotal = round( $order->get_total(), $decimals );
451
  if( $wooOrderTotal != $this->orderTotal ) {
@@ -462,24 +344,24 @@ class WC_Gateway_PPEC_Cart_Handler {
462
  $this->custom = '';
463
  $this->invoiceNumber = '';
464
 
465
- if ( ! is_numeric( $this->shipping ) )
466
  $this->shipping = 0;
467
-
468
  }
469
 
470
  public function setECParams() {
471
-
472
  $stdParams = array (
473
- 'PAYMENTREQUEST_0_AMT' => $this->orderTotal,
474
  'PAYMENTREQUEST_0_CURRENCYCODE' => $this->currency,
475
- 'PAYMENTREQUEST_0_ITEMAMT' => $this->totalItemAmount,
476
- 'PAYMENTREQUEST_0_SHIPPINGAMT' => $this->shipping,
477
  'PAYMENTREQUEST_0_INSURANCEAMT' => $this->insurance,
478
- 'PAYMENTREQUEST_0_HANDLINGAMT' => $this->handling,
479
- 'PAYMENTREQUEST_0_TAXAMT' => $this->orderTax,
480
- 'PAYMENTREQUEST_0_CUSTOM' => $this->custom,
481
- 'PAYMENTREQUEST_0_INVNUM' => $this->invoiceNumber,
482
- 'PAYMENTREQUEST_0_SHIPDISCAMT' => $this->shipDiscountAmount
 
483
  );
484
 
485
  if ( ! empty( $this->items ) ) {
@@ -488,8 +370,8 @@ class WC_Gateway_PPEC_Cart_Handler {
488
  $lineItemParams = array(
489
  'L_PAYMENTREQUEST_0_NAME' . $count => $values['name'],
490
  'L_PAYMENTREQUEST_0_DESC' . $count => ! empty( $values['description'] ) ? strip_tags( $values['description'] ) : '',
491
- 'L_PAYMENTREQUEST_0_QTY' . $count => $values['quantity'],
492
- 'L_PAYMENTREQUEST_0_AMT' . $count => $values['amount']
493
  );
494
 
495
  $stdParams = array_merge( $stdParams, $lineItemParams );
2
  /**
3
  * Cart handler.
4
  */
 
5
  if ( ! defined( 'ABSPATH' ) ) {
6
+ exit;
7
  }
8
 
9
+ /**
10
+ * WC_Gateway_PPEC_Cart_Handler handles button display in the cart.
11
+ */
12
  class WC_Gateway_PPEC_Cart_Handler {
13
 
14
  /**
37
  * Constructor.
38
  */
39
  public function __construct() {
40
+ if ( ! wc_gateway_ppec()->settings->is_enabled() ) {
41
+ return;
 
 
 
 
42
  }
43
 
44
+ add_action( 'woocommerce_before_cart_totals', array( $this, 'before_cart_totals' ) );
45
+ add_action( 'woocommerce_widget_shopping_cart_buttons', array( $this, 'display_mini_paypal_button' ), 20 );
46
+ add_action( 'woocommerce_proceed_to_checkout', array( $this, 'display_paypal_button' ), 20 );
47
  add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
48
  }
49
 
56
  }
57
  }
58
 
59
+ /**
60
+ * Display paypal button on the cart page
61
+ */
62
  public function display_paypal_button() {
63
+ $gateways = WC()->payment_gateways->get_available_payment_gateways();
64
+ $settings = wc_gateway_ppec()->settings;
 
 
65
 
66
+ if ( ! isset( $gateways['ppec_paypal'] ) ) {
 
67
  return;
68
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
69
  ?>
70
+ <div class="wcppec-checkout-buttons woo_pp_cart_buttons_div">
71
+
72
+ <?php if ( has_action( 'woocommerce_proceed_to_checkout', 'woocommerce_button_proceed_to_checkout' ) ) : ?>
73
+ <div class="wcppec-checkout-buttons__separator">
74
+ <?php _e( '&mdash; or &mdash;', 'woocommerce-gateway-paypal-express-checkout' ); ?>
75
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
76
  <?php endif; ?>
 
 
77
 
78
+ <a href="<?php echo esc_url( add_query_arg( array( 'startcheckout' => 'true' ), wc_get_page_permalink( 'cart' ) ) ); ?>" id="woo_pp_ec_button" class="wcppec-checkout-buttons__button">
79
+ <img src="<?php echo esc_url( 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/checkout-logo-' . $settings->button_size . '.png' ); ?>" alt="<?php _e( 'Check out with PayPal', 'woocommerce-gateway-paypal-express-checkout' ); ?>" style="width: auto; height: auto;">
80
+ </a>
81
+ </div>
82
  <?php
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
83
  }
84
 
85
+ /**
86
+ * Display paypal button on the cart widget
87
+ */
88
+ public function display_mini_paypal_button() {
89
+ $gateways = WC()->payment_gateways->get_available_payment_gateways();
90
+ $settings = wc_gateway_ppec()->settings;
91
 
92
+ if ( ! isset( $gateways['ppec_paypal'] ) ) {
 
93
  return;
94
  }
95
+ ?>
96
+ <a href="<?php echo esc_url( add_query_arg( array( 'startcheckout' => 'true' ), wc_get_page_permalink( 'cart' ) ) ); ?>" id="woo_pp_ec_button" class="wcppec-cart-widget-button">
97
+ <img src="<?php echo esc_url( 'https://www.paypalobjects.com/webstatic/en_US/i/btn/png/gold-rect-paypalcheckout-26px.png' ); ?>" alt="<?php _e( 'Check out with PayPal', 'woocommerce-gateway-paypal-express-checkout' ); ?>" style="width: auto; height: auto;">
98
+ </a>
99
+ <?php
100
+ }
101
 
102
+ /**
103
+ * Frontend scripts
104
+ */
105
+ public function enqueue_scripts() {
106
+ $settings = wc_gateway_ppec()->settings;
107
+ $client = wc_gateway_ppec()->client;
108
+
109
+ if ( ! $client->get_payer_id() ) {
110
  return;
111
  }
112
 
113
  wp_enqueue_style( 'wc-gateway-ppec-frontend-cart', wc_gateway_ppec()->plugin_url . 'assets/css/wc-gateway-ppec-frontend-cart.css' );
114
 
115
+ if ( is_cart() ) {
116
+ wp_enqueue_script( 'paypal-checkout-js', 'https://www.paypalobjects.com/api/checkout.js', array(), '1.0', true );
117
+ wp_enqueue_script( 'wc-gateway-ppec-frontend-in-context-checkout', wc_gateway_ppec()->plugin_url . 'assets/js/wc-gateway-ppec-frontend-in-context-checkout.js', array( 'jquery' ), wc_gateway_ppec()->version, true );
118
+ wp_localize_script( 'wc-gateway-ppec-frontend-in-context-checkout', 'wc_ppec_context',
119
+ array(
120
+ 'payer_id' => $client->get_payer_id(),
121
+ 'environment' => $settings->get_environment(),
122
+ 'locale' => $settings->get_paypal_locale(),
123
+ 'start_flow' => esc_url( add_query_arg( array( 'startcheckout' => 'true' ), wc_get_page_permalink( 'cart' ) ) ),
124
+ )
125
+ );
126
  }
127
  }
128
 
168
  // if they do not match, check to see what the merchant would like to do
169
  // options are to remove line items or add a line item to adjust for the difference
170
  if ( $this->totalItemAmount != $roundedPayPalTotal ) {
171
+ if ( 'add' === wc_gateway_ppec()->settings->get_subtotal_mismatch_behavior() ) {
 
 
 
172
  // ...
173
  // Add line item to make up different between WooCommerce calculations and PayPal calculations
174
  $cartItemAmountDifference = $this->totalItemAmount - $roundedPayPalTotal;
184
  $this->totalItemAmount += $modifyLineItem[ 'amount' ];
185
  $this->orderTotal += $modifyLineItem[ 'amount' ];
186
 
187
+ } else {
188
  // ...
189
  // Omit line items altogether
190
  unset($this->items);
194
 
195
  // enter discount shenanigans. item total cannot be 0 so make modifications accordingly
196
  if ( $this->totalItemAmount == $discounts ) {
197
+ // ...
198
+ // Omit line items altogether
199
+ unset($this->items);
200
+ $this->shipDiscountAmount = 0;
201
+ $this->totalItemAmount -= $discounts;
202
+ $this->orderTotal -= $discounts;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
203
  } else {
204
  // Build PayPal_Cart object as normal
205
  if ( $discounts > 0 ) {
217
  $this->totalItemAmount -= $discounts;
218
  $this->orderTotal -= $discounts;
219
  }
220
+
221
  // If the totals don't line up, adjust the tax to make it work (cause it's probably a tax mismatch).
222
  $wooOrderTotal = round( WC()->cart->total, $decimals );
223
  if( $wooOrderTotal != $this->orderTotal ) {
234
  $this->custom = '';
235
  $this->invoiceNumber = '';
236
 
237
+ if ( ! is_numeric( $this->shipping ) ) {
238
  $this->shipping = 0;
239
+ }
240
  }
241
 
242
  public function loadOrderDetails( $order_id ) {
265
  );
266
 
267
  $this->items[] = $item;
268
+
269
  $roundedPayPalTotal += round( $amount * $values['qty'], $decimals );
270
  }
271
 
281
  // if they do not match, check to see what the merchant would like to do
282
  // options are to remove line items or add a line item to adjust for the difference
283
  if ( $this->totalItemAmount != $roundedPayPalTotal ) {
284
+ if ( 'add' === wc_gateway_ppec()->settings->get_subtotal_mismatch_behavior() ) {
 
 
 
285
  // ...
286
  // Add line item to make up different between WooCommerce calculations and PayPal calculations
287
  $cartItemAmountDifference = $this->totalItemAmount - $roundedPayPalTotal;
295
 
296
  $this->items[] = $modifyLineItem;
297
 
298
+ } else {
299
  // ...
300
  // Omit line items altogether
301
  unset($this->items);
305
 
306
  // enter discount shenanigans. item total cannot be 0 so make modifications accordingly
307
  if ( $this->totalItemAmount == $discounts ) {
308
+ // Omit line items altogether
309
+ unset($this->items);
310
+ $this->shipDiscountAmount = 0;
311
+ $this->totalItemAmount -= $discounts;
312
+ $this->orderTotal -= $discounts;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
313
  } else {
314
  // Build PayPal_Cart object as normal
315
  if ( $discounts > 0 ) {
327
 
328
  $this->shipDiscountAmount = 0;
329
  }
330
+
331
  // If the totals don't line up, adjust the tax to make it work (cause it's probably a tax mismatch).
332
  $wooOrderTotal = round( $order->get_total(), $decimals );
333
  if( $wooOrderTotal != $this->orderTotal ) {
344
  $this->custom = '';
345
  $this->invoiceNumber = '';
346
 
347
+ if ( ! is_numeric( $this->shipping ) ) {
348
  $this->shipping = 0;
349
+ }
350
  }
351
 
352
  public function setECParams() {
 
353
  $stdParams = array (
354
+ 'PAYMENTREQUEST_0_AMT' => $this->orderTotal,
355
  'PAYMENTREQUEST_0_CURRENCYCODE' => $this->currency,
356
+ 'PAYMENTREQUEST_0_ITEMAMT' => $this->totalItemAmount,
357
+ 'PAYMENTREQUEST_0_SHIPPINGAMT' => $this->shipping,
358
  'PAYMENTREQUEST_0_INSURANCEAMT' => $this->insurance,
359
+ 'PAYMENTREQUEST_0_HANDLINGAMT' => $this->handling,
360
+ 'PAYMENTREQUEST_0_TAXAMT' => $this->orderTax,
361
+ 'PAYMENTREQUEST_0_CUSTOM' => $this->custom,
362
+ 'PAYMENTREQUEST_0_INVNUM' => $this->invoiceNumber,
363
+ 'PAYMENTREQUEST_0_SHIPDISCAMT' => $this->shipDiscountAmount,
364
+ 'NOSHIPPING' => WC()->cart->needs_shipping() ? 0 : 1,
365
  );
366
 
367
  if ( ! empty( $this->items ) ) {
370
  $lineItemParams = array(
371
  'L_PAYMENTREQUEST_0_NAME' . $count => $values['name'],
372
  'L_PAYMENTREQUEST_0_DESC' . $count => ! empty( $values['description'] ) ? strip_tags( $values['description'] ) : '',
373
+ 'L_PAYMENTREQUEST_0_QTY' . $count => $values['quantity'],
374
+ 'L_PAYMENTREQUEST_0_AMT' . $count => $values['amount']
375
  );
376
 
377
  $stdParams = array_merge( $stdParams, $lineItemParams );
includes/class-wc-gateway-ppec-checkout-details.php CHANGED
@@ -63,7 +63,7 @@ class PayPal_Checkout_Details {
63
 
64
  foreach ( $getECResponse as $index => $value ) {
65
  if ( array_key_exists( $index, $map ) ) {
66
- $this->$map[ $index ] = $value;
67
  }
68
  }
69
 
@@ -188,7 +188,7 @@ class PayPal_Checkout_Payment_Details {
188
  foreach ( $map as $index => $value ) {
189
  $var_name = 'PAYMENTREQUEST_' . $bucketNum . '_' . $index;
190
  if ( array_key_exists( $var_name, $getECResponse ) ) {
191
- $this->$value = $getECResponse[ $var_name ];
192
  $found_any = true;
193
  }
194
  }
@@ -236,18 +236,18 @@ class PayPal_Checkout_Payment_Item_Details {
236
 
237
  public function loadFromGetECResponse( $getECResponse, $bucketNum, $itemNum ) {
238
  $map = array(
239
- 'NAME' => 'name',
240
- 'DESC' => 'description',
241
- 'AMT' => 'amount',
242
  'NUMBER' => 'item_number',
243
- 'QTY' => 'quantity',
244
- 'TAXAMT' => 'tax_amount'
245
  );
246
 
247
  foreach ( $map as $index => $value ) {
248
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_' . $index . $itemNum;
249
  if ( array_key_exists( $var_name, $getECResponse ) ) {
250
- $this->$value = $getECResponse[ $var_name ];
251
  }
252
  }
253
 
@@ -292,7 +292,7 @@ class PayPal_Checkout_Payment_Item_Physical_Details {
292
  foreach ( $map as $index => $value ) {
293
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_ITEM' . $index . $itemNum;
294
  if ( array_key_exists( $var_name, $getECResponse ) ) {
295
- $this->$value = $getECResponse[ $var_name ];
296
  $found_any = true;
297
  }
298
  }
@@ -319,7 +319,7 @@ class PayPal_Checkout_Payment_Item_Ebay_Item_Details {
319
  foreach ( $map as $index => $value ) {
320
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_' . $index . $itemNum;
321
  if ( array_key_exists( $var_name, $getECResponse ) ) {
322
- $this->$value = $getECResponse[ $var_name ];
323
  $found_any = true;
324
  }
325
  }
@@ -352,7 +352,7 @@ class PayPal_Checkout_Shipping_Option_Details {
352
  $found_any = false;
353
  foreach ( $getECResponse as $index => $value ) {
354
  if ( array_key_exists( $index, $map ) ) {
355
- $this->$map[ $index ] = $value;
356
  $found_any = true;
357
  }
358
  }
@@ -380,7 +380,7 @@ class PayPal_Checkout_Instrument_Details {
380
 
381
  foreach ( $getECResponse as $index => $value ) {
382
  if ( array_key_exists( $index, $map ) ) {
383
- $this->$map[ $index ] = $value;
384
  $found_any = true;
385
  }
386
  }
@@ -466,7 +466,7 @@ class PayPal_Checkout_Payer_Details {
466
 
467
  foreach ( $getECResponse as $index => $value ) {
468
  if ( array_key_exists( $index, $map ) ) {
469
- $this->$map[ $index ] = $value;
470
  $found_any = true;
471
  }
472
  if ( preg_match( '/^BILLTONAME|STREET|STREET2|CITY|STATE|ZIP|COUNTRY|COUNTRYNAME|ADDRESSOWNER|ADDRESSSTATUS$/', $index ) ) {
@@ -507,7 +507,7 @@ class PayPal_Checkout_Gift_Details {
507
 
508
  foreach ( $getECResponse as $index => $value ) {
509
  if ( array_key_exists( $index, $map ) ) {
510
- $this->$map[ $index ] = $value;
511
  $found_any = true;
512
  }
513
  }
63
 
64
  foreach ( $getECResponse as $index => $value ) {
65
  if ( array_key_exists( $index, $map ) ) {
66
+ $this->{ $map[ $index ] } = $value;
67
  }
68
  }
69
 
188
  foreach ( $map as $index => $value ) {
189
  $var_name = 'PAYMENTREQUEST_' . $bucketNum . '_' . $index;
190
  if ( array_key_exists( $var_name, $getECResponse ) ) {
191
+ $this->{ $value } = $getECResponse[ $var_name ];
192
  $found_any = true;
193
  }
194
  }
236
 
237
  public function loadFromGetECResponse( $getECResponse, $bucketNum, $itemNum ) {
238
  $map = array(
239
+ 'NAME' => 'name',
240
+ 'DESC' => 'description',
241
+ 'AMT' => 'amount',
242
  'NUMBER' => 'item_number',
243
+ 'QTY' => 'quantity',
244
+ 'TAXAMT' => 'tax_amount',
245
  );
246
 
247
  foreach ( $map as $index => $value ) {
248
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_' . $index . $itemNum;
249
  if ( array_key_exists( $var_name, $getECResponse ) ) {
250
+ $this->{ $value } = $getECResponse[ $var_name ];
251
  }
252
  }
253
 
292
  foreach ( $map as $index => $value ) {
293
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_ITEM' . $index . $itemNum;
294
  if ( array_key_exists( $var_name, $getECResponse ) ) {
295
+ $this->{ $value } = $getECResponse[ $var_name ];
296
  $found_any = true;
297
  }
298
  }
319
  foreach ( $map as $index => $value ) {
320
  $var_name = 'L_PAYMENTREQUEST_' . $bucketNum . '_' . $index . $itemNum;
321
  if ( array_key_exists( $var_name, $getECResponse ) ) {
322
+ $this->{ $value } = $getECResponse[ $var_name ];
323
  $found_any = true;
324
  }
325
  }
352
  $found_any = false;
353
  foreach ( $getECResponse as $index => $value ) {
354
  if ( array_key_exists( $index, $map ) ) {
355
+ $this->{ $map[ $index ] } = $value;
356
  $found_any = true;
357
  }
358
  }
380
 
381
  foreach ( $getECResponse as $index => $value ) {
382
  if ( array_key_exists( $index, $map ) ) {
383
+ $this->{ $map[ $index ] } = $value;
384
  $found_any = true;
385
  }
386
  }
466
 
467
  foreach ( $getECResponse as $index => $value ) {
468
  if ( array_key_exists( $index, $map ) ) {
469
+ $this->{ $map[ $index ] } = $value;
470
  $found_any = true;
471
  }
472
  if ( preg_match( '/^BILLTONAME|STREET|STREET2|CITY|STATE|ZIP|COUNTRY|COUNTRYNAME|ADDRESSOWNER|ADDRESSSTATUS$/', $index ) ) {
507
 
508
  foreach ( $getECResponse as $index => $value ) {
509
  if ( array_key_exists( $index, $map ) ) {
510
+ $this->{ $map[ $index ] } = $value;
511
  $found_any = true;
512
  }
513
  }
includes/class-wc-gateway-ppec-checkout-handler.php CHANGED
@@ -24,255 +24,218 @@ require_once( $includes_path . 'class-wc-gateway-ppec-address.php' );
24
 
25
  class WC_Gateway_PPEC_Checkout_Handler {
26
 
27
- protected $_suppressShippingAddress;
28
-
29
  // $_shippingAddress can be a single PayPal_Address object, or an array of PayPal_Address objects
30
  // (for the purposes of doing parallel payments).
31
  protected $_shippingAddress;
32
- protected $_requestBillingAgreement;
33
- protected $_enablePayPalCredit;
34
 
35
  public function __construct() {
36
- $this->_suppressShippingAddress = false;
37
  $this->_shippingAddress = false;
38
- $this->_requestBillingAgreement = false;
39
 
40
- add_action( 'woocommerce_init', array( $this, 'init' ) );
 
 
41
 
42
  add_action( 'wp', array( $this, 'maybe_return_from_paypal' ) );
43
  add_action( 'wp', array( $this, 'maybe_cancel_checkout_with_paypal' ) );
44
  add_action( 'woocommerce_cart_emptied', array( $this, 'maybe_clear_session_data' ) );
45
 
46
- add_action( 'woocommerce_before_checkout_process', array( $this, 'before_checkout_process' ) );
47
- add_filter( 'woocommerce_checkout_fields', array( $this, 'make_billing_address_optional' ) );
48
- add_action( 'woocommerce_after_checkout_form', array( $this, 'after_checkout_form' ) );
49
  add_action( 'woocommerce_available_payment_gateways', array( $this, 'maybe_disable_other_gateways' ) );
50
- add_action( 'woocommerce_available_payment_gateways', array( $this, 'maybe_disable_paypal_credit' ) );
51
  add_action( 'woocommerce_review_order_after_submit', array( $this, 'maybe_render_cancel_link' ) );
52
-
53
- add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
54
  }
55
 
 
 
 
 
 
 
 
56
  public function init() {
57
- // If the buyer clicked on the "Check Out with PayPal" button, we need to wait for the cart
58
- // totals to be available. Unfortunately that doesn't happen until
59
- // woocommerce_before_cart_totals executes, and there is already output sent to the browser by
60
- // this point. So, to get around this issue, we'll enable output buffering to prevent WP from
61
- // sending anything back to the browser.
62
  if ( isset( $_GET['startcheckout'] ) && 'true' === $_GET['startcheckout'] ) {
63
  ob_start();
64
  }
65
  }
66
 
67
- public function maybe_return_from_paypal() {
68
- if ( empty( $_GET['woo-paypal-return'] ) ) {
69
- return;
70
- }
71
-
72
- // If the token and payer ID aren't there, just ignore this request
73
- if ( empty( $_GET['token'] ) || empty( $_GET['PayerID'] ) ) {
74
- return;
75
- }
76
-
77
- $token = $_GET['token'];
78
- $payer_id = $_GET['PayerID'];
79
-
80
- try {
81
- $checkout_details = $this->getCheckoutDetails( $token );
82
- } catch( PayPal_API_Exception $e ) {
83
- wc_add_notice( __( 'Sorry, an error occurred while trying to retrieve your information from PayPal. Please try again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
84
- return;
85
- } catch( PayPal_Missing_Session_Exception $e ) {
86
- wc_add_notice( __( 'Your PayPal checkout session has expired. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
87
- return;
88
- }
89
-
90
- if ( $this->session_has_expired( $token ) ) {
91
- wc_add_notice( __( 'Your PayPal checkout session has expired. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
92
- return;
93
- }
94
-
95
- $session = WC()->session->paypal;
96
- $session->checkout_completed = true;
97
- $session->payerID = $payer_id;
98
-
99
- WC()->session->paypal = $session;
100
-
101
- if ( $session->using_ppc ) {
102
- WC()->session->chosen_payment_method = 'ppec_paypal_credit';
103
- } else {
104
- WC()->session->chosen_payment_method = 'ppec_paypal';
105
- }
106
-
107
- if ( 'order' == $session->leftFrom && $session->order_id ) {
108
- // Try to complete the payment now.
109
- try {
110
- $order_id = $session->order_id;
111
- $payment_details = $this->completePayment( $order_id, $session->token, $session->payerID );
112
- $transaction_id = $payment_details->payments[0]->transaction_id;
113
-
114
- // TODO: Handle things like eChecks, giropay, etc.
115
- $order = wc_get_order( $order_id );
116
- $order->payment_complete( $transaction_id );
117
- $order->add_order_note( sprintf( __( 'PayPal transaction completed; transaction ID = %s', 'woocommerce-gateway-paypal-express-checkout' ), $transaction_id ) );
118
- $order->reduce_order_stock();
119
- WC()->cart->empty_cart();
120
- unset( WC()->session->paypal );
121
-
122
- wp_safe_redirect( $order->get_checkout_order_received_url() );
123
- exit;
124
-
125
- } catch( PayPal_Missing_Session_Exception $e ) {
126
-
127
- // For some reason, our session data is missing. Generally,
128
- // if we've made it this far, this shouldn't happen.
129
- wc_add_notice( __( 'Sorry, an error occurred while trying to process your payment. Please try again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
130
-
131
- } catch( PayPal_API_Exception $e ) {
132
-
133
- // Did we get a 10486 or 10422 back from PayPal? If so,
134
- // this means we need to send the buyer back over to PayPal
135
- // to have them pick out a new funding method.
136
- $need_to_redirect_back = false;
137
- foreach ( $e->errors as $error ) {
138
- if ( '10486' == $error->error_code || '10422' == $error->error_code ) {
139
- $need_to_redirect_back = true;
140
- }
141
- }
142
-
143
- if ( $need_to_redirect_back ) {
144
- $settings = wc_gateway_ppec()->settings->loadSettings();
145
- $session->checkout_completed = false;
146
- $session->leftFrom = 'order';
147
- $session->order_id = $order_id;
148
- WC()->session->paypal = $session;
149
- wp_safe_redirect( $settings->getPayPalRedirectUrl( $session->token, true ) );
150
- exit;
151
- } else {
152
- $final_output = '<ul>';
153
- foreach ( $e->errors as $error ) {
154
- $final_output .= '<li>' . __( $error->maptoBuyerFriendlyError(), 'woocommerce-gateway-paypal-express-checkout' ) . '</li>';
155
- }
156
- $final_output .= '</ul>';
157
- wc_add_notice( __( 'Payment error:', 'woocommerce-gateway-paypal-express-checkout' ) . $final_output, 'error' );
158
- return;
159
- }
160
- }
161
  }
 
162
  }
163
 
164
  /**
165
- * Before checkout process.
166
- *
167
- * Turn off use of the buyer email in the payment method title so that it
168
- * doesn't appear in emails.
169
  *
170
- * @return void
171
  */
172
- public function before_checkout_process() {
173
- WC_Gateway_PPEC::$use_buyer_email = false;
174
- }
175
 
176
- public function make_billing_address_optional( $checkout_fields ) {
177
- $session = WC()->session->paypal;
178
- if ( is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) && $session->checkout_completed && $session->expiry_time >= time() && $session->payerID ) {
179
- $checkout_fields['billing']['billing_address_1']['required'] = false;
180
- $checkout_fields['billing']['billing_address_1']['class'][] = 'ppec-bypass';
181
- $checkout_fields['billing']['billing_address_1']['class'][] = 'hidden';
182
-
183
- $checkout_fields['billing']['billing_address_2']['required'] = false;
184
- $checkout_fields['billing']['billing_address_2']['class'][] = 'ppec-bypass';
185
- $checkout_fields['billing']['billing_address_2']['class'][] = 'hidden';
186
-
187
- $checkout_fields['billing']['billing_city']['required'] = false;
188
- $checkout_fields['billing']['billing_city']['class'][] = 'ppec-bypass';
189
- $checkout_fields['billing']['billing_city']['class'][] = 'hidden';
190
-
191
- $checkout_fields['billing']['billing_state']['required'] = false;
192
- $checkout_fields['billing']['billing_state']['class'][] = 'ppec-bypass';
193
- $checkout_fields['billing']['billing_state']['class'][] = 'hidden';
194
-
195
- $checkout_fields['billing']['billing_postcode' ]['required'] = false;
196
- $checkout_fields['billing']['billing_postcode']['class'][] = 'ppec-bypass';
197
- $checkout_fields['billing']['billing_postcode']['class'][] = 'hidden';
198
  }
 
199
 
200
- return $checkout_fields;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
201
  }
202
 
203
  /**
204
- * After checkout form.
205
  */
206
- public function after_checkout_form() {
207
- $settings = wc_gateway_ppec()->settings->loadSettings();
208
- if ( ! $settings->enabled ) {
209
- return;
210
- }
211
 
212
- $api_credentials = $settings->getActiveApiCredentials();
213
- if ( ! is_callable( array( $api_credentials, 'get_payer_id' ) ) ) {
214
  return;
215
  }
 
 
 
 
 
216
 
217
- if ( $settings->enableInContextCheckout ) {
218
- $session = WC()->session->paypal;
219
-
220
- // Make sure no session being set from cart.
221
- if ( $session && is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) ) {
222
- if ( $session->checkout_completed ) {
223
- return;
224
- }
225
-
226
- if ( $session->expiry_time > time() ) {
227
- return;
228
- }
229
-
230
- if ( ! empty( $session->payerID ) ) {
231
- return;
232
- }
233
- }
 
 
 
 
 
 
234
 
235
- // This div is necessary for PayPal to properly display its lightbox.
236
- ?>
237
- <div id="woo_pp_icc_container" style="display: none;"></div>
238
- <?php
239
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
240
  }
241
 
242
  /**
243
- * Enqueue front-end scripts on checkout page.
244
  */
245
- public function enqueue_scripts() {
246
- if ( ! is_checkout() ) {
247
  return;
248
  }
249
 
250
- $settings = wc_gateway_ppec()->settings->loadSettings();
251
- if ( ! $settings->enabled ) {
252
- return;
253
- }
254
 
255
- $api_credentials = $settings->getActiveApiCredentials();
256
- if ( ! is_callable( array( $api_credentials, 'get_payer_id' ) ) ) {
257
  return;
258
  }
259
 
260
- wp_enqueue_style( 'wc-gateway-ppec-frontend-checkout', wc_gateway_ppec()->plugin_url . 'assets/css/wc-gateway-ppec-frontend-checkout.css', array(), wc_gateway_ppec()->version );
 
 
 
 
 
 
 
 
 
 
 
 
261
 
262
- // On the checkout page, only load the JS if we plan on sending them over to PayPal.
263
- $payer_id = $api_credentials->get_payer_id();
264
- if ( $settings->enableInContextCheckout && ! empty( $payer_id ) ) {
265
- $session = WC()->session->paypal;
266
- if ( ! $session
267
- || ! is_a( $session, 'WC_Gateway_PPEC_Session_Data' )
268
- || ! $session->checkout_completed || $session->expiry_time < time()
269
- || ! $session->payerID ) {
270
 
271
- wp_enqueue_script( 'wc-gateway-ppec-frontend-checkout', wc_gateway_ppec()->plugin_url . 'assets/js/wc-gateway-ppec-frontend-checkout.js', array( 'jquery' ), wc_gateway_ppec()->version, true );
272
- wp_localize_script( 'wc-gateway-ppec-frontend-checkout', 'wc_ppec', array( 'payer_id' => $payer_id ) );
273
 
274
- wp_enqueue_script( 'paypal-checkout-js', 'https://www.paypalobjects.com/api/checkout.js', array(), null, true );
 
 
 
 
 
275
  }
 
 
 
 
 
 
 
 
 
 
276
  }
277
  }
278
 
@@ -292,27 +255,10 @@ class WC_Gateway_PPEC_Checkout_Handler {
292
  unset( $gateways[ $id ] );
293
  }
294
  }
295
- }
296
 
297
- // If PPEC is enabled, removed PayPal standard.
298
- if ( wc_gateway_ppec()->settings->loadSettings()->enabled ) {
299
- unset( $gateways['paypal'] );
300
- }
301
-
302
- return $gateways;
303
- }
304
-
305
- /**
306
- * If base location is not US, disable PayPal Credit.
307
- *
308
- * @since 1.0.0
309
- * @param array $gateways Available gateways
310
- *
311
- * @return array Available gateways
312
- */
313
- public function maybe_disable_paypal_credit( $gateways ) {
314
- if ( isset( $gateways['ppec_paypal_credit'] ) && 'US' !== WC()->countries->get_base_country() ) {
315
- unset( $gateways['ppec_paypal_credit'] );
316
  }
317
 
318
  return $gateways;
@@ -341,7 +287,9 @@ class WC_Gateway_PPEC_Checkout_Handler {
341
  public function maybe_cancel_checkout_with_paypal() {
342
  if ( is_cart() && ! empty( $_GET['wc-gateway-ppec-clear-session'] ) ) {
343
  $this->maybe_clear_session_data();
344
- wc_add_notice( __( 'You have cancelled Checkout with PayPal. Please try to process your order again.', 'woocommerce-gateway-paypal-express-checkout' ), 'notice' );
 
 
345
  }
346
  }
347
 
@@ -352,7 +300,7 @@ class WC_Gateway_PPEC_Checkout_Handler {
352
  * @since 1.0.0
353
  */
354
  public function maybe_clear_session_data() {
355
- if ( $this->has_active_session() ) {
356
  unset( WC()->session->paypal );
357
  }
358
  }
@@ -368,16 +316,7 @@ class WC_Gateway_PPEC_Checkout_Handler {
368
  */
369
  public function session_has_expired( $token ) {
370
  $session = WC()->session->paypal;
371
-
372
- return (
373
- ! $session
374
- ||
375
- ! is_a( $session, 'WC_Gateway_PPEC_Session_Data' )
376
- ||
377
- $session->expiry_time < time()
378
- ||
379
- $token !== $session->token
380
- );
381
  }
382
 
383
  /**
@@ -389,7 +328,6 @@ class WC_Gateway_PPEC_Checkout_Handler {
389
  */
390
  public function has_active_session() {
391
  $session = WC()->session->paypal;
392
-
393
  return ( is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) && $session->payerID && $session->expiry_time > time() );
394
  }
395
 
@@ -411,18 +349,6 @@ class WC_Gateway_PPEC_Checkout_Handler {
411
  return $token;
412
  }
413
 
414
- public function enablePayPalCredit( $enable = true ) {
415
- $this->_enablePayPalCredit = $enable;
416
- }
417
-
418
- public function suppressShippingAddress( $suppress = true ) {
419
- if ( $suppress ) {
420
- $this->_suppressShippingAddress = true;
421
- } else {
422
- $this->_suppressShippingAddress = false;
423
- }
424
- }
425
-
426
  public function setShippingAddress( $address ) {
427
  if ( is_a( $address, 'PayPal_Address' ) ) {
428
  $this->_shippingAddress = $address;
@@ -444,31 +370,10 @@ class WC_Gateway_PPEC_Checkout_Handler {
444
  }
445
  }
446
 
447
- public function requestBillingAgreement( $request = true ) {
448
- if ( $request ) {
449
- $this->_requestBillingAgreement = true;
450
- } else {
451
- $this->_requestBillingAgreement = false;
452
- }
453
- }
454
-
455
  public function getSetExpressCheckoutParameters() {
456
  // First off, get the cart parameters
457
  $params = wc_gateway_ppec()->cart->setECParams();
458
 
459
- // Now work through the checkout-level variables.
460
- if ( $this->_suppressShippingAddress ) {
461
- $params['NOSHIPPING'] = 1;
462
- }
463
-
464
- if ( $this->_requestBillingAgreement ) {
465
- $params['BILLINGTYPE'] = 'MerchantInitiatedBilling';
466
- }
467
-
468
- if ( $this->_enablePayPalCredit ) {
469
- $params['USERSELECTEDFUNDINGSOURCE'] = 'Finance';
470
- }
471
-
472
  if ( false !== $this->_shippingAddress ) {
473
  if ( is_array( $this->_shippingAddress ) ) {
474
  foreach ( $this->_shippingAddress as $index => $value ) {
@@ -501,7 +406,7 @@ class WC_Gateway_PPEC_Checkout_Handler {
501
  return $params;
502
  }
503
 
504
- protected function isSuccess( $response ) {
505
  if ( 'Success' == $response['ACK'] || 'SuccessWithWarning' == $response['ACK'] ) {
506
  return true;
507
  } else {
@@ -535,20 +440,10 @@ class WC_Gateway_PPEC_Checkout_Handler {
535
 
536
  wc_gateway_ppec()->cart->loadCartDetails();
537
 
538
- $settings = wc_gateway_ppec()->settings->loadSettings();
539
-
540
- $needs_shipping = WC()->cart->needs_shipping();
541
- $this->suppressShippingAddress( ! $needs_shipping );
542
-
543
- $using_ppc = false;
544
-
545
- if ( array_key_exists( 'use-ppc', $_GET ) && 'true' == $_GET['use-ppc'] ) {
546
- $this->enablePayPalCredit();
547
- $using_ppc = true;
548
- }
549
 
550
  $params = array_merge(
551
- $settings->getSetECShortcutParameters(),
552
  $this->getSetExpressCheckoutParameters()
553
  );
554
 
@@ -561,39 +456,35 @@ class WC_Gateway_PPEC_Checkout_Handler {
561
  $params['RETURNURL'] = $this->get_return_url();
562
  $params['CANCELURL'] = $this->get_cancel_url();
563
 
564
- if ( $this->_requestBillingAgreement ) {
565
- $params['BILLINGTYPE'] = 'MerchantInitiatedBilling';
566
- }
567
-
568
  $response = wc_gateway_ppec()->client->set_express_checkout( $params );
569
- if ( $this->isSuccess( $response ) ) {
570
  // Save some data to the session.
571
  WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
572
- $response['TOKEN'],
573
- 'cart',
574
- false,
575
- $needs_shipping,
576
- $this->_requestBillingAgreement,
577
- $settings->getECTokenSessionLength(),
578
- $using_ppc
579
  );
580
 
581
- return $settings->getPayPalRedirectUrl( $response['TOKEN'], false );
582
  } else {
583
  throw new PayPal_API_Exception( $response );
584
  }
585
  }
586
 
587
- public function start_checkout_from_checkout( $order_id, $use_ppc = false ) {
588
 
589
  wc_gateway_ppec()->cart->loadOrderDetails( $order_id );
590
 
591
- $settings = wc_gateway_ppec()->settings->loadSettings();
592
 
593
  //new wc order > get address from that order > new pp address > assign address from order to new pp address > $this->setShippingAddress(pp address object)
594
  $getAddress = wc_get_order( $order_id );
595
  $shipAddressName = $getAddress->shipping_first_name . ' ' . $getAddress->shipping_last_name;
596
 
 
597
  $shipAddress = new PayPal_Address;
598
  $shipAddress->setName($shipAddressName);
599
  $shipAddress->setStreet1($getAddress->shipping_address_1);
@@ -601,15 +492,23 @@ class WC_Gateway_PPEC_Checkout_Handler {
601
  $shipAddress->setCity($getAddress->shipping_city);
602
  $shipAddress->setState($getAddress->shipping_state);
603
  $shipAddress->setZip($getAddress->shipping_postcode);
604
- $shipAddress->setCountry($getAddress->shipping_country);
 
 
 
 
 
 
 
 
 
605
 
606
  $this->setShippingAddress( $shipAddress );
607
- $this->enablePayPalCredit( $use_ppc );
608
 
609
  // Do we also need to grab the phone number and pass it through?
610
 
611
  $params = array_merge(
612
- $settings->getSetECMarkParameters(),
613
  $this->getSetExpressCheckoutParameters()
614
  );
615
 
@@ -619,33 +518,24 @@ class WC_Gateway_PPEC_Checkout_Handler {
619
  $params['BRANDNAME'] = $brand_name;
620
  }
621
 
622
- $params['RETURNURL'] = $this->get_return_url();
623
- $params['CANCELURL'] = $this->get_cancel_url();
624
-
625
- if ( $this->_requestBillingAgreement ) {
626
- $params['BILLINGTYPE'] = 'MerchantInitiatedBilling';
627
- }
628
-
629
  $params['ADDROVERRIDE'] = '1';
630
-
631
- $needs_shipping = WC()->cart->needs_shipping();
632
- $this->suppressShippingAddress( $needs_shipping );
633
-
634
  $response = wc_gateway_ppec()->client->set_express_checkout( $params );
635
 
636
- if ( $this->isSuccess( $response ) ) {
637
  // Save some data to the session.
638
  WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
639
- $response['TOKEN'],
640
- 'order',
641
- $order_id,
642
- $needs_shipping,
643
- $this->_requestBillingAgreement,
644
- $settings->getECTokenSessionLength(),
645
- $use_ppc
646
  );
647
 
648
- return $settings->getPayPalRedirectUrl( $response['TOKEN'], true );
649
  } else {
650
  throw new PayPal_API_Exception( $response );
651
  }
@@ -653,7 +543,6 @@ class WC_Gateway_PPEC_Checkout_Handler {
653
  }
654
 
655
  public function getCheckoutDetails( $token = false ) {
656
-
657
  if ( false === $token ) {
658
  $token = $_GET['token'];
659
  }
@@ -663,88 +552,51 @@ class WC_Gateway_PPEC_Checkout_Handler {
663
  if ( 'Success' == $response['ACK'] || 'SuccessWithWarning' == $response['ACK'] ) {
664
  $checkout_details = new PayPal_Checkout_Details();
665
  $checkout_details->loadFromGetECResponse( $response );
666
-
667
- $session_data = WC()->session->paypal;
668
- if ( null === $session_data ) {
669
- throw new PayPal_Missing_Session_Exception();
670
- }
671
-
672
- if ( is_a( $session_data, 'WC_Gateway_PPEC_Session_Data' ) && $token === $session_data->token ) {
673
- $session_data->checkout_details = $checkout_details;
674
- WC()->session->paypal = $session_data;
675
- } else {
676
- throw new PayPal_Missing_Session_Exception();
677
- }
678
-
679
  return $checkout_details;
680
  } else {
681
  throw new PayPal_API_Exception( $response );
682
  }
683
  }
684
 
685
- public function completePayment( $order_id, $token, $payerID ) {
686
-
687
- // Make sure our session data is there before we do something we might regret later
688
- $session_data = WC()->session->paypal;
689
- if ( null === $session_data ) {
690
- throw new PayPal_Missing_Session_Exception();
691
- }
692
 
693
- if ( is_a( $session_data, 'WC_Gateway_PPEC_Session_Data' ) && $token == $session_data->token ) {
694
- WC()->session->paypal = $session_data;
695
- } else {
696
  throw new PayPal_Missing_Session_Exception();
697
  }
698
 
699
- // Now make sure we have the GetEC data. If not, well then we'll just fetch it now, pardner.
700
- if ( ! $session_data->checkout_details || ! is_a( $session_data->checkout_details, 'PayPal_Checkout_Details' ) ) {
701
- $this->getCheckoutDetails( $token );
702
- }
703
-
704
- wc_gateway_ppec()->cart->loadOrderDetails( $order_id );
705
-
706
- $settings = wc_gateway_ppec()->settings->loadSettings();
707
-
708
- $order = wc_get_order( $order_id );
709
-
710
- if ( $session_data->shipping_required ) {
711
- $shipAddressName = $order->shipping_first_name . ' ' . $order->shipping_last_name;
712
- $shipAddress = new PayPal_Address;
713
- $shipAddress->setName($shipAddressName);
714
- $shipAddress->setStreet1($order->shipping_address_1);
715
- $shipAddress->setStreet2($order->shipping_address_2);
716
- $shipAddress->setCity($order->shipping_city);
717
- $shipAddress->setState($order->shipping_state);
718
- $shipAddress->setZip($order->shipping_postcode);
719
- $shipAddress->setCountry($order->shipping_country);
720
- $this->setShippingAddress( $shipAddress );
721
- }
722
-
723
- $params = array_merge(
724
- $settings->getDoECParameters(),
725
- $this->getDoExpressCheckoutParameters( $token, $payerID )
726
- );
727
-
728
- $params['PAYMENTREQUEST_0_INVNUM'] = $order->get_order_number();
729
 
730
- $response = wc_gateway_ppec()->client->do_express_checkout_payment( $params );
 
 
 
 
 
 
 
731
 
732
- if ( $this->isSuccess( $response ) ) {
733
  $payment_details = new PayPal_Payment_Details();
734
  $payment_details->loadFromDoECResponse( $response );
735
 
736
- $meta = get_post_meta( $order_id, '_woo_pp_txnData', true );
737
- if ( ! empty($meta) ) {
738
  $txnData = $meta;
739
  } else {
740
  $txnData = array( 'refundable_txns' => array() );
741
  }
742
 
743
- $paymentAction = $settings->paymentAction;
744
- if ( 'Sale' == $paymentAction ) {
745
  $txn = array(
746
- 'txnID' => $payment_details->payments[0]->transaction_id,
747
- 'amount' => $order->get_total(),
748
  'refunded_amount' => 0
749
  );
750
  if ( 'Completed' == $payment_details->payments[0]->payment_status ) {
@@ -754,17 +606,42 @@ class WC_Gateway_PPEC_Checkout_Handler {
754
  }
755
  $txnData['refundable_txns'][] = $txn;
756
 
757
- } elseif ( 'Authorization' == $paymentAction ) {
758
  $txnData['auth_status'] = 'NotCompleted';
759
  }
760
 
761
  $txnData['txn_type'] = $paymentAction;
762
 
763
- update_post_meta( $order_id, '_woo_pp_txnData', $txnData );
 
 
 
764
 
765
- return $payment_details;
 
766
  } else {
767
  throw new PayPal_API_Exception( $response );
768
  }
769
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
770
  }
24
 
25
  class WC_Gateway_PPEC_Checkout_Handler {
26
 
 
 
27
  // $_shippingAddress can be a single PayPal_Address object, or an array of PayPal_Address objects
28
  // (for the purposes of doing parallel payments).
29
  protected $_shippingAddress;
 
 
30
 
31
  public function __construct() {
 
32
  $this->_shippingAddress = false;
 
33
 
34
+ add_action( 'init', array( $this, 'init' ) );
35
+ add_filter( 'the_title', array( $this, 'endpoint_page_titles' ) );
36
+ add_action( 'woocommerce_checkout_init', array( $this, 'checkout_init' ) );
37
 
38
  add_action( 'wp', array( $this, 'maybe_return_from_paypal' ) );
39
  add_action( 'wp', array( $this, 'maybe_cancel_checkout_with_paypal' ) );
40
  add_action( 'woocommerce_cart_emptied', array( $this, 'maybe_clear_session_data' ) );
41
 
 
 
 
42
  add_action( 'woocommerce_available_payment_gateways', array( $this, 'maybe_disable_other_gateways' ) );
 
43
  add_action( 'woocommerce_review_order_after_submit', array( $this, 'maybe_render_cancel_link' ) );
 
 
44
  }
45
 
46
+ /**
47
+ * If the buyer clicked on the "Check Out with PayPal" button, we need to wait for the cart
48
+ * totals to be available. Unfortunately that doesn't happen until
49
+ * woocommerce_before_cart_totals executes, and there is already output sent to the browser by
50
+ * this point. So, to get around this issue, we'll enable output buffering to prevent WP from
51
+ * sending anything back to the browser.
52
+ */
53
  public function init() {
 
 
 
 
 
54
  if ( isset( $_GET['startcheckout'] ) && 'true' === $_GET['startcheckout'] ) {
55
  ob_start();
56
  }
57
  }
58
 
59
+ /**
60
+ * Handle endpoint page title
61
+ * @param string $title
62
+ * @return string
63
+ */
64
+ public function endpoint_page_titles( $title ) {
65
+ if ( is_main_query() && in_the_loop() && is_page() && is_checkout() && $this->has_active_session() ) {
66
+ $title = __( 'Confirm your PayPal order', 'woocommerce-gateway-paypal-express-checkout' );
67
+ remove_filter( 'the_title', array( $this, 'endpoint_page_titles' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
+ return $title;
70
  }
71
 
72
  /**
73
+ * Prepare billing and shipping details if there's active sesssion during checkout.
 
 
 
74
  *
75
+ * @param WC_Checkout $checkout
76
  */
77
+ function checkout_init( $checkout ) {
78
+ global $wp_query, $wp;
 
79
 
80
+ if ( $this->has_active_session() ) {
81
+ // We don't neeed billing and shipping to confirm a paypal order.
82
+ $checkout->checkout_fields['billing'] = array();
83
+ $checkout->checkout_fields['shipping'] = array();
84
+
85
+ remove_action( 'woocommerce_checkout_billing', array( $checkout, 'checkout_form_billing' ) );
86
+ remove_action( 'woocommerce_checkout_shipping', array( $checkout, 'checkout_form_shipping' ) );
87
+ add_action( 'woocommerce_checkout_billing', array( $this, 'paypal_billing_details' ) );
88
+ add_action( 'woocommerce_checkout_shipping', array( $this, 'paypal_shipping_details' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
89
  }
90
+ }
91
 
92
+ /**
93
+ * Show billing information.
94
+ */
95
+ public function paypal_billing_details() {
96
+ $session = WC()->session->get( 'paypal' );
97
+ $token = isset( $_GET['token'] ) ? $_GET['token'] : $session->token;
98
+ $checkout_details = $this->getCheckoutDetails( $token );
99
+ ?>
100
+ <h3><?php _e( 'Billing details', 'woocommerce-gateway-paypal-express-checkout' ); ?></h3>
101
+ <ul>
102
+ <?php if ( $checkout_details->payer_details->billing_address ) : ?>
103
+ <li><strong><?php _e( 'Address:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong></br><?php echo WC()->countries->get_formatted_address( $this->get_mapped_billing_address( $checkout_details ) ); ?></li>
104
+ <?php else : ?>
105
+ <li><strong><?php _e( 'Name:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong> <?php echo esc_html( $checkout_details->payer_details->first_name . ' ' . $checkout_details->payer_details->last_name ); ?></li>
106
+ <?php endif; ?>
107
+
108
+ <?php if ( ! empty( $checkout_details->payer_details->email ) ) : ?>
109
+ <li><strong><?php _e( 'Email:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong> <?php echo esc_html( $checkout_details->payer_details->email ); ?></li>
110
+ <?php endif; ?>
111
+
112
+ <?php if ( ! empty( $checkout_details->payer_details->phone_number ) ) : ?>
113
+ <li><strong><?php _e( 'Tel:', 'woocommerce-gateway-paypal-express-checkout' ) ?></strong> <?php echo esc_html( $checkout_details->payer_details->phone_number ); ?></li>
114
+ <?php endif; ?>
115
+ </ul>
116
+ <?php
117
  }
118
 
119
  /**
120
+ * Show shipping information.
121
  */
122
+ public function paypal_shipping_details() {
123
+ $session = WC()->session->get( 'paypal' );
124
+ $token = isset( $_GET['token'] ) ? $_GET['token'] : $session->token;
125
+ $checkout_details = $this->getCheckoutDetails( $token );
 
126
 
127
+ if ( ! $session->needs_shipping ) {
 
128
  return;
129
  }
130
+ ?>
131
+ <h3><?php _e( 'Shipping details', 'woocommerce-gateway-paypal-express-checkout' ); ?></h3>
132
+ <?php
133
+ echo WC()->countries->get_formatted_address( $this->get_mapped_shipping_address( $checkout_details ) );
134
+ }
135
 
136
+ /**
137
+ * Map PayPal billing address to WC shipping address
138
+ * @param object $checkout_details
139
+ * @return array
140
+ */
141
+ public function get_mapped_billing_address( $checkout_details ) {
142
+ if ( empty( $checkout_details->payer_details ) ) {
143
+ return array();
144
+ }
145
+ return array(
146
+ 'first_name' => $checkout_details->payer_details->first_name,
147
+ 'last_name' => $checkout_details->payer_details->last_name,
148
+ 'company' => $checkout_details->payer_details->business_name,
149
+ 'address_1' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getStreet1() : '',
150
+ 'address_2' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getStreet2() : '',
151
+ 'city' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getCity() : '',
152
+ 'state' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getState() : '',
153
+ 'postcode' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getZip() : '',
154
+ 'country' => $checkout_details->payer_details->billing_address ? $checkout_details->payer_details->billing_address->getCountry() : $checkout_details->payer_details->country,
155
+ 'phone' => $checkout_details->payer_details->phone_number,
156
+ 'email' => $checkout_details->payer_details->email,
157
+ );
158
+ }
159
 
160
+ /**
161
+ * Map PayPal shipping address to WC shipping address
162
+ * @param object $checkout_details
163
+ * @return array
164
+ */
165
+ public function get_mapped_shipping_address( $checkout_details ) {
166
+ if ( empty( $checkout_details->payments[0] ) || empty( $checkout_details->payments[0]->shipping_address ) ) {
167
+ return array();
168
+ }
169
+ $name = explode( ' ', $checkout_details->payments[0]->shipping_address->getName() );
170
+ $first_name = array_shift( $name );
171
+ $last_name = implode( ' ', $name );
172
+ return array(
173
+ 'first_name' => $first_name,
174
+ 'last_name' => $last_name,
175
+ 'company' => $checkout_details->payer_details->business_name,
176
+ 'address_1' => $checkout_details->payments[0]->shipping_address->getStreet1(),
177
+ 'address_2' => $checkout_details->payments[0]->shipping_address->getStreet2(),
178
+ 'city' => $checkout_details->payments[0]->shipping_address->getCity(),
179
+ 'state' => $checkout_details->payments[0]->shipping_address->getState(),
180
+ 'postcode' => $checkout_details->payments[0]->shipping_address->getZip(),
181
+ 'country' => $checkout_details->payments[0]->shipping_address->getCountry(),
182
+ );
183
  }
184
 
185
  /**
186
+ * Checks data is correctly set when returning from PayPal Express Checkout
187
  */
188
+ public function maybe_return_from_paypal() {
189
+ if ( empty( $_GET['woo-paypal-return'] ) || empty( $_GET['token'] ) || empty( $_GET['PayerID'] ) ) {
190
  return;
191
  }
192
 
193
+ $token = $_GET['token'];
194
+ $payer_id = $_GET['PayerID'];
195
+ $session = WC()->session->get( 'paypal' );
 
196
 
197
+ if ( empty( $session ) || $this->session_has_expired( $token ) ) {
198
+ wc_add_notice( __( 'Your PayPal checkout session has expired. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
199
  return;
200
  }
201
 
202
+ // Store values in session
203
+ $session->checkout_completed = true;
204
+ $session->payerID = $payer_id;
205
+ WC()->session->set( 'paypal', $session );
206
+
207
+ try {
208
+ $checkout_details = $this->getCheckoutDetails( $token );
209
+
210
+ // If commit was true, take payment right now
211
+ if ( 'order' === $session->source && $session->order_id ) {
212
+
213
+ // Get order
214
+ $order = wc_get_order( $session->order_id );
215
 
216
+ // Store address given by PayPal
217
+ $order->set_address( $this->get_mapped_shipping_address( $checkout_details ), 'shipping' );
 
 
 
 
 
 
218
 
219
+ // Complete the payment now.
220
+ $this->do_payment( $order, $session->token, $session->payerID );
221
 
222
+ // Clear Cart
223
+ WC()->cart->empty_cart();
224
+
225
+ // Redirect
226
+ wp_redirect( $order->get_checkout_order_received_url() );
227
+ exit;
228
  }
229
+ } catch( PayPal_API_Exception $e ) {
230
+ wc_add_notice( __( 'Sorry, an error occurred while trying to retrieve your information from PayPal. Please try again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
231
+ $this->maybe_clear_session_data();
232
+ wp_safe_redirect( wc_get_page_permalink( 'cart' ) );
233
+ exit;
234
+ } catch( PayPal_Missing_Session_Exception $e ) {
235
+ wc_add_notice( __( 'Your PayPal checkout session has expired. Please check out again.', 'woocommerce-gateway-paypal-express-checkout' ), 'error' );
236
+ $this->maybe_clear_session_data();
237
+ wp_safe_redirect( wc_get_page_permalink( 'cart' ) );
238
+ exit;
239
  }
240
  }
241
 
255
  unset( $gateways[ $id ] );
256
  }
257
  }
 
258
 
259
+ // If using PayPal standard (this is admin choice) we don't need to also show PayPal EC on checkout.
260
+ } elseif ( is_checkout() && ( isset( $gateways['paypal'] ) || 'no' === wc_gateway_ppec()->settings->mark_enabled ) ) {
261
+ unset( $gateways['ppec_paypal'] );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
262
  }
263
 
264
  return $gateways;
287
  public function maybe_cancel_checkout_with_paypal() {
288
  if ( is_cart() && ! empty( $_GET['wc-gateway-ppec-clear-session'] ) ) {
289
  $this->maybe_clear_session_data();
290
+ if ( ! wc_has_notice( __( 'You have cancelled Checkout with PayPal. Please try to process your order again.', 'woocommerce-gateway-paypal-express-checkout' ), 'notice' ) ) {
291
+ wc_add_notice( __( 'You have cancelled Checkout with PayPal. Please try to process your order again.', 'woocommerce-gateway-paypal-express-checkout' ), 'notice' );
292
+ }
293
  }
294
  }
295
 
300
  * @since 1.0.0
301
  */
302
  public function maybe_clear_session_data() {
303
+ if ( $this->has_active_session() ) {
304
  unset( WC()->session->paypal );
305
  }
306
  }
316
  */
317
  public function session_has_expired( $token ) {
318
  $session = WC()->session->paypal;
319
+ return ( ! $session || ! is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) || $session->expiry_time < time() || $token !== $session->token );
 
 
 
 
 
 
 
 
 
320
  }
321
 
322
  /**
328
  */
329
  public function has_active_session() {
330
  $session = WC()->session->paypal;
 
331
  return ( is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) && $session->payerID && $session->expiry_time > time() );
332
  }
333
 
349
  return $token;
350
  }
351
 
 
 
 
 
 
 
 
 
 
 
 
 
352
  public function setShippingAddress( $address ) {
353
  if ( is_a( $address, 'PayPal_Address' ) ) {
354
  $this->_shippingAddress = $address;
370
  }
371
  }
372
 
 
 
 
 
 
 
 
 
373
  public function getSetExpressCheckoutParameters() {
374
  // First off, get the cart parameters
375
  $params = wc_gateway_ppec()->cart->setECParams();
376
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  if ( false !== $this->_shippingAddress ) {
378
  if ( is_array( $this->_shippingAddress ) ) {
379
  foreach ( $this->_shippingAddress as $index => $value ) {
406
  return $params;
407
  }
408
 
409
+ protected function is_success( $response ) {
410
  if ( 'Success' == $response['ACK'] || 'SuccessWithWarning' == $response['ACK'] ) {
411
  return true;
412
  } else {
440
 
441
  wc_gateway_ppec()->cart->loadCartDetails();
442
 
443
+ $settings = wc_gateway_ppec()->settings;
 
 
 
 
 
 
 
 
 
 
444
 
445
  $params = array_merge(
446
+ $settings->get_set_express_checkout_shortcut_params(),
447
  $this->getSetExpressCheckoutParameters()
448
  );
449
 
456
  $params['RETURNURL'] = $this->get_return_url();
457
  $params['CANCELURL'] = $this->get_cancel_url();
458
 
 
 
 
 
459
  $response = wc_gateway_ppec()->client->set_express_checkout( $params );
460
+ if ( $this->is_success( $response ) ) {
461
  // Save some data to the session.
462
  WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
463
+ array(
464
+ 'token' => $response['TOKEN'],
465
+ 'source' => 'cart',
466
+ 'needs_shipping' => WC()->cart->needs_shipping(),
467
+ 'expires_in' => $settings->get_token_session_length()
468
+ )
 
469
  );
470
 
471
+ return $settings->get_paypal_redirect_url( $response['TOKEN'], false );
472
  } else {
473
  throw new PayPal_API_Exception( $response );
474
  }
475
  }
476
 
477
+ public function start_checkout_from_checkout( $order_id ) {
478
 
479
  wc_gateway_ppec()->cart->loadOrderDetails( $order_id );
480
 
481
+ $settings = wc_gateway_ppec()->settings;
482
 
483
  //new wc order > get address from that order > new pp address > assign address from order to new pp address > $this->setShippingAddress(pp address object)
484
  $getAddress = wc_get_order( $order_id );
485
  $shipAddressName = $getAddress->shipping_first_name . ' ' . $getAddress->shipping_last_name;
486
 
487
+
488
  $shipAddress = new PayPal_Address;
489
  $shipAddress->setName($shipAddressName);
490
  $shipAddress->setStreet1($getAddress->shipping_address_1);
492
  $shipAddress->setCity($getAddress->shipping_city);
493
  $shipAddress->setState($getAddress->shipping_state);
494
  $shipAddress->setZip($getAddress->shipping_postcode);
495
+
496
+ // In case merchant only expects domestic shipping and hides shipping
497
+ // country, fallback to base country.
498
+ //
499
+ // @see https://github.com/woothemes/woocommerce-gateway-paypal-express-checkout/issues/139
500
+ $shipping_country = $getAddress->shipping_country;
501
+ if ( empty( $shipping_country ) ) {
502
+ $shipping_country = WC()->countries->get_base_country();
503
+ }
504
+ $shipAddress->setCountry( $shipping_country );
505
 
506
  $this->setShippingAddress( $shipAddress );
 
507
 
508
  // Do we also need to grab the phone number and pass it through?
509
 
510
  $params = array_merge(
511
+ $settings->get_set_express_checkout_mark_params(),
512
  $this->getSetExpressCheckoutParameters()
513
  );
514
 
518
  $params['BRANDNAME'] = $brand_name;
519
  }
520
 
521
+ $params['RETURNURL'] = $this->get_return_url();
522
+ $params['CANCELURL'] = $this->get_cancel_url();
 
 
 
 
 
523
  $params['ADDROVERRIDE'] = '1';
 
 
 
 
524
  $response = wc_gateway_ppec()->client->set_express_checkout( $params );
525
 
526
+ if ( $this->is_success( $response ) ) {
527
  // Save some data to the session.
528
  WC()->session->paypal = new WC_Gateway_PPEC_Session_Data(
529
+ array(
530
+ 'token' => $response['TOKEN'],
531
+ 'source' => 'order',
532
+ 'order_id' => $order_id,
533
+ 'needs_shipping' => WC()->cart->needs_shipping(),
534
+ 'expires_in' => $settings->get_token_session_length()
535
+ )
536
  );
537
 
538
+ return $settings->get_paypal_redirect_url( $response['TOKEN'], true );
539
  } else {
540
  throw new PayPal_API_Exception( $response );
541
  }
543
  }
544
 
545
  public function getCheckoutDetails( $token = false ) {
 
546
  if ( false === $token ) {
547
  $token = $_GET['token'];
548
  }
552
  if ( 'Success' == $response['ACK'] || 'SuccessWithWarning' == $response['ACK'] ) {
553
  $checkout_details = new PayPal_Checkout_Details();
554
  $checkout_details->loadFromGetECResponse( $response );
 
 
 
 
 
 
 
 
 
 
 
 
 
555
  return $checkout_details;
556
  } else {
557
  throw new PayPal_API_Exception( $response );
558
  }
559
  }
560
 
561
+ /**
562
+ * Complete a payment that has been authorized via PPEC.
563
+ */
564
+ public function do_payment( $order, $token, $payerID ) {
565
+ $settings = wc_gateway_ppec()->settings;
566
+ $session_data = WC()->session->get( 'paypal', null );
 
567
 
568
+ if ( ! $order || null === $session_data || $this->session_has_expired( $token ) || empty( $payerID ) ) {
 
 
569
  throw new PayPal_Missing_Session_Exception();
570
  }
571
 
572
+ // Ensure details are set
573
+ wc_gateway_ppec()->cart->loadOrderDetails( $order->id );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
574
 
575
+ // Generate params to send to paypal, then do request
576
+ $response = wc_gateway_ppec()->client->do_express_checkout_payment( array_merge(
577
+ $settings->get_do_express_checkout_params(),
578
+ $this->getDoExpressCheckoutParameters( $token, $payerID ),
579
+ array(
580
+ 'PAYMENTREQUEST_0_INVNUM' => $settings->invoice_prefix . $order->get_order_number(),
581
+ )
582
+ ) );
583
 
584
+ if ( $this->is_success( $response ) ) {
585
  $payment_details = new PayPal_Payment_Details();
586
  $payment_details->loadFromDoECResponse( $response );
587
 
588
+ $meta = get_post_meta( $order->id, '_woo_pp_txnData', true );
589
+ if ( ! empty( $meta ) ) {
590
  $txnData = $meta;
591
  } else {
592
  $txnData = array( 'refundable_txns' => array() );
593
  }
594
 
595
+ $paymentAction = $settings->get_paymentaction();
596
+ if ( 'sale' == $paymentAction ) {
597
  $txn = array(
598
+ 'txnID' => $payment_details->payments[0]->transaction_id,
599
+ 'amount' => $order->get_total(),
600
  'refunded_amount' => 0
601
  );
602
  if ( 'Completed' == $payment_details->payments[0]->payment_status ) {
606
  }
607
  $txnData['refundable_txns'][] = $txn;
608
 
609
+ } elseif ( 'authorization' == $paymentAction ) {
610
  $txnData['auth_status'] = 'NotCompleted';
611
  }
612
 
613
  $txnData['txn_type'] = $paymentAction;
614
 
615
+ update_post_meta( $order->id, '_woo_pp_txnData', $txnData );
616
+
617
+ // Payment was taken so clear session
618
+ $this->maybe_clear_session_data();
619
 
620
+ // Handle order
621
+ $this->handle_payment_response( $order, $payment_details->payments[0] );
622
  } else {
623
  throw new PayPal_API_Exception( $response );
624
  }
625
  }
626
+
627
+ /**
628
+ * Handle result of do_payment
629
+ */
630
+ public function handle_payment_response( $order, $payment ) {
631
+ // Store meta data to order
632
+ update_post_meta( $order->id, '_paypal_status', strtolower( $payment->payment_status ) );
633
+ update_post_meta( $order->id, '_transaction_id', $payment->transaction_id );
634
+
635
+ // Handle $payment response
636
+ if ( 'completed' === strtolower( $payment->payment_status ) ) {
637
+ $order->payment_complete( $payment->transaction_id );
638
+ } else {
639
+ if ( 'authorization' === $payment->pending_reason ) {
640
+ $order->update_status( 'on-hold', __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce-gateway-paypal-express-checkout' ) );
641
+ } else {
642
+ $order->update_status( 'on-hold', sprintf( __( 'Payment pending (%s).', 'woocommerce-gateway-paypal-express-checkout' ), $payment->pending_reason ) );
643
+ }
644
+ $order->reduce_order_stock();
645
+ }
646
+ }
647
  }
includes/class-wc-gateway-ppec-client.php CHANGED
@@ -39,8 +39,11 @@ class WC_Gateway_PPEC_Client {
39
  *
40
  */
41
  public function __construct( $credential, $environment = 'live' ) {
42
- $this->_credential = $credential;
43
  $this->_environment = $environment;
 
 
 
 
44
  }
45
 
46
  /**
@@ -52,6 +55,26 @@ class WC_Gateway_PPEC_Client {
52
  $this->_credential = $credential;
53
  }
54
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
55
  /**
56
  * Set environment for the client.
57
  *
@@ -113,6 +136,7 @@ class WC_Gateway_PPEC_Client {
113
  'body' => $body,
114
  'user-agent' => __CLASS__,
115
  'httpversion' => '1.1',
 
116
  );
117
 
118
  // For cURL transport.
@@ -289,6 +313,8 @@ class WC_Gateway_PPEC_Client {
289
  }
290
  }
291
 
 
 
292
  return $result['PAL'];
293
  }
294
 
39
  *
40
  */
41
  public function __construct( $credential, $environment = 'live' ) {
 
42
  $this->_environment = $environment;
43
+
44
+ if ( is_a( $credential, 'WC_Gateway_PPEC_Client_Credential' ) ) {
45
+ $this->set_credential( $credential );
46
+ }
47
  }
48
 
49
  /**
55
  $this->_credential = $credential;
56
  }
57
 
58
+ /**
59
+ * Get payer ID from API.
60
+ */
61
+ public function get_payer_id() {
62
+ $option_key = 'woocommerce_ppec_payer_id_' . $this->_environment . '_' . md5( $this->_credential->get_username() . ':' . $this->_credential->get_password() );
63
+
64
+ if ( $payer_id = get_option( $option_key ) ) {
65
+ return $payer_id;
66
+ } else {
67
+ $result = $this->get_pal_details();
68
+
69
+ if ( ! empty( $result['PAL'] ) ) {
70
+ update_option( $option_key, wc_clean( $result['PAL'] ) );
71
+ return $payer_id;
72
+ }
73
+ }
74
+
75
+ return false;
76
+ }
77
+
78
  /**
79
  * Set environment for the client.
80
  *
136
  'body' => $body,
137
  'user-agent' => __CLASS__,
138
  'httpversion' => '1.1',
139
+ 'timeout' => 30,
140
  );
141
 
142
  // For cURL transport.
313
  }
314
  }
315
 
316
+ update_option( 'woocommerce_ppec_payer_id_' . $this->_environment . '_' . md5( $this->_credential->get_username() . ':' . $this->_credential->get_password() ), wc_clean( $result['PAL'] ) );
317
+
318
  return $result['PAL'];
319
  }
320
 
includes/class-wc-gateway-ppec-gateway-loader.php CHANGED
@@ -4,42 +4,29 @@
4
  */
5
 
6
  if ( ! defined( 'ABSPATH' ) ) {
7
- exit; // Exit if accessed directly
8
  }
9
 
10
  class WC_Gateway_PPEC_Gateway_Loader {
11
 
 
 
 
12
  public function __construct() {
13
  $includes_path = wc_gateway_ppec()->includes_path;
14
 
15
  require_once( $includes_path . 'class-wc-gateway-ppec-refund.php' );
16
  require_once( $includes_path . 'abstracts/abstract-wc-gateway-ppec.php' );
17
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal.php' );
18
- require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal-credit.php' );
19
 
20
  add_filter( 'woocommerce_payment_gateways', array( $this, 'payment_gateways' ) );
21
  }
22
 
 
 
 
23
  public function payment_gateways( $methods ) {
24
- // Defer this check for next release when ppec is ready.
25
- // If the buyer already went through the PP checkout, then filter out the
26
- // option they didn't select.
27
- // $session = is_admin() ? false : WC()->session->get( 'paypal' );
28
- // if ( ( is_checkout() || is_ajax() ) && $session && is_a( $session, 'WC_Gateway_PPEC_Session_Data' ) &&
29
- // $session->checkout_completed && $session->expiry_time >= time() &&
30
- // $session->payerID ) {
31
- // if ( $session->using_ppc ) {
32
- // $methods[] = 'WC_Gateway_PPEC_With_PayPal_Credit';
33
- // } else {
34
- // $methods[] = 'WC_Gateway_PPEC_With_PayPal';
35
- // }
36
- // } else {
37
- // $methods[] = 'WC_Gateway_PPEC_With_PayPal';
38
- // $methods[] = 'WC_Gateway_PPEC_With_PayPal_Credit';
39
- // }
40
-
41
  $methods[] = 'WC_Gateway_PPEC_With_PayPal';
42
-
43
  return $methods;
44
  }
45
  }
4
  */
5
 
6
  if ( ! defined( 'ABSPATH' ) ) {
7
+ exit;
8
  }
9
 
10
  class WC_Gateway_PPEC_Gateway_Loader {
11
 
12
+ /**
13
+ * Constructor.
14
+ */
15
  public function __construct() {
16
  $includes_path = wc_gateway_ppec()->includes_path;
17
 
18
  require_once( $includes_path . 'class-wc-gateway-ppec-refund.php' );
19
  require_once( $includes_path . 'abstracts/abstract-wc-gateway-ppec.php' );
20
  require_once( $includes_path . 'class-wc-gateway-ppec-with-paypal.php' );
 
21
 
22
  add_filter( 'woocommerce_payment_gateways', array( $this, 'payment_gateways' ) );
23
  }
24
 
25
+ /**
26
+ * Init gateways
27
+ */
28
  public function payment_gateways( $methods ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29
  $methods[] = 'WC_Gateway_PPEC_With_PayPal';
 
30
  return $methods;
31
  }
32
  }
includes/class-wc-gateway-ppec-ips-handler.php CHANGED
@@ -159,7 +159,6 @@ class WC_Gateway_PPEC_IPS_Handler {
159
  }
160
  }
161
 
162
- // TODO: Check for IPS certificate-style.
163
  $creds = new WC_Gateway_PPEC_Client_Credential_Signature(
164
  $_GET['api_username'],
165
  $_GET['api_password'],
@@ -169,22 +168,14 @@ class WC_Gateway_PPEC_IPS_Handler {
169
  $error_msgs = array();
170
  try {
171
  $payer_id = wc_gateway_ppec()->client->test_api_credentials( $creds, $env );
 
172
  if ( ! $payer_id ) {
173
  $this->_redirect_with_messages( __( 'Easy Setup was able to obtain your API credentials, but was unable to verify that they work correctly. Please make sure your PayPal account is set up properly and try Easy Setup again.', 'woocommerce-gateway-paypal-express-checkout' ) );
174
  }
175
- $creds->set_payer_id( $payer_id );
176
- } catch( PayPal_API_Exception $ex ) {
177
- $error_msgs[] = array(
178
- 'warning' => __( 'Easy Setup was able to obtain your API credentials, but an error occurred while trying to verify that they work correctly. Please try Easy Setup again.', 'woocommerce-gateway-paypal-express-checkout' )
179
- );
180
- }
181
 
182
- $is_enabled_for_billing_address = false;
183
- try {
184
- $is_enabled_for_billing_address = wc_gateway_ppec()->client->test_for_billing_address_enabled( $creds, $env );
185
  } catch( PayPal_API_Exception $ex ) {
186
  $error_msgs[] = array(
187
- 'warning' => __( 'Easy Setup encountered an error while trying to determine which features are enabled on your PayPal account. You may not see all of the features below that are enabled for your PayPal account. To try again, click "Save Changes".', 'woocommerce-gateway-paypal-express-checkout' )
188
  );
189
  }
190
 
@@ -192,26 +183,30 @@ class WC_Gateway_PPEC_IPS_Handler {
192
  'success' => __( 'Success! Your PayPal account has been set up successfully.', 'woocommerce-gateway-paypal-express-checkout' )
193
  );
194
 
195
- $settings = wc_gateway_ppec()->settings->loadSettings();
196
-
197
- if ( ! $settings->enabled ) {
198
- $error_msgs[] = array(
199
- 'warning' => __( 'PayPal Express Checkout is not enabled. To allow your buyers to pay with PayPal, make sure "Enable PayPal Express Checkout" is checked.', 'woocommerce-gateway-paypal-express-checkout' )
200
- );
201
- }
202
-
203
  if ( ! empty( $error_msgs ) ) {
204
- wc_gateway_ppec_log( sprintf( '%s: returned back from IPS flow but with warnings/errors: %s', __METHOD__, print_r( $error_msgs, true ) ) );
205
  }
206
 
207
- $settings->environment = $env;
208
- if ( 'live' == $env ) {
209
- $settings->liveApiCredentials = $creds;
 
 
 
 
 
 
 
210
  } else {
211
- $settings->sandboxApiCredentials = $creds;
 
 
 
 
 
212
  }
213
 
214
- $settings->saveSettings();
215
 
216
  $this->_redirect_with_messages( $error_msgs );
217
  }
159
  }
160
  }
161
 
 
162
  $creds = new WC_Gateway_PPEC_Client_Credential_Signature(
163
  $_GET['api_username'],
164
  $_GET['api_password'],
168
  $error_msgs = array();
169
  try {
170
  $payer_id = wc_gateway_ppec()->client->test_api_credentials( $creds, $env );
171
+
172
  if ( ! $payer_id ) {
173
  $this->_redirect_with_messages( __( 'Easy Setup was able to obtain your API credentials, but was unable to verify that they work correctly. Please make sure your PayPal account is set up properly and try Easy Setup again.', 'woocommerce-gateway-paypal-express-checkout' ) );
174
  }
 
 
 
 
 
 
175
 
 
 
 
176
  } catch( PayPal_API_Exception $ex ) {
177
  $error_msgs[] = array(
178
+ 'warning' => __( 'Easy Setup was able to obtain your API credentials, but an error occurred while trying to verify that they work correctly. Please try Easy Setup again.', 'woocommerce-gateway-paypal-express-checkout' )
179
  );
180
  }
181
 
183
  'success' => __( 'Success! Your PayPal account has been set up successfully.', 'woocommerce-gateway-paypal-express-checkout' )
184
  );
185
 
 
 
 
 
 
 
 
 
186
  if ( ! empty( $error_msgs ) ) {
187
+ wc_gateway_ppec_log( sprintf( '%s: returned back from IPS flow: %s', __METHOD__, print_r( $error_msgs, true ) ) );
188
  }
189
 
190
+ // Save credentials to settings API
191
+ $settings_array = (array) get_option( 'woocommerce_ppec_paypal_settings', array() );
192
+
193
+ if ( 'live' === $env ) {
194
+ $settings_array['environment'] = 'live';
195
+ $settings_array['api_username'] = $creds->get_username();
196
+ $settings_array['api_password'] = $creds->get_password();
197
+ $settings_array['api_signature'] = is_callable( array( $creds, 'get_signature' ) ) ? $creds->get_signature() : '';
198
+ $settings_array['api_certificate'] = is_callable( array( $creds, 'get_certificate' ) ) ? $creds->get_certificate() : '';
199
+ $settings_array['api_subject'] = $creds->get_subject();
200
  } else {
201
+ $settings_array['environment'] = 'sandbox';
202
+ $settings_array['sandbox_api_username'] = $creds->get_username();
203
+ $settings_array['sandbox_api_password'] = $creds->get_password();
204
+ $settings_array['sandbox_api_signature'] = is_callable( array( $creds, 'get_signature' ) ) ? $creds->get_signature() : '';
205
+ $settings_array['sandbox_api_certificate'] = is_callable( array( $creds, 'get_certificate' ) ) ? $creds->get_certificate() : '';
206
+ $settings_array['sandbox_api_subject'] = $creds->get_subject();
207
  }
208
 
209
+ update_option( 'woocommerce_ppec_paypal_settings', $settings_array );
210
 
211
  $this->_redirect_with_messages( $error_msgs );
212
  }
includes/class-wc-gateway-ppec-plugin.php CHANGED
@@ -76,6 +76,64 @@ class WC_Gateway_PPEC_Plugin {
76
  $this->plugin_path = trailingslashit( plugin_dir_path( $this->file ) );
77
  $this->plugin_url = trailingslashit( plugin_dir_url( $this->file ) );
78
  $this->includes_path = $this->plugin_path . trailingslashit( 'includes' );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  }
80
 
81
  /**
@@ -85,7 +143,6 @@ class WC_Gateway_PPEC_Plugin {
85
  register_activation_hook( $this->file, array( $this, 'activate' ) );
86
 
87
  add_action( 'plugins_loaded', array( $this, 'bootstrap' ) );
88
- add_filter( 'plugin_action_links_' . plugin_basename( $this->file ), array( $this, 'plugin_action_links' ) );
89
  add_filter( 'allowed_redirect_hosts' , array( $this, 'whitelist_paypal_domains_for_redirect' ) );
90
  }
91
 
@@ -168,7 +225,6 @@ class WC_Gateway_PPEC_Plugin {
168
  throw new Exception( $openssl_warning, self::DEPENDENCIES_UNSATISFIED );
169
  }
170
 
171
-
172
  if ( ! version_compare( $matches[1], '1.0.1', '>=' ) ) {
173
  throw new Exception( $openssl_warning, self::DEPENDENCIES_UNSATISFIED );
174
  }
@@ -183,8 +239,8 @@ class WC_Gateway_PPEC_Plugin {
183
  * @throws Exception
184
  */
185
  protected function _check_credentials() {
186
- $credential = $this->settings->getActiveApiCredentials();
187
- if ( ! is_a( $credential, 'WC_Gateway_PPEC_Client_Credential' ) ) {
188
  $setting_link = $this->get_admin_setting_link();
189
  throw new Exception( __( 'PayPal Express Checkout is almost ready. To get started, <a href="' . $setting_link . '">connect your PayPal account</a>.', 'woocommerce-gateway-paypal-express-checkout' ), self::NOT_CONNECTED );
190
  }
@@ -202,14 +258,6 @@ class WC_Gateway_PPEC_Plugin {
202
  * Callback for activation hook.
203
  */
204
  public function activate() {
205
- // Enable some options that we recommend for all merchants.
206
- add_option( 'pp_woo_enabled', true );
207
- add_option( 'pp_woo_allowGuestCheckout', true );
208
- add_option( 'pp_woo_enableInContextCheckout', true );
209
- /* defer ppc for next next release.
210
- add_option( 'pp_woo_ppc_enabled', true );
211
- */
212
-
213
  if ( ! isset( $this->setings ) ) {
214
  require_once( $this->includes_path . 'class-wc-gateway-ppec-settings.php' );
215
  $settings = new WC_Gateway_PPEC_Settings();
@@ -229,10 +277,7 @@ class WC_Gateway_PPEC_Plugin {
229
  */
230
  protected function _load_handlers() {
231
  // Client.
232
- require_once( $this->includes_path . 'abstracts/abstract-wc-gateway-ppec-client-credential.php' );
233
- require_once( $this->includes_path . 'class-wc-gateway-ppec-client-credential-certificate.php' );
234
- require_once( $this->includes_path . 'class-wc-gateway-ppec-client-credential-signature.php' );
235
- require_once( $this->includes_path . 'class-wc-gateway-ppec-client.php' );
236
 
237
  // Load handlers.
238
  require_once( $this->includes_path . 'class-wc-gateway-ppec-settings.php' );
@@ -242,41 +287,36 @@ class WC_Gateway_PPEC_Plugin {
242
  require_once( $this->includes_path . 'class-wc-gateway-ppec-cart-handler.php' );
243
  require_once( $this->includes_path . 'class-wc-gateway-ppec-ips-handler.php' );
244
 
245
- $this->settings = new WC_Gateway_PPEC_Settings();
246
- $this->settings->loadSettings();
247
-
248
  $this->gateway_loader = new WC_Gateway_PPEC_Gateway_Loader();
249
  $this->admin = new WC_Gateway_PPEC_Admin_Handler();
250
  $this->checkout = new WC_Gateway_PPEC_Checkout_Handler();
251
  $this->cart = new WC_Gateway_PPEC_Cart_Handler();
252
  $this->ips = new WC_Gateway_PPEC_IPS_Handler();
253
-
254
- $this->client = new WC_Gateway_PPEC_Client( $this->settings->getActiveApiCredentials(), $this->settings->environment );
255
  }
256
 
257
  /**
258
- * Adds plugin action links
259
  *
260
- * @since 1.0.0
261
  */
262
- public function plugin_action_links( $links ) {
263
- $setting_link = $this->get_admin_setting_link();
264
-
265
- $plugin_links = array(
266
- '<a href="' . $setting_link . '">' . __( 'Settings', 'woocommerce-gateway-paypal-express-checkout' ) . '</a>',
267
- '<a href="http://docs.woothemes.com/document/woocommerce-gateway-paypal-express-checkout/">' . __( 'Docs', 'woocommerce-gateway-paypal-express-checkout' ) . '</a>',
268
- '<a href="http://support.woothemes.com/">' . __( 'Support', 'woocommerce-gateway-paypal-express-checkout' ) . '</a>',
269
- );
270
- return array_merge( $plugin_links, $links );
271
  }
272
 
 
 
 
273
  public function get_admin_setting_link() {
274
  if ( version_compare( WC()->version, '2.6', '>=' ) ) {
275
  $section_slug = 'ppec_paypal';
276
  } else {
277
  $section_slug = strtolower( 'WC_Gateway_PPEC_With_PayPal' );
278
  }
279
-
280
  return admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $section_slug );
281
  }
282
 
@@ -294,8 +334,6 @@ class WC_Gateway_PPEC_Plugin {
294
  $domains[] = 'paypal.com';
295
  $domains[] = 'www.sandbox.paypal.com';
296
  $domains[] = 'sandbox.paypal.com';
297
-
298
  return $domains;
299
  }
300
-
301
  }
76
  $this->plugin_path = trailingslashit( plugin_dir_path( $this->file ) );
77
  $this->plugin_url = trailingslashit( plugin_dir_url( $this->file ) );
78
  $this->includes_path = $this->plugin_path . trailingslashit( 'includes' );
79
+
80
+ // Updates
81
+ if ( version_compare( $version, get_option( 'wc_ppec_version' ), '>' ) ) {
82
+ $this->run_updater( $version );
83
+ }
84
+ }
85
+
86
+ /**
87
+ * Handle updates.
88
+ * @param [type] $new_version [description]
89
+ * @return [type] [description]
90
+ */
91
+ private function run_updater( $new_version ) {
92
+ // Map old settings to settings API
93
+ if ( get_option( 'pp_woo_enabled' ) ) {
94
+ $settings_array = (array) get_option( 'woocommerce_ppec_paypal_settings', array() );
95
+ $settings_array['enabled'] = get_option( 'pp_woo_enabled' ) ? 'yes' : 'no';
96
+ $settings_array['logo_image_url'] = get_option( 'pp_woo_logoImageUrl' );
97
+ $settings_array['paymentAction'] = strtolower( get_option( 'pp_woo_paymentAction', 'sale' ) );
98
+ $settings_array['subtotal_mismatch_behavior'] = 'addLineItem' === get_option( 'pp_woo_subtotalMismatchBehavior' ) ? 'add' : 'drop';
99
+ $settings_array['environment'] = get_option( 'pp_woo_environment' );
100
+ $settings_array['button_size'] = get_option( 'pp_woo_button_size' );
101
+ $settings_array['instant_payments'] = get_option( 'pp_woo_blockEChecks' );
102
+ $settings_array['require_billing'] = get_option( 'pp_woo_requireBillingAddress' );
103
+ $settings_array['debug'] = get_option( 'pp_woo_logging_enabled' ) ? 'yes' : 'no';
104
+
105
+ // Make sure button size is correct.
106
+ if ( ! in_array( $settings_array['button_size'], array( 'small', 'medium', 'large' ) ) ) {
107
+ $settings_array['button_size'] = 'medium';
108
+ }
109
+
110
+ // Load client classes before `is_a` check on credentials instance.
111
+ $this->_load_client();
112
+
113
+ $live = get_option( 'pp_woo_liveApiCredentials' );
114
+ $sandbox = get_option( 'pp_woo_sandboxApiCredentials' );
115
+
116
+ if ( $live && is_a( $live, 'WC_Gateway_PPEC_Client_Credential' ) ) {
117
+ $settings_array['api_username'] = $live->get_username();
118
+ $settings_array['api_password'] = $live->get_password();
119
+ $settings_array['api_signature'] = is_callable( array( $live, 'get_signature' ) ) ? $live->get_signature() : '';
120
+ $settings_array['api_certificate'] = is_callable( array( $live, 'get_certificate' ) ) ? $live->get_certificate() : '';
121
+ $settings_array['api_subject'] = $live->get_subject();
122
+ }
123
+
124
+ if ( $sandbox && is_a( $sandbox, 'WC_Gateway_PPEC_Client_Credential' ) ) {
125
+ $settings_array['sandbox_api_username'] = $sandbox->get_username();
126
+ $settings_array['sandbox_api_password'] = $sandbox->get_password();
127
+ $settings_array['sandbox_api_signature'] = is_callable( array( $sandbox, 'get_signature' ) ) ? $sandbox->get_signature() : '';
128
+ $settings_array['sandbox_api_certificate'] = is_callable( array( $sandbox, 'get_certificate' ) ) ? $sandbox->get_certificate() : '';
129
+ $settings_array['sandbox_api_subject'] = $sandbox->get_subject();
130
+ }
131
+
132
+ update_option( 'woocommerce_ppec_paypal_settings', $settings_array );
133
+ delete_option( 'pp_woo_enabled' );
134
+ }
135
+
136
+ update_option( 'wc_ppec_version', $new_version );
137
  }
138
 
139
  /**
143
  register_activation_hook( $this->file, array( $this, 'activate' ) );
144
 
145
  add_action( 'plugins_loaded', array( $this, 'bootstrap' ) );
 
146
  add_filter( 'allowed_redirect_hosts' , array( $this, 'whitelist_paypal_domains_for_redirect' ) );
147
  }
148
 
225
  throw new Exception( $openssl_warning, self::DEPENDENCIES_UNSATISFIED );
226
  }
227
 
 
228
  if ( ! version_compare( $matches[1], '1.0.1', '>=' ) ) {
229
  throw new Exception( $openssl_warning, self::DEPENDENCIES_UNSATISFIED );
230
  }
239
  * @throws Exception
240
  */
241
  protected function _check_credentials() {
242
+ $credential = $this->settings->get_active_api_credentials();
243
+ if ( ! is_a( $credential, 'WC_Gateway_PPEC_Client_Credential' ) || '' === $credential->get_username() ) {
244
  $setting_link = $this->get_admin_setting_link();
245
  throw new Exception( __( 'PayPal Express Checkout is almost ready. To get started, <a href="' . $setting_link . '">connect your PayPal account</a>.', 'woocommerce-gateway-paypal-express-checkout' ), self::NOT_CONNECTED );
246
  }
258
  * Callback for activation hook.
259
  */
260
  public function activate() {
 
 
 
 
 
 
 
 
261
  if ( ! isset( $this->setings ) ) {
262
  require_once( $this->includes_path . 'class-wc-gateway-ppec-settings.php' );
263
  $settings = new WC_Gateway_PPEC_Settings();
277
  */
278
  protected function _load_handlers() {
279
  // Client.
280
+ $this->_load_client();
 
 
 
281
 
282
  // Load handlers.
283
  require_once( $this->includes_path . 'class-wc-gateway-ppec-settings.php' );
287
  require_once( $this->includes_path . 'class-wc-gateway-ppec-cart-handler.php' );
288
  require_once( $this->includes_path . 'class-wc-gateway-ppec-ips-handler.php' );
289
 
290
+ $this->settings = new WC_Gateway_PPEC_Settings();
 
 
291
  $this->gateway_loader = new WC_Gateway_PPEC_Gateway_Loader();
292
  $this->admin = new WC_Gateway_PPEC_Admin_Handler();
293
  $this->checkout = new WC_Gateway_PPEC_Checkout_Handler();
294
  $this->cart = new WC_Gateway_PPEC_Cart_Handler();
295
  $this->ips = new WC_Gateway_PPEC_IPS_Handler();
296
+ $this->client = new WC_Gateway_PPEC_Client( $this->settings->get_active_api_credentials(), $this->settings->environment );
 
297
  }
298
 
299
  /**
300
+ * Load client.
301
  *
302
+ * @since 1.1.0
303
  */
304
+ protected function _load_client() {
305
+ require_once( $this->includes_path . 'abstracts/abstract-wc-gateway-ppec-client-credential.php' );
306
+ require_once( $this->includes_path . 'class-wc-gateway-ppec-client-credential-certificate.php' );
307
+ require_once( $this->includes_path . 'class-wc-gateway-ppec-client-credential-signature.php' );
308
+ require_once( $this->includes_path . 'class-wc-gateway-ppec-client.php' );
 
 
 
 
309
  }
310
 
311
+ /**
312
+ * Link to settings screen.
313
+ */
314
  public function get_admin_setting_link() {
315
  if ( version_compare( WC()->version, '2.6', '>=' ) ) {
316
  $section_slug = 'ppec_paypal';
317
  } else {
318
  $section_slug = strtolower( 'WC_Gateway_PPEC_With_PayPal' );
319
  }
 
320
  return admin_url( 'admin.php?page=wc-settings&tab=checkout&section=' . $section_slug );
321
  }
322
 
334
  $domains[] = 'paypal.com';
335
  $domains[] = 'www.sandbox.paypal.com';
336
  $domains[] = 'sandbox.paypal.com';
 
337
  return $domains;
338
  }
 
339
  }
includes/class-wc-gateway-ppec-refund.php CHANGED
@@ -6,6 +6,20 @@ if ( ! defined( 'ABSPATH' ) ) {
6
 
7
  class WC_Gateway_PPEC_Refund {
8
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
  public static function refund_order( $order, $amount, $refundType, $reason, $currency ) {
10
 
11
  // add refund params
6
 
7
  class WC_Gateway_PPEC_Refund {
8
 
9
+ /**
10
+ * Refund an order.
11
+ *
12
+ * @throws \PayPal_API_Exception
13
+ *
14
+ * @param WC_Order $order Order to refund
15
+ * @param float $amount Amount to refund
16
+ * @param string $refundType Type of refund (Partial or Full)
17
+ * @param string $reason Reason to refund
18
+ * @param string $current Currency of refund
19
+ *
20
+ * @return null|string If exception is thrown, null is returned. Otherwise
21
+ * ID of refund transaction is returned.
22
+ */
23
  public static function refund_order( $order, $amount, $refundType, $reason, $currency ) {
24
 
25
  // add refund params
includes/class-wc-gateway-ppec-session-data.php CHANGED
@@ -6,31 +6,35 @@ if ( ! defined( 'ABSPATH' ) ) {
6
 
7
  class WC_Gateway_PPEC_Session_Data {
8
 
9
- public $leftFrom = false; // 'cart' or 'order'
10
- public $order_id = false; // if $leftFrom is 'order', this should be the order ID
11
- public $billingAgreementRequested = false; // true if a billing agreement was requested in the SetEC call, false otherwise
12
- public $checkout_details = false; // Will be populated with the GetEC details later
13
- public $shipping_required = false; // True if a shipping address is required for this transaction, false otherwise
14
- public $checkout_completed = false; // True if the buyer has just returned from PayPal and we should select PayPal as the payment method
15
- public $token = false; // The EC token
16
- public $payerID = false; // The buyer's payer ID, once they come back from PayPal
17
- public $expiry_time = false; // The time at which the token will expire
18
- public $using_ppc = false; // Whether the buyer is checking out with PayPal Credit
19
 
20
- public function __construct( $token, $leftFrom = 'cart', $order_id = false, $shipping_required = true, $billingAgreementRequested = false, $expires_in = 10800, $using_ppc = false ) {
21
- if ( 'cart' == $leftFrom || 'order' == $leftFrom ) {
22
- $this->leftFrom = $leftFrom;
23
- }
24
- if ( 'order' == $leftFrom ) {
25
- $this->order_id = $order_id;
26
- }
 
 
 
 
 
27
 
28
- $this->token = $token;
29
- $this->shipping_required = $shipping_required;
30
- $this->billingAgreementRequested = $billingAgreementRequested;
 
31
 
32
- $this->expiry_time = time() + $expires_in;
33
-
34
- $this->using_ppc = $using_ppc;
35
  }
36
  }
6
 
7
  class WC_Gateway_PPEC_Session_Data {
8
 
9
+ public $source = false; // 'cart' or 'order'
10
+ public $order_id = false; // if $source is 'order', this should be the order ID
11
+ public $checkout_details = false; // Will be populated with the GetEC details later
12
+ public $needs_shipping = false; // True if a shipping address is required for this transaction, false otherwise
13
+ public $checkout_completed = false; // True if the buyer has just returned from PayPal and we should select PayPal as the payment method
14
+ public $token = false; // The EC token
15
+ public $payerID = false; // The buyer's payer ID, once they come back from PayPal
16
+ public $expiry_time = false; // The time at which the token will expire
 
 
17
 
18
+ /**
19
+ * Constructor
20
+ * @param array $args
21
+ */
22
+ public function __construct( $args = array() ) {
23
+ $args = wp_parse_args( $args, array(
24
+ 'token' => '',
25
+ 'source' => 'cart',
26
+ 'order_id' => false,
27
+ 'needs_shipping' => true,
28
+ 'expires_in' => 10800,
29
+ ) );
30
 
31
+ $this->token = $args['token'];
32
+ $this->source = $args['source'];
33
+ $this->needs_shipping = $args['needs_shipping'];
34
+ $this->expiry_time = time() + $args['expires_in'];
35
 
36
+ if ( 'order' === $this->source ) {
37
+ $this->order_id = $args['order_id'];
38
+ }
39
  }
40
  }
includes/class-wc-gateway-ppec-settings.php CHANGED
@@ -1,160 +1,103 @@
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
- exit; // Exit if accessed directly
5
  }
6
 
 
 
 
7
  class WC_Gateway_PPEC_Settings {
8
 
9
- protected $params;
10
- protected $validParams = array(
11
- 'enabled',
12
- 'logging_enabled',
13
- 'ppcEnabled',
14
- 'environment',
15
- 'liveApiCredentials',
16
- 'sandboxApiCredentials',
17
- 'enableInContextCheckout',
18
- 'buttonSize',
19
- 'markSize',
20
- 'logoImageUrl',
21
- 'paymentAction',
22
- 'allowGuestCheckout',
23
- 'zeroSubtotalBehavior',
24
- 'subtotalMismatchBehavior',
25
- 'ipnUrl',
26
- 'blockEChecks',
27
- 'requireBillingAddress',
28
- 'liveAccountIsEnabledForBillingAddress',
29
- 'sbAccountIsEnabledForBillingAddress',
30
- );
31
-
32
  protected $_supportedLocale = array(
33
  'da_DK', 'de_DE', 'en_AU', 'en_GB', 'en_US', 'es_ES', 'fr_CA', 'fr_FR',
34
  'he_IL', 'id_ID', 'it_IT', 'ja_JP', 'nl_NL', 'no_NO', 'pl_PL', 'pt_BR',
35
  'pt_PT', 'ru_RU', 'sv_SE', 'th_TH', 'tr_TR', 'zh_CN', 'zh_HK', 'zh_TW',
36
  );
37
 
38
- const PaymentActionSale = 'Sale';
39
- const PaymentActionAuthorization = 'Authorization';
40
-
41
- const zeroSubtotalBehaviorModifyItems = 'modifyItems';
42
- const zeroSubtotalBehaviorOmitLineItems = 'omitLineItems';
43
- const zeroSubtotalBehaviorPassCouponsAsShippingDiscount = 'passCouponsAsShippingDiscount';
44
-
45
- const subtotalMismatchBehaviorAddLineItem = 'addLineItem';
46
- const subtotalMismatchBehaviorDropLineItems = 'dropLineItems';
47
-
48
- const buttonSizeSmall = 'small';
49
- const buttonSizeMedium = 'medium';
50
-
51
- const markSizeSmall = 'small';
52
- const markSizeMedium = 'medium';
53
- const markSizeLarge = 'large';
54
-
55
  /**
56
  * Flag to indicate setting has been loaded from DB.
57
- *
58
  * @var bool
59
  */
60
  private $_is_setting_loaded = false;
61
 
62
- public function __get( $name ) {
63
- if ( in_array( $name, $this->validParams ) ) {
64
- // Run the value through sanitization functions, if they exist
65
- $func_name = '_sanitize_' . $name;
66
- if ( method_exists( $this, $func_name ) ) {
67
- return $this->$func_name( $this->params[ $name ] );
68
- } else if ( array_key_exists( $name, $this->params ) ) {
69
- return $this->params[ $name ];
70
- } else {
71
- return null;
72
- }
73
  }
74
-
75
  return null;
76
  }
77
 
78
- public function __set( $name, $value ) {
79
- if ( in_array( $name, $this->validParams ) ) {
80
- // Run the value through sanitization and validation functions, if they exist
81
- $func_name = '_sanitize_' . $name;
82
- if ( method_exists( $this, $func_name ) ) {
83
- $value = $this->$func_name( $value );
84
- }
85
-
86
- $func_name = '_validate_' . $name;
87
- if ( method_exists( $this, $func_name ) ) {
88
- if ( $this->$func_name( $value ) ) {
89
- $this->params[ $name ] = $value;
90
- }
91
- } else {
92
- $this->params[ $name ] = $value;
93
- }
94
- }
95
  }
96
 
97
- public function __isset( $name ) {
98
- if ( in_array( $name, $this->validParams ) ) {
99
- return true;
100
- } else {
101
- return false;
102
- }
103
  }
104
 
105
- public function setApiSignatureCredentials( $username, $password, $signature, $subject = false, $environment = 'sandbox' ) {
106
- if ( 'live' == $environment ) {
107
- $this->liveApiCredentials = new WC_Gateway_PPEC_Client_Credential_Signature( $username, $password, $signature, $subject );
108
- } else {
109
- $this->sandboxApiCredentials = new WC_Gateway_PPEC_Client_Credential_Signature( $username, $password, $signature, $subject );
 
 
 
 
 
110
  }
 
 
 
111
  }
112
 
113
- public function setApiCertificateCredentialsFromFile( $username, $password, $certFile, $subject = false, $environment = 'sandbox' ) {
114
- $certString = file_get_contents( $certFile );
115
- if ( FALSE === $cert ) {
116
- // Failed to load the certificate
117
- // TODO: Add some logging
118
- return false;
 
 
 
119
  }
120
-
121
- $this->setApiCertificateCredentialsFromString( $username, $password, $certString, $subject, $environment );
122
-
123
- return true;
124
-
125
  }
126
 
127
- public function setApiCertificateCredentialsFromString( $username, $password, $certString, $subject = false, $environment = 'sandbox' ) {
128
- if ( 'live' == $environment ) {
129
- $this->liveApiCredentials = new WC_Gateway_PPEC_Client_Credential_Certificate( $username, $password, $certString, $subject );
 
 
 
 
130
  } else {
131
- $this->sandboxApiCredentials = new WC_Gateway_PPEC_Client_Credential_Certificate( $username, $password, $certString, $subject );
132
  }
133
  }
134
 
135
- public function getActiveApiCredentials() {
136
- if ( $this->environment == 'live' ) {
137
- return $this->liveApiCredentials;
 
 
 
 
138
  } else {
139
- return $this->sandboxApiCredentials;
140
  }
141
  }
142
 
143
- public function getPayPalRedirectUrl( $token, $commit = false ) {
144
  $url = 'https://www.';
145
 
146
- if ( $this->environment != 'live' ) {
147
  $url .= 'sandbox.';
148
  }
149
 
150
  $url .= 'paypal.com/';
151
-
152
- if ( $this->enableInContextCheckout ) {
153
- $url .= 'checkoutnow?';
154
- } else {
155
- $url .= 'cgi-bin/webscr?cmd=_express-checkout&';
156
- }
157
-
158
  $url .= 'token=' . urlencode( $token );
159
 
160
  if ( $commit ) {
@@ -164,28 +107,14 @@ class WC_Gateway_PPEC_Settings {
164
  return $url;
165
  }
166
 
167
- public function getSetECShortcutParameters() {
168
- return $this->getBaseSetECShortcutParameters();
169
- }
170
-
171
- public function getSetECMarkParameters() {
172
- return $this->getBaseSetECMarkParameters();
173
- }
174
- public function getDoECParameters() {
175
- return $this->getBaseDoECParameters();
176
- }
177
-
178
- /**
179
- * TODO: Probably merge with getSetECShortcutParameters
180
- */
181
- protected function getBaseSetECShortcutParameters( $buckets = 1 ) {
182
  $params = array();
183
 
184
- if ( $this->logoImageUrl ) {
185
- $params['LOGOIMG'] = $this->logoImageUrl;
186
  }
187
 
188
- if ( $this->allowGuestCheckout ) {
189
  $params['SOLUTIONTYPE'] = 'Sole';
190
  }
191
 
@@ -197,29 +126,29 @@ class WC_Gateway_PPEC_Settings {
197
  }
198
  }
199
 
200
- if ( $this->requireBillingAddress ) {
201
  $params['REQBILLINGADDRESS'] = '1';
202
  }
203
 
204
  foreach ( $buckets as $bucketNum ) {
205
- $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->paymentAction;
206
- if ( $this->blockEChecks ) $params[ 'PAYMENTREQUEST_' . $bucketNum . '_ALLOWEDPAYMENTMETHOD' ] = 'InstantPaymentOnly';
 
 
 
207
  }
208
 
209
  return $params;
210
  }
211
 
212
- /**
213
- * TODO: Probably merge with getSetECMarkParameters
214
- */
215
- protected function getBaseSetECMarkParameters( $buckets = 1 ) {
216
  $params = array();
217
 
218
- if ( $this->logoImageUrl ) {
219
- $params['LOGOIMG'] = $this->logoImageUrl;
220
  }
221
 
222
- if ( $this->allowGuestCheckout ) {
223
  $params['SOLUTIONTYPE'] = 'Sole';
224
  }
225
 
@@ -231,24 +160,21 @@ class WC_Gateway_PPEC_Settings {
231
  }
232
  }
233
 
234
- if ( $this->requireBillingAddress ) {
235
  $params['REQBILLINGADDRESS'] = '1';
236
  }
237
 
238
  foreach ( $buckets as $bucketNum ) {
239
- $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->paymentAction;
240
- if ( $this->blockEChecks ) {
 
241
  $params[ 'PAYMENTREQUEST_' . $bucketNum . '_ALLOWEDPAYMENTMETHOD' ] = 'InstantPaymentOnly';
242
  }
243
  }
244
 
245
  return $params;
246
  }
247
-
248
- /**
249
- * TODO: Probably merge with getDoECParameters
250
- */
251
- protected function getBaseDoECParameters( $buckets = 1 ) {
252
  $params = array();
253
  if ( ! is_array( $buckets ) ) {
254
  $numBuckets = $buckets;
@@ -259,115 +185,57 @@ class WC_Gateway_PPEC_Settings {
259
  }
260
 
261
  foreach ( $buckets as $bucketNum ) {
262
- $params[ 'PAYMENTREQUEST_' . $bucketNum . '_NOTIFYURL' ] = $this->ipnUrl;
263
- $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->paymentAction;
264
  }
265
 
266
  return $params;
267
  }
268
 
269
- protected function _sanitize_zeroSubtotalBehavior( $behavior ) {
270
- if ( self::zeroSubtotalBehaviorModifyItems == $behavior ||
271
- self::zeroSubtotalBehaviorOmitLineItems == $behavior ||
272
- self::zeroSubtotalBehaviorPassCouponsAsShippingDiscount == $behavior ) {
273
- return $behavior;
274
- } else {
275
- return self::zeroSubtotalBehaviorModifyItems;
276
- }
277
- }
278
-
279
- protected function _sanitize_subtotalMismatchBehavior( $behavior ) {
280
- if ( self::subtotalMismatchBehaviorAddLineItem == $behavior ||
281
- self::subtotalMismatchBehaviorDropLineItems == $behavior ) {
282
- return $behavior;
283
- } else {
284
- return self::subtotalMismatchBehaviorAddLineItem;
285
- }
286
- }
287
-
288
- protected function _sanitize_buttonSize( $size ) {
289
- if ( in_array( $size, array( self::buttonSizeSmall, self::buttonSizeMedium ) ) ) {
290
- return $size;
291
- } else {
292
- return self::buttonSizeMedium;
293
- }
294
  }
295
 
296
- protected function _sanitize_markSize( $size ) {
297
- if ( self::markSizeSmall == $size ||
298
- self::markSizeMedium == $size ||
299
- self::markSizeLarge == $size ) {
300
- return $size;
301
- } else {
302
- return self::markSizeSmall;
303
- }
304
  }
305
 
306
- protected function _validate_paymentAction( $value ) {
307
- return in_array( $value, array( self::PaymentActionSale, self::PaymentActionAuthorization ) );
 
 
 
 
308
  }
309
 
310
  /**
311
- * Load settings from DB.
312
- *
313
- * @param bool $force_reload Force reload, ignore
314
- *
315
- * @return WC_Gateway_PPEC_Settings Instance of WC_Gateway_PPEC_Settings
316
  */
317
- public function loadSettings( $force_reload = false ) {
318
- if ( $this->_is_setting_loaded && ! $force_reload ) {
319
- return $this;
320
- }
321
-
322
- $this->enabled = get_option( 'pp_woo_enabled' );
323
- // $this->ppcEnabled = get_option( 'pp_woo_ppc_enabled' );
324
- $this->logging_enabled = get_option( 'pp_woo_logging_enabled' );
325
- $this->ppcEnabled = false; // defer this for next release.
326
- $this->buttonSize = get_option( 'pp_woo_button_size' );
327
- $this->markSize = get_option( 'pp_woo_mark_size' );
328
- $this->liveApiCredentials = get_option( 'pp_woo_liveApiCredentials' );
329
- $this->sandboxApiCredentials = get_option( 'pp_woo_sandboxApiCredentials' );
330
- $this->environment = get_option( 'pp_woo_environment' );
331
- $this->logoImageUrl = get_option( 'pp_woo_logoImageUrl' );
332
- $this->ipnUrl = get_option( 'pp_woo_ipnUrl' );
333
- $this->paymentAction = get_option( 'pp_woo_paymentAction' );
334
- $this->allowGuestCheckout = get_option( 'pp_woo_allowGuestCheckout' );
335
- $this->blockEChecks = get_option( 'pp_woo_blockEChecks' );
336
- $this->requireBillingAddress = get_option( 'pp_woo_requireBillingAddress' );
337
- $this->zeroSubtotalBehavior = get_option( 'pp_woo_zeroSubtotalBehavior' );
338
- $this->subtotalMismatchBehavior = get_option( 'pp_woo_subtotalMismatchBehavior' );
339
- $this->enableInContextCheckout = get_option( 'pp_woo_enableInContextCheckout' );
340
- $this->liveAccountIsEnabledForBillingAddress = get_option( 'pp_woo_liveAccountIsEnabledForBillingAddress' );
341
- $this->sbAccountIsEnabledForBillingAddress = get_option( 'pp_woo_sbAccountIsEnabledForBillingAddress' );
342
-
343
- $this->_is_setting_loaded = true;
344
-
345
- return $this;
346
  }
347
 
348
- public function saveSettings() {
349
- update_option( 'pp_woo_enabled' , $this->enabled );
350
- update_option( 'pp_woo_logging_enabled' , $this->logging_enabled );
351
- update_option( 'pp_woo_ppc_enabled' , $this->ppcEnabled );
352
- update_option( 'pp_woo_button_size' , $this->buttonSize );
353
- update_option( 'pp_woo_mark_size' , $this->markSize );
354
- update_option( 'pp_woo_liveApiCredentials' , $this->liveApiCredentials );
355
- update_option( 'pp_woo_sandboxApiCredentials' , $this->sandboxApiCredentials );
356
- update_option( 'pp_woo_environment' , $this->environment );
357
- update_option( 'pp_woo_logoImageUrl' , $this->logoImageUrl );
358
- update_option( 'pp_woo_ipnUrl' , $this->ipnUrl );
359
- update_option( 'pp_woo_paymentAction' , $this->paymentAction );
360
- update_option( 'pp_woo_allowGuestCheckout' , $this->allowGuestCheckout );
361
- update_option( 'pp_woo_blockEChecks' , $this->blockEChecks );
362
- update_option( 'pp_woo_requireBillingAddress' , $this->requireBillingAddress );
363
- update_option( 'pp_woo_zeroSubtotalBehavior' , $this->zeroSubtotalBehavior );
364
- update_option( 'pp_woo_subtotalMismatchBehavior' , $this->subtotalMismatchBehavior );
365
- update_option( 'pp_woo_enableInContextCheckout' , $this->enableInContextCheckout );
366
- update_option( 'pp_woo_liveAccountIsEnabledForBillingAddress', $this->liveAccountIsEnabledForBillingAddress );
367
- update_option( 'pp_woo_sbAccountIsEnabledForBillingAddress' , $this->sbAccountIsEnabledForBillingAddress );
368
  }
369
 
370
- public function getECTokenSessionLength() {
 
 
 
 
371
  // Really, we should map this to a merchant-configurable setting, but for now, we'll just set it to the default (3 hours).
372
  return 10800;
373
  }
@@ -378,28 +246,24 @@ class WC_Gateway_PPEC_Settings {
378
  * @return bool True if it has restriction otherwise false
379
  */
380
  public function currency_has_decimal_restriction() {
381
- // Because PayPal will not accept HUF, TWD, or JPY with any decimal places,
382
- // we'll have to make sure that Woo uses 0 decimal places if the merchant
383
- // is using any of these three currencies.
384
- $currency = get_woocommerce_currency();
385
- $decimals = absint( get_option( 'woocommerce_price_num_decimals', 2 ) );
386
- $settings = $this->loadSettings();
387
-
388
  return (
389
- $settings->enabled
390
  &&
391
- in_array( $currency, array( 'HUF', 'TWD', 'JPY' ) )
392
  &&
393
- 0 !== $decimals
394
  );
395
  }
396
 
 
 
 
 
397
  public function get_paypal_locale() {
398
  $locale = get_locale();
399
  if ( ! in_array( $locale, $this->_supportedLocale ) ) {
400
  $locale = 'en_US';
401
  }
402
-
403
  return $locale;
404
  }
405
  }
1
  <?php
2
 
3
  if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
  }
6
 
7
+ /**
8
+ * Handles settings retrieval from the settings API.
9
+ */
10
  class WC_Gateway_PPEC_Settings {
11
 
12
+ protected $_settings = array();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
13
  protected $_supportedLocale = array(
14
  'da_DK', 'de_DE', 'en_AU', 'en_GB', 'en_US', 'es_ES', 'fr_CA', 'fr_FR',
15
  'he_IL', 'id_ID', 'it_IT', 'ja_JP', 'nl_NL', 'no_NO', 'pl_PL', 'pt_BR',
16
  'pt_PT', 'ru_RU', 'sv_SE', 'th_TH', 'tr_TR', 'zh_CN', 'zh_HK', 'zh_TW',
17
  );
18
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  /**
20
  * Flag to indicate setting has been loaded from DB.
 
21
  * @var bool
22
  */
23
  private $_is_setting_loaded = false;
24
 
25
+ public function __get( $key ) {
26
+ if ( array_key_exists( $key, $this->_settings ) ) {
27
+ return $this->_settings[ $key ];
 
 
 
 
 
 
 
 
28
  }
 
29
  return null;
30
  }
31
 
32
+ public function __isset( $name ) {
33
+ return array_key_exists( $key, $this->_settings );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
34
  }
35
 
36
+ public function __construct() {
37
+ $this->load_settings();
 
 
 
 
38
  }
39
 
40
+ /**
41
+ * Load settings from DB.
42
+ *
43
+ * @param bool $force_reload Force reload, ignore
44
+ *
45
+ * @return WC_Gateway_PPEC_Settings Instance of WC_Gateway_PPEC_Settings
46
+ */
47
+ public function load_settings( $force_reload = false ) {
48
+ if ( $this->_is_setting_loaded && ! $force_reload ) {
49
+ return $this;
50
  }
51
+ $this->_settings = (array) get_option( 'woocommerce_ppec_paypal_settings', array() );
52
+ $this->_is_setting_loaded = true;
53
+ return $this;
54
  }
55
 
56
+ /**
57
+ * Get API credentials for the live envionment.
58
+ * @return object
59
+ */
60
+ public function get_live_api_credentials() {
61
+ if ( $this->api_signature ) {
62
+ return new WC_Gateway_PPEC_Client_Credential_Signature( $this->api_username, $this->api_password, $this->api_signature, $this->api_subject );
63
+ } else {
64
+ return new WC_Gateway_PPEC_Client_Credential_Certificate( $this->api_username, $this->api_password, $this->api_certificate, $this->api_subject );
65
  }
 
 
 
 
 
66
  }
67
 
68
+ /**
69
+ * Get API credentials for the live envionment.
70
+ * @return object.
71
+ */
72
+ public function get_sandbox_api_credentials() {
73
+ if ( $this->sandbox_api_signature ) {
74
+ return new WC_Gateway_PPEC_Client_Credential_Signature( $this->sandbox_api_username, $this->sandbox_api_password, $this->sandbox_api_signature, $this->sandbox_api_subject );
75
  } else {
76
+ return new WC_Gateway_PPEC_Client_Credential_Certificate( $this->sandbox_api_username, $this->sandbox_api_password, $this->sandbox_api_certificate, $this->sandbox_api_subject );
77
  }
78
  }
79
 
80
+ /**
81
+ * Get API credentials for the current envionment.
82
+ * @return object|false if invalid
83
+ */
84
+ public function get_active_api_credentials() {
85
+ if ( 'live' === $this->get_environment() ) {
86
+ return $this->get_live_api_credentials();
87
  } else {
88
+ return $this->get_sandbox_api_credentials();
89
  }
90
  }
91
 
92
+ public function get_paypal_redirect_url( $token, $commit = false ) {
93
  $url = 'https://www.';
94
 
95
+ if ( $this->environment !== 'live' ) {
96
  $url .= 'sandbox.';
97
  }
98
 
99
  $url .= 'paypal.com/';
100
+ $url .= 'checkoutnow?';
 
 
 
 
 
 
101
  $url .= 'token=' . urlencode( $token );
102
 
103
  if ( $commit ) {
107
  return $url;
108
  }
109
 
110
+ public function get_set_express_checkout_shortcut_params( $buckets = 1 ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
111
  $params = array();
112
 
113
+ if ( $this->logo_image_url ) {
114
+ $params['LOGOIMG'] = $this->logo_image_url;
115
  }
116
 
117
+ if ( false === apply_filters( 'woocommerce_paypal_express_checkout_allow_guests', true ) ) {
118
  $params['SOLUTIONTYPE'] = 'Sole';
119
  }
120
 
126
  }
127
  }
128
 
129
+ if ( 'yes' === $this->require_billing ) {
130
  $params['REQBILLINGADDRESS'] = '1';
131
  }
132
 
133
  foreach ( $buckets as $bucketNum ) {
134
+ $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->get_paymentaction();
135
+
136
+ if ( 'yes' === $this->instant_payments && 'sale' === $this->get_paymentaction() ) {
137
+ $params[ 'PAYMENTREQUEST_' . $bucketNum . '_ALLOWEDPAYMENTMETHOD' ] = 'InstantPaymentOnly';
138
+ }
139
  }
140
 
141
  return $params;
142
  }
143
 
144
+ public function get_set_express_checkout_mark_params( $buckets = 1 ) {
 
 
 
145
  $params = array();
146
 
147
+ if ( $this->logo_image_url ) {
148
+ $params['LOGOIMG'] = $this->logo_image_url;
149
  }
150
 
151
+ if ( false === apply_filters( 'woocommerce_paypal_express_checkout_allow_guests', true ) ) {
152
  $params['SOLUTIONTYPE'] = 'Sole';
153
  }
154
 
160
  }
161
  }
162
 
163
+ if ( 'yes' === $this->require_billing ) {
164
  $params['REQBILLINGADDRESS'] = '1';
165
  }
166
 
167
  foreach ( $buckets as $bucketNum ) {
168
+ $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->get_paymentaction();
169
+
170
+ if ( 'yes' === $this->instant_payments && 'sale' === $this->get_paymentaction() ) {
171
  $params[ 'PAYMENTREQUEST_' . $bucketNum . '_ALLOWEDPAYMENTMETHOD' ] = 'InstantPaymentOnly';
172
  }
173
  }
174
 
175
  return $params;
176
  }
177
+ public function get_do_express_checkout_params( $buckets = 1 ) {
 
 
 
 
178
  $params = array();
179
  if ( ! is_array( $buckets ) ) {
180
  $numBuckets = $buckets;
185
  }
186
 
187
  foreach ( $buckets as $bucketNum ) {
188
+ $params[ 'PAYMENTREQUEST_' . $bucketNum . '_PAYMENTACTION' ] = $this->get_paymentaction();
 
189
  }
190
 
191
  return $params;
192
  }
193
 
194
+ /**
195
+ * Is PPEC enabled
196
+ * @return bool
197
+ */
198
+ public function is_enabled() {
199
+ return 'yes' === $this->enabled;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
200
  }
201
 
202
+ /**
203
+ * Is logging enabled
204
+ * @return bool
205
+ */
206
+ public function is_logging_enabled() {
207
+ return 'yes' === $this->debug;
 
 
208
  }
209
 
210
+ /**
211
+ * Payment action
212
+ * @return string
213
+ */
214
+ public function get_paymentaction() {
215
+ return $this->paymentaction === 'authorization' ? 'authorization' : 'sale';
216
  }
217
 
218
  /**
219
+ * Payment action
220
+ * @return string
 
 
 
221
  */
222
+ public function get_environment() {
223
+ return $this->environment === 'sandbox' ? 'sandbox' : 'live';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  }
225
 
226
+ /**
227
+ * Subtotal mismatches
228
+ * @return string
229
+ */
230
+ public function get_subtotal_mismatch_behavior() {
231
+ return $this->subtotal_mismatch_behavior === 'drop' ? 'drop' : 'add';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
232
  }
233
 
234
+ /**
235
+ * Get session length.
236
+ * @return int
237
+ */
238
+ public function get_token_session_length() {
239
  // Really, we should map this to a merchant-configurable setting, but for now, we'll just set it to the default (3 hours).
240
  return 10800;
241
  }
246
  * @return bool True if it has restriction otherwise false
247
  */
248
  public function currency_has_decimal_restriction() {
 
 
 
 
 
 
 
249
  return (
250
+ 'yes' === $this->enabled
251
  &&
252
+ in_array( get_woocommerce_currency(), array( 'HUF', 'TWD', 'JPY' ) )
253
  &&
254
+ 0 !== absint( get_option( 'woocommerce_price_num_decimals', 2 ) )
255
  );
256
  }
257
 
258
+ /**
259
+ * Get locale for PayPal.
260
+ * @return string
261
+ */
262
  public function get_paypal_locale() {
263
  $locale = get_locale();
264
  if ( ! in_array( $locale, $this->_supportedLocale ) ) {
265
  $locale = 'en_US';
266
  }
 
267
  return $locale;
268
  }
269
  }
includes/class-wc-gateway-ppec-with-paypal.php CHANGED
@@ -6,17 +6,7 @@ if ( ! defined( 'ABSPATH' ) ) {
6
 
7
  class WC_Gateway_PPEC_With_PayPal extends WC_Gateway_PPEC {
8
  public function __construct() {
9
-
10
  $this->id = 'ppec_paypal';
11
-
12
  parent::__construct();
13
-
14
- $settings = wc_gateway_ppec()->settings->loadSettings();
15
-
16
- $this->icon = 'https://www.paypalobjects.com/webstatic/en_US/i/buttons/pp-acceptance-' . $settings->markSize . '.png';
17
- $this->enabled = $settings->enabled ? 'yes' : 'no';
18
- $this->title = __( 'PayPal', 'woocommerce-gateway-paypal-express-checkout' );
19
- $this->description = __( 'A PayPal Account is not necessary. All credit card payments will be processed by PayPal.', 'woocommerce-gateway-paypal-express-checkout' );
20
  }
21
  }
22
-
6
 
7
  class WC_Gateway_PPEC_With_PayPal extends WC_Gateway_PPEC {
8
  public function __construct() {
 
9
  $this->id = 'ppec_paypal';
 
10
  parent::__construct();
 
 
 
 
 
 
 
11
  }
12
  }
 
includes/functions.php CHANGED
@@ -8,16 +8,13 @@ function woo_pp_start_checkout() {
8
  wp_safe_redirect( $redirect_url );
9
  exit;
10
  } catch( PayPal_API_Exception $e ) {
11
- $final_output = '';
12
- foreach ( $e->errors as $error ) {
13
- $final_output .= '<li>' . __( $error->mapToBuyerFriendlyError(), 'woocommerce-gateway-paypal-express-checkout' ) . '</li>';
14
- }
15
- wc_add_notice( __( 'Payment error:', 'woocommerce-gateway-paypal-express-checkout' ) . $final_output, 'error' );
16
 
17
  $redirect_url = WC()->cart->get_cart_url();
18
- $settings = wc_gateway_ppec()->settings->loadSettings();
 
19
 
20
- if( 'yes' == $settings->enabled && $settings->enableInContextCheckout && $settings->getActiveApiCredentials()->get_payer_id() ) {
21
  ob_end_clean();
22
  ?>
23
  <script type="text/javascript">
@@ -40,6 +37,14 @@ function woo_pp_start_checkout() {
40
  }
41
  }
42
 
 
 
 
 
 
 
 
 
43
  /**
44
  * Log a message via WC_Logger.
45
  *
@@ -49,7 +54,7 @@ function wc_gateway_ppec_log( $message ) {
49
  static $wc_ppec_logger;
50
 
51
  // No need to write to log file if logging is disabled.
52
- if ( ! wc_gateway_ppec()->settings->loadSettings()->logging_enabled ) {
53
  return false;
54
  }
55
 
8
  wp_safe_redirect( $redirect_url );
9
  exit;
10
  } catch( PayPal_API_Exception $e ) {
11
+ wc_gateway_ppec_format_paypal_api_exception( $e->errors );
 
 
 
 
12
 
13
  $redirect_url = WC()->cart->get_cart_url();
14
+ $settings = wc_gateway_ppec()->settings;
15
+ $client = wc_gateway_ppec()->client;
16
 
17
+ if ( $settings->is_enabled() && $client->get_payer_id() ) {
18
  ob_end_clean();
19
  ?>
20
  <script type="text/javascript">
37
  }
38
  }
39
 
40
+ function wc_gateway_ppec_format_paypal_api_exception( $errors ) {
41
+ $error_strings = array();
42
+ foreach ( $errors as $error ) {
43
+ $error_strings[] = $error->maptoBuyerFriendlyError();
44
+ }
45
+ wc_add_notice( __( 'Payment error:', 'woocommerce-gateway-paypal-express-checkout' ) . '<ul><li>' . implode( '</li><li>', $error_strings ) . '</li></ul>', 'error' );
46
+ }
47
+
48
  /**
49
  * Log a message via WC_Logger.
50
  *
54
  static $wc_ppec_logger;
55
 
56
  // No need to write to log file if logging is disabled.
57
+ if ( ! wc_gateway_ppec()->settings->is_logging_enabled() ) {
58
  return false;
59
  }
60
 
includes/settings/settings-ppec.php ADDED
@@ -0,0 +1,295 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ if ( ! defined( 'ABSPATH' ) ) {
4
+ exit;
5
+ }
6
+
7
+ $needs_creds = empty( $this->get_option( 'api_username' ) );
8
+ $needs_sandbox_creds = empty( $this->get_option( 'sandbox_api_username' ) );
9
+ $enable_ips = wc_gateway_ppec()->ips->is_supported();
10
+
11
+ if ( $enable_ips && $needs_creds ) {
12
+ $ips_button = '<a href="' . esc_url( wc_gateway_ppec()->ips->get_signup_url( 'live' ) ) . '" class="button button-primary">' . __( 'Setup or link an existing PayPal account', 'woocommerce-gateway-paypal-express-checkout' ) . '</a>';
13
+ $api_creds_text = sprintf( __( '%s or <a href="#" class="ppec-toggle-settings">click here to toggle manual API credential input</a>.', 'woocommerce-gateway-paypal-express-checkout' ), $ips_button );
14
+ } else {
15
+ $api_creds_text = '';
16
+ }
17
+
18
+ if ( $enable_ips && $needs_sandbox_creds ) {
19
+ $sandbox_ips_button = '<a href="' . esc_url( wc_gateway_ppec()->ips->get_signup_url( 'sandbox' ) ) . '" class="button button-primary">' . __( 'Setup or link an existing PayPal Sandbox account', 'woocommerce-gateway-paypal-express-checkout' ) . '</a>';
20
+ $sandbox_api_creds_text = sprintf( __( '%s or <a href="#" class="ppec-toggle-sandbox-settings">click here to toggle manual API credential input</a>.', 'woocommerce-gateway-paypal-express-checkout' ), $sandbox_ips_button );
21
+ } else {
22
+ $sandbox_api_creds_text = '';
23
+ }
24
+
25
+ wc_enqueue_js( "
26
+ jQuery( function( $ ) {
27
+ var ppec_mark_fields = '#woocommerce_ppec_paypal_title, #woocommerce_ppec_paypal_description';
28
+ var ppec_live_fields = '#woocommerce_ppec_paypal_api_username, #woocommerce_ppec_paypal_api_password, #woocommerce_ppec_paypal_api_signature, #woocommerce_ppec_paypal_api_certificate, #woocommerce_ppec_paypal_api_subject';
29
+ var ppec_sandbox_fields = '#woocommerce_ppec_paypal_sandbox_api_username, #woocommerce_ppec_paypal_sandbox_api_password, #woocommerce_ppec_paypal_sandbox_api_signature, #woocommerce_ppec_paypal_sandbox_api_certificate, #woocommerce_ppec_paypal_sandbox_api_subject';
30
+
31
+ var enable_toggle = $( 'a.ppec-toggle-settings' ).length > 0;
32
+ var enable_sandbox_toggle = $( 'a.ppec-toggle-sandbox-settings' ).length > 0;
33
+
34
+ $( '#woocommerce_ppec_paypal_environment' ).change(function(){
35
+ $( ppec_sandbox_fields + ',' + ppec_live_fields ).closest( 'tr' ).hide();
36
+
37
+ if ( 'live' === $( this ).val() ) {
38
+ $( '#woocommerce_ppec_paypal_api_credentials, #woocommerce_ppec_paypal_api_credentials + p' ).show();
39
+ $( '#woocommerce_ppec_paypal_sandbox_api_credentials, #woocommerce_ppec_paypal_sandbox_api_credentials + p' ).hide();
40
+
41
+ if ( ! enable_toggle ) {
42
+ $( ppec_live_fields ).closest( 'tr' ).show();
43
+ }
44
+ } else {
45
+ $( '#woocommerce_ppec_paypal_api_credentials, #woocommerce_ppec_paypal_api_credentials + p' ).hide();
46
+ $( '#woocommerce_ppec_paypal_sandbox_api_credentials, #woocommerce_ppec_paypal_sandbox_api_credentials + p' ).show();
47
+
48
+ if ( ! enable_sandbox_toggle ) {
49
+ $( ppec_sandbox_fields ).closest( 'tr' ).show();
50
+ }
51
+ }
52
+ }).change();
53
+
54
+ $( '#woocommerce_ppec_paypal_mark_enabled' ).change(function(){
55
+ if ( $( this ).is( ':checked' ) ) {
56
+ $( ppec_mark_fields ).closest( 'tr' ).show();
57
+ } else {
58
+ $( ppec_mark_fields ).closest( 'tr' ).hide();
59
+ }
60
+ }).change();
61
+
62
+ $( '#woocommerce_ppec_paypal_paymentaction' ).change(function(){
63
+ if ( 'sale' === $( this ).val() ) {
64
+ $( '#woocommerce_ppec_paypal_instant_payments' ).closest( 'tr' ).show();
65
+ } else {
66
+ $( '#woocommerce_ppec_paypal_instant_payments' ).closest( 'tr' ).hide();
67
+ }
68
+ }).change();
69
+
70
+ if ( enable_toggle ) {
71
+ $( document ).on( 'click', '.ppec-toggle-settings', function() {
72
+ $( ppec_live_fields ).closest( 'tr' ).toggle();
73
+ } );
74
+ }
75
+ if ( enable_sandbox_toggle ) {
76
+ $( document ).on( 'click', '.ppec-toggle-sandbox-settings', function() {
77
+ $( ppec_sandbox_fields ).closest( 'tr' ).toggle();
78
+ } );
79
+ }
80
+ });
81
+ " );
82
+
83
+ /**
84
+ * Settings for PayPal Gateway.
85
+ */
86
+ return array(
87
+ 'enabled' => array(
88
+ 'title' => __( 'Enable/Disable', 'woocommerce-gateway-paypal-express-checkout' ),
89
+ 'type' => 'checkbox',
90
+ 'label' => __( 'Enable PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' ),
91
+ 'description' => __( 'This enables PayPal Express Checkout which allows customers to checkout directly via PayPal from your cart page.', 'woocommerce-gateway-paypal-express-checkout' ),
92
+ 'desc_tip' => true,
93
+ 'default' => 'yes'
94
+ ),
95
+ 'button_size' => array(
96
+ 'title' => __( 'Button Size', 'woocommerce-gateway-paypal-express-checkout' ),
97
+ 'type' => 'select',
98
+ 'class' => 'wc-enhanced-select',
99
+ 'description' => __( 'PayPal offers different sizes of the "PayPal Checkout" buttons, allowing you to select a size that best fits your site\'s theme. This setting will allow you to choose which size button(s) appear on your cart page.', 'woocommerce-gateway-paypal-express-checkout' ),
100
+ 'default' => 'large',
101
+ 'desc_tip' => true,
102
+ 'options' => array(
103
+ 'small' => __( 'Small', 'woocommerce-gateway-paypal-express-checkout' ),
104
+ 'medium' => __( 'Medium', 'woocommerce-gateway-paypal-express-checkout' ),
105
+ 'large' => __( 'Large', 'woocommerce-gateway-paypal-express-checkout' )
106
+ )
107
+ ),
108
+ 'environment' => array(
109
+ 'title' => __( 'Environment', 'woocommerce-gateway-paypal-express-checkout' ),
110
+ 'type' => 'select',
111
+ 'class' => 'wc-enhanced-select',
112
+ 'description' => __( 'This setting specifies whether you will process live transactions, or whether you will process simulated transactions using the PayPal Sandbox.', 'woocommerce-gateway-paypal-express-checkout' ),
113
+ 'default' => 'live',
114
+ 'desc_tip' => true,
115
+ 'options' => array(
116
+ 'live' => __( 'Live', 'woocommerce-gateway-paypal-express-checkout' ),
117
+ 'sandbox' => __( 'Sandbox', 'woocommerce-gateway-paypal-express-checkout' ),
118
+ )
119
+ ),
120
+ 'mark_enabled' => array(
121
+ 'title' => __( 'PayPal Mark', 'woocommerce-gateway-paypal-express-checkout' ),
122
+ 'type' => 'checkbox',
123
+ 'label' => __( 'Enable the PayPal Mark on regular checkout', 'woocommerce-gateway-paypal-express-checkout' ),
124
+ 'description' => __( 'This enables the PayPal mark, which can be shown on regular WooCommerce checkout to use PayPal Express Checkout like a regular WooCommerce gateway.', 'woocommerce-gateway-paypal-express-checkout' ),
125
+ 'desc_tip' => true,
126
+ 'default' => 'no'
127
+ ),
128
+ 'title' => array(
129
+ 'title' => __( 'Title', 'woocommerce-gateway-paypal-express-checkout' ),
130
+ 'type' => 'text',
131
+ 'description' => __( 'This controls the title which the user sees during checkout.', 'woocommerce-gateway-paypal-express-checkout' ),
132
+ 'default' => __( 'PayPal Express Checkout', 'woocommerce-gateway-paypal-express-checkout' ),
133
+ 'desc_tip' => true,
134
+ ),
135
+ 'description' => array(
136
+ 'title' => __( 'Description', 'woocommerce-gateway-paypal-express-checkout' ),
137
+ 'type' => 'text',
138
+ 'desc_tip' => true,
139
+ 'description' => __( 'This controls the description which the user sees during checkout.', 'woocommerce-gateway-paypal-express-checkout' ),
140
+ 'default' => __( 'Pay using either your PayPal account or credit card. All credit card payments will be processed by PayPal.', 'woocommerce-gateway-paypal-express-checkout' )
141
+ ),
142
+
143
+ 'api_credentials' => array(
144
+ 'title' => __( 'API Credentials', 'woocommerce-gateway-paypal-express-checkout' ),
145
+ 'type' => 'title',
146
+ 'description' => $api_creds_text,
147
+ ),
148
+ 'api_username' => array(
149
+ 'title' => __( 'Live API Username', 'woocommerce-gateway-paypal-express-checkout' ),
150
+ 'type' => 'text',
151
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
152
+ 'default' => '',
153
+ 'desc_tip' => true,
154
+ ),
155
+ 'api_password' => array(
156
+ 'title' => __( 'Live API Password', 'woocommerce-gateway-paypal-express-checkout' ),
157
+ 'type' => 'password',
158
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
159
+ 'default' => '',
160
+ 'desc_tip' => true,
161
+ ),
162
+ 'api_signature' => array(
163
+ 'title' => __( 'Live API Signature', 'woocommerce-gateway-paypal-express-checkout' ),
164
+ 'type' => 'text',
165
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
166
+ 'default' => '',
167
+ 'desc_tip' => true,
168
+ 'placeholder' => __( 'Optional if you provide a certificate below', 'woocommerce-gateway-paypal-express-checkout' )
169
+ ),
170
+ 'api_certificate' => array(
171
+ 'title' => __( 'Live API Certificate', 'woocommerce-gateway-paypal-express-checkout' ),
172
+ 'type' => 'file',
173
+ 'description' => $this->get_certificate_info( $this->get_option( 'api_certificate' ) ),
174
+ 'default' => '',
175
+ ),
176
+ 'api_subject' => array(
177
+ 'title' => __( 'Live API Subject', 'woocommerce-gateway-paypal-express-checkout' ),
178
+ 'type' => 'text',
179
+ 'description' => __( 'If you\'re processing transactions on behalf of someone else\'s PayPal account, enter their email address or Secure Merchant Account ID (also known as a Payer ID) here. Generally, you must have API permissions in place with the other account in order to process anything other than "sale" transactions for them.', 'woocommerce-gateway-paypal-express-checkout' ),
180
+ 'default' => '',
181
+ 'desc_tip' => true,
182
+ 'placeholder' => __( 'Optional', 'woocommerce-gateway-paypal-express-checkout' )
183
+ ),
184
+
185
+ 'sandbox_api_credentials' => array(
186
+ 'title' => __( 'Sandbox API Credentials', 'woocommerce-gateway-paypal-express-checkout' ),
187
+ 'type' => 'title',
188
+ 'description' => $sandbox_api_creds_text,
189
+ ),
190
+ 'sandbox_api_username' => array(
191
+ 'title' => __( 'Sandbox API Username', 'woocommerce-gateway-paypal-express-checkout' ),
192
+ 'type' => 'text',
193
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
194
+ 'default' => '',
195
+ 'desc_tip' => true,
196
+ ),
197
+ 'sandbox_api_password' => array(
198
+ 'title' => __( 'Sandbox API Password', 'woocommerce-gateway-paypal-express-checkout' ),
199
+ 'type' => 'password',
200
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
201
+ 'default' => '',
202
+ 'desc_tip' => true,
203
+ ),
204
+ 'sandbox_api_signature' => array(
205
+ 'title' => __( 'Sandbox API Signature', 'woocommerce-gateway-paypal-express-checkout' ),
206
+ 'type' => 'text',
207
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
208
+ 'default' => '',
209
+ 'desc_tip' => true,
210
+ ),
211
+ 'sandbox_api_certificate' => array(
212
+ 'title' => __( 'Sandbox API Certificate', 'woocommerce-gateway-paypal-express-checkout' ),
213
+ 'type' => 'file',
214
+ 'description' => __( 'Get your API credentials from PayPal.', 'woocommerce-gateway-paypal-express-checkout' ),
215
+ 'default' => '',
216
+ 'desc_tip' => true,
217
+ ),
218
+ 'sandbox_api_subject' => array(
219
+ 'title' => __( 'Sandbox API Subject', 'woocommerce-gateway-paypal-express-checkout' ),
220
+ 'type' => 'text',
221
+ 'description' => __( 'If you\'re processing transactions on behalf of someone else\'s PayPal account, enter their email address or Secure Merchant Account ID (also known as a Payer ID) here. Generally, you must have API permissions in place with the other account in order to process anything other than "sale" transactions for them.', 'woocommerce-gateway-paypal-express-checkout' ),
222
+ 'default' => '',
223
+ 'desc_tip' => true,
224
+ 'placeholder' => __( 'Optional', 'woocommerce-gateway-paypal-express-checkout' )
225
+ ),
226
+
227
+ 'advanced' => array(
228
+ 'title' => __( 'Advanced Settings', 'woocommerce-gateway-paypal-express-checkout' ),
229
+ 'type' => 'title',
230
+ 'description' => '',
231
+ ),
232
+ 'debug' => array(
233
+ 'title' => __( 'Debug Log', 'woocommerce-gateway-paypal-express-checkout' ),
234
+ 'type' => 'checkbox',
235
+ 'label' => __( 'Enable Logging', 'woocommerce-gateway-paypal-express-checkout' ),
236
+ 'default' => 'no',
237
+ 'desc_tip' => true,
238
+ 'description' => __( 'Log PayPal events, such as IPN requests.', 'woocommerce-gateway-paypal-express-checkout' ),
239
+ ),
240
+ 'invoice_prefix' => array(
241
+ 'title' => __( 'Invoice Prefix', 'woocommerce-gateway-paypal-express-checkout' ),
242
+ 'type' => 'text',
243
+ 'description' => __( 'Please enter a prefix for your invoice numbers. If you use your PayPal account for multiple stores ensure this prefix is unique as PayPal will not allow orders with the same invoice number.', 'woocommerce-gateway-paypal-express-checkout' ),
244
+ 'default' => 'WC-',
245
+ 'desc_tip' => true,
246
+ ),
247
+ 'require_billing' => array(
248
+ 'title' => __( 'Billing Addresses', 'woocommerce-gateway-paypal-express-checkout' ),
249
+ 'type' => 'checkbox',
250
+ 'label' => __( 'Require Billing Address', 'woocommerce-gateway-paypal-express-checkout' ),
251
+ 'default' => 'no',
252
+ 'desc_tip' => true,
253
+ 'description' => __( 'PayPal does not share buyer billing details with you. However, there are times when you must collect the buyer billing address to fulfill an essential business function (such as determining whether you must charge the buyer tax). Enable this function to collect the address before payment is taken.', 'woocommerce-gateway-paypal-express-checkout' ),
254
+ ),
255
+ 'paymentaction' => array(
256
+ 'title' => __( 'Payment Action', 'woocommerce-gateway-paypal-express-checkout' ),
257
+ 'type' => 'select',
258
+ 'class' => 'wc-enhanced-select',
259
+ 'description' => __( 'Choose whether you wish to capture funds immediately or authorize payment only.', 'woocommerce-gateway-paypal-express-checkout' ),
260
+ 'default' => 'sale',
261
+ 'desc_tip' => true,
262
+ 'options' => array(
263
+ 'sale' => __( 'Sale', 'woocommerce-gateway-paypal-express-checkout' ),
264
+ 'authorization' => __( 'Authorize', 'woocommerce-gateway-paypal-express-checkout' )
265
+ )
266
+ ),
267
+ 'instant_payments' => array(
268
+ 'title' => __( 'Instant Payments', 'woocommerce-gateway-paypal-express-checkout' ),
269
+ 'type' => 'checkbox',
270
+ 'label' => __( 'Require Instant Payment', 'woocommerce-gateway-paypal-express-checkout' ),
271
+ 'default' => 'no',
272
+ 'desc_tip' => true,
273
+ 'description' => __( 'If you enable this setting, PayPal will be instructed not to allow the buyer to use funding sources that take additional time to complete (for example, eChecks). Instead, the buyer will be required to use an instant funding source, such as an instant transfer, a credit/debit card, or PayPal Credit.', 'woocommerce-gateway-paypal-express-checkout' ),
274
+ ),
275
+ 'logo_image_url' => array(
276
+ 'title' => __( 'Logo Image URL', 'woocommerce-gateway-paypal-express-checkout' ),
277
+ 'type' => 'text',
278
+ 'description' => __( 'If you want PayPal to co-brand the checkout page with your logo, enter the URL of your logo image here.<br/>The image must be no larger than 190x60, GIF, PNG, or JPG format, and should be served over HTTPS.', 'woocommerce-gateway-paypal-express-checkout' ),
279
+ 'default' => '',
280
+ 'desc_tip' => true,
281
+ 'placeholder' => __( 'Optional', 'woocommerce-gateway-paypal-express-checkout' ),
282
+ ),
283
+ 'subtotal_mismatch_behavior' => array(
284
+ 'title' => __( 'Subtotal Mismatch Behavior', 'woocommerce-gateway-paypal-express-checkout' ),
285
+ 'type' => 'select',
286
+ 'class' => 'wc-enhanced-select',
287
+ 'description' => __( 'Internally, WC calculates line item prices and taxes out to four decimal places; however, PayPal can only handle amounts out to two decimal places (or, depending on the currency, no decimal places at all). Occasionally, this can cause discrepancies between the way WooCommerce calculates prices versus the way PayPal calculates them. If a mismatch occurs, this option controls how the order is dealt with so payment can still be taken.', 'woocommerce-gateway-paypal-express-checkout' ),
288
+ 'default' => 'add',
289
+ 'desc_tip' => true,
290
+ 'options' => array(
291
+ 'add' => __( 'Add another line item', 'woocommerce-gateway-paypal-express-checkout' ),
292
+ 'drop' => __( 'Do not send line items to PayPal', 'woocommerce-gateway-paypal-express-checkout' ),
293
+ )
294
+ ),
295
+ );
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: automattic, woothemes, akeda, dwainm, royho, allendav, slash1andy,
3
  Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, store, sales, sell, shop, shopping, cart, checkout, configurable, paypal
4
  Requires at least: 4.4
5
  Tested up to: 4.4
6
- Stable tag: 1.0.4
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -56,7 +56,7 @@ Yes it does - production and sandbox mode is driven by how you connect. You may
56
 
57
  = Where can I find documentation? =
58
 
59
- For help setting up and configuring, please refer to our [user guide](https://www.woothemes.com/products/woocommerce-gateway-paypal-express-checkout/)
60
 
61
  = Where can I get support or talk to other users? =
62
 
@@ -64,14 +64,19 @@ If you get stuck, you can ask for help in the Plugin Forum.
64
 
65
  = Will this plugin work with my theme? =
66
 
67
- Yes, this plugin will work with any theme, but may require some styling to make it match nicely. Please see
68
- our [codex](http://docs.woothemes.com/documentation/plugins/woocommerce/woocommerce-codex/) for help. If you're
69
  looking for a theme with built in WooCommerce integration we recommend [Storefront](http://www.woothemes.com/storefront/).
70
 
71
  = Where can I request new features or report bugs? =
72
 
73
  New feature requests and bugs reports can be made in the plugin forum.
74
 
 
 
 
 
 
 
75
  == Screenshots ==
76
 
77
  1. Click the "Click Here to Set Up Your PayPal Account" button. If you want to test before goes live, you can switch the Environment, above the button, to Sandbox.
@@ -80,26 +85,35 @@ New feature requests and bugs reports can be made in the plugin forum.
80
 
81
  == Changelog ==
82
 
83
- = 1.0.4 =
 
 
 
 
 
 
 
 
 
 
84
 
 
85
  * Fix - Wrong section slug / tab after redirected from connect.woocommerce.com
86
  * Fix - Make sure to check if credentials were set in cart and checkout pages
87
  * Fix - Removed configuration of chipers to use for TLS
88
 
89
  = 1.0.3 =
90
-
91
  * Fix - Issue where missing rounding two decimal digits of tax causing transaction being refused
92
  * Fix - Issue where custom logo image URL is not saved
93
 
94
- = 1.0.2
95
-
96
  * Fix - Strip out HTML tags from item descriptions to prevent warning from PayPal
97
  * Fix - Issue of incorrect plugin's setting link from admin plugins page when using WooCommerce 2.6
98
  * Tweak - Make enabled option to default to true
99
  * Fix - Issue of missing help icon when plugin directory is not the same as plugin's slug.
100
  * Tweak - Add admin notice to setup / connect after plugin is activated.
101
 
102
- = 1.0.1
103
  * Fix - Make sure OpenSSL is installed with 1.0.1 as the minium required version, otherwise display warning
104
  * Fix - Make sure cURL transport is available for WP HTTP API, otherwise display warning
105
  * Fix - Unhandled certificate-style API credential
3
  Tags: ecommerce, e-commerce, commerce, woothemes, wordpress ecommerce, store, sales, sell, shop, shopping, cart, checkout, configurable, paypal
4
  Requires at least: 4.4
5
  Tested up to: 4.4
6
+ Stable tag: 1.1.0
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
56
 
57
  = Where can I find documentation? =
58
 
59
+ For help setting up and configuring, please refer to our [user guide](https://docs.woocommerce.com/document/paypal-express-checkout/)
60
 
61
  = Where can I get support or talk to other users? =
62
 
64
 
65
  = Will this plugin work with my theme? =
66
 
67
+ Yes, this plugin will work with any theme, but may require some styling to make it match nicely. If you're
 
68
  looking for a theme with built in WooCommerce integration we recommend [Storefront](http://www.woothemes.com/storefront/).
69
 
70
  = Where can I request new features or report bugs? =
71
 
72
  New feature requests and bugs reports can be made in the plugin forum.
73
 
74
+ = How to remove 'Proceed to Checkout' button from cart page? =
75
+
76
+ If PayPal Express Checkout is the only enabled payment gateway and you want to remove the 'Proceed to Checkout' button from the cart, you can use this snippet:
77
+
78
+ https://gist.github.com/mikejolley/ad2ecc286c9ad6cefbb7065ba6dfef48
79
+
80
  == Screenshots ==
81
 
82
  1. Click the "Click Here to Set Up Your PayPal Account" button. If you want to test before goes live, you can switch the Environment, above the button, to Sandbox.
85
 
86
  == Changelog ==
87
 
88
+ = 1.1.0 =
89
+ * Improved flow after express checkout by removing billing and shipping fields and simply allowing shipping method selection.
90
+ * Fix - Fixed in-context checkout to work after ajax cart reload.
91
+ * Fix - Added missing 'large' button size.
92
+ * Fix - Prevent double stock reduction when payment complete.
93
+ * Fix - Allow PPE from pay page and don't use in-context checkout for PayPal Mark on checkout.
94
+ * Fix - Increase timeout to 30 to prevent error #3.
95
+ * Tweak - If the store owner decides to enable PayPal standard, respect that decision and remove EC from checkout screen.
96
+ * Tweak - Change place order button to "continue to payment".
97
+ * Tweak - Moved default button location to woocommerce_proceed_to_checkout hook.
98
+ * Tweak - Improved button appearance and look alongside regular checkout button.
99
 
100
+ = 1.0.4 =
101
  * Fix - Wrong section slug / tab after redirected from connect.woocommerce.com
102
  * Fix - Make sure to check if credentials were set in cart and checkout pages
103
  * Fix - Removed configuration of chipers to use for TLS
104
 
105
  = 1.0.3 =
 
106
  * Fix - Issue where missing rounding two decimal digits of tax causing transaction being refused
107
  * Fix - Issue where custom logo image URL is not saved
108
 
109
+ = 1.0.2 =
 
110
  * Fix - Strip out HTML tags from item descriptions to prevent warning from PayPal
111
  * Fix - Issue of incorrect plugin's setting link from admin plugins page when using WooCommerce 2.6
112
  * Tweak - Make enabled option to default to true
113
  * Fix - Issue of missing help icon when plugin directory is not the same as plugin's slug.
114
  * Tweak - Add admin notice to setup / connect after plugin is activated.
115
 
116
+ = 1.0.1 =
117
  * Fix - Make sure OpenSSL is installed with 1.0.1 as the minium required version, otherwise display warning
118
  * Fix - Make sure cURL transport is available for WP HTTP API, otherwise display warning
119
  * Fix - Unhandled certificate-style API credential
woocommerce-gateway-paypal-express-checkout.php CHANGED
@@ -2,9 +2,9 @@
2
  /**
3
  * Plugin Name: WooCommerce PayPal Express Checkout Gateway
4
  * Plugin URI: https://www.woothemes.com/products/woocommerce-gateway-paypal-express-checkout/
5
- * Description: A payment gateway for PayPal Express Checkout ( https://www.paypal.com/us/webapps/mpp/express-checkout ). Requires WC 2.5+
6
- * Version: 1.0.4
7
- * Author: Automattic/WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2016 WooCommerce / PayPal.
10
  * License: GNU General Public License v3.0
@@ -36,7 +36,7 @@ function wc_gateway_ppec() {
36
  if ( ! isset( $plugin ) ) {
37
  require_once( 'includes/class-wc-gateway-ppec-plugin.php' );
38
 
39
- $plugin = new WC_Gateway_PPEC_Plugin( __FILE__, '1.0.4' );
40
  }
41
 
42
  return $plugin;
2
  /**
3
  * Plugin Name: WooCommerce PayPal Express Checkout Gateway
4
  * Plugin URI: https://www.woothemes.com/products/woocommerce-gateway-paypal-express-checkout/
5
+ * Description: A payment gateway for PayPal Express Checkout (https://www.paypal.com/us/webapps/mpp/express-checkout).
6
+ * Version: 1.1.0
7
+ * Author: Automattic
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2016 WooCommerce / PayPal.
10
  * License: GNU General Public License v3.0
36
  if ( ! isset( $plugin ) ) {
37
  require_once( 'includes/class-wc-gateway-ppec-plugin.php' );
38
 
39
+ $plugin = new WC_Gateway_PPEC_Plugin( __FILE__, '1.1.0' );
40
  }
41
 
42
  return $plugin;