WooCommerce PayPal Express Checkout Payment Gateway - Version 1.6.6

Version Description

  • 2019-01-09 =
  • Fix - Discount items were not being included
  • Add - Filter for order details to accept decimal quantities of products
  • Fix - Unable to buy variation from product page
  • Fix - Can use PayPal from product page without inputting required fields
  • Add - Display PayPal fees under the totals on the order admin page
  • Add - Prefill name, phone, and email info in PayPal Guest Checkout from checkout screen
Download this release

Release Info

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

Code changes from version 1.6.5 to 1.6.6

assets/js/wc-gateway-ppec-generate-cart.js CHANGED
@@ -30,52 +30,62 @@
30
  $( '#woo_pp_ec_button_product > *' ).css( 'pointer-events', 'none' );
31
  } );
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  // It's a variations form, button availability should depend on its events
34
  if ( $( '.variations_form' ).length ) {
35
- $( '#woo_pp_ec_button_product' ).trigger( 'disable' );
36
 
37
  $( '.variations_form' )
38
  .on( 'show_variation', function( event, form, purchasable ) {
39
- $( '#woo_pp_ec_button_product' ).trigger( purchasable ? 'enable' : 'disable' );
 
40
  } )
41
  .on( 'hide_variation', function() {
42
- $( '#woo_pp_ec_button_product' ).trigger( 'disable' );
 
43
  } );
44
  }
45
 
46
- var get_attributes = function() {
47
- var select = $( '.variations_form' ).find( '.variations select' ),
48
- data = {},
49
- count = 0,
50
- chosen = 0;
51
-
52
- select.each( function() {
53
- var attribute_name = $( this ).data( 'attribute_name' ) || $( this ).attr( 'name' );
54
- var value = $( this ).val() || '';
55
-
56
- if ( value.length > 0 ) {
57
- chosen++;
58
- }
59
-
60
- count++;
61
- data[ attribute_name ] = value;
62
- } );
63
-
64
- return {
65
- 'count' : count,
66
- 'chosenCount': chosen,
67
- 'data' : data
68
- };
69
- };
70
 
71
  var generate_cart = function( callback ) {
72
  var data = {
73
- 'nonce': wc_ppec_generate_cart_context.generate_cart_nonce,
74
- 'qty': $( '.quantity .qty' ).val(),
75
- 'attributes': $( '.variations_form' ).length ? get_attributes().data : [],
76
- 'add-to-cart': $( '[name=add-to-cart]' ).val(),
77
  };
78
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  $.ajax( {
80
  type: 'POST',
81
  data: data,
30
  $( '#woo_pp_ec_button_product > *' ).css( 'pointer-events', 'none' );
31
  } );
32
 
33
+ // True if the product is simple or the user selected a valid variation. False on variable product without a valid variation selected
34
+ var variation_valid = true;
35
+
36
+ // True if all the fields of the product form are valid (such as required fields configured by Product Add-Ons). False otherwise
37
+ var fields_valid = true;
38
+
39
+ var form = $( 'form.cart' );
40
+
41
+ var update_button = function() {
42
+ $( '#woo_pp_ec_button_product' ).trigger( ( variation_valid && fields_valid ) ? 'enable' : 'disable' );
43
+ };
44
+
45
+ var validate_form = function() {
46
+ fields_valid = form.get( 0 ).checkValidity();
47
+ update_button();
48
+ };
49
+
50
  // It's a variations form, button availability should depend on its events
51
  if ( $( '.variations_form' ).length ) {
52
+ variation_valid = false;
53
 
54
  $( '.variations_form' )
55
  .on( 'show_variation', function( event, form, purchasable ) {
56
+ variation_valid = purchasable;
57
+ update_button();
58
  } )
59
  .on( 'hide_variation', function() {
60
+ variation_valid = false;
61
+ update_button();
62
  } );
63
  }
64
 
65
+ // Disable the button if there are invalid fields in the product page (like required fields from Product Addons)
66
+ form.on( 'change', 'select, input, textarea', function() {
67
+ // Hack: IE11 uses the previous field value for the checkValidity() check if it's called in the onChange handler
68
+ setTimeout( validate_form, 0 );
69
+ } );
70
+ validate_form();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
71
 
72
  var generate_cart = function( callback ) {
73
  var data = {
74
+ 'nonce': wc_ppec_generate_cart_context.generate_cart_nonce,
 
 
 
75
  };
76
 
77
+ var field_pairs = form.serializeArray();
78
+ for ( var i = 0; i < field_pairs.length; i++ ) {
79
+ // Prevent the default WooCommerce PHP form handler from recognizing this as an "add to cart" call
80
+ if ( 'add-to-cart' === field_pairs[ i ].name ) {
81
+ field_pairs[ i ].name = 'ppec-add-to-cart';
82
+ }
83
+ data[ field_pairs[ i ].name ] = field_pairs[ i ].value;
84
+ }
85
+
86
+ // If this is a simple product, the "Submit" button has the product ID as "value", we need to include it explicitly
87
+ data[ 'ppec-add-to-cart' ] = $( '[name=add-to-cart]' ).val();
88
+
89
  $.ajax( {
90
  type: 'POST',
91
  data: data,
changelog.txt CHANGED
@@ -1,5 +1,13 @@
1
  *** Changelog ***
2
 
 
 
 
 
 
 
 
 
3
  = 1.6.5 - 2018-10-31 =
4
  * Fix - Truncate the line item descriptions to avoid exceeding PayPal character limits.
5
  * Update - WC 3.5 compatibility.
1
  *** Changelog ***
2
 
3
+ = 1.6.6 - 2019-01-09 =
4
+ * Fix - Discount items were not being included
5
+ * Add - Filter for order details to accept decimal quantities of products
6
+ * Fix - Unable to buy variation from product page
7
+ * Fix - Can use PayPal from product page without inputting required fields
8
+ * Add - Display PayPal fees under the totals on the order admin page
9
+ * Add - Prefill name, phone, and email info in PayPal Guest Checkout from checkout screen
10
+
11
  = 1.6.5 - 2018-10-31 =
12
  * Fix - Truncate the line item descriptions to avoid exceeding PayPal character limits.
13
  * Update - WC 3.5 compatibility.
includes/class-wc-gateway-ppec-address.php CHANGED
@@ -654,7 +654,8 @@ class PayPal_Address {
654
  $prefix . 'CITY' => $this->_city,
655
  $prefix . 'STATE' => $this->_state,
656
  $prefix . 'ZIP' => $this->_zip,
657
- $prefix . 'COUNTRYCODE' => $this->_country
 
658
  );
659
 
660
  return $params;
654
  $prefix . 'CITY' => $this->_city,
655
  $prefix . 'STATE' => $this->_state,
656
  $prefix . 'ZIP' => $this->_zip,
657
+ $prefix . 'COUNTRYCODE' => $this->_country,
658
+ $prefix . 'PHONENUM' => $this->_phoneNumber,
659
  );
660
 
661
  return $params;
includes/class-wc-gateway-ppec-admin-handler.php CHANGED
@@ -29,6 +29,8 @@ class WC_Gateway_PPEC_Admin_Handler {
29
 
30
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_redirect_to_ppec_settings' ) );
31
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_reset_api_credentials' ) );
 
 
32
  }
33
 
34
  public function add_capture_charge_order_action( $actions ) {
@@ -297,4 +299,52 @@ class WC_Gateway_PPEC_Admin_Handler {
297
 
298
  wp_safe_redirect( wc_gateway_ppec()->get_admin_setting_link() );
299
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
300
  }
29
 
30
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_redirect_to_ppec_settings' ) );
31
  add_action( 'load-woocommerce_page_wc-settings', array( $this, 'maybe_reset_api_credentials' ) );
32
+
33
+ add_action( 'woocommerce_admin_order_totals_after_total', array( $this, 'display_order_fee_and_payout' ) );
34
  }
35
 
36
  public function add_capture_charge_order_action( $actions ) {
299
 
300
  wp_safe_redirect( wc_gateway_ppec()->get_admin_setting_link() );
301
  }
302
+
303
+ /**
304
+ * Displays the PayPal fee and the net total of the transaction without the PayPal charges
305
+ *
306
+ * @since 1.6.6
307
+ *
308
+ * @param int $order_id
309
+ */
310
+ public function display_order_fee_and_payout( $order_id ) {
311
+ $order = wc_get_order( $order_id );
312
+
313
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
314
+ $payment_method = $old_wc ? $order->payment_method : $order->get_payment_method();
315
+ $paypal_fee = wc_gateway_ppec_get_transaction_fee( $order );
316
+ $order_currency = $old_wc ? $order->order_currency : $order->get_currency();
317
+ $order_total = $old_wc ? $order->order_total : $order->get_total();
318
+
319
+ if ( 'ppec_paypal' !== $payment_method || ! is_numeric( $paypal_fee ) ) {
320
+ return;
321
+ }
322
+
323
+ $net = $order_total - $paypal_fee;
324
+
325
+ ?>
326
+
327
+ <tr>
328
+ <td class="label ppec-fee">
329
+ <?php echo wc_help_tip( __( 'This represents the fee PayPal collects for the transaction.', 'woocommerce-gateway-paypal-express-checkout' ) ); ?>
330
+ <?php esc_html_e( 'PayPal Fee:', 'woocommerce-gateway-paypal-express-checkout' ); ?>
331
+ </td>
332
+ <td width="1%"></td>
333
+ <td class="total">
334
+ -&nbsp;<?php echo wc_price( $paypal_fee, array( 'currency' => $order_currency ) ); ?>
335
+ </td>
336
+ </tr>
337
+ <tr>
338
+ <td class="label ppec-payout">
339
+ <?php echo wc_help_tip( __( 'This represents the net total that will be credited to your PayPal account. This may be in a different currency than is set in your PayPal account.', 'woocommerce-gateway-paypal-express-checkout' ) ); ?>
340
+ <?php esc_html_e( 'PayPal Payout:', 'woocommerce-gateway-paypal-express-checkout' ); ?>
341
+ </td>
342
+ <td width="1%"></td>
343
+ <td class="total">
344
+ <?php echo wc_price( $net, array( 'currency' => $order_currency ) ); ?>
345
+ </td>
346
+ </tr>
347
+
348
+ <?php
349
+ }
350
  }
includes/class-wc-gateway-ppec-cart-handler.php CHANGED
@@ -53,6 +53,7 @@ class WC_Gateway_PPEC_Cart_Handler {
53
 
54
  /**
55
  * Generates the cart for PayPal Checkout on a product level.
 
56
  *
57
  * @since 1.4.0
58
  */
@@ -70,8 +71,8 @@ class WC_Gateway_PPEC_Cart_Handler {
70
  WC()->shipping->reset_shipping();
71
  $product = wc_get_product( $post->ID );
72
 
73
- if ( ! empty( $_POST['add-to-cart'] ) ) {
74
- $product = wc_get_product( absint( $_POST['add-to-cart'] ) );
75
  }
76
 
77
  /**
@@ -80,11 +81,11 @@ class WC_Gateway_PPEC_Cart_Handler {
80
  * simple or variable product.
81
  */
82
  if ( $product ) {
83
- $qty = ! isset( $_POST['qty'] ) ? 1 : absint( $_POST['qty'] );
84
  wc_empty_cart();
85
 
86
  if ( $product->is_type( 'variable' ) ) {
87
- $attributes = array_map( 'wc_clean', $_POST['attributes'] );
88
 
89
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
90
  $variation_id = $product->get_matching_variation( $attributes );
@@ -93,7 +94,7 @@ class WC_Gateway_PPEC_Cart_Handler {
93
  $variation_id = $data_store->find_matching_product_variation( $product, $attributes );
94
  }
95
 
96
- WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id, $attributes );
97
  } else {
98
  WC()->cart->add_to_cart( $product->get_id(), $qty );
99
  }
@@ -193,59 +194,70 @@ class WC_Gateway_PPEC_Cart_Handler {
193
 
194
  $billing_first_name = empty( $data[ 'billing_first_name' ] ) ? '' : wc_clean( $data[ 'billing_first_name' ] );
195
  $billing_last_name = empty( $data[ 'billing_last_name' ] ) ? '' : wc_clean( $data[ 'billing_last_name' ] );
 
196
  $billing_address_1 = empty( $data[ 'billing_address_1' ] ) ? '' : wc_clean( $data[ 'billing_address_1' ] );
197
  $billing_address_2 = empty( $data[ 'billing_address_2' ] ) ? '' : wc_clean( $data[ 'billing_address_2' ] );
198
  $billing_city = empty( $data[ 'billing_city' ] ) ? '' : wc_clean( $data[ 'billing_city' ] );
199
  $billing_state = empty( $data[ 'billing_state' ] ) ? '' : wc_clean( $data[ 'billing_state' ] );
200
  $billing_postcode = empty( $data[ 'billing_postcode' ] ) ? '' : wc_clean( $data[ 'billing_postcode' ] );
201
- $billing_country = empty( $data[ 'billing_country' ] ) ? '' : wc_clean( $data[ 'billing_country' ] );
 
202
 
203
  if ( isset( $data['ship_to_different_address'] ) ) {
204
  $shipping_first_name = empty( $data[ 'shipping_first_name' ] ) ? '' : wc_clean( $data[ 'shipping_first_name' ] );
205
  $shipping_last_name = empty( $data[ 'shipping_last_name' ] ) ? '' : wc_clean( $data[ 'shipping_last_name' ] );
 
206
  $shipping_address_1 = empty( $data[ 'shipping_address_1' ] ) ? '' : wc_clean( $data[ 'shipping_address_1' ] );
207
  $shipping_address_2 = empty( $data[ 'shipping_address_2' ] ) ? '' : wc_clean( $data[ 'shipping_address_2' ] );
208
  $shipping_city = empty( $data[ 'shipping_city' ] ) ? '' : wc_clean( $data[ 'shipping_city' ] );
209
  $shipping_state = empty( $data[ 'shipping_state' ] ) ? '' : wc_clean( $data[ 'shipping_state' ] );
210
  $shipping_postcode = empty( $data[ 'shipping_postcode' ] ) ? '' : wc_clean( $data[ 'shipping_postcode' ] );
211
- $shipping_country = empty( $data[ 'shipping_country' ] ) ? '' : wc_clean( $data[ 'shipping_country' ] );
212
  } else {
213
  $shipping_first_name = $billing_first_name;
214
  $shipping_last_name = $billing_last_name;
 
215
  $shipping_address_1 = $billing_address_1;
216
  $shipping_address_2 = $billing_address_2;
217
  $shipping_city = $billing_city;
218
  $shipping_state = $billing_state;
219
  $shipping_postcode = $billing_postcode;
220
- $shipping_country = $billing_country;
221
  }
222
 
 
223
  $customer->set_shipping_address( $shipping_address_1 );
224
  $customer->set_shipping_address_2( $shipping_address_2 );
225
  $customer->set_shipping_city( $shipping_city );
226
  $customer->set_shipping_state( $shipping_state );
227
  $customer->set_shipping_postcode( $shipping_postcode );
228
- $customer->set_shipping_country( $shipping_country );
229
 
230
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
 
 
 
 
 
 
231
  $customer->set_address( $billing_address_1 );
232
  $customer->set_address_2( $billing_address_2 );
233
  $customer->set_city( $billing_city );
234
  $customer->set_state( $billing_state );
235
  $customer->set_postcode( $billing_postcode );
236
- $customer->set_country( $billing_country );
 
237
  } else {
238
  $customer->set_shipping_first_name( $shipping_first_name );
239
  $customer->set_shipping_last_name( $shipping_last_name );
240
  $customer->set_billing_first_name( $billing_first_name );
241
  $customer->set_billing_last_name( $billing_last_name );
242
 
 
243
  $customer->set_billing_address_1( $billing_address_1 );
244
  $customer->set_billing_address_2( $billing_address_2 );
245
  $customer->set_billing_city( $billing_city );
246
  $customer->set_billing_state( $billing_state );
247
  $customer->set_billing_postcode( $billing_postcode );
248
- $customer->set_billing_country( $billing_country );
 
249
  }
250
  }
251
 
53
 
54
  /**
55
  * Generates the cart for PayPal Checkout on a product level.
56
+ * TODO: Why not let the default "add-to-cart" PHP form handler insert the product into the cart? Investigate.
57
  *
58
  * @since 1.4.0
59
  */
71
  WC()->shipping->reset_shipping();
72
  $product = wc_get_product( $post->ID );
73
 
74
+ if ( ! empty( $_POST['ppec-add-to-cart'] ) ) {
75
+ $product = wc_get_product( absint( $_POST['ppec-add-to-cart'] ) );
76
  }
77
 
78
  /**
81
  * simple or variable product.
82
  */
83
  if ( $product ) {
84
+ $qty = ! isset( $_POST['quantity'] ) ? 1 : absint( $_POST['quantity'] );
85
  wc_empty_cart();
86
 
87
  if ( $product->is_type( 'variable' ) ) {
88
+ $attributes = array_map( 'wc_clean', $_POST );
89
 
90
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
91
  $variation_id = $product->get_matching_variation( $attributes );
94
  $variation_id = $data_store->find_matching_product_variation( $product, $attributes );
95
  }
96
 
97
+ WC()->cart->add_to_cart( $product->get_id(), $qty, $variation_id );
98
  } else {
99
  WC()->cart->add_to_cart( $product->get_id(), $qty );
100
  }
194
 
195
  $billing_first_name = empty( $data[ 'billing_first_name' ] ) ? '' : wc_clean( $data[ 'billing_first_name' ] );
196
  $billing_last_name = empty( $data[ 'billing_last_name' ] ) ? '' : wc_clean( $data[ 'billing_last_name' ] );
197
+ $billing_country = empty( $data[ 'billing_country' ] ) ? '' : wc_clean( $data[ 'billing_country' ] );
198
  $billing_address_1 = empty( $data[ 'billing_address_1' ] ) ? '' : wc_clean( $data[ 'billing_address_1' ] );
199
  $billing_address_2 = empty( $data[ 'billing_address_2' ] ) ? '' : wc_clean( $data[ 'billing_address_2' ] );
200
  $billing_city = empty( $data[ 'billing_city' ] ) ? '' : wc_clean( $data[ 'billing_city' ] );
201
  $billing_state = empty( $data[ 'billing_state' ] ) ? '' : wc_clean( $data[ 'billing_state' ] );
202
  $billing_postcode = empty( $data[ 'billing_postcode' ] ) ? '' : wc_clean( $data[ 'billing_postcode' ] );
203
+ $billing_phone = empty( $data[ 'billing_phone' ] ) ? '' : wc_clean( $data[ 'billing_phone' ] );
204
+ $billing_email = empty( $data[ 'billing_email' ] ) ? '' : wc_clean( $data[ 'billing_email' ] );
205
 
206
  if ( isset( $data['ship_to_different_address'] ) ) {
207
  $shipping_first_name = empty( $data[ 'shipping_first_name' ] ) ? '' : wc_clean( $data[ 'shipping_first_name' ] );
208
  $shipping_last_name = empty( $data[ 'shipping_last_name' ] ) ? '' : wc_clean( $data[ 'shipping_last_name' ] );
209
+ $shipping_country = empty( $data[ 'shipping_country' ] ) ? '' : wc_clean( $data[ 'shipping_country' ] );
210
  $shipping_address_1 = empty( $data[ 'shipping_address_1' ] ) ? '' : wc_clean( $data[ 'shipping_address_1' ] );
211
  $shipping_address_2 = empty( $data[ 'shipping_address_2' ] ) ? '' : wc_clean( $data[ 'shipping_address_2' ] );
212
  $shipping_city = empty( $data[ 'shipping_city' ] ) ? '' : wc_clean( $data[ 'shipping_city' ] );
213
  $shipping_state = empty( $data[ 'shipping_state' ] ) ? '' : wc_clean( $data[ 'shipping_state' ] );
214
  $shipping_postcode = empty( $data[ 'shipping_postcode' ] ) ? '' : wc_clean( $data[ 'shipping_postcode' ] );
 
215
  } else {
216
  $shipping_first_name = $billing_first_name;
217
  $shipping_last_name = $billing_last_name;
218
+ $shipping_country = $billing_country;
219
  $shipping_address_1 = $billing_address_1;
220
  $shipping_address_2 = $billing_address_2;
221
  $shipping_city = $billing_city;
222
  $shipping_state = $billing_state;
223
  $shipping_postcode = $billing_postcode;
 
224
  }
225
 
226
+ $customer->set_shipping_country( $shipping_country );
227
  $customer->set_shipping_address( $shipping_address_1 );
228
  $customer->set_shipping_address_2( $shipping_address_2 );
229
  $customer->set_shipping_city( $shipping_city );
230
  $customer->set_shipping_state( $shipping_state );
231
  $customer->set_shipping_postcode( $shipping_postcode );
 
232
 
233
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
234
+ $customer->shipping_first_name = $shipping_first_name;
235
+ $customer->shipping_last_name = $shipping_last_name;
236
+ $customer->billing_first_name = $billing_first_name;
237
+ $customer->billing_last_name = $billing_last_name;
238
+
239
+ $customer->set_country( $billing_country );
240
  $customer->set_address( $billing_address_1 );
241
  $customer->set_address_2( $billing_address_2 );
242
  $customer->set_city( $billing_city );
243
  $customer->set_state( $billing_state );
244
  $customer->set_postcode( $billing_postcode );
245
+ $customer->billing_phone = $billing_phone;
246
+ $customer->billing_email = $billing_email;
247
  } else {
248
  $customer->set_shipping_first_name( $shipping_first_name );
249
  $customer->set_shipping_last_name( $shipping_last_name );
250
  $customer->set_billing_first_name( $billing_first_name );
251
  $customer->set_billing_last_name( $billing_last_name );
252
 
253
+ $customer->set_billing_country( $billing_country );
254
  $customer->set_billing_address_1( $billing_address_1 );
255
  $customer->set_billing_address_2( $billing_address_2 );
256
  $customer->set_billing_city( $billing_city );
257
  $customer->set_billing_state( $billing_state );
258
  $customer->set_billing_postcode( $billing_postcode );
259
+ $customer->set_billing_phone( $billing_phone );
260
+ $customer->set_billing_email( $billing_email );
261
  }
262
  }
263
 
includes/class-wc-gateway-ppec-checkout-handler.php CHANGED
@@ -939,6 +939,9 @@ class WC_Gateway_PPEC_Checkout_Handler {
939
  // Handle $payment response
940
  if ( 'completed' === strtolower( $payment->payment_status ) ) {
941
  $order->payment_complete( $payment->transaction_id );
 
 
 
942
  } else {
943
  if ( 'authorization' === $payment->pending_reason ) {
944
  $order->update_status( 'on-hold', __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce-gateway-paypal-express-checkout' ) );
939
  // Handle $payment response
940
  if ( 'completed' === strtolower( $payment->payment_status ) ) {
941
  $order->payment_complete( $payment->transaction_id );
942
+ if ( isset( $payment->fee_amount ) ){
943
+ wc_gateway_ppec_set_transaction_fee( $order, $payment->fee_amount );
944
+ }
945
  } else {
946
  if ( 'authorization' === $payment->pending_reason ) {
947
  $order->update_status( 'on-hold', __( 'Payment authorized. Change payment status to processing or complete to capture funds.', 'woocommerce-gateway-paypal-express-checkout' ) );
includes/class-wc-gateway-ppec-client.php CHANGED
@@ -307,6 +307,10 @@ class WC_Gateway_PPEC_Client {
307
  )
308
  );
309
 
 
 
 
 
310
  if ( $args['create_billing_agreement'] ) {
311
  $params['L_BILLINGTYPE0'] = 'MerchantInitiatedBillingSingleAgreement';
312
  $params['L_BILLINGAGREEMENTDESCRIPTION0'] = $this->_get_billing_agreement_description();
@@ -432,7 +436,6 @@ class WC_Gateway_PPEC_Client {
432
 
433
  return array(
434
  'name' => 'Discount',
435
- 'description' => 'Discount Amount',
436
  'quantity' => 1,
437
  'amount' => '-' . round( $amount, $decimals ),
438
  );
@@ -450,6 +453,7 @@ class WC_Gateway_PPEC_Client {
450
  */
451
  protected function _get_details_from_cart() {
452
  $settings = wc_gateway_ppec()->settings;
 
453
 
454
  $decimals = $settings->get_number_of_decimal_digits();
455
  $rounded_total = $this->_get_rounded_total_in_cart();
@@ -461,6 +465,7 @@ class WC_Gateway_PPEC_Client {
461
  'shipping' => round( WC()->cart->shipping_total, $decimals ),
462
  'items' => $this->_get_paypal_line_items_from_cart(),
463
  'shipping_address' => $this->_get_address_from_customer(),
 
464
  );
465
 
466
  return $this->get_details( $details, $discounts, $rounded_total, WC()->cart->total );
@@ -479,7 +484,7 @@ class WC_Gateway_PPEC_Client {
479
 
480
  $items = array();
481
  foreach ( WC()->cart->cart_contents as $cart_item_key => $values ) {
482
- $amount = round( $values['line_total'] / $values['quantity'] , $decimals );
483
 
484
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
485
  $name = $values['data']->post->post_title;
@@ -572,6 +577,9 @@ class WC_Gateway_PPEC_Client {
572
  if ( $details['total_item_amount'] == $discounts ) {
573
  // Omit line items altogether.
574
  unset( $details['items'] );
 
 
 
575
  }
576
 
577
  $details['ship_discount_amount'] = 0;
@@ -616,7 +624,18 @@ class WC_Gateway_PPEC_Client {
616
  $details['items'][] = $this->_get_extra_offset_line_item( $details['total_item_amount'] - $lisum );
617
  }
618
 
619
- return $details;
 
 
 
 
 
 
 
 
 
 
 
620
  }
621
 
622
  /**
@@ -690,8 +709,12 @@ class WC_Gateway_PPEC_Client {
690
  }
691
  $shipping_address->setCountry( $shipping_country );
692
 
 
 
693
  $details['shipping_address'] = $shipping_address;
694
 
 
 
695
  return $details;
696
  }
697
 
@@ -708,8 +731,8 @@ class WC_Gateway_PPEC_Client {
708
  $old_wc = version_compare( WC_VERSION, '3.0', '<' );
709
 
710
  if ( $customer->get_shipping_address() || $customer->get_shipping_address_2() ) {
711
- $shipping_first_name = $old_wc ? '' : $customer->get_shipping_first_name();
712
- $shipping_last_name = $old_wc ? '' : $customer->get_shipping_last_name();
713
  $shipping_address_1 = $customer->get_shipping_address();
714
  $shipping_address_2 = $customer->get_shipping_address_2();
715
  $shipping_city = $customer->get_shipping_city();
@@ -719,14 +742,14 @@ class WC_Gateway_PPEC_Client {
719
  } else {
720
  // Fallback to billing in case no shipping methods are set. The address returned from PayPal
721
  // will be stored in the order as billing.
722
- $shipping_first_name = $old_wc ? '' : $customer->get_billing_first_name();
723
- $shipping_last_name = $old_wc ? '' : $customer->get_billing_last_name();
724
- $shipping_address_1 = $old_wc ? $customer->get_address() : $customer->get_billing_address_1();
725
- $shipping_address_2 = $old_wc ? $customer->get_address_2() : $customer->get_billing_address_2();
726
- $shipping_city = $old_wc ? $customer->get_city() : $customer->get_billing_city();
727
- $shipping_state = $old_wc ? $customer->get_state() : $customer->get_billing_state();
728
- $shipping_postcode = $old_wc ? $customer->get_postcode() : $customer->get_billing_postcode();
729
- $shipping_country = $old_wc ? $customer->get_country() : $customer->get_billing_country();
730
  }
731
 
732
  $shipping_address->setName( $shipping_first_name . ' ' . $shipping_last_name );
@@ -736,6 +759,7 @@ class WC_Gateway_PPEC_Client {
736
  $shipping_address->setState( $shipping_state );
737
  $shipping_address->setZip( $shipping_postcode );
738
  $shipping_address->setCountry( $shipping_country );
 
739
 
740
  return $shipping_address;
741
  }
307
  )
308
  );
309
 
310
+ if ( ! empty( $details['email'] ) ) {
311
+ $params['EMAIL'] = $details['email'];
312
+ }
313
+
314
  if ( $args['create_billing_agreement'] ) {
315
  $params['L_BILLINGTYPE0'] = 'MerchantInitiatedBillingSingleAgreement';
316
  $params['L_BILLINGAGREEMENTDESCRIPTION0'] = $this->_get_billing_agreement_description();
436
 
437
  return array(
438
  'name' => 'Discount',
 
439
  'quantity' => 1,
440
  'amount' => '-' . round( $amount, $decimals ),
441
  );
453
  */
454
  protected function _get_details_from_cart() {
455
  $settings = wc_gateway_ppec()->settings;
456
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
457
 
458
  $decimals = $settings->get_number_of_decimal_digits();
459
  $rounded_total = $this->_get_rounded_total_in_cart();
465
  'shipping' => round( WC()->cart->shipping_total, $decimals ),
466
  'items' => $this->_get_paypal_line_items_from_cart(),
467
  'shipping_address' => $this->_get_address_from_customer(),
468
+ 'email' => $old_wc ? WC()->customer->billing_email : WC()->customer->get_billing_email(),
469
  );
470
 
471
  return $this->get_details( $details, $discounts, $rounded_total, WC()->cart->total );
484
 
485
  $items = array();
486
  foreach ( WC()->cart->cart_contents as $cart_item_key => $values ) {
487
+ $amount = round( $values['line_subtotal'] / $values['quantity'] , $decimals );
488
 
489
  if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
490
  $name = $values['data']->post->post_title;
577
  if ( $details['total_item_amount'] == $discounts ) {
578
  // Omit line items altogether.
579
  unset( $details['items'] );
580
+ } else if ( $discounts > 0 && $discounts < $details['total_item_amount'] ) {
581
+ // Else if there is discount, add them to the line-items
582
+ $details['items'][] = $this->_get_extra_discount_line_item($discounts);
583
  }
584
 
585
  $details['ship_discount_amount'] = 0;
624
  $details['items'][] = $this->_get_extra_offset_line_item( $details['total_item_amount'] - $lisum );
625
  }
626
 
627
+ /**
628
+ * Filter PayPal order details.
629
+ *
630
+ * Provide opportunity for developers to modify details passed to PayPal.
631
+ * This was originally introduced to add a mechanism to allow for
632
+ * decimal product quantity support.
633
+ *
634
+ * @since 1.6.6
635
+ *
636
+ * @param array $details Current PayPal order details
637
+ */
638
+ return apply_filters( 'woocommerce_paypal_express_checkout_get_details', $details );
639
  }
640
 
641
  /**
709
  }
710
  $shipping_address->setCountry( $shipping_country );
711
 
712
+ $shipping_address->setPhoneNumber( $old_wc ? $order->billing_phone : $order->get_billing_phone() );
713
+
714
  $details['shipping_address'] = $shipping_address;
715
 
716
+ $details['email'] = $old_wc ? $order->billing_email : $order->get_billing_email();
717
+
718
  return $details;
719
  }
720
 
731
  $old_wc = version_compare( WC_VERSION, '3.0', '<' );
732
 
733
  if ( $customer->get_shipping_address() || $customer->get_shipping_address_2() ) {
734
+ $shipping_first_name = $old_wc ? $customer->shipping_first_name : $customer->get_shipping_first_name();
735
+ $shipping_last_name = $old_wc ? $customer->shipping_last_name : $customer->get_shipping_last_name();
736
  $shipping_address_1 = $customer->get_shipping_address();
737
  $shipping_address_2 = $customer->get_shipping_address_2();
738
  $shipping_city = $customer->get_shipping_city();
742
  } else {
743
  // Fallback to billing in case no shipping methods are set. The address returned from PayPal
744
  // will be stored in the order as billing.
745
+ $shipping_first_name = $old_wc ? $customer->billing_first_name : $customer->get_billing_first_name();
746
+ $shipping_last_name = $old_wc ? $customer->billing_last_name : $customer->get_billing_last_name();
747
+ $shipping_address_1 = $old_wc ? $customer->get_address() : $customer->get_billing_address_1();
748
+ $shipping_address_2 = $old_wc ? $customer->get_address_2() : $customer->get_billing_address_2();
749
+ $shipping_city = $old_wc ? $customer->get_city() : $customer->get_billing_city();
750
+ $shipping_state = $old_wc ? $customer->get_state() : $customer->get_billing_state();
751
+ $shipping_postcode = $old_wc ? $customer->get_postcode() : $customer->get_billing_postcode();
752
+ $shipping_country = $old_wc ? $customer->get_country() : $customer->get_billing_country();
753
  }
754
 
755
  $shipping_address->setName( $shipping_first_name . ' ' . $shipping_last_name );
759
  $shipping_address->setState( $shipping_state );
760
  $shipping_address->setZip( $shipping_postcode );
761
  $shipping_address->setCountry( $shipping_country );
762
+ $shipping_address->setPhoneNumber( $old_wc ? $customer->billing_phone : $customer->get_billing_phone() );
763
 
764
  return $shipping_address;
765
  }
includes/class-wc-gateway-ppec-ipn-handler.php CHANGED
@@ -166,9 +166,10 @@ class WC_Gateway_PPEC_IPN_Handler extends WC_Gateway_PPEC_PayPal_Request_Handler
166
  * @param array $posted_data Posted data
167
  */
168
  protected function payment_status_completed( $order, $posted_data ) {
169
- $order_id = version_compare( WC_VERSION, '3.0', '<' ) ? $order->id : $order->get_id();
 
170
 
171
- if ( $order->has_status( array( 'processing', 'completed' ) ) ) {
172
  wc_gateway_ppec_log( 'Aborting, Order #' . $order_id . ' is already complete.' );
173
  exit;
174
  }
@@ -182,8 +183,7 @@ class WC_Gateway_PPEC_IPN_Handler extends WC_Gateway_PPEC_PayPal_Request_Handler
182
  $this->payment_complete( $order, ( ! empty( $posted_data['txn_id'] ) ? wc_clean( $posted_data['txn_id'] ) : '' ), __( 'IPN payment completed', 'woocommerce-gateway-paypal-express-checkout' ) );
183
  if ( ! empty( $posted_data['mc_fee'] ) ) {
184
  // Log paypal transaction fee.
185
- $transaction_fee = wc_clean( $posted_data['mc_fee'] );
186
- update_post_meta( $order_id, 'PayPal Transaction Fee', $transaction_fee );
187
  }
188
  } else {
189
  if ( 'authorization' === $posted_data['pending_reason'] ) {
@@ -321,6 +321,10 @@ class WC_Gateway_PPEC_IPN_Handler extends WC_Gateway_PPEC_PayPal_Request_Handler
321
  }
322
  }
323
 
 
 
 
 
324
  if ( ! empty( $posted_data['txn_id'] ) ) {
325
  update_post_meta( $old_wc ? $order->id : $order->get_id(), '_transaction_id', wc_clean( $posted_data['txn_id'] ) );
326
  }
166
  * @param array $posted_data Posted data
167
  */
168
  protected function payment_status_completed( $order, $posted_data ) {
169
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
170
+ $order_id = $old_wc ? $order->id : $order->get_id();
171
 
172
+ if ( $order->has_status( array( 'completed' ) ) ) {
173
  wc_gateway_ppec_log( 'Aborting, Order #' . $order_id . ' is already complete.' );
174
  exit;
175
  }
183
  $this->payment_complete( $order, ( ! empty( $posted_data['txn_id'] ) ? wc_clean( $posted_data['txn_id'] ) : '' ), __( 'IPN payment completed', 'woocommerce-gateway-paypal-express-checkout' ) );
184
  if ( ! empty( $posted_data['mc_fee'] ) ) {
185
  // Log paypal transaction fee.
186
+ wc_gateway_ppec_set_transaction_fee( $order, $posted_data['mc_fee'] );
 
187
  }
188
  } else {
189
  if ( 'authorization' === $posted_data['pending_reason'] ) {
321
  }
322
  }
323
 
324
+ if ( ! $old_wc ) {
325
+ $order->save_meta_data();
326
+ }
327
+
328
  if ( ! empty( $posted_data['txn_id'] ) ) {
329
  update_post_meta( $old_wc ? $order->id : $order->get_id(), '_transaction_id', wc_clean( $posted_data['txn_id'] ) );
330
  }
includes/functions.php CHANGED
@@ -90,3 +90,67 @@ function wc_gateway_ppec_is_credit_supported() {
90
  function wc_gateway_ppec_is_using_credit() {
91
  return ! empty( $_GET['use-ppc'] ) && 'true' === $_GET['use-ppc'];
92
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
  function wc_gateway_ppec_is_using_credit() {
91
  return ! empty( $_GET['use-ppc'] ) && 'true' === $_GET['use-ppc'];
92
  }
93
+
94
+ const PPEC_FEE_META_NAME_OLD = 'PayPal Transaction Fee';
95
+ const PPEC_FEE_META_NAME_NEW = '_paypal_transaction_fee';
96
+
97
+ /**
98
+ * Sets the PayPal Fee in the order metadata
99
+ *
100
+ * @since 1.6.6
101
+ *
102
+ * @param object $order Order to modify
103
+ * @param string $fee Fee to save
104
+ */
105
+ function wc_gateway_ppec_set_transaction_fee( $order, $fee ) {
106
+ if ( empty( $fee ) ) {
107
+ return;
108
+ }
109
+ $fee = wc_clean( $fee );
110
+ if ( version_compare( WC_VERSION, '3.0', '<' ) ) {
111
+ update_post_meta( $order->id, PPEC_FEE_META_NAME_NEW, $fee );
112
+ } else {
113
+ $order->update_meta_data( PPEC_FEE_META_NAME_NEW, $fee );
114
+ $order->save_meta_data();
115
+ }
116
+ }
117
+
118
+ /**
119
+ * Gets the PayPal Fee from the order metadata, migrates if the fee was saved under a legacy key
120
+ *
121
+ * @since 1.6.6
122
+ *
123
+ * @param object $order Order to read
124
+ * @return string Returns the fee or an empty string if the fee has not been set on the order
125
+ */
126
+ function wc_gateway_ppec_get_transaction_fee( $order ) {
127
+ $old_wc = version_compare( WC_VERSION, '3.0', '<' );
128
+
129
+ //retrieve the fee using the new key
130
+ if ( $old_wc ) {
131
+ $fee = get_post_meta( $order->id, PPEC_FEE_META_NAME_NEW, true );
132
+ } else {
133
+ $fee = $order->get_meta( PPEC_FEE_META_NAME_NEW, true );
134
+ }
135
+
136
+ //if the fee was found, return
137
+ if ( is_numeric( $fee ) ) {
138
+ return $fee;
139
+ }
140
+
141
+ //attempt to retrieve the old meta, delete its old key, and migrate it to the new one
142
+ if ( $old_wc ) {
143
+ $fee = get_post_meta( $order->id, PPEC_FEE_META_NAME_OLD, true );
144
+ delete_post_meta( $order->id, PPEC_FEE_META_NAME_OLD );
145
+ } else {
146
+ $fee = $order->get_meta( PPEC_FEE_META_NAME_OLD, true );
147
+ $order->delete_meta_data( PPEC_FEE_META_NAME_OLD );
148
+ $order->save_meta_data();
149
+ }
150
+
151
+ if ( is_numeric( $fee ) ) {
152
+ wc_gateway_ppec_set_transaction_fee( $order, $fee );
153
+ }
154
+
155
+ return $fee;
156
+ }
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: automattic, woothemes, akeda, dwainm, royho, allendav, slash1andy, woosteve, spraveenitpro, mikedmoore, fernashes, shellbeezy, danieldudzic, mikaey, fullysupportedphil, dsmithweb, corsonr, bor0, zandyring, pauldechov
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.9.8
6
- Stable tag: 1.6.5
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
@@ -101,6 +101,14 @@ Please use this to inform us about bugs, or make contributions via PRs.
101
 
102
  == Changelog ==
103
 
 
 
 
 
 
 
 
 
104
  = 1.6.5 - 2018-10-31 =
105
  * Fix - Truncate the line item descriptions to avoid exceeding PayPal character limits.
106
  * Update - WC 3.5 compatibility.
2
  Contributors: automattic, woothemes, akeda, dwainm, royho, allendav, slash1andy, woosteve, spraveenitpro, mikedmoore, fernashes, shellbeezy, danieldudzic, mikaey, fullysupportedphil, dsmithweb, corsonr, bor0, zandyring, pauldechov
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: 5.0.2
6
+ Stable tag: 1.6.6
7
  License: GPLv3
8
  License URI: http://www.gnu.org/licenses/gpl-3.0.html
9
 
101
 
102
  == Changelog ==
103
 
104
+ = 1.6.6 - 2019-01-09 =
105
+ * Fix - Discount items were not being included
106
+ * Add - Filter for order details to accept decimal quantities of products
107
+ * Fix - Unable to buy variation from product page
108
+ * Fix - Can use PayPal from product page without inputting required fields
109
+ * Add - Display PayPal fees under the totals on the order admin page
110
+ * Add - Prefill name, phone, and email info in PayPal Guest Checkout from checkout screen
111
+
112
  = 1.6.5 - 2018-10-31 =
113
  * Fix - Truncate the line item descriptions to avoid exceeding PayPal character limits.
114
  * Update - WC 3.5 compatibility.
woocommerce-gateway-paypal-express-checkout.php CHANGED
@@ -3,7 +3,7 @@
3
  * Plugin Name: WooCommerce PayPal Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Checkout (https://www.paypal.com/us/webapps/mpp/paypal-checkout).
6
- * Version: 1.6.5
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2018 WooCommerce / PayPal.
3
  * Plugin Name: WooCommerce PayPal Checkout Gateway
4
  * Plugin URI: https://woocommerce.com/products/woocommerce-gateway-paypal-express-checkout/
5
  * Description: A payment gateway for PayPal Checkout (https://www.paypal.com/us/webapps/mpp/paypal-checkout).
6
+ * Version: 1.6.6
7
  * Author: WooCommerce
8
  * Author URI: https://woocommerce.com
9
  * Copyright: © 2018 WooCommerce / PayPal.