WooCommerce Square - Version 1.0.28

Version Description

  • 2018-04-04 =
  • Fix - Double inventory sync for newly created products.
  • Fix - Infinite loop with pagination, where Square keeps sending the same link.
  • Fix - Remove usage of deprecated jQuery method.
  • Fix - Sync job should not be sending anything if there are no stock changes.
  • Fix - Trigger to decrease stock upon purchase not working
  • Tweak - Add logging and skip sync in case store's currency/country is not allowed.
  • Tweak - Improve debug logging when fetching inventory
  • Tweak - Inventory reduction in Square will be treated as stock sale.
Download this release

Release Info

Developer bor0
Plugin Icon 128x128 WooCommerce Square
Version 1.0.28
Comparing to
See all releases

Code changes from version 1.0.27 to 1.0.28

assets/js/wc-square-admin-scripts.js CHANGED
@@ -45,7 +45,11 @@ jQuery( document ).ready( function( $ ) {
45
  });
46
  },
47
 
48
- init: function() {
 
 
 
 
49
 
50
  $( '.woocommerce_page_wc-settings' ).on( 'click', '#wc-to-square, #square-to-wc', function( e ) {
51
  e.preventDefault();
@@ -76,6 +80,11 @@ jQuery( document ).ready( function( $ ) {
76
  $.wc_square_admin.sync( 0, $( this ).attr( 'id' ) );
77
  });
78
 
 
 
 
 
 
79
  $( document.body ).on( 'change', '#woocommerce_square_testmode', function() {
80
  if ( $( this ).is( ':checked' ) ) {
81
  $( '#woocommerce_square_application_id' ).parents( 'tr' ).eq(0).hide();
45
  });
46
  },
47
 
48
+ init_sync_buttons: function() {
49
+ if ( ! wc_square_local.country_currency ) {
50
+ $( '#wc-to-square, #square-to-wc' ).attr( 'disabled', 'disabled' );
51
+ return;
52
+ }
53
 
54
  $( '.woocommerce_page_wc-settings' ).on( 'click', '#wc-to-square, #square-to-wc', function( e ) {
55
  e.preventDefault();
80
  $.wc_square_admin.sync( 0, $( this ).attr( 'id' ) );
81
  });
82
 
83
+ },
84
+
85
+ init: function() {
86
+ this.init_sync_buttons();
87
+
88
  $( document.body ).on( 'change', '#woocommerce_square_testmode', function() {
89
  if ( $( this ).is( ':checked' ) ) {
90
  $( '#woocommerce_square_application_id' ).parents( 'tr' ).eq(0).hide();
assets/js/wc-square-admin-scripts.min.js CHANGED
@@ -1 +1 @@
1
- jQuery(document).ready(function(e){"use strict";e.wc_square_admin={sync:function(o,c){var r={security:wc_square_local.ajaxSyncNonce,process:parseInt(o,10),action:"wc-to-square"===c?"wc_to_square":"square_to_wc"};e.ajax({type:"POST",data:r,url:wc_square_local.admin_ajax_url}).done(function(o){"done"===o.process?(e("body").trigger("woocommerce_square_wc_to_square_sync_complete",[o]),e("table.form-table").unblock(),e(".wc-square-progress-bar span").css({width:o.percentage+"%"}).parent(".wc-square-progress-bar").fadeOut("slow",function(){alert(o.message)})):(e(".wc-square-progress-bar span").css({width:o.percentage+"%"}),e.wc_square_admin.sync(parseInt(o.process,10),o.type))}).fail(function(o,c,r){e("table.form-table").unblock(),console.log(r),alert(r)})},init:function(){e(".woocommerce_page_wc-settings").on("click","#wc-to-square, #square-to-wc",function(o){if(o.preventDefault(),confirm(wc_square_local.i18n.confirm_sync)){var c=e(this).parents("table.form-table"),r=e('<div class="wc-square-progress-bar wc-square-stripes"><span class="step"></span></div>');e(".wc-square-progress-bar").remove(),c.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),c.after(r),e.wc_square_admin.sync(0,e(this).attr("id"))}}),e(document.body).on("change","#woocommerce_square_testmode",function(){e(this).is(":checked")?(e("#woocommerce_square_application_id").parents("tr").eq(0).hide(),e("#woocommerce_square_token").parents("tr").eq(0).hide(),e("#woocommerce_square_sandbox_application_id").parents("tr").eq(0).show(),e("#woocommerce_square_sandbox_token").parents("tr").eq(0).show()):(e("#woocommerce_square_application_id").parents("tr").eq(0).show(),e("#woocommerce_square_token").parents("tr").eq(0).show(),e("#woocommerce_square_sandbox_application_id").parents("tr").eq(0).hide(),e("#woocommerce_square_sandbox_token").parents("tr").eq(0).hide())}),e("#woocommerce_square_testmode").trigger("change"),e(document.body).on("change","#woocommerce_squareconnect_sync_products",function(){e(this).is(":checked")?(e("#woocommerce_squareconnect_sync_categories").parents("tr").eq(0).show(),e("#woocommerce_squareconnect_sync_inventory").parents("tr").eq(0).show(),e("#woocommerce_squareconnect_sync_images").parents("tr").eq(0).show()):(e("#woocommerce_squareconnect_sync_categories").parents("tr").eq(0).hide(),e("#woocommerce_squareconnect_sync_inventory").parents("tr").eq(0).hide(),e("#woocommerce_squareconnect_sync_images").parents("tr").eq(0).hide())}),e("#woocommerce_squareconnect_sync_products").trigger("change")}},e.wc_square_admin.init()});
1
+ jQuery(document).ready(function(e){"use strict";e.wc_square_admin={sync:function(o,c){var r={security:wc_square_local.ajaxSyncNonce,process:parseInt(o,10),action:"wc-to-square"===c?"wc_to_square":"square_to_wc"};e.ajax({type:"POST",data:r,url:wc_square_local.admin_ajax_url}).done(function(o){"done"===o.process?(e("body").trigger("woocommerce_square_wc_to_square_sync_complete",[o]),e("table.form-table").unblock(),e(".wc-square-progress-bar span").css({width:o.percentage+"%"}).parent(".wc-square-progress-bar").fadeOut("slow",function(){alert(o.message)})):(e(".wc-square-progress-bar span").css({width:o.percentage+"%"}),e.wc_square_admin.sync(parseInt(o.process,10),o.type))}).fail(function(o,c,r){e("table.form-table").unblock(),console.log(r),alert(r)})},init_sync_buttons:function(){wc_square_local.country_currency?e(".woocommerce_page_wc-settings").on("click","#wc-to-square, #square-to-wc",function(o){if(o.preventDefault(),confirm(wc_square_local.i18n.confirm_sync)){var c=e(this).parents("table.form-table"),r=e('<div class="wc-square-progress-bar wc-square-stripes"><span class="step"></span></div>');e(".wc-square-progress-bar").remove(),c.block({message:null,overlayCSS:{background:"#fff",opacity:.6}}),c.after(r),e.wc_square_admin.sync(0,e(this).attr("id"))}}):e("#wc-to-square, #square-to-wc").attr("disabled","disabled")},init:function(){this.init_sync_buttons(),e(document.body).on("change","#woocommerce_square_testmode",function(){e(this).is(":checked")?(e("#woocommerce_square_application_id").parents("tr").eq(0).hide(),e("#woocommerce_square_token").parents("tr").eq(0).hide(),e("#woocommerce_square_sandbox_application_id").parents("tr").eq(0).show(),e("#woocommerce_square_sandbox_token").parents("tr").eq(0).show()):(e("#woocommerce_square_application_id").parents("tr").eq(0).show(),e("#woocommerce_square_token").parents("tr").eq(0).show(),e("#woocommerce_square_sandbox_application_id").parents("tr").eq(0).hide(),e("#woocommerce_square_sandbox_token").parents("tr").eq(0).hide())}),e("#woocommerce_square_testmode").trigger("change"),e(document.body).on("change","#woocommerce_squareconnect_sync_products",function(){e(this).is(":checked")?(e("#woocommerce_squareconnect_sync_categories").parents("tr").eq(0).show(),e("#woocommerce_squareconnect_sync_inventory").parents("tr").eq(0).show(),e("#woocommerce_squareconnect_sync_images").parents("tr").eq(0).show()):(e("#woocommerce_squareconnect_sync_categories").parents("tr").eq(0).hide(),e("#woocommerce_squareconnect_sync_inventory").parents("tr").eq(0).hide(),e("#woocommerce_squareconnect_sync_images").parents("tr").eq(0).hide())}),e("#woocommerce_squareconnect_sync_products").trigger("change")}},e.wc_square_admin.init()});
assets/js/wc-square-payments.js CHANGED
@@ -114,7 +114,7 @@
114
  // remove any error messages first
115
  $( '.payment_method_square .woocommerce-error' ).remove();
116
 
117
- if ( $( '#payment_method_square' ).is( ':checked' ) && $( 'input.square-nonce' ).size() === 0 ) {
118
  wcSquarePaymentForm.requestCardNonce();
119
 
120
  return false;
@@ -128,7 +128,7 @@
128
  // remove any error messages first
129
  $( '.payment_method_square .woocommerce-error' ).remove();
130
 
131
- if ( $( '#payment_method_square' ).is( ':checked' ) && $( 'input.square-nonce' ).size() === 0 ) {
132
  wcSquarePaymentForm.requestCardNonce();
133
 
134
  return false;
114
  // remove any error messages first
115
  $( '.payment_method_square .woocommerce-error' ).remove();
116
 
117
+ if ( $( '#payment_method_square' ).is( ':checked' ) && $( 'input.square-nonce' ).length === 0 ) {
118
  wcSquarePaymentForm.requestCardNonce();
119
 
120
  return false;
128
  // remove any error messages first
129
  $( '.payment_method_square .woocommerce-error' ).remove();
130
 
131
+ if ( $( '#payment_method_square' ).is( ':checked' ) && $( 'input.square-nonce' ).length === 0 ) {
132
  wcSquarePaymentForm.requestCardNonce();
133
 
134
  return false;
assets/js/wc-square-payments.min.js CHANGED
@@ -1 +1 @@
1
- !function(e){"use strict";var o;e.wc_square_payments={init:function(){e(document.body).on("updated_checkout",function(){e.wc_square_payments.loadForm()}),e("form#order_review").length&&e.wc_square_payments.loadForm();var o=square_params.custom_form_trigger_element;o.length&&e(document.body).on("click",o,function(){e.wc_square_payments.loadForm()}),e(document.body).on("click","#payment_method_square",function(){e(".payment_box.payment_method_square").css({display:"block",visibility:"visible",height:"auto"})})},loadForm:function(){e("#payment_method_square").length&&(e("#payment_method_square").is(":checked")||e(".payment_box.payment_method_square").css({display:"block",visibility:"hidden",height:"0"}),"object"===e.type(o)&&o.destroy(),(o=new SqPaymentForm({env:square_params.environment,applicationId:square_params.application_id,inputClass:"sq-input",cardNumber:{elementId:"sq-card-number",placeholder:square_params.placeholder_card_number},cvv:{elementId:"sq-cvv",placeholder:square_params.placeholder_card_cvv},expirationDate:{elementId:"sq-expiration-date",placeholder:square_params.placeholder_card_expiration},postalCode:{elementId:"sq-postal-code",placeholder:square_params.placeholder_card_postal_code},callbacks:{cardNonceResponseReceived:function(o,r,a){if(o){var t="";t+='<ul class="woocommerce_error woocommerce-error">',e(o).each(function(e,o){t+="<li>"+o.message+"</li>"}),t+="</ul>",e(".payment_method_square fieldset").eq(0).prepend(t)}else{var n=e("form.woocommerce-checkout, form#order_review");n.append('<input type="hidden" class="square-nonce" name="square_nonce" value="'+r+'" />'),n.submit()}},paymentFormLoaded:function(){o.setPostalCode(e("#billing_postcode").val())},unsupportedBrowserDetected:function(){var o="";o+='<ul class="woocommerce_error woocommerce-error">',o+="<li>"+square_params.unsupported_browser+"</li>",o+="</ul>",e(".payment_method_square fieldset").eq(0).prepend(o)}},inputStyles:e.parseJSON(square_params.payment_form_input_styles)})).build(),e("form.woocommerce-checkout").on("checkout_place_order_square",function(r){return e(".payment_method_square .woocommerce-error").remove(),!e("#payment_method_square").is(":checked")||0!==e("input.square-nonce").size()||(o.requestCardNonce(),!1)}),e("form#order_review").on("submit",function(r){return e(".payment_method_square .woocommerce-error").remove(),!e("#payment_method_square").is(":checked")||0!==e("input.square-nonce").size()||(o.requestCardNonce(),!1)}),e(document.body).on("checkout_error",function(){e("input.square-nonce").remove()}),setTimeout(function(){e("#payment_method_square").is(":checked")||e(".payment_box.payment_method_square").css({display:"none",visibility:"visible",height:"auto"})},1e3))}},e.wc_square_payments.init()}(jQuery);
1
+ !function(e){"use strict";var o;e.wc_square_payments={init:function(){e(document.body).on("updated_checkout",function(){e.wc_square_payments.loadForm()}),e("form#order_review").length&&e.wc_square_payments.loadForm();var o=square_params.custom_form_trigger_element;o.length&&e(document.body).on("click",o,function(){e.wc_square_payments.loadForm()}),e(document.body).on("click","#payment_method_square",function(){e(".payment_box.payment_method_square").css({display:"block",visibility:"visible",height:"auto"})})},loadForm:function(){e("#payment_method_square").length&&(e("#payment_method_square").is(":checked")||e(".payment_box.payment_method_square").css({display:"block",visibility:"hidden",height:"0"}),"object"===e.type(o)&&o.destroy(),(o=new SqPaymentForm({env:square_params.environment,applicationId:square_params.application_id,inputClass:"sq-input",cardNumber:{elementId:"sq-card-number",placeholder:square_params.placeholder_card_number},cvv:{elementId:"sq-cvv",placeholder:square_params.placeholder_card_cvv},expirationDate:{elementId:"sq-expiration-date",placeholder:square_params.placeholder_card_expiration},postalCode:{elementId:"sq-postal-code",placeholder:square_params.placeholder_card_postal_code},callbacks:{cardNonceResponseReceived:function(o,r,a){if(o){var t="";t+='<ul class="woocommerce_error woocommerce-error">',e(o).each(function(e,o){t+="<li>"+o.message+"</li>"}),t+="</ul>",e(".payment_method_square fieldset").eq(0).prepend(t)}else{var n=e("form.woocommerce-checkout, form#order_review");n.append('<input type="hidden" class="square-nonce" name="square_nonce" value="'+r+'" />'),n.submit()}},paymentFormLoaded:function(){o.setPostalCode(e("#billing_postcode").val())},unsupportedBrowserDetected:function(){var o="";o+='<ul class="woocommerce_error woocommerce-error">',o+="<li>"+square_params.unsupported_browser+"</li>",o+="</ul>",e(".payment_method_square fieldset").eq(0).prepend(o)}},inputStyles:e.parseJSON(square_params.payment_form_input_styles)})).build(),e("form.woocommerce-checkout").on("checkout_place_order_square",function(r){return e(".payment_method_square .woocommerce-error").remove(),!e("#payment_method_square").is(":checked")||0!==e("input.square-nonce").length||(o.requestCardNonce(),!1)}),e("form#order_review").on("submit",function(r){return e(".payment_method_square .woocommerce-error").remove(),!e("#payment_method_square").is(":checked")||0!==e("input.square-nonce").length||(o.requestCardNonce(),!1)}),e(document.body).on("checkout_error",function(){e("input.square-nonce").remove()}),setTimeout(function(){e("#payment_method_square").is(":checked")||e(".payment_box.payment_method_square").css({display:"none",visibility:"visible",height:"auto"})},1e3))}},e.wc_square_payments.init()}(jQuery);
changelog.txt CHANGED
@@ -1,5 +1,15 @@
1
  *** WooCommerce Square Changelog ***
2
 
 
 
 
 
 
 
 
 
 
 
3
  2018-02-19 - version 1.0.27
4
  * Fix - In some cases request timeouts are not set long enough causing timeout errors.
5
  * Fix - Square to WC sync sets products with 0 quantity to In Stock.
1
  *** WooCommerce Square Changelog ***
2
 
3
+ 2018-04-04 - version 1.0.28
4
+ * Fix - Double inventory sync for newly created products.
5
+ * Fix - Infinite loop with pagination, where Square keeps sending the same link.
6
+ * Fix - Remove usage of deprecated jQuery method.
7
+ * Fix - Sync job should not be sending anything if there are no stock changes.
8
+ * Fix - Trigger to decrease stock upon purchase not working
9
+ * Tweak - Add logging and skip sync in case store's currency/country is not allowed.
10
+ * Tweak - Improve debug logging when fetching inventory
11
+ * Tweak - Inventory reduction in Square will be treated as stock sale.
12
+
13
  2018-02-19 - version 1.0.27
14
  * Fix - In some cases request timeouts are not set long enough causing timeout errors.
15
  * Fix - Square to WC sync sets products with 0 quantity to In Stock.
includes/class-wc-square-client.php CHANGED
@@ -200,10 +200,12 @@ class WC_Square_Client {
200
 
201
  $request_url = $this->get_request_url( $path );
202
  $return_data = array();
 
 
203
 
204
  while ( true ) {
205
 
206
- $response = $this->http_request( $debug_label, $request_url, $method, $body );
207
 
208
  if ( ! $response ) {
209
 
@@ -236,8 +238,15 @@ class WC_Square_Client {
236
  // Set up the next page URL for the following loop
237
  if ( ( 'GET' === $method ) && preg_match( '/Link:( |)<(.+)>;rel=("|\')next("|\')/i', $link_header, $rel_link_matches ) ) {
238
 
 
 
 
 
 
239
  $request_url = $rel_link_matches[2];
240
  $body = null;
 
 
241
 
242
  } else {
243
 
200
 
201
  $request_url = $this->get_request_url( $path );
202
  $return_data = array();
203
+ $page_label = '';
204
+ $page_count = 1;
205
 
206
  while ( true ) {
207
 
208
+ $response = $this->http_request( $debug_label . $page_label, $request_url, $method, $body );
209
 
210
  if ( ! $response ) {
211
 
238
  // Set up the next page URL for the following loop
239
  if ( ( 'GET' === $method ) && preg_match( '/Link:( |)<(.+)>;rel=("|\')next("|\')/i', $link_header, $rel_link_matches ) ) {
240
 
241
+ // Check if we're at the end of pagination.
242
+ if ( $request_url === $rel_link_matches[2] ) {
243
+ return $return_data;
244
+ }
245
+
246
  $request_url = $rel_link_matches[2];
247
  $body = null;
248
+ $page_count++;
249
+ $page_label = sprintf( ' - Fetching page %d', $page_count );
250
 
251
  } else {
252
 
includes/class-wc-square-sync-from-square.php CHANGED
@@ -302,6 +302,11 @@ class WC_Square_Sync_From_Square {
302
  * @param stdClass $square_item
303
  */
304
  public function sync_inventory( WC_Product $wc_product, $square_item ) {
 
 
 
 
 
305
 
306
  $wc_variation_ids = WC_Square_Utils::get_stock_managed_wc_variation_ids( $wc_product );
307
  $square_inventory = $this->connect->get_square_inventory();
@@ -323,6 +328,14 @@ class WC_Square_Sync_From_Square {
323
 
324
  $square_stock = (int) $square_inventory[ $square_variation_id ];
325
  $wc_variation = wc_get_product( $wc_variation_id );
 
 
 
 
 
 
 
 
326
  $result = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation->set_stock( $square_stock ) : wc_update_product_stock( $wc_variation, $square_stock );
327
 
328
  }
@@ -335,6 +348,12 @@ class WC_Square_Sync_From_Square {
335
  * @todo if searching for square id fails, check for SKU
336
  */
337
  public function sync_all_inventory() {
 
 
 
 
 
 
338
  try {
339
  set_time_limit( apply_filters( 'woocommerce_square_inventory_sync_timeout_limit', 200 ) );
340
 
@@ -368,6 +387,14 @@ class WC_Square_Sync_From_Square {
368
  $product_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation_product->parent->id : $wc_variation_product->get_parent_id();
369
  }
370
 
 
 
 
 
 
 
 
 
371
  if ( is_object( $wc_variation_product ) && ! WC_Square_Utils::skip_product_sync( $product_id ) ) {
372
  version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation_product->set_stock( (int) $stock ) : wc_update_product_stock( $wc_variation_product, (int) $stock );
373
  }
302
  * @param stdClass $square_item
303
  */
304
  public function sync_inventory( WC_Product $wc_product, $square_item ) {
305
+ if ( ! Woocommerce_Square::instance()->is_allowed_countries()
306
+ || ! Woocommerce_Square::instance()->is_allowed_currencies() ) {
307
+ WC_Square_Sync_Logger::log( '[Square -> WC] Error syncing inventory for WC Product - Country or Currency mismatch' );
308
+ return;
309
+ }
310
 
311
  $wc_variation_ids = WC_Square_Utils::get_stock_managed_wc_variation_ids( $wc_product );
312
  $square_inventory = $this->connect->get_square_inventory();
328
 
329
  $square_stock = (int) $square_inventory[ $square_variation_id ];
330
  $wc_variation = wc_get_product( $wc_variation_id );
331
+
332
+ $current_stock = $wc_variation->get_stock_quantity();
333
+
334
+ // Do not trigger sync if setting same stock quantity
335
+ if ( $square_stock === $current_stock ) {
336
+ continue;
337
+ }
338
+
339
  $result = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation->set_stock( $square_stock ) : wc_update_product_stock( $wc_variation, $square_stock );
340
 
341
  }
348
  * @todo if searching for square id fails, check for SKU
349
  */
350
  public function sync_all_inventory() {
351
+ if ( ! Woocommerce_Square::instance()->is_allowed_countries()
352
+ || ! Woocommerce_Square::instance()->is_allowed_currencies() ) {
353
+ WC_Square_Sync_Logger::log( '[Square -> WC] Error syncing all inventory - Country or Currency mismatch' );
354
+ return;
355
+ }
356
+
357
  try {
358
  set_time_limit( apply_filters( 'woocommerce_square_inventory_sync_timeout_limit', 200 ) );
359
 
387
  $product_id = version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation_product->parent->id : $wc_variation_product->get_parent_id();
388
  }
389
 
390
+ $current_stock = $wc_variation_product->get_stock_quantity();
391
+
392
+ // Do not trigger sync if setting same stock quantity
393
+ if ( $stock === $current_stock ) {
394
+ WC_Square_Sync_Logger::log( sprintf( '[Square -> WC] Syncing WC product inventory for Square Item ID %s - No change in stock quantity for product/variation, skipping.', $variation_id ) );
395
+ continue;
396
+ }
397
+
398
  if ( is_object( $wc_variation_product ) && ! WC_Square_Utils::skip_product_sync( $product_id ) ) {
399
  version_compare( WC_VERSION, '3.0.0', '<' ) ? $wc_variation_product->set_stock( (int) $stock ) : wc_update_product_stock( $wc_variation_product, (int) $stock );
400
  }
includes/class-wc-square-sync-to-square-wp-hooks.php CHANGED
@@ -49,6 +49,14 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
49
  */
50
  protected $enabled = true;
51
 
 
 
 
 
 
 
 
 
52
  /**
53
  * WC_Square_Sync_To_Square_WordPress_Hooks constructor.
54
  *
@@ -115,9 +123,13 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
115
 
116
  if ( 'WC_Square_Integration' !== $param ) {
117
 
118
- add_action( 'woocommerce_product_set_stock', array( $this, 'schedule_on_product_set_stock' ) );
 
 
 
119
 
120
- add_action( 'woocommerce_variation_set_stock', array( $this, 'schedule_on_variation_set_stock' ) );
 
121
  }
122
  }
123
 
@@ -142,16 +154,10 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
142
  }
143
 
144
  if ( is_object( $wc_product ) && ! empty( $wc_product ) ) {
145
- $this->square->sync_product( $wc_product, $this->sync_categories, $this->sync_inventory, $this->sync_images );
146
  }
147
 
148
  WC_Square_Utils::delete_transients();
149
-
150
- if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
151
- add_action( 'save_post', array( $this, 'pre_wc_30_on_save_post' ), 10, 2 );
152
- } else {
153
- add_action( 'woocommerce_before_product_object_save', array( $this, 'on_save_post' ), 10, 2 );
154
- }
155
  }
156
 
157
  /**
@@ -166,7 +172,7 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
166
  $post = get_post( $product->get_id() );
167
 
168
  if ( ! $this->enabled
169
- || ( defined( 'DOING_AJAX' ) && DOING_AJAX ) // TODO: Look into removing this check.
170
  || ( defined( 'WP_LOAD_IMPORTERS' ) && WP_LOAD_IMPORTERS )
171
  || wp_is_post_revision( $post )
172
  || wp_is_post_autosave( $post )
@@ -176,14 +182,17 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
176
  return;
177
  }
178
 
 
 
 
 
 
179
  $args = array(
180
  $product->get_id(),
181
  uniqid(), // this is needed due to WP not scheduling new events with same name and args
182
  );
183
 
184
  wp_schedule_single_event( time() + 60, 'wc_square_save_post_event', $args );
185
-
186
- remove_action( 'woocommerce_before_product_object_save', array( $this, 'on_save_post' ) );
187
  }
188
 
189
  /**
@@ -213,8 +222,6 @@ class WC_Square_Sync_To_Square_WordPress_Hooks {
213
  );
214
 
215
  wp_schedule_single_event( time() + 60, 'wc_square_save_post_event', $args );
216
-
217
- remove_action( 'save_post', array( $this, 'pre_wc_30_on_save_post' ) );
218
  }
219
 
220
  /**
49
  */
50
  protected $enabled = true;
51
 
52
+ /**
53
+ * Keep track of which products have already assigned a sync job
54
+ *
55
+ * @var array
56
+ */
57
+ protected $products_synced = array(
58
+ );
59
+
60
  /**
61
  * WC_Square_Sync_To_Square_WordPress_Hooks constructor.
62
  *
123
 
124
  if ( 'WC_Square_Integration' !== $param ) {
125
 
126
+ // Only add the stock hooks for versions below 3.0. In versions
127
+ // >= 3.0 the save hook will take care of stock inventory as well.
128
+ if ( version_compare( WC_VERSION, '3.0.0', '<' ) ) {
129
+ add_action( 'woocommerce_product_set_stock', array( $this, 'schedule_on_product_set_stock' ) );
130
 
131
+ add_action( 'woocommerce_variation_set_stock', array( $this, 'schedule_on_variation_set_stock' ) );
132
+ }
133
  }
134
  }
135
 
154
  }
155
 
156
  if ( is_object( $wc_product ) && ! empty( $wc_product ) ) {
157
+ $this->square->sync_product( $wc_product, $this->sync_categories, $this->sync_categories, $this->sync_images );
158
  }
159
 
160
  WC_Square_Utils::delete_transients();
 
 
 
 
 
 
161
  }
162
 
163
  /**
172
  $post = get_post( $product->get_id() );
173
 
174
  if ( ! $this->enabled
175
+ || in_array( $product->get_id(), $this->products_synced )
176
  || ( defined( 'WP_LOAD_IMPORTERS' ) && WP_LOAD_IMPORTERS )
177
  || wp_is_post_revision( $post )
178
  || wp_is_post_autosave( $post )
182
  return;
183
  }
184
 
185
+ // Because of metaboxes, core may fire save on the product a couple of times.
186
+ // TODO: This workaround should be resolved once we re-architecture Square to
187
+ // use Action Scheduler (or something similar, a queue) to manage jobs.
188
+ $this->products_synced[] = $product->get_id();
189
+
190
  $args = array(
191
  $product->get_id(),
192
  uniqid(), // this is needed due to WP not scheduling new events with same name and args
193
  );
194
 
195
  wp_schedule_single_event( time() + 60, 'wc_square_save_post_event', $args );
 
 
196
  }
197
 
198
  /**
222
  );
223
 
224
  wp_schedule_single_event( time() + 60, 'wc_square_save_post_event', $args );
 
 
225
  }
226
 
227
  /**
includes/class-wc-square-sync-to-square.php CHANGED
@@ -174,6 +174,12 @@ class WC_Square_Sync_To_Square {
174
 
175
  }
176
 
 
 
 
 
 
 
177
  // Look for a Square Item with a matching SKU
178
  $square_item = $this->get_square_item_for_wc_product( $wc_product );
179
 
@@ -219,6 +225,12 @@ class WC_Square_Sync_To_Square {
219
  * @param bool $create
220
  */
221
  public function sync_inventory( WC_Product $wc_product, $create = false ) {
 
 
 
 
 
 
222
  // refresh cache first to get the latest inventory
223
  $this->connect->refresh_inventory_cache();
224
 
@@ -245,7 +257,25 @@ class WC_Square_Sync_To_Square {
245
 
246
  $delta = $wc_stock - $square_stock;
247
 
248
- $result = $this->connect->update_square_inventory( $square_variation_id, $delta );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
 
250
  if ( ! $result ) {
251
 
174
 
175
  }
176
 
177
+ if ( ! Woocommerce_Square::instance()->is_allowed_countries()
178
+ || ! Woocommerce_Square::instance()->is_allowed_currencies() ) {
179
+ WC_Square_Sync_Logger::log( '[WC -> Square] Error syncing inventory for WC Product - Country or Currency mismatch' );
180
+ return;
181
+ }
182
+
183
  // Look for a Square Item with a matching SKU
184
  $square_item = $this->get_square_item_for_wc_product( $wc_product );
185
 
225
  * @param bool $create
226
  */
227
  public function sync_inventory( WC_Product $wc_product, $create = false ) {
228
+ if ( ! Woocommerce_Square::instance()->is_allowed_countries()
229
+ || ! Woocommerce_Square::instance()->is_allowed_currencies() ) {
230
+ WC_Square_Sync_Logger::log( '[WC -> Square] Error syncing inventory for WC Product - Country or Currency mismatch' );
231
+ return;
232
+ }
233
+
234
  // refresh cache first to get the latest inventory
235
  $this->connect->refresh_inventory_cache();
236
 
257
 
258
  $delta = $wc_stock - $square_stock;
259
 
260
+ // Do not trigger inventory update if there is no stock changes.
261
+ if ( $delta == 0 ) {
262
+ WC_Square_Sync_Logger::log( sprintf( '[WC -> Square] Syncing WC product inventory for WC Product %d - No change in stock quantity for product/variation, skipping.', $wc_variation_id ) );
263
+ continue;
264
+ }
265
+
266
+ // Assume delta is gt 0, i.e. we received stock
267
+ $type = 'RECEIVE_STOCK';
268
+
269
+ if ( $delta < 0 ) {
270
+ // Delta is lt 0, so it is treated as sales
271
+ $type = 'SALE';
272
+ }
273
+
274
+ $result = $this->connect->update_square_inventory(
275
+ $square_variation_id,
276
+ $delta,
277
+ apply_filters( 'woocommerce_square_inventory_type', $type, $delta )
278
+ );
279
 
280
  if ( ! $result ) {
281
 
languages/woocommerce-square.pot CHANGED
@@ -2,10 +2,10 @@
2
  # This file is distributed under the same license as the WooCommerce Square package.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WooCommerce Square 1.0.27\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-square/issues\n"
8
- "POT-Creation-Date: 2018-02-19 20:34:24+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
@@ -615,26 +615,26 @@ msgid ""
615
  "GBP, JPY, or USD."
616
  msgstr ""
617
 
618
- #: woocommerce-square.php:330
619
  msgid ""
620
  "This process may take awhile depending on the amount of items that need to "
621
  "be synced. Please do not close this tab/window or else the sync will "
622
  "terminate. Click OK to continue to sync."
623
  msgstr ""
624
 
625
- #: woocommerce-square.php:388
626
  msgid ""
627
  "WooCommerce Square Plugin requires WooCommerce to be installed and active. "
628
  "You can download %s here."
629
  msgstr ""
630
 
631
- #: woocommerce-square.php:406
632
  msgid ""
633
  "WooCommerce Square is almost ready. To get started, %1$sconnect your Square "
634
  "Account.%2$s"
635
  msgstr ""
636
 
637
- #: woocommerce-square.php:410
638
  msgid ""
639
  "WooCommerce Square is almost ready. Please %1$sset your business "
640
  "location.%2$s"
2
  # This file is distributed under the same license as the WooCommerce Square package.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WooCommerce Square 1.0.28\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-square/issues\n"
8
+ "POT-Creation-Date: 2018-04-04 08:49:02+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
615
  "GBP, JPY, or USD."
616
  msgstr ""
617
 
618
+ #: woocommerce-square.php:331
619
  msgid ""
620
  "This process may take awhile depending on the amount of items that need to "
621
  "be synced. Please do not close this tab/window or else the sync will "
622
  "terminate. Click OK to continue to sync."
623
  msgstr ""
624
 
625
+ #: woocommerce-square.php:389
626
  msgid ""
627
  "WooCommerce Square Plugin requires WooCommerce to be installed and active. "
628
  "You can download %s here."
629
  msgstr ""
630
 
631
+ #: woocommerce-square.php:407
632
  msgid ""
633
  "WooCommerce Square is almost ready. To get started, %1$sconnect your Square "
634
  "Account.%2$s"
635
  msgstr ""
636
 
637
+ #: woocommerce-square.php:411
638
  msgid ""
639
  "WooCommerce Square is almost ready. Please %1$sset your business "
640
  "location.%2$s"
readme.txt CHANGED
@@ -1,10 +1,10 @@
1
  === WooCommerce Square ===
2
- Contributors: automattic, royho, woothemes
3
  Tags: credit card, square, woocommerce, inventory sync
4
  Requires at least: 4.4
5
  Tested up to: 4.9
6
  Requires PHP: 5.6
7
- Stable tag: 1.0.27
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
@@ -57,6 +57,16 @@ If you get stuck, you can ask for help in the Plugin Forum.
57
 
58
  == Changelog ==
59
 
 
 
 
 
 
 
 
 
 
 
60
  = 1.0.27 - 2018-02-19 =
61
  * Fix - In some cases request timeouts are not set long enough causing timeout errors.
62
  * Fix - Square to WC sync sets products with 0 quantity to In Stock.
1
  === WooCommerce Square ===
2
+ Contributors: automattic, royho, woothemes, bor0
3
  Tags: credit card, square, woocommerce, inventory sync
4
  Requires at least: 4.4
5
  Tested up to: 4.9
6
  Requires PHP: 5.6
7
+ Stable tag: 1.0.28
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
57
 
58
  == Changelog ==
59
 
60
+ = 1.0.28 - 2018-04-04 =
61
+ * Fix - Double inventory sync for newly created products.
62
+ * Fix - Infinite loop with pagination, where Square keeps sending the same link.
63
+ * Fix - Remove usage of deprecated jQuery method.
64
+ * Fix - Sync job should not be sending anything if there are no stock changes.
65
+ * Fix - Trigger to decrease stock upon purchase not working
66
+ * Tweak - Add logging and skip sync in case store's currency/country is not allowed.
67
+ * Tweak - Improve debug logging when fetching inventory
68
+ * Tweak - Inventory reduction in Square will be treated as stock sale.
69
+
70
  = 1.0.27 - 2018-02-19 =
71
  * Fix - In some cases request timeouts are not set long enough causing timeout errors.
72
  * Fix - Square to WC sync sets products with 0 quantity to In Stock.
woocommerce-square.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /**
3
  * Plugin Name: WooCommerce Square
4
- * Version: 1.0.27
5
  * Plugin URI: https://woocommerce.com/products/square/
6
  * Description: Adds ability to sync inventory between WooCommerce and Square POS. In addition, you can also make purchases through the Square payment gateway.
7
  * Author: WooCommerce
@@ -23,7 +23,7 @@ if ( ! defined( 'ABSPATH' ) ) {
23
 
24
  if ( ! class_exists( 'Woocommerce_Square' ) ) :
25
 
26
- define( 'WC_SQUARE_VERSION', '1.0.27' );
27
 
28
  /**
29
  * Main class.
@@ -324,9 +324,10 @@ if ( ! class_exists( 'Woocommerce_Square' ) ) :
324
  wp_enqueue_script( 'wc-square-admin-scripts' );
325
 
326
  $localized_vars = array(
327
- 'admin_ajax_url' => admin_url( 'admin-ajax.php' ),
328
- 'ajaxSyncNonce' => wp_create_nonce( 'square-sync' ),
329
- 'i18n' => array(
 
330
  'confirm_sync' => __( 'This process may take awhile depending on the amount of items that need to be synced. Please do not close this tab/window or else the sync will terminate. Click OK to continue to sync.', 'woocommerce-square' ),
331
  ),
332
  );
1
  <?php
2
  /**
3
  * Plugin Name: WooCommerce Square
4
+ * Version: 1.0.28
5
  * Plugin URI: https://woocommerce.com/products/square/
6
  * Description: Adds ability to sync inventory between WooCommerce and Square POS. In addition, you can also make purchases through the Square payment gateway.
7
  * Author: WooCommerce
23
 
24
  if ( ! class_exists( 'Woocommerce_Square' ) ) :
25
 
26
+ define( 'WC_SQUARE_VERSION', '1.0.28' );
27
 
28
  /**
29
  * Main class.
324
  wp_enqueue_script( 'wc-square-admin-scripts' );
325
 
326
  $localized_vars = array(
327
+ 'admin_ajax_url' => admin_url( 'admin-ajax.php' ),
328
+ 'ajaxSyncNonce' => wp_create_nonce( 'square-sync' ),
329
+ 'country_currency' => $this->is_allowed_countries() && $this->is_allowed_currencies(),
330
+ 'i18n' => array(
331
  'confirm_sync' => __( 'This process may take awhile depending on the amount of items that need to be synced. Please do not close this tab/window or else the sync will terminate. Click OK to continue to sync.', 'woocommerce-square' ),
332
  ),
333
  );