WooCommerce Square - Version 2.1.0

Version Description

  • 2020.02.11 =
  • Feature - Add support for SCA (3D Secure 2)
  • Fix - Minor fixes to the Sync completed emails
  • Tweak - Add email notifications when connection issues are detected
  • Fix - Category sync when WooCommerce is the System of Record and there have been changes in Square
Download this release

Release Info

Developer automattic
Plugin Icon 128x128 WooCommerce Square
Version 2.1.0
Comparing to
See all releases

Code changes from version 2.0.8 to 2.1.0

Files changed (141) hide show
  1. assets/js/frontend/wc-square.coffee +157 -18
  2. assets/js/frontend/wc-square.min.js +1 -1
  3. assets/js/frontend/wc-square.min.js.map +1 -1
  4. i18n/languages/woocommerce-square.pot +77 -39
  5. includes/Admin/Products.php +0 -687
  6. includes/Emails/Access_Token_Email.php +120 -0
  7. includes/Emails/Base_Email.php +196 -0
  8. includes/Emails/Sync_Completed.php +34 -193
  9. includes/Gateway.php +33 -6
  10. includes/Gateway/API/Requests/Customers.php +5 -0
  11. includes/Gateway/API/Requests/Transactions.php +5 -0
  12. includes/Gateway/Card_Handler.php +23 -0
  13. includes/Gateway/Payment_Form.php +83 -24
  14. includes/Handlers/Background_Job.php +2 -6
  15. includes/Handlers/Connection.php +3 -0
  16. includes/Handlers/Email.php +22 -18
  17. includes/Plugin.php +1 -1
  18. includes/Sync/Manual_Synchronization.php +10 -14
  19. readme.txt +10 -6
  20. templates/emails/plain/{square-sync-completed.php → square-email.php} +2 -3
  21. trunk/templates/emails/square-sync-completed.php → templates/emails/square-email.php +1 -2
  22. templates/emails/square-sync-completed.php +0 -42
  23. trunk/assets/css/admin/wc-square-admin.min.css +0 -2
  24. trunk/assets/css/admin/wc-square-admin.min.css.map +0 -1
  25. trunk/assets/css/admin/wc-square-admin.scss +0 -74
  26. trunk/assets/css/frontend/wc-square.min.css +0 -2
  27. trunk/assets/css/frontend/wc-square.min.css.map +0 -1
  28. trunk/assets/css/frontend/wc-square.scss +0 -76
  29. trunk/assets/js/admin/wc-square-admin-products.coffee +0 -355
  30. trunk/assets/js/admin/wc-square-admin-products.min.js +0 -2
  31. trunk/assets/js/admin/wc-square-admin-products.min.js.map +0 -1
  32. trunk/assets/js/admin/wc-square-admin-settings.coffee +0 -257
  33. trunk/assets/js/admin/wc-square-admin-settings.min.js +0 -2
  34. trunk/assets/js/admin/wc-square-admin-settings.min.js.map +0 -1
  35. trunk/assets/js/frontend/wc-square.coffee +0 -451
  36. trunk/assets/js/frontend/wc-square.min.js +0 -2
  37. trunk/assets/js/frontend/wc-square.min.js.map +0 -1
  38. trunk/i18n/languages/woocommerce-square.pot +0 -3215
  39. trunk/includes/AJAX.php +0 -288
  40. trunk/includes/API.php +0 -885
  41. trunk/includes/API/Request.php +0 -206
  42. trunk/includes/API/Requests/Catalog.php +0 -288
  43. trunk/includes/API/Requests/Customers.php +0 -84
  44. trunk/includes/API/Requests/Inventory.php +0 -214
  45. trunk/includes/API/Requests/Locations.php +0 -65
  46. trunk/includes/API/Response.php +0 -120
  47. trunk/includes/API/Responses/Catalog.php +0 -40
  48. trunk/includes/API/Responses/Connection_Refresh_Response.php +0 -100
  49. trunk/includes/API/Responses/Inventory.php +0 -72
  50. trunk/includes/API/Responses/Locations.php +0 -55
  51. trunk/includes/Admin.php +0 -219
  52. trunk/includes/Admin/Privacy.php +0 -106
  53. trunk/includes/Admin/Settings_Page.php +0 -197
  54. trunk/includes/Admin/Sync_Page.php +0 -379
  55. trunk/includes/Emails/Sync_Completed.php +0 -425
  56. trunk/includes/Functions.php +0 -40
  57. trunk/includes/Gateway.php +0 -783
  58. trunk/includes/Gateway/API.php +0 -498
  59. trunk/includes/Gateway/API/Requests/Customers.php +0 -162
  60. trunk/includes/Gateway/API/Requests/Orders.php +0 -338
  61. trunk/includes/Gateway/API/Requests/Transactions.php +0 -254
  62. trunk/includes/Gateway/API/Response.php +0 -144
  63. trunk/includes/Gateway/API/Responses/Charge.php +0 -187
  64. trunk/includes/Gateway/API/Responses/Create_Customer.php +0 -53
  65. trunk/includes/Gateway/API/Responses/Create_Customer_Card.php +0 -72
  66. trunk/includes/Gateway/API/Responses/Get_Customer.php +0 -76
  67. trunk/includes/Gateway/API/Responses/Refund.php +0 -86
  68. trunk/includes/Gateway/Card_Handler.php +0 -50
  69. trunk/includes/Gateway/Customer_Helper.php +0 -192
  70. trunk/includes/Gateway/Payment_Form.php +0 -222
  71. trunk/includes/Handlers/Background_Job.php +0 -367
  72. trunk/includes/Handlers/Category.php +0 -235
  73. trunk/includes/Handlers/Connection.php +0 -516
  74. trunk/includes/Handlers/Email.php +0 -129
  75. trunk/includes/Handlers/Order.php +0 -260
  76. trunk/includes/Handlers/Product.php +0 -1389
  77. trunk/includes/Handlers/Product/Woo_SOR.php +0 -292
  78. trunk/includes/Handlers/Products.php +0 -719
  79. trunk/includes/Handlers/Sync.php +0 -501
  80. trunk/includes/Lifecycle.php +0 -426
  81. trunk/includes/Plugin.php +0 -898
  82. trunk/includes/Settings.php +0 -825
  83. trunk/includes/Sync/Catalog_Item.php +0 -149
  84. trunk/includes/Sync/Interval_Polling.php +0 -272
  85. trunk/includes/Sync/Job.php +0 -223
  86. trunk/includes/Sync/Manual_Synchronization.php +0 -1754
  87. trunk/includes/Sync/Product_Import.php +0 -1141
  88. trunk/includes/Sync/Records.php +0 -390
  89. trunk/includes/Sync/Records/Record.php +0 -603
  90. trunk/includes/Sync/Stepped_Job.php +0 -233
  91. trunk/includes/Utilities/Encryption_Utility.php +0 -265
  92. trunk/includes/Utilities/Money_Utility.php +0 -161
  93. trunk/readme.txt +0 -181
  94. trunk/templates/emails/plain/square-sync-completed.php +0 -46
  95. trunk/vendor/autoload.php +0 -7
  96. trunk/vendor/composer/ClassLoader.php +0 -445
  97. trunk/vendor/composer/LICENSE +0 -21
  98. trunk/vendor/composer/autoload_classmap.php +0 -9
  99. trunk/vendor/composer/autoload_namespaces.php +0 -9
  100. trunk/vendor/composer/autoload_psr4.php +0 -10
  101. trunk/vendor/composer/autoload_real.php +0 -52
  102. trunk/vendor/composer/autoload_static.php +0 -31
  103. trunk/vendor/composer/installed.json +0 -109
  104. trunk/vendor/prospress/action-scheduler/.github/release-drafter.yml +0 -15
  105. trunk/vendor/prospress/action-scheduler/.gitignore +0 -3
  106. trunk/vendor/prospress/action-scheduler/.travis.yml +0 -37
  107. trunk/vendor/prospress/action-scheduler/README.md +0 -41
  108. trunk/vendor/prospress/action-scheduler/action-scheduler.php +0 -47
  109. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler.php +0 -133
  110. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Abstract_ListTable.php +0 -656
  111. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Abstract_QueueRunner.php +0 -216
  112. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Action.php +0 -75
  113. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ActionClaim.php +0 -23
  114. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ActionFactory.php +0 -111
  115. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_AdminView.php +0 -78
  116. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_CanceledAction.php +0 -21
  117. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Compatibility.php +0 -99
  118. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_CronSchedule.php +0 -57
  119. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_DateTime.php +0 -76
  120. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Exception.php +0 -11
  121. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_FatalErrorMonitor.php +0 -55
  122. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_FinishedAction.php +0 -16
  123. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_IntervalSchedule.php +0 -60
  124. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_InvalidActionException.php +0 -28
  125. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php +0 -533
  126. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_LogEntry.php +0 -67
  127. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php +0 -98
  128. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullAction.php +0 -16
  129. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullLogEntry.php +0 -11
  130. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullSchedule.php +0 -19
  131. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_QueueCleaner.php +0 -155
  132. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_QueueRunner.php +0 -115
  133. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Schedule.php +0 -18
  134. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_SimpleSchedule.php +0 -44
  135. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php +0 -212
  136. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_TimezoneHelper.php +0 -152
  137. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Versions.php +0 -62
  138. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php +0 -210
  139. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php +0 -145
  140. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_wpCommentLogger.php +0 -240
  141. trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php +0 -37
assets/js/frontend/wc-square.coffee CHANGED
@@ -25,12 +25,16 @@ jQuery( document ).ready ( $ ) ->
25
  @enabled_card_types = args.enabled_card_types
26
  @square_card_types = args.square_card_types
27
 
28
- @logging_enabled = args.logging_enabled
29
- @general_error = args.general_error
30
- @ajax_url = args.ajax_url
31
- @ajax_log_nonce = args.ajax_log_nonce
32
- @input_styles = args.input_styles
33
- @application_id = args.application_id
 
 
 
 
34
 
35
  # which payment form?
36
  if $( 'form.checkout' ).length
@@ -46,7 +50,7 @@ jQuery( document ).ready ( $ ) ->
46
  this.handle_add_payment_method_page()
47
 
48
  else
49
- console.log( 'No payment form found!' )
50
  return
51
 
52
  # localized error messages
@@ -55,6 +59,7 @@ jQuery( document ).ready ( $ ) ->
55
  # unblock the UI and clear any payment nonces when a server-side error occurs
56
  $( document.body ).on( 'checkout_error', ->
57
  $( "input[name=wc-square-credit-card-payment-nonce]" ).val( '' )
 
58
  )
59
 
60
 
@@ -187,7 +192,8 @@ jQuery( document ).ready ( $ ) ->
187
  $postal_code = $( "#wc-#{@id_dasherized}-postal-code-hosted" )
188
 
189
  return {
190
- applicationId: @application_id
 
191
  cardNumber: {
192
  elementId: $card_number.attr( 'id' )
193
  placeholder: $card_number.data( 'placeholder' )
@@ -208,7 +214,7 @@ jQuery( document ).ready ( $ ) ->
208
  inputStyles: @input_styles
209
  callbacks: {
210
  inputEventReceived: ( event ) => this.handle_input_event( event )
211
- cardNonceResponseReceived: ( errors, nonce, cardData ) => this.handle_response( errors, nonce, cardData )
212
  unsupportedBrowserDetected: => this.handle_unsupported_browser()
213
  paymentFormLoaded: => this.handle_form_loaded()
214
  }
@@ -276,29 +282,50 @@ jQuery( document ).ready ( $ ) ->
276
  # bail when already processing
277
  return false if @form.is( '.processing' )
278
 
279
- # let through if nonce is already present
280
  if this.has_nonce()
281
  this.log 'Payment nonce present, placing order'
282
  return true
283
 
284
- return true if $( ".payment_method_#{ @id }" ).find( '.js-wc-square-credit-card-payment-token:checked' ).val()
285
 
286
- this.log 'Requesting payment nonce'
287
 
288
- this.block_ui()
 
289
 
290
- @payment_form.requestCardNonce()
 
 
 
 
 
 
 
291
 
 
 
 
292
  return false
293
 
294
 
295
- # Handles the Square payment form response.
296
  #
297
- # @since 2.0.0
 
 
 
 
 
 
 
 
 
298
  #
299
  # @param Object[] errors validation errors, if any
300
  # @param String nonce payment nonce
301
- handle_response: ( errors, nonce, cardData ) ->
 
302
 
303
  # if we have real errors to display from Square
304
  if errors
@@ -316,7 +343,7 @@ jQuery( document ).ready ( $ ) ->
316
 
317
  # if we made it this far, we have payment data
318
  this.log 'Card data received'
319
- console.log cardData
320
  this.log_data( cardData, 'response' )
321
 
322
  if cardData.last_4
@@ -334,10 +361,110 @@ jQuery( document ).ready ( $ ) ->
334
  # payment nonce data
335
  $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val( nonce )
336
 
 
 
 
 
 
 
 
 
337
  # now that we have a nonce, resubmit the form
338
  @form.submit()
339
 
340
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
341
  # Handles unsupported browsers.
342
  #
343
  # @since 2.0.0
@@ -352,6 +479,10 @@ jQuery( document ).ready ( $ ) ->
352
 
353
  this.log 'Error getting payment data', 'error'
354
 
 
 
 
 
355
  messages = []
356
 
357
  if errors
@@ -416,6 +547,14 @@ jQuery( document ).ready ( $ ) ->
416
  has_nonce: -> $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val()
417
 
418
 
 
 
 
 
 
 
 
 
419
  # Logs data to the debug log via AJAX.
420
  #
421
  # @since 2.0.0
25
  @enabled_card_types = args.enabled_card_types
26
  @square_card_types = args.square_card_types
27
 
28
+ @ajax_log_nonce = args.ajax_log_nonce
29
+ @ajax_url = args.ajax_url
30
+ @application_id = args.application_id
31
+ @currency_code = args.currency_code
32
+ @general_error = args.general_error
33
+ @input_styles = args.input_styles
34
+ @is_3ds_enabled = args.is_3d_secure_enabled
35
+ @is_add_payment_method_page = args.is_add_payment_method_page
36
+ @location_id = args.location_id
37
+ @logging_enabled = args.logging_enabled
38
 
39
  # which payment form?
40
  if $( 'form.checkout' ).length
50
  this.handle_add_payment_method_page()
51
 
52
  else
53
+ this.log 'No payment form found!'
54
  return
55
 
56
  # localized error messages
59
  # unblock the UI and clear any payment nonces when a server-side error occurs
60
  $( document.body ).on( 'checkout_error', ->
61
  $( "input[name=wc-square-credit-card-payment-nonce]" ).val( '' )
62
+ $( "input[name=wc-square-credit-card-buyer-verification-token]" ).val( '' )
63
  )
64
 
65
 
192
  $postal_code = $( "#wc-#{@id_dasherized}-postal-code-hosted" )
193
 
194
  return {
195
+ applicationId: @application_id,
196
+ locationId: @location_id,
197
  cardNumber: {
198
  elementId: $card_number.attr( 'id' )
199
  placeholder: $card_number.data( 'placeholder' )
214
  inputStyles: @input_styles
215
  callbacks: {
216
  inputEventReceived: ( event ) => this.handle_input_event( event )
217
+ cardNonceResponseReceived: ( errors, nonce, cardData ) => this.handle_card_nonce_response( errors, nonce, cardData )
218
  unsupportedBrowserDetected: => this.handle_unsupported_browser()
219
  paymentFormLoaded: => this.handle_form_loaded()
220
  }
282
  # bail when already processing
283
  return false if @form.is( '.processing' )
284
 
285
+ # let through if nonce is already present - nonce is only present on non-tokenized payments
286
  if this.has_nonce()
287
  this.log 'Payment nonce present, placing order'
288
  return true
289
 
290
+ tokenized_card_id = this.get_tokenized_payment_method_id()
291
 
292
+ if tokenized_card_id
293
 
294
+ # if 3DS is disabled and paying with a saved method, no further validation needed
295
+ return true unless @is_3ds_enabled
296
 
297
+ if this.has_verification_token()
298
+ this.log 'Tokenized payment verification token present, placing order'
299
+ return true
300
+
301
+ this.log 'Requesting verification token for tokenized payment'
302
+ this.block_ui()
303
+ @payment_form.verifyBuyer tokenized_card_id, this.get_verification_details(), this.handle_verify_buyer_response
304
+ return false
305
 
306
+ this.log 'Requesting payment nonce'
307
+ this.block_ui()
308
+ @payment_form.requestCardNonce()
309
  return false
310
 
311
 
312
+ # Gets the selected tokenized payment method ID, if there is one.
313
  #
314
+ # @since 2.1.0
315
+ #
316
+ # @return String
317
+ get_tokenized_payment_method_id: ->
318
+ return $( ".payment_method_#{ @id }" ).find( '.js-wc-square-credit-card-payment-token:checked' ).val()
319
+
320
+
321
+ # Handles the Square payment form card nonce response.
322
+ #
323
+ # @since 2.1.0
324
  #
325
  # @param Object[] errors validation errors, if any
326
  # @param String nonce payment nonce
327
+ # @param Object cardData non-confidential info about the card used
328
+ handle_card_nonce_response: ( errors, nonce, cardData ) ->
329
 
330
  # if we have real errors to display from Square
331
  if errors
343
 
344
  # if we made it this far, we have payment data
345
  this.log 'Card data received'
346
+ this.log cardData
347
  this.log_data( cardData, 'response' )
348
 
349
  if cardData.last_4
361
  # payment nonce data
362
  $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val( nonce )
363
 
364
+ # if 3ds is enabled, we need to verify the buyer and record the verification token before continuing
365
+ if @is_3ds_enabled
366
+
367
+ this.log 'Verifying buyer'
368
+
369
+ @payment_form.verifyBuyer nonce, this.get_verification_details(), this.handle_verify_buyer_response
370
+ return
371
+
372
  # now that we have a nonce, resubmit the form
373
  @form.submit()
374
 
375
 
376
+ # Handles the response from a call to verifyBuyer()
377
+ #
378
+ # @since 2.1.0
379
+ #
380
+ # @param Object[] errors verification errors, if any
381
+ # @param Object verification_result the results of verification
382
+ handle_verify_buyer_response: ( errors, verification_result ) =>
383
+
384
+ if errors
385
+ return this.handle_errors( errors )
386
+
387
+ # no errors, but also no verification token
388
+ if not verification_result or not verification_result.token
389
+
390
+ message = 'Verification token is missing from the Square response'
391
+
392
+ this.log message, 'error'
393
+ this.log_data message, 'response'
394
+
395
+ return this.handle_errors()
396
+
397
+ this.log 'Verification result received'
398
+ this.log verification_result
399
+
400
+ $( "input[name=wc-#{@id_dasherized}-buyer-verification-token]" ).val( verification_result.token )
401
+
402
+ @form.submit()
403
+
404
+
405
+ # Gets a verification details object to be used in verifyBuyer()
406
+ #
407
+ # @since 2.1.0
408
+ #
409
+ # @return Object verification details object
410
+ get_verification_details: ->
411
+
412
+ verification_details = {
413
+ billingContact: {
414
+ familyName: $( '#billing_last_name' ).val()
415
+ givenName: $( '#billing_first_name' ).val()
416
+ email: $( '#billing_email' ).val()
417
+ country: $( '#billing_country' ).val()
418
+ region: $( '#billing_state' ).val()
419
+ city: $( '#billing_city' ).val()
420
+ postalCode: $( '#billing_postcode' ).val()
421
+ phone: $( '#billing_phone' ).val()
422
+ addressLines: [
423
+ $( '#billing_address_1' ).val(),
424
+ $( '#billing_address_2' ).val()
425
+ ]
426
+ }
427
+ intent: this.get_intent()
428
+ }
429
+
430
+ if 'CHARGE' is verification_details.intent
431
+ verification_details.amount = this.get_amount()
432
+ verification_details.currencyCode = @currency_code
433
+
434
+ this.log verification_details
435
+
436
+ return verification_details
437
+
438
+
439
+ # Gets the intent of this processing - either 'CHARGE' or 'STORE'
440
+ #
441
+ # The gateway stores cards before processing a payment, so this checks whether the customer checked "save method"
442
+ # at checkout, and isn't otherwise using a saved method already.
443
+ #
444
+ # @since 2.1.0
445
+ #
446
+ # return String {'CHARGE'|'STORE'}
447
+ get_intent: ->
448
+
449
+ $save_method_input = $( '#wc-square-credit-card-tokenize-payment-method' )
450
+
451
+ if $save_method_input.is( 'input:checkbox' )
452
+ save_payment_method = $save_method_input.is( ':checked' )
453
+ else
454
+ save_payment_method = $save_method_input.val() is 'true'
455
+
456
+ return if not this.get_tokenized_payment_method_id() and save_payment_method then 'STORE' else 'CHARGE'
457
+
458
+
459
+ # Gets the amount of this payment.
460
+ #
461
+ # @since 2.1.0
462
+ #
463
+ # return String
464
+ get_amount: ->
465
+ return $( "input[name=wc-#{@id_dasherized}-amount]" ).val()
466
+
467
+
468
  # Handles unsupported browsers.
469
  #
470
  # @since 2.0.0
479
 
480
  this.log 'Error getting payment data', 'error'
481
 
482
+ # clear any previous nonces
483
+ $( "input[name=wc-square-credit-card-payment-nonce]" ).val( '' )
484
+ $( "input[name=wc-square-credit-card-buyer-verification-token]" ).val( '' )
485
+
486
  messages = []
487
 
488
  if errors
547
  has_nonce: -> $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val()
548
 
549
 
550
+ # Determines if a verification token is present in the hidden input.
551
+ #
552
+ # @since 2.1.0
553
+ #
554
+ # @return Bool
555
+ has_verification_token: -> $( "input[name=wc-#{@id_dasherized}-buyer-verification-token]" ).val()
556
+
557
+
558
  # Logs data to the debug log via AJAX.
559
  #
560
  # @since 2.0.0
assets/js/frontend/wc-square.min.js CHANGED
@@ -1,2 +1,2 @@
1
- "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(t,n,a){return n&&e(t.prototype,n),a&&e(t,a),t}}();(function(){var e=[].indexOf;jQuery(document).ready(function(t){return window.WC_Square_Payment_Form_Handler=function(){function n(e){if(_classCallCheck(this,n),this.set_payment_fields=this.set_payment_fields.bind(this),this.get_form_params=this.get_form_params.bind(this),this.handle_input_event=this.handle_input_event.bind(this),this.id=e.id,this.id_dasherized=e.id_dasherized,this.csc_required=e.csc_required,this.enabled_card_types=e.enabled_card_types,this.square_card_types=e.square_card_types,this.logging_enabled=e.logging_enabled,this.general_error=e.general_error,this.ajax_url=e.ajax_url,this.ajax_log_nonce=e.ajax_log_nonce,this.input_styles=e.input_styles,this.application_id=e.application_id,t("form.checkout").length)this.form=t("form.checkout"),this.handle_checkout_page();else if(t("form#order_review").length)this.form=t("form#order_review"),this.handle_pay_page();else{if(!t("form#add_payment_method").length)return void console.log("No payment form found!");this.form=t("form#add_payment_method"),this.handle_add_payment_method_page()}this.params=window.sv_wc_payment_gateway_payment_form_params,t(document.body).on("checkout_error",function(){return t("input[name=wc-square-credit-card-payment-nonce]").val("")}),t(document.body).on("click","#payment_method_"+this.id,function(){if(this.payment_form)return this.log("Recalculating payment form size"),this.payment_form.recalculateSize()})}return _createClass(n,[{key:"handle_checkout_page",value:function(){var e=this;return t(document.body).on("updated_checkout",function(){return e.set_payment_fields()}),t(document.body).on("updated_checkout",function(){return e.handle_saved_payment_methods()}),this.form.on("checkout_place_order_"+this.id,function(){return e.validate_payment_data()})}},{key:"handle_saved_payment_methods",value:function(){var e,n;if(n=this.id_dasherized,e=t("div.js-wc-"+n+"-new-payment-method-form"),t("input.js-wc-"+this.id_dasherized+"-payment-token").change(function(){return t("input.js-wc-"+n+"-payment-token:checked").val()?e.slideUp(200):e.slideDown(200)}).change(),t("input#createaccount").change(function(){var e;return e=t("input.js-wc-"+n+"-tokenize-payment-method").closest("p.form-row"),t(this).is(":checked")?(e.slideDown(),e.next().show()):(e.hide(),e.next().hide())}),!t("input#createaccount").is(":checked"))return t("input#createaccount").change()}},{key:"handle_pay_page",value:function(){var e=this;return this.set_payment_fields(),this.handle_saved_payment_methods(),this.form.submit(function(){if(t("#order_review input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"handle_add_payment_method_page",value:function(){var e=this;return this.set_payment_fields(),this.form.submit(function(){if(t("#add_payment_method input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"set_payment_fields",value:function(){return this.payment_form&&(this.log("Destroying payment form"),this.payment_form.destroy()),this.log("Building payment form"),this.payment_form=new SqPaymentForm(this.get_form_params()),this.payment_form.build()}},{key:"get_form_params",value:function(){var e,n,a,r,i=this;return e=t("#wc-"+this.id_dasherized+"-account-number-hosted"),a=t("#wc-"+this.id_dasherized+"-expiry-hosted"),n=t("#wc-"+this.id_dasherized+"-csc-hosted"),r=t("#wc-"+this.id_dasherized+"-postal-code-hosted"),{applicationId:this.application_id,cardNumber:{elementId:e.attr("id"),placeholder:e.data("placeholder")},expirationDate:{elementId:a.attr("id"),placeholder:a.data("placeholder")},cvv:{elementId:n.attr("id"),placeholder:n.data("placeholder")},postalCode:{elementId:r.attr("id"),placeholder:r.data("placeholder")},inputClass:"wc-"+this.id_dasherized+"-payment-field",inputStyles:this.input_styles,callbacks:{inputEventReceived:function(e){return i.handle_input_event(e)},cardNonceResponseReceived:function(e,t,n){return i.handle_response(e,t,n)},unsupportedBrowserDetected:function(){return i.handle_unsupported_browser()},paymentFormLoaded:function(){return i.handle_form_loaded()}}}}},{key:"handle_form_loaded",value:function(){if(this.log("Payment form loaded"),this.payment_form.setPostalCode(t("#billing_postcode").val()),t("form.checkout").length||t("#billing_postcode").val())return t(".wc-square-credit-card-card-postal-code-parent").addClass("hidden")}},{key:"handle_input_event",value:function(e){var n;if(n=t("#"+e.elementId),"cardBrandChanged"===e.eventType)return this.handle_card_brand_change(e.cardBrand,n)}},{key:"handle_card_brand_change",value:function(n,a){var r;return this.log("Card brand changed to "+n),a.attr("class",function(e,t){return t.replace(/(^|\s)card-type-\S+/g,"")}),r="plain",null!=n&&"unknown"!==n||(n=""),null!=this.square_card_types[n]&&(n=this.square_card_types[n]),r=n&&e.call(this.enabled_card_types,n)<0?"invalid":n,t("input[name=wc-"+this.id_dasherized+"-card-type]").val(n),a.addClass("card-type-"+r)}},{key:"validate_payment_data",value:function(){return!this.form.is(".processing")&&(this.has_nonce()?(this.log("Payment nonce present, placing order"),!0):!!t(".payment_method_"+this.id).find(".js-wc-square-credit-card-payment-token:checked").val()||(this.log("Requesting payment nonce"),this.block_ui(),this.payment_form.requestCardNonce(),!1))}},{key:"handle_response",value:function(e,n,a){var r;return e?this.handle_errors(e):n?(this.log("Card data received"),console.log(a),this.log_data(a,"response"),a.last_4&&t("input[name=wc-"+this.id_dasherized+"-last-four]").val(a.last_4),a.exp_month&&t("input[name=wc-"+this.id_dasherized+"-exp-month]").val(a.exp_month),a.exp_year&&t("input[name=wc-"+this.id_dasherized+"-exp-year]").val(a.exp_year),a.billing_postal_code&&t("input[name=wc-square-credit-card-payment-postcode]").val(a.billing_postal_code),t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val(n),this.form.submit()):(r="Nonce is missing from the Square response",this.log(r,"error"),this.log_data(r,"response"),this.handle_errors())}},{key:"handle_unsupported_browser",value:function(){}},{key:"handle_errors",value:function(){var e,n=this,a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return this.log("Error getting payment data","error"),e=[],a&&(console.error(a),t(a).each(function(t,r){var i;return"UNSUPPORTED_CARD_BRAND"===(i=r.type)||"VALIDATION_ERROR"===i?e.push(r.message):n.log_data(a,"response")})),0===e.length&&e.push(this.general_error),this.render_errors(e),this.unblock_ui()}},{key:"render_errors",value:function(e){return t(".woocommerce-error, .woocommerce-message").remove(),this.form.prepend('<ul class="woocommerce-error"><li>'+e.join("</li><li>")+"</li></ul>"),this.form.removeClass("processing").unblock(),this.form.find(".input-text, select").blur(),t("html, body").animate({scrollTop:this.form.offset().top-100},1e3)}},{key:"block_ui",value:function(){return this.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}},{key:"unblock_ui",value:function(){return this.form.unblock()}},{key:"has_nonce",value:function(){return t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val()}},{key:"log_data",value:function(e,n){var a;if(this.logging_enabled)return a={action:"wc_"+this.id+"_log_js_data",security:this.ajax_log_nonce,type:n,data:e},t.ajax({url:this.ajax_url,data:a})}},{key:"log",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"notice";if(this.logging_enabled)return"error"===t?console.error("Square Error: "+e):console.log("Square: "+e)}}]),n}()})}).call(void 0);
2
  //# sourceMappingURL=wc-square.min.js.map
1
+ "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var i=t[n];i.enumerable=i.enumerable||!1,i.configurable=!0,"value"in i&&(i.writable=!0),Object.defineProperty(e,i.key,i)}}return function(t,n,i){return n&&e(t.prototype,n),i&&e(t,i),t}}();(function(){var e=[].indexOf;jQuery(document).ready(function(t){return window.WC_Square_Payment_Form_Handler=function(){function n(e){if(_classCallCheck(this,n),this.set_payment_fields=this.set_payment_fields.bind(this),this.get_form_params=this.get_form_params.bind(this),this.handle_input_event=this.handle_input_event.bind(this),this.handle_verify_buyer_response=this.handle_verify_buyer_response.bind(this),this.id=e.id,this.id_dasherized=e.id_dasherized,this.csc_required=e.csc_required,this.enabled_card_types=e.enabled_card_types,this.square_card_types=e.square_card_types,this.ajax_log_nonce=e.ajax_log_nonce,this.ajax_url=e.ajax_url,this.application_id=e.application_id,this.currency_code=e.currency_code,this.general_error=e.general_error,this.input_styles=e.input_styles,this.is_3ds_enabled=e.is_3d_secure_enabled,this.is_add_payment_method_page=e.is_add_payment_method_page,this.location_id=e.location_id,this.logging_enabled=e.logging_enabled,t("form.checkout").length)this.form=t("form.checkout"),this.handle_checkout_page();else if(t("form#order_review").length)this.form=t("form#order_review"),this.handle_pay_page();else{if(!t("form#add_payment_method").length)return void this.log("No payment form found!");this.form=t("form#add_payment_method"),this.handle_add_payment_method_page()}this.params=window.sv_wc_payment_gateway_payment_form_params,t(document.body).on("checkout_error",function(){return t("input[name=wc-square-credit-card-payment-nonce]").val(""),t("input[name=wc-square-credit-card-buyer-verification-token]").val("")}),t(document.body).on("click","#payment_method_"+this.id,function(){if(this.payment_form)return this.log("Recalculating payment form size"),this.payment_form.recalculateSize()})}return _createClass(n,[{key:"handle_checkout_page",value:function(){var e=this;return t(document.body).on("updated_checkout",function(){return e.set_payment_fields()}),t(document.body).on("updated_checkout",function(){return e.handle_saved_payment_methods()}),this.form.on("checkout_place_order_"+this.id,function(){return e.validate_payment_data()})}},{key:"handle_saved_payment_methods",value:function(){var e,n;if(n=this.id_dasherized,e=t("div.js-wc-"+n+"-new-payment-method-form"),t("input.js-wc-"+this.id_dasherized+"-payment-token").change(function(){return t("input.js-wc-"+n+"-payment-token:checked").val()?e.slideUp(200):e.slideDown(200)}).change(),t("input#createaccount").change(function(){var e;return e=t("input.js-wc-"+n+"-tokenize-payment-method").closest("p.form-row"),t(this).is(":checked")?(e.slideDown(),e.next().show()):(e.hide(),e.next().hide())}),!t("input#createaccount").is(":checked"))return t("input#createaccount").change()}},{key:"handle_pay_page",value:function(){var e=this;return this.set_payment_fields(),this.handle_saved_payment_methods(),this.form.submit(function(){if(t("#order_review input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"handle_add_payment_method_page",value:function(){var e=this;return this.set_payment_fields(),this.form.submit(function(){if(t("#add_payment_method input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"set_payment_fields",value:function(){return this.payment_form&&(this.log("Destroying payment form"),this.payment_form.destroy()),this.log("Building payment form"),this.payment_form=new SqPaymentForm(this.get_form_params()),this.payment_form.build()}},{key:"get_form_params",value:function(){var e,n,i,a,r=this;return e=t("#wc-"+this.id_dasherized+"-account-number-hosted"),i=t("#wc-"+this.id_dasherized+"-expiry-hosted"),n=t("#wc-"+this.id_dasherized+"-csc-hosted"),a=t("#wc-"+this.id_dasherized+"-postal-code-hosted"),{applicationId:this.application_id,locationId:this.location_id,cardNumber:{elementId:e.attr("id"),placeholder:e.data("placeholder")},expirationDate:{elementId:i.attr("id"),placeholder:i.data("placeholder")},cvv:{elementId:n.attr("id"),placeholder:n.data("placeholder")},postalCode:{elementId:a.attr("id"),placeholder:a.data("placeholder")},inputClass:"wc-"+this.id_dasherized+"-payment-field",inputStyles:this.input_styles,callbacks:{inputEventReceived:function(e){return r.handle_input_event(e)},cardNonceResponseReceived:function(e,t,n){return r.handle_card_nonce_response(e,t,n)},unsupportedBrowserDetected:function(){return r.handle_unsupported_browser()},paymentFormLoaded:function(){return r.handle_form_loaded()}}}}},{key:"handle_form_loaded",value:function(){if(this.log("Payment form loaded"),this.payment_form.setPostalCode(t("#billing_postcode").val()),t("form.checkout").length||t("#billing_postcode").val())return t(".wc-square-credit-card-card-postal-code-parent").addClass("hidden")}},{key:"handle_input_event",value:function(e){var n;if(n=t("#"+e.elementId),"cardBrandChanged"===e.eventType)return this.handle_card_brand_change(e.cardBrand,n)}},{key:"handle_card_brand_change",value:function(n,i){var a;return this.log("Card brand changed to "+n),i.attr("class",function(e,t){return t.replace(/(^|\s)card-type-\S+/g,"")}),a="plain",null!=n&&"unknown"!==n||(n=""),null!=this.square_card_types[n]&&(n=this.square_card_types[n]),a=n&&e.call(this.enabled_card_types,n)<0?"invalid":n,t("input[name=wc-"+this.id_dasherized+"-card-type]").val(n),i.addClass("card-type-"+a)}},{key:"validate_payment_data",value:function(){var e;return!this.form.is(".processing")&&(this.has_nonce()?(this.log("Payment nonce present, placing order"),!0):(e=this.get_tokenized_payment_method_id())?!this.is_3ds_enabled||(this.has_verification_token()?(this.log("Tokenized payment verification token present, placing order"),!0):(this.log("Requesting verification token for tokenized payment"),this.block_ui(),this.payment_form.verifyBuyer(e,this.get_verification_details(),this.handle_verify_buyer_response),!1)):(this.log("Requesting payment nonce"),this.block_ui(),this.payment_form.requestCardNonce(),!1))}},{key:"get_tokenized_payment_method_id",value:function(){return t(".payment_method_"+this.id).find(".js-wc-square-credit-card-payment-token:checked").val()}},{key:"handle_card_nonce_response",value:function(e,n,i){var a;return e?this.handle_errors(e):n?(this.log("Card data received"),this.log(i),this.log_data(i,"response"),i.last_4&&t("input[name=wc-"+this.id_dasherized+"-last-four]").val(i.last_4),i.exp_month&&t("input[name=wc-"+this.id_dasherized+"-exp-month]").val(i.exp_month),i.exp_year&&t("input[name=wc-"+this.id_dasherized+"-exp-year]").val(i.exp_year),i.billing_postal_code&&t("input[name=wc-square-credit-card-payment-postcode]").val(i.billing_postal_code),t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val(n),this.is_3ds_enabled?(this.log("Verifying buyer"),void this.payment_form.verifyBuyer(n,this.get_verification_details(),this.handle_verify_buyer_response)):this.form.submit()):(a="Nonce is missing from the Square response",this.log(a,"error"),this.log_data(a,"response"),this.handle_errors())}},{key:"handle_verify_buyer_response",value:function(e,n){var i;return e?this.handle_errors(e):n&&n.token?(this.log("Verification result received"),this.log(n),t("input[name=wc-"+this.id_dasherized+"-buyer-verification-token]").val(n.token),this.form.submit()):(i="Verification token is missing from the Square response",this.log(i,"error"),this.log_data(i,"response"),this.handle_errors())}},{key:"get_verification_details",value:function(){var e;return"CHARGE"===(e={billingContact:{familyName:t("#billing_last_name").val(),givenName:t("#billing_first_name").val(),email:t("#billing_email").val(),country:t("#billing_country").val(),region:t("#billing_state").val(),city:t("#billing_city").val(),postalCode:t("#billing_postcode").val(),phone:t("#billing_phone").val(),addressLines:[t("#billing_address_1").val(),t("#billing_address_2").val()]},intent:this.get_intent()}).intent&&(e.amount=this.get_amount(),e.currencyCode=this.currency_code),this.log(e),e}},{key:"get_intent",value:function(){var e,n;return e=t("#wc-square-credit-card-tokenize-payment-method"),n=e.is("input:checkbox")?e.is(":checked"):"true"===e.val(),!this.get_tokenized_payment_method_id()&&n?"STORE":"CHARGE"}},{key:"get_amount",value:function(){return t("input[name=wc-"+this.id_dasherized+"-amount]").val()}},{key:"handle_unsupported_browser",value:function(){}},{key:"handle_errors",value:function(){var e,n=this,i=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return this.log("Error getting payment data","error"),t("input[name=wc-square-credit-card-payment-nonce]").val(""),t("input[name=wc-square-credit-card-buyer-verification-token]").val(""),e=[],i&&(console.error(i),t(i).each(function(t,a){var r;return"UNSUPPORTED_CARD_BRAND"===(r=a.type)||"VALIDATION_ERROR"===r?e.push(a.message):n.log_data(i,"response")})),0===e.length&&e.push(this.general_error),this.render_errors(e),this.unblock_ui()}},{key:"render_errors",value:function(e){return t(".woocommerce-error, .woocommerce-message").remove(),this.form.prepend('<ul class="woocommerce-error"><li>'+e.join("</li><li>")+"</li></ul>"),this.form.removeClass("processing").unblock(),this.form.find(".input-text, select").blur(),t("html, body").animate({scrollTop:this.form.offset().top-100},1e3)}},{key:"block_ui",value:function(){return this.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}},{key:"unblock_ui",value:function(){return this.form.unblock()}},{key:"has_nonce",value:function(){return t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val()}},{key:"has_verification_token",value:function(){return t("input[name=wc-"+this.id_dasherized+"-buyer-verification-token]").val()}},{key:"log_data",value:function(e,n){var i;if(this.logging_enabled)return i={action:"wc_"+this.id+"_log_js_data",security:this.ajax_log_nonce,type:n,data:e},t.ajax({url:this.ajax_url,data:i})}},{key:"log",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"notice";if(this.logging_enabled)return"error"===t?console.error("Square Error: "+e):console.log("Square: "+e)}}]),n}()})}).call(void 0);
2
  //# sourceMappingURL=wc-square.min.js.map
assets/js/frontend/wc-square.min.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["wc-square.min.js"],"names":["_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","key","protoProps","staticProps","prototype","indexOf","jQuery","document","ready","$","window","WC_Square_Payment_Form_Handler","args","this","set_payment_fields","bind","get_form_params","handle_input_event","id","id_dasherized","csc_required","enabled_card_types","square_card_types","logging_enabled","general_error","ajax_url","ajax_log_nonce","input_styles","application_id","form","handle_checkout_page","handle_pay_page","console","log","handle_add_payment_method_page","params","body","on","val","payment_form","recalculateSize","value","_this","handle_saved_payment_methods","validate_payment_data","$new_payment_method_selection","change","slideUp","slideDown","$parent_row","closest","is","next","show","hide","_this2","submit","_this3","destroy","SqPaymentForm","build","$card_number","$csc","$expiration","$postal_code","_this4","applicationId","cardNumber","elementId","attr","placeholder","data","expirationDate","cvv","postalCode","inputClass","inputStyles","callbacks","inputEventReceived","event","cardNonceResponseReceived","errors","nonce","cardData","handle_response","unsupportedBrowserDetected","handle_unsupported_browser","paymentFormLoaded","handle_form_loaded","setPostalCode","addClass","$input","eventType","handle_card_brand_change","cardBrand","brand","card_class","c","replace","call","has_nonce","find","block_ui","requestCardNonce","message","handle_errors","log_data","last_4","exp_month","exp_year","billing_postal_code","messages","_this5","arguments","undefined","error","each","index","ref","type","push","render_errors","unblock_ui","remove","prepend","join","removeClass","unblock","blur","animate","scrollTop","offset","top","block","overlayCSS","background","opacity","ajax_data","action","security","ajax","url"],"mappings":"AAAA,aAIA,SAASA,gBAAgBC,EAAUC,GAAe,KAAMD,aAAoBC,GAAgB,MAAM,IAAIC,UAAU,qCAFhH,IAAIC,aAAe,WAAc,SAASC,EAAiBC,EAAQC,GAAS,IAAK,IAAIC,EAAI,EAAGA,EAAID,EAAME,OAAQD,IAAK,CAAE,IAAIE,EAAaH,EAAMC,GAAIE,EAAWC,WAAaD,EAAWC,aAAc,EAAOD,EAAWE,cAAe,EAAU,UAAWF,IAAYA,EAAWG,UAAW,GAAMC,OAAOC,eAAeT,EAAQI,EAAWM,IAAKN,IAAiB,OAAO,SAAUR,EAAae,EAAYC,GAAiJ,OAA9HD,GAAYZ,EAAiBH,EAAYiB,UAAWF,GAAiBC,GAAab,EAAiBH,EAAagB,GAAqBhB,GAA7gB,IAInB,WAME,IAAIkB,KAAaA,QAEjBC,OAAOC,UAAUC,MAAM,SAAUC,GAM/B,OAAOC,OAAOC,+BAAiC,WAI7C,SAASA,EAA+BC,GA6BtC,GA5BA3B,gBAAgB4B,KAAMF,GAKtBE,KAAKC,mBAAqBD,KAAKC,mBAAmBC,KAAKF,MAMvDA,KAAKG,gBAAkBH,KAAKG,gBAAgBD,KAAKF,MAIjDA,KAAKI,mBAAqBJ,KAAKI,mBAAmBF,KAAKF,MACvDA,KAAKK,GAAKN,EAAKM,GACfL,KAAKM,cAAgBP,EAAKO,cAC1BN,KAAKO,aAAeR,EAAKQ,aACzBP,KAAKQ,mBAAqBT,EAAKS,mBAC/BR,KAAKS,kBAAoBV,EAAKU,kBAC9BT,KAAKU,gBAAkBX,EAAKW,gBAC5BV,KAAKW,cAAgBZ,EAAKY,cAC1BX,KAAKY,SAAWb,EAAKa,SACrBZ,KAAKa,eAAiBd,EAAKc,eAC3Bb,KAAKc,aAAef,EAAKe,aACzBd,KAAKe,eAAiBhB,EAAKgB,eAEvBnB,EAAE,iBAAiBf,OACrBmB,KAAKgB,KAAOpB,EAAE,iBACdI,KAAKiB,4BACA,GAAIrB,EAAE,qBAAqBf,OAChCmB,KAAKgB,KAAOpB,EAAE,qBACdI,KAAKkB,sBACA,CAAA,IAAItB,EAAE,2BAA2Bf,OAKtC,YADAsC,QAAQC,IAAI,0BAHZpB,KAAKgB,KAAOpB,EAAE,2BACdI,KAAKqB,iCAMPrB,KAAKsB,OAASzB,OAAkD,0CAEhED,EAAEF,SAAS6B,MAAMC,GAAG,iBAAkB,WACpC,OAAO5B,EAAE,mDAAmD6B,IAAI,MAElE7B,EAAEF,SAAS6B,MAAMC,GAAG,QAAS,mBAAqBxB,KAAKK,GAAI,WACzD,GAAIL,KAAK0B,aAEP,OADA1B,KAAKoB,IAAI,mCACFpB,KAAK0B,aAAaC,oBAwb/B,OA9aAnD,aAAasB,IACXV,IAAK,uBACLwC,MAAO,WACL,IAAIC,EAAQ7B,KAaZ,OAVAJ,EAAEF,SAAS6B,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAM5B,uBAKfL,EAAEF,SAAS6B,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAMC,iCAGR9B,KAAKgB,KAAKQ,GAAG,wBAA0BxB,KAAKK,GAAI,WACrD,OAAOwB,EAAME,6BASjB3C,IAAK,+BACLwC,MAAO,WACL,IAAII,EAA+B1B,EA6BnC,GA3BAA,EAAgBN,KAAKM,cACrB0B,EAAgCpC,EAAE,aAAeU,EAAgB,4BAEjEV,EAAE,eAAiBI,KAAKM,cAAgB,kBAAkB2B,OAAO,WAG/D,OADoCrC,EAAE,eAAiBU,EAAgB,0BAA0BmB,MAGxFO,EAA8BE,QAAQ,KAGtCF,EAA8BG,UAAU,OAEhDF,SAGHrC,EAAE,uBAAuBqC,OAAO,WAC9B,IAAIG,EAEJ,OADAA,EAAcxC,EAAE,eAAiBU,EAAgB,4BAA4B+B,QAAQ,cACjFzC,EAAEI,MAAMsC,GAAG,aACbF,EAAYD,YACLC,EAAYG,OAAOC,SAE1BJ,EAAYK,OACLL,EAAYG,OAAOE,WAGzB7C,EAAE,uBAAuB0C,GAAG,YAC/B,OAAO1C,EAAE,uBAAuBqC,YASpC7C,IAAK,kBACLwC,MAAO,WACL,IAAIc,EAAS1C,KAMb,OAJAA,KAAKC,qBAELD,KAAK8B,+BAEE9B,KAAKgB,KAAK2B,OAAO,WACtB,GAAI/C,EAAE,oDAAoD6B,QAAUiB,EAAOrC,GAEzE,OAAOqC,EAAOX,6BAUpB3C,IAAK,iCACLwC,MAAO,WACL,IAAIgB,EAAS5C,KAIb,OAFAA,KAAKC,qBAEED,KAAKgB,KAAK2B,OAAO,WACtB,GAAI/C,EAAE,0DAA0D6B,QAAUmB,EAAOvC,GAE/E,OAAOuC,EAAOb,6BAKpB3C,IAAK,qBACLwC,MAAO,WAOL,OANI5B,KAAK0B,eACP1B,KAAKoB,IAAI,2BACTpB,KAAK0B,aAAamB,WAEpB7C,KAAKoB,IAAI,yBACTpB,KAAK0B,aAAe,IAAIoB,cAAc9C,KAAKG,mBACpCH,KAAK0B,aAAaqB,WAG3B3D,IAAK,kBACLwC,MAAO,WACL,IAEIoB,EAAcC,EAAMC,EAAaC,EAFjCC,EAASpD,KAOb,OAJAgD,EAAepD,EAAE,OAASI,KAAKM,cAAgB,0BAC/C4C,EAActD,EAAE,OAASI,KAAKM,cAAgB,kBAC9C2C,EAAOrD,EAAE,OAASI,KAAKM,cAAgB,eACvC6C,EAAevD,EAAE,OAASI,KAAKM,cAAgB,wBAE7C+C,cAAerD,KAAKe,eACpBuC,YACEC,UAAWP,EAAaQ,KAAK,MAC7BC,YAAaT,EAAaU,KAAK,gBAEjCC,gBACEJ,UAAWL,EAAYM,KAAK,MAC5BC,YAAaP,EAAYQ,KAAK,gBAEhCE,KACEL,UAAWN,EAAKO,KAAK,MACrBC,YAAaR,EAAKS,KAAK,gBAEzBG,YACEN,UAAWJ,EAAaK,KAAK,MAC7BC,YAAaN,EAAaO,KAAK,gBAEjCI,WAAY,MAAQ9D,KAAKM,cAAgB,iBACzCyD,YAAa/D,KAAKc,aAClBkD,WACEC,mBAAoB,SAA4BC,GAC9C,OAAOd,EAAOhD,mBAAmB8D,IAEnCC,0BAA2B,SAAmCC,EAAQC,EAAOC,GAC3E,OAAOlB,EAAOmB,gBAAgBH,EAAQC,EAAOC,IAE/CE,2BAA4B,WAC1B,OAAOpB,EAAOqB,8BAEhBC,kBAAmB,WACjB,OAAOtB,EAAOuB,2BAWtBvF,IAAK,qBACLwC,MAAO,WAIL,GAHA5B,KAAKoB,IAAI,uBACTpB,KAAK0B,aAAakD,cAAchF,EAAE,qBAAqB6B,OAEnD7B,EAAE,iBAAiBf,QAAUe,EAAE,qBAAqB6B,MACtD,OAAO7B,EAAE,kDAAkDiF,SAAS,aAIxEzF,IAAK,qBACLwC,MAAO,SAA4BsC,GACjC,IAAIY,EAEJ,GADAA,EAASlF,EAAE,IAAMsE,EAAMX,WACC,qBAApBW,EAAMa,UACR,OAAO/E,KAAKgF,yBAAyBd,EAAMe,UAAWH,MAS1D1F,IAAK,2BACLwC,MAAO,SAAkCsD,EAAOJ,GAC9C,IAAIK,EAmBJ,OAlBAnF,KAAKoB,IAAI,yBAA2B8D,GAEpCJ,EAAOtB,KAAK,QAAS,SAAU5E,EAAGwG,GAChC,OAAOA,EAAEC,QAAQ,uBAAwB,MAE3CF,EAAa,QACA,MAATD,GAA2B,YAAVA,IACnBA,EAAQ,IAE2B,MAAjClF,KAAKS,kBAAkByE,KACzBA,EAAQlF,KAAKS,kBAAkByE,IAG/BC,EADED,GAAS1F,EAAQ8F,KAAKtF,KAAKQ,mBAAoB0E,GAAS,EAC7C,UAEAA,EAEftF,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAIyD,GACtDJ,EAAOD,SAAS,aAAeM,MAQxC/F,IAAK,wBACLwC,MAAO,WACL,OAAI5B,KAAKgB,KAAKsB,GAAG,iBAKbtC,KAAKuF,aACPvF,KAAKoB,IAAI,yCACF,KAELxB,EAAE,mBAAqBI,KAAKK,IAAImF,KAAK,mDAAmD/D,QAG5FzB,KAAKoB,IAAI,4BACTpB,KAAKyF,WACLzF,KAAK0B,aAAagE,oBACX,OAWTtG,IAAK,kBACLwC,MAAO,SAAyBwC,EAAQC,EAAOC,GAC7C,IAAIqB,EAEJ,OAAIvB,EACKpE,KAAK4F,cAAcxB,GAGvBC,GAOLrE,KAAKoB,IAAI,sBACTD,QAAQC,IAAIkD,GACZtE,KAAK6F,SAASvB,EAAU,YACpBA,EAASwB,QACXlG,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAI6C,EAASwB,QAEpExB,EAASyB,WACXnG,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAI6C,EAASyB,WAEpEzB,EAAS0B,UACXpG,EAAE,iBAAmBI,KAAKM,cAAgB,cAAcmB,IAAI6C,EAAS0B,UAEnE1B,EAAS2B,qBACXrG,EAAE,sDAAsD6B,IAAI6C,EAAS2B,qBAGvErG,EAAE,iBAAmBI,KAAKM,cAAgB,mBAAmBmB,IAAI4C,GAE1DrE,KAAKgB,KAAK2B,WAxBfgD,EAAU,4CACV3F,KAAKoB,IAAIuE,EAAS,SAClB3F,KAAK6F,SAASF,EAAS,YAChB3F,KAAK4F,oBA6BhBxG,IAAK,6BACLwC,MAAO,eAQPxC,IAAK,gBACLwC,MAAO,WACL,IAIIsE,EAJAC,EAASnG,KAEToE,EAASgC,UAAUvH,OAAS,QAAsBwH,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,KAuBjF,OApBApG,KAAKoB,IAAI,6BAA8B,SACvC8E,KACI9B,IACFjD,QAAQmF,MAAMlC,GACdxE,EAAEwE,GAAQmC,KAAK,SAAUC,EAAOF,GAC9B,IAAIG,EAEJ,MAA2B,4BAAtBA,EAAMH,EAAMI,OAA8C,qBAARD,EAC9CP,EAASS,KAAKL,EAAMX,SAGpBQ,EAAON,SAASzB,EAAQ,eAKb,IAApB8B,EAASrH,QACXqH,EAASS,KAAK3G,KAAKW,eAErBX,KAAK4G,cAAcV,GACZlG,KAAK6G,gBAQdzH,IAAK,gBACLwC,MAAO,SAAuBwC,GAS5B,OAPAxE,EAAE,4CAA4CkH,SAE9C9G,KAAKgB,KAAK+F,QAAQ,qCAAuC3C,EAAO4C,KAAK,aAAe,cAEpFhH,KAAKgB,KAAKiG,YAAY,cAAcC,UACpClH,KAAKgB,KAAKwE,KAAK,uBAAuB2B,OAE/BvH,EAAE,cAAcwH,SACrBC,UAAWrH,KAAKgB,KAAKsG,SAASC,IAAM,KACnC,QAQLnI,IAAK,WACLwC,MAAO,WACL,OAAO5B,KAAKgB,KAAKwG,OACf7B,QAAS,KACT8B,YACEC,WAAY,OACZC,QAAS,SAUfvI,IAAK,aACLwC,MAAO,WACL,OAAO5B,KAAKgB,KAAKkG,aASnB9H,IAAK,YACLwC,MAAO,WACL,OAAOhC,EAAE,iBAAmBI,KAAKM,cAAgB,mBAAmBmB,SAWtErC,IAAK,WACLwC,MAAO,SAAkB8B,EAAMgD,GAC7B,IAAIkB,EAEJ,GAAK5H,KAAKU,gBASV,OANAkH,GACEC,OAAU,MAAQ7H,KAAKK,GAAK,eAC5ByH,SAAY9H,KAAKa,eACjB6F,KAAQA,EACRhD,KAAQA,GAEH9D,EAAEmI,MACPC,IAAKhI,KAAKY,SACV8C,KAAMkE,OASVxI,IAAK,MACLwC,MAAO,SAAa+D,GAClB,IAAIe,EAAON,UAAUvH,OAAS,QAAsBwH,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,SAG/E,GAAKpG,KAAKU,gBAGV,MAAa,UAATgG,EACKvF,QAAQmF,MAAM,iBAAmBX,GAEjCxE,QAAQC,IAAI,WAAauE,OAK/B7F,EA/esC,OAkfhDwF,UAAKe","file":"wc-square.min.js"}
1
+ {"version":3,"sources":["wc-square.min.js"],"names":["_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","key","protoProps","staticProps","prototype","indexOf","jQuery","document","ready","$","window","WC_Square_Payment_Form_Handler","args","this","set_payment_fields","bind","get_form_params","handle_input_event","handle_verify_buyer_response","id","id_dasherized","csc_required","enabled_card_types","square_card_types","ajax_log_nonce","ajax_url","application_id","currency_code","general_error","input_styles","is_3ds_enabled","is_3d_secure_enabled","is_add_payment_method_page","location_id","logging_enabled","form","handle_checkout_page","handle_pay_page","log","handle_add_payment_method_page","params","body","on","val","payment_form","recalculateSize","value","_this","handle_saved_payment_methods","validate_payment_data","$new_payment_method_selection","change","slideUp","slideDown","$parent_row","closest","is","next","show","hide","_this2","submit","_this3","destroy","SqPaymentForm","build","$card_number","$csc","$expiration","$postal_code","_this4","applicationId","locationId","cardNumber","elementId","attr","placeholder","data","expirationDate","cvv","postalCode","inputClass","inputStyles","callbacks","inputEventReceived","event","cardNonceResponseReceived","errors","nonce","cardData","handle_card_nonce_response","unsupportedBrowserDetected","handle_unsupported_browser","paymentFormLoaded","handle_form_loaded","setPostalCode","addClass","$input","eventType","handle_card_brand_change","cardBrand","brand","card_class","c","replace","call","tokenized_card_id","has_nonce","get_tokenized_payment_method_id","has_verification_token","block_ui","verifyBuyer","get_verification_details","requestCardNonce","find","message","handle_errors","log_data","last_4","exp_month","exp_year","billing_postal_code","verification_result","token","verification_details","billingContact","familyName","givenName","email","country","region","city","phone","addressLines","intent","get_intent","amount","get_amount","currencyCode","$save_method_input","save_payment_method","messages","_this5","arguments","undefined","console","error","each","index","ref","type","push","render_errors","unblock_ui","remove","prepend","join","removeClass","unblock","blur","animate","scrollTop","offset","top","block","overlayCSS","background","opacity","ajax_data","action","security","ajax","url"],"mappings":"AAAA,aAIA,SAASA,gBAAgBC,EAAUC,GAAe,KAAMD,aAAoBC,GAAgB,MAAM,IAAIC,UAAU,qCAFhH,IAAIC,aAAe,WAAc,SAASC,EAAiBC,EAAQC,GAAS,IAAK,IAAIC,EAAI,EAAGA,EAAID,EAAME,OAAQD,IAAK,CAAE,IAAIE,EAAaH,EAAMC,GAAIE,EAAWC,WAAaD,EAAWC,aAAc,EAAOD,EAAWE,cAAe,EAAU,UAAWF,IAAYA,EAAWG,UAAW,GAAMC,OAAOC,eAAeT,EAAQI,EAAWM,IAAKN,IAAiB,OAAO,SAAUR,EAAae,EAAYC,GAAiJ,OAA9HD,GAAYZ,EAAiBH,EAAYiB,UAAWF,GAAiBC,GAAab,EAAiBH,EAAagB,GAAqBhB,GAA7gB,IAInB,WAME,IAAIkB,KAAaA,QAEjBC,OAAOC,UAAUC,MAAM,SAAUC,GAM/B,OAAOC,OAAOC,+BAAiC,WAI7C,SAASA,EAA+BC,GAwCtC,GAvCA3B,gBAAgB4B,KAAMF,GAKtBE,KAAKC,mBAAqBD,KAAKC,mBAAmBC,KAAKF,MAMvDA,KAAKG,gBAAkBH,KAAKG,gBAAgBD,KAAKF,MAIjDA,KAAKI,mBAAqBJ,KAAKI,mBAAmBF,KAAKF,MAOvDA,KAAKK,6BAA+BL,KAAKK,6BAA6BH,KAAKF,MAC3EA,KAAKM,GAAKP,EAAKO,GACfN,KAAKO,cAAgBR,EAAKQ,cAC1BP,KAAKQ,aAAeT,EAAKS,aACzBR,KAAKS,mBAAqBV,EAAKU,mBAC/BT,KAAKU,kBAAoBX,EAAKW,kBAC9BV,KAAKW,eAAiBZ,EAAKY,eAC3BX,KAAKY,SAAWb,EAAKa,SACrBZ,KAAKa,eAAiBd,EAAKc,eAC3Bb,KAAKc,cAAgBf,EAAKe,cAC1Bd,KAAKe,cAAgBhB,EAAKgB,cAC1Bf,KAAKgB,aAAejB,EAAKiB,aACzBhB,KAAKiB,eAAiBlB,EAAKmB,qBAC3BlB,KAAKmB,2BAA6BpB,EAAKoB,2BACvCnB,KAAKoB,YAAcrB,EAAKqB,YACxBpB,KAAKqB,gBAAkBtB,EAAKsB,gBAExBzB,EAAE,iBAAiBf,OACrBmB,KAAKsB,KAAO1B,EAAE,iBACdI,KAAKuB,4BACA,GAAI3B,EAAE,qBAAqBf,OAChCmB,KAAKsB,KAAO1B,EAAE,qBACdI,KAAKwB,sBACA,CAAA,IAAI5B,EAAE,2BAA2Bf,OAKtC,YADAmB,KAAKyB,IAAI,0BAHTzB,KAAKsB,KAAO1B,EAAE,2BACdI,KAAK0B,iCAMP1B,KAAK2B,OAAS9B,OAAkD,0CAEhED,EAAEF,SAASkC,MAAMC,GAAG,iBAAkB,WAEpC,OADAjC,EAAE,mDAAmDkC,IAAI,IAClDlC,EAAE,8DAA8DkC,IAAI,MAE7ElC,EAAEF,SAASkC,MAAMC,GAAG,QAAS,mBAAqB7B,KAAKM,GAAI,WACzD,GAAIN,KAAK+B,aAEP,OADA/B,KAAKyB,IAAI,mCACFzB,KAAK+B,aAAaC,oBAikB/B,OAvjBAxD,aAAasB,IACXV,IAAK,uBACL6C,MAAO,WACL,IAAIC,EAAQlC,KAaZ,OAVAJ,EAAEF,SAASkC,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAMjC,uBAKfL,EAAEF,SAASkC,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAMC,iCAGRnC,KAAKsB,KAAKO,GAAG,wBAA0B7B,KAAKM,GAAI,WACrD,OAAO4B,EAAME,6BASjBhD,IAAK,+BACL6C,MAAO,WACL,IAAII,EAA+B9B,EA6BnC,GA3BAA,EAAgBP,KAAKO,cACrB8B,EAAgCzC,EAAE,aAAeW,EAAgB,4BAEjEX,EAAE,eAAiBI,KAAKO,cAAgB,kBAAkB+B,OAAO,WAG/D,OADoC1C,EAAE,eAAiBW,EAAgB,0BAA0BuB,MAGxFO,EAA8BE,QAAQ,KAGtCF,EAA8BG,UAAU,OAEhDF,SAGH1C,EAAE,uBAAuB0C,OAAO,WAC9B,IAAIG,EAEJ,OADAA,EAAc7C,EAAE,eAAiBW,EAAgB,4BAA4BmC,QAAQ,cACjF9C,EAAEI,MAAM2C,GAAG,aACbF,EAAYD,YACLC,EAAYG,OAAOC,SAE1BJ,EAAYK,OACLL,EAAYG,OAAOE,WAGzBlD,EAAE,uBAAuB+C,GAAG,YAC/B,OAAO/C,EAAE,uBAAuB0C,YASpClD,IAAK,kBACL6C,MAAO,WACL,IAAIc,EAAS/C,KAMb,OAJAA,KAAKC,qBAELD,KAAKmC,+BAEEnC,KAAKsB,KAAK0B,OAAO,WACtB,GAAIpD,EAAE,oDAAoDkC,QAAUiB,EAAOzC,GAEzE,OAAOyC,EAAOX,6BAUpBhD,IAAK,iCACL6C,MAAO,WACL,IAAIgB,EAASjD,KAIb,OAFAA,KAAKC,qBAEED,KAAKsB,KAAK0B,OAAO,WACtB,GAAIpD,EAAE,0DAA0DkC,QAAUmB,EAAO3C,GAE/E,OAAO2C,EAAOb,6BAKpBhD,IAAK,qBACL6C,MAAO,WAOL,OANIjC,KAAK+B,eACP/B,KAAKyB,IAAI,2BACTzB,KAAK+B,aAAamB,WAEpBlD,KAAKyB,IAAI,yBACTzB,KAAK+B,aAAe,IAAIoB,cAAcnD,KAAKG,mBACpCH,KAAK+B,aAAaqB,WAG3BhE,IAAK,kBACL6C,MAAO,WACL,IAEIoB,EAAcC,EAAMC,EAAaC,EAFjCC,EAASzD,KAOb,OAJAqD,EAAezD,EAAE,OAASI,KAAKO,cAAgB,0BAC/CgD,EAAc3D,EAAE,OAASI,KAAKO,cAAgB,kBAC9C+C,EAAO1D,EAAE,OAASI,KAAKO,cAAgB,eACvCiD,EAAe5D,EAAE,OAASI,KAAKO,cAAgB,wBAE7CmD,cAAe1D,KAAKa,eACpB8C,WAAY3D,KAAKoB,YACjBwC,YACEC,UAAWR,EAAaS,KAAK,MAC7BC,YAAaV,EAAaW,KAAK,gBAEjCC,gBACEJ,UAAWN,EAAYO,KAAK,MAC5BC,YAAaR,EAAYS,KAAK,gBAEhCE,KACEL,UAAWP,EAAKQ,KAAK,MACrBC,YAAaT,EAAKU,KAAK,gBAEzBG,YACEN,UAAWL,EAAaM,KAAK,MAC7BC,YAAaP,EAAaQ,KAAK,gBAEjCI,WAAY,MAAQpE,KAAKO,cAAgB,iBACzC8D,YAAarE,KAAKgB,aAClBsD,WACEC,mBAAoB,SAA4BC,GAC9C,OAAOf,EAAOrD,mBAAmBoE,IAEnCC,0BAA2B,SAAmCC,EAAQC,EAAOC,GAC3E,OAAOnB,EAAOoB,2BAA2BH,EAAQC,EAAOC,IAE1DE,2BAA4B,WAC1B,OAAOrB,EAAOsB,8BAEhBC,kBAAmB,WACjB,OAAOvB,EAAOwB,2BAWtB7F,IAAK,qBACL6C,MAAO,WAIL,GAHAjC,KAAKyB,IAAI,uBACTzB,KAAK+B,aAAamD,cAActF,EAAE,qBAAqBkC,OAEnDlC,EAAE,iBAAiBf,QAAUe,EAAE,qBAAqBkC,MACtD,OAAOlC,EAAE,kDAAkDuF,SAAS,aAIxE/F,IAAK,qBACL6C,MAAO,SAA4BuC,GACjC,IAAIY,EAEJ,GADAA,EAASxF,EAAE,IAAM4E,EAAMX,WACC,qBAApBW,EAAMa,UACR,OAAOrF,KAAKsF,yBAAyBd,EAAMe,UAAWH,MAS1DhG,IAAK,2BACL6C,MAAO,SAAkCuD,EAAOJ,GAC9C,IAAIK,EAmBJ,OAlBAzF,KAAKyB,IAAI,yBAA2B+D,GAEpCJ,EAAOtB,KAAK,QAAS,SAAUlF,EAAG8G,GAChC,OAAOA,EAAEC,QAAQ,uBAAwB,MAE3CF,EAAa,QACA,MAATD,GAA2B,YAAVA,IACnBA,EAAQ,IAE2B,MAAjCxF,KAAKU,kBAAkB8E,KACzBA,EAAQxF,KAAKU,kBAAkB8E,IAG/BC,EADED,GAAShG,EAAQoG,KAAK5F,KAAKS,mBAAoB+E,GAAS,EAC7C,UAEAA,EAEf5F,EAAE,iBAAmBI,KAAKO,cAAgB,eAAeuB,IAAI0D,GACtDJ,EAAOD,SAAS,aAAeM,MAQxCrG,IAAK,wBACL6C,MAAO,WACL,IAAI4D,EACJ,OAAI7F,KAAKsB,KAAKqB,GAAG,iBAKb3C,KAAK8F,aACP9F,KAAKyB,IAAI,yCACF,IAEToE,EAAoB7F,KAAK+F,oCAElB/F,KAAKiB,iBAINjB,KAAKgG,0BACPhG,KAAKyB,IAAI,gEACF,IAETzB,KAAKyB,IAAI,uDACTzB,KAAKiG,WACLjG,KAAK+B,aAAamE,YAAYL,EAAmB7F,KAAKmG,2BAA4BnG,KAAKK,+BAChF,KAETL,KAAKyB,IAAI,4BACTzB,KAAKiG,WACLjG,KAAK+B,aAAaqE,oBACX,OAUThH,IAAK,kCACL6C,MAAO,WACL,OAAOrC,EAAE,mBAAqBI,KAAKM,IAAI+F,KAAK,mDAAmDvE,SAYjG1C,IAAK,6BACL6C,MAAO,SAAoCyC,EAAQC,EAAOC,GACxD,IAAI0B,EAEJ,OAAI5B,EACK1E,KAAKuG,cAAc7B,GAGvBC,GAOL3E,KAAKyB,IAAI,sBACTzB,KAAKyB,IAAImD,GACT5E,KAAKwG,SAAS5B,EAAU,YACpBA,EAAS6B,QACX7G,EAAE,iBAAmBI,KAAKO,cAAgB,eAAeuB,IAAI8C,EAAS6B,QAEpE7B,EAAS8B,WACX9G,EAAE,iBAAmBI,KAAKO,cAAgB,eAAeuB,IAAI8C,EAAS8B,WAEpE9B,EAAS+B,UACX/G,EAAE,iBAAmBI,KAAKO,cAAgB,cAAcuB,IAAI8C,EAAS+B,UAEnE/B,EAASgC,qBACXhH,EAAE,sDAAsDkC,IAAI8C,EAASgC,qBAGvEhH,EAAE,iBAAmBI,KAAKO,cAAgB,mBAAmBuB,IAAI6C,GAE7D3E,KAAKiB,gBACPjB,KAAKyB,IAAI,wBACTzB,KAAK+B,aAAamE,YAAYvB,EAAO3E,KAAKmG,2BAA4BnG,KAAKK,+BAItEL,KAAKsB,KAAK0B,WA9BfsD,EAAU,4CACVtG,KAAKyB,IAAI6E,EAAS,SAClBtG,KAAKwG,SAASF,EAAS,YAChBtG,KAAKuG,oBA8BhBnH,IAAK,+BACL6C,MAAO,SAAsCyC,EAAQmC,GACnD,IAAIP,EACJ,OAAI5B,EACK1E,KAAKuG,cAAc7B,GAGvBmC,GAAwBA,EAAoBC,OAMjD9G,KAAKyB,IAAI,gCACTzB,KAAKyB,IAAIoF,GACTjH,EAAE,iBAAmBI,KAAKO,cAAgB,8BAA8BuB,IAAI+E,EAAoBC,OACzF9G,KAAKsB,KAAK0B,WARfsD,EAAU,yDACVtG,KAAKyB,IAAI6E,EAAS,SAClBtG,KAAKwG,SAASF,EAAS,YAChBtG,KAAKuG,oBAehBnH,IAAK,2BACL6C,MAAO,WACL,IAAI8E,EAoBJ,MALI,YAdJA,GACEC,gBACEC,WAAYrH,EAAE,sBAAsBkC,MACpCoF,UAAWtH,EAAE,uBAAuBkC,MACpCqF,MAAOvH,EAAE,kBAAkBkC,MAC3BsF,QAASxH,EAAE,oBAAoBkC,MAC/BuF,OAAQzH,EAAE,kBAAkBkC,MAC5BwF,KAAM1H,EAAE,iBAAiBkC,MACzBqC,WAAYvE,EAAE,qBAAqBkC,MACnCyF,MAAO3H,EAAE,kBAAkBkC,MAC3B0F,cAAe5H,EAAE,sBAAsBkC,MAAOlC,EAAE,sBAAsBkC,QAExE2F,OAAQzH,KAAK0H,eAEuBD,SACpCV,EAAqBY,OAAS3H,KAAK4H,aACnCb,EAAqBc,aAAe7H,KAAKc,eAE3Cd,KAAKyB,IAAIsF,GACFA,KAaT3H,IAAK,aACL6C,MAAO,WACL,IAAI6F,EAAoBC,EAOxB,OANAD,EAAqBlI,EAAE,kDAErBmI,EADED,EAAmBnF,GAAG,kBACFmF,EAAmBnF,GAAG,YAEO,SAA7BmF,EAAmBhG,OAEtC9B,KAAK+F,mCAAqCgC,EACtC,QAEA,YAWX3I,IAAK,aACL6C,MAAO,WACL,OAAOrC,EAAE,iBAAmBI,KAAKO,cAAgB,YAAYuB,SAQ/D1C,IAAK,6BACL6C,MAAO,eAQP7C,IAAK,gBACL6C,MAAO,WACL,IAII+F,EAJAC,EAASjI,KAET0E,EAASwD,UAAUrJ,OAAS,QAAsBsJ,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,KA0BjF,OAvBAlI,KAAKyB,IAAI,6BAA8B,SAEvC7B,EAAE,mDAAmDkC,IAAI,IACzDlC,EAAE,8DAA8DkC,IAAI,IACpEkG,KACItD,IACF0D,QAAQC,MAAM3D,GACd9E,EAAE8E,GAAQ4D,KAAK,SAAUC,EAAOF,GAC9B,IAAIG,EAEJ,MAA2B,4BAAtBA,EAAMH,EAAMI,OAA8C,qBAARD,EAC9CR,EAASU,KAAKL,EAAM/B,SAGpB2B,EAAOzB,SAAS9B,EAAQ,eAKb,IAApBsD,EAASnJ,QACXmJ,EAASU,KAAK1I,KAAKe,eAErBf,KAAK2I,cAAcX,GACZhI,KAAK4I,gBAQdxJ,IAAK,gBACL6C,MAAO,SAAuByC,GAS5B,OAPA9E,EAAE,4CAA4CiJ,SAE9C7I,KAAKsB,KAAKwH,QAAQ,qCAAuCpE,EAAOqE,KAAK,aAAe,cAEpF/I,KAAKsB,KAAK0H,YAAY,cAAcC,UACpCjJ,KAAKsB,KAAK+E,KAAK,uBAAuB6C,OAE/BtJ,EAAE,cAAcuJ,SACrBC,UAAWpJ,KAAKsB,KAAK+H,SAASC,IAAM,KACnC,QAQLlK,IAAK,WACL6C,MAAO,WACL,OAAOjC,KAAKsB,KAAKiI,OACfjD,QAAS,KACTkD,YACEC,WAAY,OACZC,QAAS,SAUftK,IAAK,aACL6C,MAAO,WACL,OAAOjC,KAAKsB,KAAK2H,aASnB7J,IAAK,YACL6C,MAAO,WACL,OAAOrC,EAAE,iBAAmBI,KAAKO,cAAgB,mBAAmBuB,SAUtE1C,IAAK,yBACL6C,MAAO,WACL,OAAOrC,EAAE,iBAAmBI,KAAKO,cAAgB,8BAA8BuB,SAWjF1C,IAAK,WACL6C,MAAO,SAAkB+B,EAAMyE,GAC7B,IAAIkB,EAEJ,GAAK3J,KAAKqB,gBASV,OANAsI,GACEC,OAAU,MAAQ5J,KAAKM,GAAK,eAC5BuJ,SAAY7J,KAAKW,eACjB8H,KAAQA,EACRzE,KAAQA,GAEHpE,EAAEkK,MACPC,IAAK/J,KAAKY,SACVoD,KAAM2F,OASVvK,IAAK,MACL6C,MAAO,SAAaqE,GAClB,IAAImC,EAAOP,UAAUrJ,OAAS,QAAsBsJ,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,SAG/E,GAAKlI,KAAKqB,gBAGV,MAAa,UAAToH,EACKL,QAAQC,MAAM,iBAAmB/B,GAEjC8B,QAAQ3G,IAAI,WAAa6E,OAK/BxG,EApoBsC,OAuoBhD8F,UAAKuC","file":"wc-square.min.js"}
i18n/languages/woocommerce-square.pot CHANGED
@@ -1,15 +1,15 @@
1
- # Copyright (C) 2019 WooCommerce
2
  # This file is distributed under the GNU General Public License v3.0.
3
  msgid ""
4
  msgstr ""
5
- "Project-Id-Version: WooCommerce Square 2.0.8\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-square/issues\n"
8
- "POT-Creation-Date: 2019-12-09 08:50:47+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
15
  "X-Generator: grunt-wp-i18n 1.0.3\n"
@@ -194,7 +194,7 @@ msgstr ""
194
  msgid "Actions"
195
  msgstr ""
196
 
197
- #: includes/Admin/Sync_Page.php:173 includes/Emails/Sync_Completed.php:329
198
  #. translators: Placeholder: %d number of products synced with Square
199
  #. translators: Placeholder: %d products count
200
  msgid "%d product"
@@ -320,65 +320,88 @@ msgid ""
320
  "sales from other channels."
321
  msgstr ""
322
 
323
- #: includes/Emails/Sync_Completed.php:51
324
- msgid "Square sync completed"
 
 
 
 
325
  msgstr ""
326
 
327
- #: includes/Emails/Sync_Completed.php:52
 
 
328
  msgid ""
329
- "This email is sent once a manual sync has been completed between "
330
- "WooCommerce and Square"
331
  msgstr ""
332
 
333
- #: includes/Emails/Sync_Completed.php:93
 
 
 
 
 
 
 
 
 
 
 
 
 
334
  #. translators: Placeholder: %s - default email subject text
335
  msgid ""
336
  "This controls the email subject line. Leave blank to use the default "
337
  "subject: %s"
338
  msgstr ""
339
 
340
- #: includes/Emails/Sync_Completed.php:101
341
  msgid "Recipient(s)"
342
  msgstr ""
343
 
344
- #: includes/Emails/Sync_Completed.php:104
345
  #. translators: Placeholder: %s default email address
346
  msgid ""
347
  "Enter recipients (comma separated) for this email. Defaults to admin email: "
348
  "%s"
349
  msgstr ""
350
 
351
- #: includes/Emails/Sync_Completed.php:126
352
- msgid "Square sync failed"
353
  msgstr ""
354
 
355
- #: includes/Emails/Sync_Completed.php:209
356
- #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
357
- #. </a> HTML link tag
358
- msgid "%1$sInspect status logs%2$s"
 
 
 
 
359
  msgstr ""
360
 
361
- #: includes/Emails/Sync_Completed.php:215
362
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
363
  #. </a> HTML link tag
364
  msgid "%1$sEnable logging%2$s"
365
  msgstr ""
366
 
367
- #: includes/Emails/Sync_Completed.php:222
368
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
369
  #. </a> HTML link tag, %3$s - additional action
370
  msgid "The sync job has failed. %1$sClick for more details%2$s, or %3$s."
371
  msgstr ""
372
 
373
- #: includes/Emails/Sync_Completed.php:230
374
  msgid "Inspect status logs"
375
  msgstr ""
376
 
377
- #: includes/Emails/Sync_Completed.php:232 includes/Settings.php:229
378
  msgid "Enable Logging"
379
  msgstr ""
380
 
381
- #: includes/Emails/Sync_Completed.php:237
382
  #. translators: Placeholders: %s - additional action
383
  msgid "The sync job has failed. Check sync records, or %s."
384
  msgstr ""
@@ -393,11 +416,11 @@ msgstr ""
393
  msgid "Adjustment"
394
  msgstr ""
395
 
396
- #: includes/Gateway/Payment_Form.php:95
397
  msgid "Postal code"
398
  msgstr ""
399
 
400
- #: includes/Gateway/Payment_Form.php:147 includes/Gateway.php:193
401
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:216
402
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2758
403
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:376
@@ -408,33 +431,33 @@ msgstr ""
408
  msgid "Allow customers to use Square to securely pay with their credit cards"
409
  msgstr ""
410
 
411
- #: includes/Gateway.php:379
412
  msgid "Refunds must be made within 120 days of the original payment date."
413
  msgstr ""
414
 
415
- #: includes/Gateway.php:404
416
  msgid ""
417
  "Could not find original transaction tender. Please refund this transaction "
418
  "from your Square dashboard."
419
  msgstr ""
420
 
421
- #: includes/Gateway.php:519
422
  msgid "Customer Profiles"
423
  msgstr ""
424
 
425
- #: includes/Handlers/Background_Job.php:340
426
  msgid "Clear Square Sync"
427
  msgstr ""
428
 
429
- #: includes/Handlers/Background_Job.php:341
430
  msgid "Clear"
431
  msgstr ""
432
 
433
- #: includes/Handlers/Background_Job.php:342
434
  msgid "This tool will clear any ongoing Square product syncs."
435
  msgstr ""
436
 
437
- #: includes/Handlers/Background_Job.php:361
438
  msgid "Success! You can now sync your products."
439
  msgstr ""
440
 
@@ -450,11 +473,11 @@ msgstr ""
450
  msgid "Disconnected successfully"
451
  msgstr ""
452
 
453
- #: includes/Handlers/Connection.php:382
454
  msgid "Connect with Square"
455
  msgstr ""
456
 
457
- #: includes/Handlers/Connection.php:402
458
  msgid "Disconnect from Square"
459
  msgstr ""
460
 
@@ -3002,17 +3025,32 @@ msgctxt "Date - Time"
3002
  msgid "Time"
3003
  msgstr ""
3004
 
3005
- #: includes/Emails/Sync_Completed.php:53
 
 
 
 
 
3006
  msgctxt "Email subject"
3007
  msgid "[WooCommerce] Square sync completed"
3008
  msgstr ""
3009
 
3010
- #: includes/Emails/Sync_Completed.php:54
 
 
 
 
 
 
 
 
 
 
3011
  msgctxt "Email heading with merge tag placeholder"
3012
  msgid "Square sync completed for {product_count}"
3013
  msgstr ""
3014
 
3015
- #: includes/Emails/Sync_Completed.php:55
3016
  msgctxt "Email body with merge tag placeholders"
3017
  msgid ""
3018
  "Square sync completed for {site_title} at {sync_completed_date} "
@@ -3212,4 +3250,4 @@ msgstr ""
3212
  #. translators: https:www.skyverge.com/for-translators-environments/
3213
  msgctxt "software environment"
3214
  msgid "Production"
3215
- msgstr ""
1
+ # Copyright (C) 2020 WooCommerce
2
  # This file is distributed under the GNU General Public License v3.0.
3
  msgid ""
4
  msgstr ""
5
+ "Project-Id-Version: WooCommerce Square 2.1.0\n"
6
  "Report-Msgid-Bugs-To: "
7
  "https://github.com/woocommerce/woocommerce-square/issues\n"
8
+ "POT-Creation-Date: 2020-02-10 19:58:42+00:00\n"
9
  "MIME-Version: 1.0\n"
10
  "Content-Type: text/plain; charset=utf-8\n"
11
  "Content-Transfer-Encoding: 8bit\n"
12
+ "PO-Revision-Date: 2020-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
15
  "X-Generator: grunt-wp-i18n 1.0.3\n"
194
  msgid "Actions"
195
  msgstr ""
196
 
197
+ #: includes/Admin/Sync_Page.php:173 includes/Emails/Sync_Completed.php:204
198
  #. translators: Placeholder: %d number of products synced with Square
199
  #. translators: Placeholder: %d products count
200
  msgid "%d product"
320
  "sales from other channels."
321
  msgstr ""
322
 
323
+ #: includes/Emails/Access_Token_Email.php:45
324
+ msgid "Square Access Token problems"
325
+ msgstr ""
326
+
327
+ #: includes/Emails/Access_Token_Email.php:46
328
+ msgid "This email is sent when problems with Access Token are encountered"
329
  msgstr ""
330
 
331
+ #: includes/Emails/Access_Token_Email.php:99
332
+ #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
333
+ #. </a> HTML link tag
334
  msgid ""
335
+ "In order to continue accepting payments, please %1$sdisconnect and "
336
+ "re-connect your site%2$s."
337
  msgstr ""
338
 
339
+ #: includes/Emails/Access_Token_Email.php:106
340
+ #: includes/Emails/Sync_Completed.php:100
341
+ #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
342
+ #. </a> HTML link tag
343
+ msgid "%1$sInspect status logs%2$s"
344
+ msgstr ""
345
+
346
+ #: includes/Emails/Access_Token_Email.php:111
347
+ msgid ""
348
+ "In order to continue accepting payments, please disconnect and re-connect "
349
+ "your site at "
350
+ msgstr ""
351
+
352
+ #: includes/Emails/Base_Email.php:103
353
  #. translators: Placeholder: %s - default email subject text
354
  msgid ""
355
  "This controls the email subject line. Leave blank to use the default "
356
  "subject: %s"
357
  msgstr ""
358
 
359
+ #: includes/Emails/Base_Email.php:111
360
  msgid "Recipient(s)"
361
  msgstr ""
362
 
363
+ #: includes/Emails/Base_Email.php:114
364
  #. translators: Placeholder: %s default email address
365
  msgid ""
366
  "Enter recipients (comma separated) for this email. Defaults to admin email: "
367
  "%s"
368
  msgstr ""
369
 
370
+ #: includes/Emails/Sync_Completed.php:45
371
+ msgid "Square sync completed"
372
  msgstr ""
373
 
374
+ #: includes/Emails/Sync_Completed.php:46
375
+ msgid ""
376
+ "This email is sent once a manual sync has been completed between "
377
+ "WooCommerce and Square"
378
+ msgstr ""
379
+
380
+ #: includes/Emails/Sync_Completed.php:70
381
+ msgid "Square sync failed"
382
  msgstr ""
383
 
384
+ #: includes/Emails/Sync_Completed.php:106
385
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
386
  #. </a> HTML link tag
387
  msgid "%1$sEnable logging%2$s"
388
  msgstr ""
389
 
390
+ #: includes/Emails/Sync_Completed.php:113
391
  #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
392
  #. </a> HTML link tag, %3$s - additional action
393
  msgid "The sync job has failed. %1$sClick for more details%2$s, or %3$s."
394
  msgstr ""
395
 
396
+ #: includes/Emails/Sync_Completed.php:121
397
  msgid "Inspect status logs"
398
  msgstr ""
399
 
400
+ #: includes/Emails/Sync_Completed.php:123 includes/Settings.php:229
401
  msgid "Enable Logging"
402
  msgstr ""
403
 
404
+ #: includes/Emails/Sync_Completed.php:128
405
  #. translators: Placeholders: %s - additional action
406
  msgid "The sync job has failed. Check sync records, or %s."
407
  msgstr ""
416
  msgid "Adjustment"
417
  msgstr ""
418
 
419
+ #: includes/Gateway/Payment_Form.php:150
420
  msgid "Postal code"
421
  msgstr ""
422
 
423
+ #: includes/Gateway/Payment_Form.php:203 includes/Gateway.php:195
424
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:216
425
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2758
426
  #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:376
431
  msgid "Allow customers to use Square to securely pay with their credit cards"
432
  msgstr ""
433
 
434
+ #: includes/Gateway.php:385
435
  msgid "Refunds must be made within 120 days of the original payment date."
436
  msgstr ""
437
 
438
+ #: includes/Gateway.php:410
439
  msgid ""
440
  "Could not find original transaction tender. Please refund this transaction "
441
  "from your Square dashboard."
442
  msgstr ""
443
 
444
+ #: includes/Gateway.php:525
445
  msgid "Customer Profiles"
446
  msgstr ""
447
 
448
+ #: includes/Handlers/Background_Job.php:336
449
  msgid "Clear Square Sync"
450
  msgstr ""
451
 
452
+ #: includes/Handlers/Background_Job.php:337
453
  msgid "Clear"
454
  msgstr ""
455
 
456
+ #: includes/Handlers/Background_Job.php:338
457
  msgid "This tool will clear any ongoing Square product syncs."
458
  msgstr ""
459
 
460
+ #: includes/Handlers/Background_Job.php:357
461
  msgid "Success! You can now sync your products."
462
  msgstr ""
463
 
473
  msgid "Disconnected successfully"
474
  msgstr ""
475
 
476
+ #: includes/Handlers/Connection.php:385
477
  msgid "Connect with Square"
478
  msgstr ""
479
 
480
+ #: includes/Handlers/Connection.php:405
481
  msgid "Disconnect from Square"
482
  msgstr ""
483
 
3025
  msgid "Time"
3026
  msgstr ""
3027
 
3028
+ #: includes/Emails/Access_Token_Email.php:47
3029
+ msgctxt "Email subject"
3030
+ msgid "[WooCommerce] There was a problem with your Square Access Token"
3031
+ msgstr ""
3032
+
3033
+ #: includes/Emails/Sync_Completed.php:47
3034
  msgctxt "Email subject"
3035
  msgid "[WooCommerce] Square sync completed"
3036
  msgstr ""
3037
 
3038
+ #: includes/Emails/Access_Token_Email.php:48
3039
+ msgctxt "Email heading"
3040
+ msgid "There was a problem with your Square Access Token"
3041
+ msgstr ""
3042
+
3043
+ #: includes/Emails/Access_Token_Email.php:49
3044
+ msgctxt "Square connection problems email body."
3045
+ msgid "Heads up! There may be a problem with your connection to Square."
3046
+ msgstr ""
3047
+
3048
+ #: includes/Emails/Sync_Completed.php:48
3049
  msgctxt "Email heading with merge tag placeholder"
3050
  msgid "Square sync completed for {product_count}"
3051
  msgstr ""
3052
 
3053
+ #: includes/Emails/Sync_Completed.php:49
3054
  msgctxt "Email body with merge tag placeholders"
3055
  msgid ""
3056
  "Square sync completed for {site_title} at {sync_completed_date} "
3250
  #. translators: https:www.skyverge.com/for-translators-environments/
3251
  msgctxt "software environment"
3252
  msgid "Production"
3253
+ msgstr ""
includes/Admin/Products.php DELETED
@@ -1,687 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Admin;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Product;
30
- use WooCommerce\Square\Sync\Records;
31
-
32
- /**
33
- * Products admin handler.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Products {
38
-
39
-
40
- /** @var array associative array of product error codes and messages */
41
- private $product_errors;
42
-
43
- /** @var array associative array of memoized errors being output for a product at one time */
44
- private $output_errors = [];
45
-
46
- /** @var int[] array of product IDs that have been scheduled for sync in this request */
47
- private $products_to_sync = [];
48
-
49
- /** @var int[] array of product IDs that have been scheduled for deletion in this request */
50
- private $products_to_delete = [];
51
-
52
-
53
- /**
54
- * Sets up the products admin handler.
55
- *
56
- * @since 2.0.0
57
- */
58
- public function __construct() {
59
-
60
- // add common errors
61
- $this->product_errors = [
62
- 'missing_sku' => __( "Please add a SKU to sync this product with Square. The SKU must match the item's SKU in your Square account.", 'woocommerce-square' ),
63
- 'missing_variation_sku' => __( "Please add a SKU to every variation of this variable product for syncing with Square. Each SKU must match the corresponding item's SKU in your Square account.", 'woocommerce-square' ),
64
- 'multiple_attributes' => __( 'Products with multiple variation attributes cannot be synced with Square.', 'woocommerce-square' ),
65
- ];
66
-
67
- // add hooks
68
- $this->add_products_edit_screen_hooks();
69
- $this->add_product_edit_screen_hooks();
70
- $this->add_product_sync_hooks();
71
- }
72
-
73
-
74
- /**
75
- * Adds hooks to the admin products edit screen.
76
- *
77
- * Products filtering, bulk actions, etc.
78
- *
79
- * @since 2.0.0
80
- */
81
- private function add_products_edit_screen_hooks() {
82
-
83
- // adds an option to the "Filter by product type" dropdown
84
- add_action( 'restrict_manage_posts', [ $this, 'add_filter_products_synced_with_square_option' ] );
85
- // allow filtering products by sync status by altering results
86
- add_filter( 'request', [ $this, 'filter_products_synced_with_square' ] );
87
-
88
- // prevent copying Square data when duplicating a product automatically
89
- add_action( 'woocommerce_product_duplicate', [ $this, 'handle_product_duplication' ], 20, 2 );
90
-
91
- // handle quick/bulk edit actions in the products edit screen for setting sync status
92
- add_action( 'woocommerce_product_quick_edit_end', [ $this, 'add_quick_edit_inputs' ] );
93
- add_action( 'woocommerce_product_bulk_edit_end', [ $this, 'add_bulk_edit_inputs' ] );
94
- add_action( 'woocommerce_product_quick_edit_save', [ $this, 'set_synced_with_square' ] );
95
- add_action( 'woocommerce_product_bulk_edit_save', [ $this, 'set_synced_with_square' ] );
96
- }
97
-
98
-
99
- /**
100
- * Adds hooks to individual products edit screens.
101
- *
102
- * Product data input fields, variations, etc.
103
- *
104
- * @since 2.0.0
105
- */
106
- private function add_product_edit_screen_hooks() {
107
-
108
- add_action( 'woocommerce_variation_options', [ $this, 'add_variation_manage_stock' ] );
109
-
110
- // handle individual products input fields for setting sync status
111
- add_action( 'woocommerce_product_options_general_product_data', [ $this, 'add_product_data_fields' ] );
112
- add_action( 'woocommerce_admin_process_product_object', [ $this, 'process_product_data' ], 20 );
113
- add_action( 'woocommerce_before_product_object_save', [ $this, 'maybe_adjust_square_stock'] );
114
-
115
- add_action( 'admin_notices', [ $this, 'add_notice_product_hidden_from_catalog' ] );
116
- }
117
-
118
-
119
- /**
120
- * Adds our own hidden "manage stock" input to the variation fields.
121
- *
122
- * We disable the core checkbox, but this causes stock management to be disabled for the variations because the
123
- * disabled field doesn't get POSTed. This overrides the checkbox value so that we can still disable it in the UI.
124
- *
125
- * @since 2.0.2
126
- *
127
- * @param int $loop currently looped variation
128
- */
129
- public function add_variation_manage_stock( $loop ) {
130
-
131
- if ( ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
132
- return;
133
- }
134
-
135
- ?> <input type="hidden" id="wc_square_variation_manage_stock" name="variable_manage_stock[<?php echo esc_attr( $loop ); ?>]" value="1" /> <?php
136
- }
137
-
138
-
139
- /**
140
- * Adds hooks to sync products that have been updated.
141
- *
142
- * @since 2.0.0
143
- */
144
- private function add_product_sync_hooks() {
145
-
146
- add_action( 'woocommerce_update_product', [ $this, 'maybe_stage_product_for_sync' ] );
147
- add_action( 'trashed_post', [ $this, 'maybe_stage_products_for_deletion' ] );
148
- add_action( 'shutdown', [ $this, 'maybe_sync_staged_products' ] );
149
- add_action( 'shutdown', [ $this, 'maybe_delete_staged_products' ] );
150
- }
151
-
152
-
153
- /**
154
- * Adds an option to filter products by sync status.
155
- *
156
- * @internal
157
- *
158
- * @since 2.0.0
159
- *
160
- * @param string $post_type the post type context
161
- */
162
- public function add_filter_products_synced_with_square_option( $post_type ) {
163
-
164
- if ( 'product' !== $post_type ) {
165
- return;
166
- }
167
-
168
- $label = esc_html__( 'Synced with Square', 'woocommerce-square' );
169
- $selected = isset( $_GET['product_type'] ) && 'synced-with-square' === $_GET['product_type'] ? 'selected=\"selected\"' : '';
170
-
171
- wc_enqueue_js( "
172
- jQuery( document ).ready( function( $ ) {
173
- $( 'select#dropdown_product_type' ).append( '<option value=\"synced-with-square\" ' + '" . $selected . "' + '>' + '" . $label ."' + '</option>' );
174
- } );
175
- " );
176
- }
177
-
178
-
179
- /**
180
- * Filters products in admin edit screen by sync status with Square.
181
- *
182
- * @internal
183
- *
184
- * @since 2.0.0
185
- *
186
- * @param array $query_vars query variables
187
- * @return array
188
- */
189
- public function filter_products_synced_with_square( $query_vars ){
190
- global $typenow;
191
-
192
- if ( 'product' === $typenow && isset( $_GET['product_type'] ) && 'synced-with-square' === $_GET['product_type'] ) {
193
-
194
- // not really a product type, otherwise WooCommerce will handle it as such
195
- unset( $query_vars['product_type'] );
196
-
197
- if ( ! isset( $query_vars['tax_query'] ) ) {
198
- $query_vars['tax_query'] = [];
199
- } else {
200
- $query_vars['tax_query']['relation'] = 'AND';
201
- }
202
-
203
- $query_vars['tax_query'][] = [
204
- 'taxonomy' => Product::SYNCED_WITH_SQUARE_TAXONOMY,
205
- 'field' => 'slug',
206
- 'terms' => [ 'yes' ],
207
- ];
208
- }
209
-
210
- return $query_vars;
211
- }
212
-
213
-
214
- /**
215
- * Adds general product data options to a product metabox.
216
- *
217
- * @internal
218
- *
219
- * @since 2.0.0
220
- */
221
- public function add_product_data_fields() {
222
- global $product_object;
223
-
224
- if ( ! $product_object instanceof \WC_Product ) {
225
- return;
226
- }
227
-
228
- // don't show fields if product sync is disabled
229
- if ( ! wc_square()->get_settings_handler()->is_product_sync_enabled() ) {
230
- return;
231
- }
232
-
233
- ?>
234
- <div class="wc-square-sync-with-square options_group show_if_simple show_if_variable">
235
- <?php
236
-
237
- $selector = '_' . Product::SYNCED_WITH_SQUARE_TAXONOMY;
238
- $value = Product::is_synced_with_square( $product_object ) ? 'yes' : 'no';
239
- $errors = [];
240
-
241
- if ( $product_object->is_type( 'variable' ) ) {
242
-
243
- if ( Product::has_multiple_variation_attributes( $product_object ) ) {
244
-
245
- $errors[] = 'multiple_attributes';
246
-
247
- } else {
248
-
249
- foreach ( $product_object->get_children() as $child ) {
250
-
251
- $child = wc_get_product( $child );
252
-
253
- if ( $child && ! $child->get_sku() ) {
254
- $errors[] = 'missing_variation_sku';
255
- }
256
- }
257
- }
258
-
259
- } elseif ( ! $product_object->get_sku() ) {
260
-
261
- $errors[] = 'missing_sku';
262
- }
263
-
264
- $setting_label = wc_square()->get_settings_handler()->is_system_of_record_square() ? __( 'Update product data with Square data', 'woocommerce-square' ) : __( 'Send product data to Square', 'woocommerce-square' );
265
-
266
- woocommerce_wp_checkbox( [
267
- 'id' => $selector,
268
- 'label' => __( 'Sync with Square', 'woocommerce-square' ),
269
- 'value' => $value,
270
- 'cbvalue' => 'yes',
271
- 'default' => 'no',
272
- 'description' => $setting_label,
273
- 'custom_attributes' => ! empty( $errors ) ? [ 'disabled' => 'disabled' ] : [],
274
- ] );
275
-
276
- ?>
277
- <p class="form-field wc-square-sync-with-square-errors">
278
- <?php foreach ( $this->product_errors as $error_code => $error_message ) : ?>
279
- <?php $styles = ! in_array( $error_code, $errors, true ) ? 'display:none; color:#A00;' : 'display:block; color:#A00;'; ?>
280
- <span class="wc-square-sync-with-square-error <?php echo sanitize_html_class( $error_code ); ?>" style="<?php echo $styles; ?>"><?php echo esc_html( $error_message ); ?></span>
281
- <?php endforeach; ?>
282
- </p>
283
-
284
- <input type="hidden" id="<?php echo esc_attr( Product::SQUARE_VARIATION_ID_META_KEY ); ?>" value="<?php echo esc_attr( $product_object->get_meta( Product::SQUARE_VARIATION_ID_META_KEY ) ); ?>" />
285
-
286
- </div>
287
- <?php
288
- }
289
-
290
-
291
- /**
292
- * Outputs HTML with a dropdown field to mark a product to be synced with Square.
293
- *
294
- * @since 2.0.0
295
- *
296
- * @param bool $bulk whether the field is meant for bulk edit
297
- */
298
- private function output_synced_with_square_edit_field( $bulk = false ) {
299
-
300
- ?>
301
- <div class="inline-edit-group wc-square-sync-with-square">
302
- <label>
303
- <span class="title"><?php esc_html_e( 'Sync with Square?', 'woocommerce-square' ); ?></span>
304
- <span class="input-text-wrap">
305
- <select class="square-synced" name="<?php echo esc_attr( Product::SYNCED_WITH_SQUARE_TAXONOMY ); ?>">
306
- <?php if ( true === $bulk ) : // in bulk actions there's the option to leave the value unchanged (or unset) ?>
307
- <option value="">&mdash; <?php esc_html_e( 'No change', 'woocommerce-square' ); ?> &mdash;</option>
308
- <?php endif; ?>
309
- <option value="no"><?php esc_html_e( 'No', 'woocommerce-square' ); ?></option>
310
- <option value="yes"><?php esc_html_e( 'Yes', 'woocommerce-square' ); ?></option>
311
- </select>
312
- </span>
313
- </label>
314
- <p class="form-field wc-square-sync-with-square-errors">
315
- <?php foreach ( $this->product_errors as $error_code => $error_message ) : ?>
316
- <span class="wc-square-sync-with-square-error <?php echo $error_code; ?>" style="display:none; color:#A00;"><?php echo esc_html( $error_message ); ?></span>
317
- <?php endforeach; ?>
318
- </p>
319
- </div>
320
- <?php
321
- }
322
-
323
-
324
- /**
325
- * Adds quick edit fields to the products screen.
326
- *
327
- * @internal
328
- *
329
- * @since 2.0.0
330
- */
331
- public function add_quick_edit_inputs() {
332
-
333
- $this->output_synced_with_square_edit_field();
334
- }
335
-
336
-
337
- /**
338
- * Adds bulk edit fields to the products screen.
339
- *
340
- * @internal
341
- *
342
- * @since 2.0.0
343
- */
344
- public function add_bulk_edit_inputs() {
345
-
346
- $this->output_synced_with_square_edit_field( true );
347
- }
348
-
349
-
350
- /**
351
- * Stages a product for sync with Square on product save if Woo is the SOR and the product is set to 'synced with square'.
352
- *
353
- * @internal
354
- *
355
- * @since 2.0.0
356
- *
357
- * @param int $product_id the product ID
358
- */
359
- public function maybe_stage_product_for_sync( $product_id ) {
360
-
361
- if ( ! defined( 'DOING_SQUARE_SYNC' ) && ! in_array( $product_id, $this->products_to_sync ) && wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
362
-
363
- $product = wc_get_product( $product_id );
364
-
365
- if ( $product && Product::is_synced_with_square( $product ) ) {
366
-
367
- // the triggering action for this method can be called multiple times in a single request - keep track
368
- // of product IDs that have been scheduled for sync here to avoid multiple syncs on the same request
369
- $this->products_to_sync[] = $product_id;
370
- }
371
- }
372
- }
373
-
374
-
375
- /**
376
- * Initializes a synchronization event for any staged products in this request.
377
- *
378
- * @internal
379
- *
380
- * @since 2.0.0
381
- */
382
- public function maybe_sync_staged_products() {
383
-
384
- if ( ! defined( 'DOING_SQUARE_SYNC' ) && ! empty( $this->products_to_sync ) && wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
385
-
386
- wc_square()->get_sync_handler()->start_manual_sync( true, $this->products_to_sync );
387
- }
388
- }
389
-
390
-
391
- /**
392
- * Removes a product from Square if it is deleted locally and Woo is the SOR.
393
- *
394
- * @since 2.0.0
395
- *
396
- * @param int $product_id the product ID
397
- */
398
- public function maybe_stage_products_for_deletion( $product_id ) {
399
-
400
- if ( wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
401
-
402
- $product = wc_get_product( $product_id );
403
-
404
- if ( $product && Product::is_synced_with_square( $product ) ) {
405
-
406
- // the triggering action for this method can be called multiple times in a single request - keep track
407
- // of product IDs that have been scheduled for sync here to avoid multiple syncs on the same request
408
- $this->products_to_delete[] = $product_id;
409
- }
410
- }
411
- }
412
-
413
-
414
- /**
415
- * Deletes any products staged for remote deletion.
416
- *
417
- * @since 2.0.0
418
- */
419
- public function maybe_delete_staged_products() {
420
-
421
- if ( ! empty( $this->products_to_delete ) && wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
422
-
423
- wc_square()->get_sync_handler()->start_manual_deletion( $this->products_to_delete );
424
- }
425
- }
426
-
427
-
428
- /**
429
- * Sets a product's synced with Square status for quick/bulk edit action.
430
- *
431
- * @internal
432
- *
433
- * @since 2.0.0
434
- *
435
- * @param \WC_Product $product a product object
436
- */
437
- public function set_synced_with_square( $product ) {
438
-
439
- $posted_data_key = Product::SYNCED_WITH_SQUARE_TAXONOMY;
440
-
441
- if ( 'woocommerce_product_bulk_edit_save' === current_action() ) {
442
- $default_value = null; // in bulk actions this will preserve the existing setting if nothing is specified
443
- } else {
444
- $default_value = 'no'; // in individual products context, the value should be always an explicit yes or no
445
- }
446
-
447
- $square_synced = isset( $_REQUEST[ $posted_data_key ] ) && in_array( $_REQUEST[ $posted_data_key ], [ 'yes', 'no' ], true ) ? $_REQUEST[ $posted_data_key ] : $default_value;
448
-
449
- if ( is_string( $square_synced ) ) {
450
-
451
- Product::set_synced_with_square( $product, $square_synced );
452
- }
453
- }
454
-
455
-
456
- /**
457
- * Updates Square sync status for a product upon saving.
458
- *
459
- * @internal
460
- *
461
- * @since 2.0.0
462
- *
463
- * @param \WC_Product $product product object
464
- */
465
- public function process_product_data( $product ) {
466
-
467
- // don't process fields if product sync is disabled
468
- if ( ! wc_square()->get_settings_handler()->is_product_sync_enabled() ) {
469
- return;
470
- }
471
-
472
- // bail if no valid product found, if it's a variation, errors have already been output
473
- if ( ! $product || ( $product instanceof \WC_Product_Variation || $product->is_type( 'product_variation' ) ) || ! empty( $this->output_errors[ $product->get_id() ] ) ) {
474
- return;
475
- }
476
-
477
- $errors = [];
478
- $posted_key = '_' . Product::SYNCED_WITH_SQUARE_TAXONOMY;
479
- $set_synced = isset( $_POST[ $posted_key ] ) && 'yes' === $_POST[ $posted_key ];
480
- $was_synced = Product::is_synced_with_square( $product );
481
-
482
- // condition has unchanged
483
- if ( ! $set_synced && ! $was_synced ) {
484
- return;
485
- }
486
-
487
- $is_variable = $product->is_type( 'variable' ) && $product->has_child();
488
-
489
- if ( $set_synced || $was_synced ) {
490
-
491
- if ( $is_variable ) {
492
-
493
- if ( Product::has_multiple_variation_attributes( $product ) ) {
494
- $errors['multiple_attributes'] = $this->product_errors['multiple_attributes'];
495
- }
496
-
497
- // if the product is variable, also its variations should have a matching SKU
498
- if ( isset( $this->product_errors['missing_variation_sku'] ) ) {
499
-
500
- foreach ( $product->get_children() as $variation_id ) {
501
-
502
- $variation = wc_get_product( $variation_id );
503
-
504
- if ( $variation && empty( $variation->get_sku() ) ) {
505
-
506
- $errors['missing_variation_sku'] = $this->product_errors['missing_variation_sku'];
507
- break;
508
- }
509
- }
510
- }
511
-
512
- } elseif ( isset( $this->product_errors['missing_sku'] ) && empty( $product->get_sku() ) ) {
513
-
514
- $errors['missing_sku'] = $this->product_errors['missing_sku'];
515
- }
516
- }
517
-
518
- if ( ! empty( $errors ) ) {
519
-
520
- // if the instruction is to sync the Product but there are errors, remove the link and display the errors
521
- Product::unset_synced_with_square( $product );
522
-
523
- foreach ( $errors as $error ) {
524
- wc_square()->get_message_handler()->add_error( $error );
525
- }
526
-
527
- } elseif ( $set_synced && $is_variable && wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
528
-
529
- // if syncing inventory with Square, parent variable products don't manage stock
530
- $product->set_manage_stock( false );
531
-
532
- // if there are no errors, and the product is variable, force enable stock management for all its variations
533
- foreach ( $product->get_children() as $variation_id ) {
534
-
535
- if ( $variation = wc_get_product( $variation_id ) ) {
536
- $variation->set_manage_stock( true );
537
- $variation->save();
538
- }
539
- }
540
- }
541
-
542
- // finally, set the product sync with Square flag
543
- Product::set_synced_with_square( $product, $set_synced ? 'yes' : 'no' );
544
- }
545
-
546
-
547
- /**
548
- * Adjusts a product's Square stock.
549
- *
550
- * @since 2.0.0
551
- *
552
- * @param \WC_Product $product product object
553
- */
554
- public function maybe_adjust_square_stock( $product ) {
555
-
556
- // this is hooked in to general product object save, so scope to specifically saving products via the admin
557
- if ( ! doing_action( 'wp_ajax_woocommerce_save_variations' ) && ! doing_action( 'woocommerce_admin_process_product_object' ) ) {
558
- return;
559
- }
560
-
561
- // only send stock updates for Woo SOR
562
- if ( ! wc_square()->get_settings_handler()->is_system_of_record_woocommerce() || ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
563
- return;
564
- }
565
-
566
- if ( ! $product instanceof \WC_Product || ! Product::is_synced_with_square( $product ) ) {
567
- return;
568
- }
569
-
570
- $square_id = $product->get_meta( Product::SQUARE_VARIATION_ID_META_KEY );
571
-
572
- // only send when the product has an associated Square ID
573
- if ( ! $square_id ) {
574
- return;
575
- }
576
-
577
- // set to manage stock if not a variable product
578
- $product->set_manage_stock( ! $product->is_type( 'variable' ) );
579
-
580
- $data = $product->get_data();
581
- $changes = $product->get_changes();
582
- $change = 0;
583
-
584
- if ( isset( $data['stock_quantity'], $changes['stock_quantity'] ) ) {
585
- $change = (int) $changes['stock_quantity'] - $data['stock_quantity'];
586
- }
587
-
588
- if ( $change !== 0 ) {
589
-
590
- try {
591
-
592
- if ( $change > 0 ) {
593
- wc_square()->get_api()->add_inventory( $square_id, $change );
594
- } else {
595
- wc_square()->get_api()->remove_inventory( $square_id, $change );
596
- }
597
-
598
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
599
-
600
- wc_square()->log( 'Could not adjust Square inventory for ' . $product->get_formatted_name() . '. ' . $exception->getMessage() );
601
-
602
- $quantity = (float) $data['stock_quantity'];
603
-
604
- // if the API request fails, set the product quantity back from whence it came
605
- $product->set_stock_quantity( $quantity );
606
- }
607
- }
608
- }
609
-
610
-
611
- /**
612
- * Prevents copying Square data when duplicating a product in admin.
613
- *
614
- * @internal
615
- *
616
- * @since 2.0.0
617
- *
618
- * @param \WC_Product $duplicated_product product duplicate
619
- * @param \WC_Product $original_product product duplicated
620
- */
621
- public function handle_product_duplication( $duplicated_product, $original_product ) {
622
-
623
- if ( Product::is_synced_with_square( $original_product ) ) {
624
- Product::unset_synced_with_square( $duplicated_product );
625
- }
626
-
627
- $duplicated_product->delete_meta_data( Product::SQUARE_ID_META_KEY );
628
- $duplicated_product->delete_meta_data( Product::SQUARE_VARIATION_ID_META_KEY );
629
-
630
- if ( $duplicated_product->is_type( 'variable' ) ) {
631
-
632
- foreach ( $duplicated_product->get_children() as $duplicated_variation_id ) {
633
-
634
- if ( $duplicated_product_variation = wc_get_product( $duplicated_variation_id ) ) {
635
-
636
- $duplicated_product_variation->delete_meta_data( Product::SQUARE_VARIATION_ID_META_KEY );
637
- $duplicated_product_variation->save_meta_data();
638
- }
639
- }
640
- }
641
-
642
- $duplicated_product->save_meta_data();
643
- }
644
-
645
-
646
- /**
647
- * Outputs an admin notice when a product was hidden from catalog upon a sync error.
648
- *
649
- * @internal
650
- *
651
- * @since 2.0.0
652
- */
653
- public function add_notice_product_hidden_from_catalog() {
654
- global $current_screen, $post;
655
-
656
- if ( $post && $current_screen && 'product' === $current_screen->id ) {
657
-
658
- $product = wc_get_product( $post );
659
-
660
- if ( $product && 'hidden' === $product->get_catalog_visibility() ) {
661
-
662
- $product_id = $product->get_id();
663
- $records = Records::get_records( [ 'product' => $product_id ] );
664
-
665
- foreach ( $records as $record ) {
666
-
667
- if ( $record->was_product_hidden() && $product_id === $record->get_product_id() ) {
668
-
669
- wc_square()->get_message_handler()->add_warning(
670
- sprintf(
671
- /* translators: Placeholder: %1$s - date (localized), %2$s - time (localized), %3$s - opening <a> HTML link tag, %4$s closing </a> HTML link tag */
672
- esc_html__( 'The product catalog visibility has been set to "hidden", as a matching product could not be found in Square on %1$s at %2$s. %3$sCheck sync records%4$s.', 'woocommerce-square' ),
673
- date_i18n( wc_date_format(), $record->get_timestamp() ),
674
- date_i18n( wc_time_format(), $record->get_timestamp() ),
675
- '<a href="' . esc_url( add_query_arg( [ 'section' => 'update' ], wc_square()->get_settings_url() ) ) . '">', '</a>'
676
- )
677
- );
678
-
679
- break;
680
- }
681
- }
682
- }
683
- }
684
- }
685
-
686
-
687
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
includes/Emails/Access_Token_Email.php ADDED
@@ -0,0 +1,120 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WooCommerce Square
4
+ *
5
+ * This source file is subject to the GNU General Public License v3.0
6
+ * that is bundled with this package in the file license.txt.
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.gnu.org/licenses/gpl-3.0.html
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to license@woocommerce.com so we can send you a copy immediately.
12
+ *
13
+ * DISCLAIMER
14
+ *
15
+ * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
+ * versions in the future. If you wish to customize WooCommerce Square for your
17
+ * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
+ *
19
+ * @author WooCommerce
20
+ * @copyright Copyright: (c) 2019, Automattic, Inc.
21
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
+ */
23
+
24
+ namespace WooCommerce\Square\Emails;
25
+
26
+ use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
+
28
+ defined( 'ABSPATH' ) or exit;
29
+
30
+ /**
31
+ * Sync completed email.
32
+ *
33
+ * @since 2.1.0
34
+ */
35
+ class Access_Token_Email extends Base_Email {
36
+ /**
37
+ * Email constructor.
38
+ *
39
+ * @since 2.1.0
40
+ */
41
+ public function __construct() {
42
+ // set properties
43
+ $this->id = 'wc_square_access_token_email';
44
+ $this->customer_email = false;
45
+ $this->title = __( 'Square Access Token problems', 'woocommerce-square' );
46
+ $this->description = __( 'This email is sent when problems with Access Token are encountered', 'woocommerce-square' );
47
+ $this->subject = _x( '[WooCommerce] There was a problem with your Square Access Token', 'Email subject', 'woocommerce-square');
48
+ $this->heading = _x( 'There was a problem with your Square Access Token', 'Email heading', 'woocommerce-square');
49
+ $this->body = _x( 'Heads up! There may be a problem with your connection to Square.', 'Square connection problems email body.', 'woocommerce-square' );
50
+
51
+ $this->enabled_default = 'yes';
52
+
53
+ // call parent constructor
54
+ parent::__construct();
55
+
56
+ // set default recipient
57
+ $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
58
+ }
59
+
60
+ /**
61
+ * Triggers the email.
62
+ *
63
+ * @since 2.1.0
64
+ */
65
+ public function trigger() {
66
+ if ( ! $this->is_enabled() || ! $this->has_recipients() ) {
67
+ return;
68
+ }
69
+
70
+ // send the email at most once a day
71
+ $already_sent = get_transient( 'wc_square_access_token_email_sent' );
72
+ if ( false !== $already_sent ) {
73
+ return;
74
+ }
75
+ set_transient( 'wc_square_access_token_email_sent', true, DAY_IN_SECONDS );
76
+
77
+ $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
78
+ }
79
+
80
+ /**
81
+ * Gets the arguments that should be passed to an email template.
82
+ *
83
+ * @since 2.1.0
84
+ *
85
+ * @param array $args optional associative array with additional arguments
86
+ * @return array
87
+ */
88
+ protected function get_template_args( $args = [] ) {
89
+ $html = empty( $args['plain_text'] );
90
+
91
+ $email_body = $this->body;
92
+
93
+ $square = wc_square();
94
+ $settings_url = esc_url( $square->get_settings_url() );
95
+ $logs_url = esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) );
96
+ if ( $html ) {
97
+ $email_body .= ' ' . sprintf(
98
+ /* translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing </a> HTML link tag */
99
+ esc_html__( 'In order to continue accepting payments, please %1$sdisconnect and re-connect your site%2$s.', 'woocommerce-square' ),
100
+ '<a href="' . esc_url( $settings_url ) .'">', '</a>'
101
+ );
102
+
103
+ if ( $square->get_settings_handler()->is_debug_enabled() ) {
104
+ $email_body .= '<br/><br/>' . sprintf(
105
+ /* translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing </a> HTML link tag */
106
+ esc_html__( '%1$sInspect status logs%2$s', 'woocommerce-square' ),
107
+ '<a href="' . $logs_url . '">', '</a>'
108
+ );
109
+ }
110
+ } else {
111
+ $email_body .= ' ' + esc_html__( 'In order to continue accepting payments, please disconnect and re-connect your site at ', 'woocommerce-square' ) . $settings_url;
112
+ }
113
+
114
+ return array_merge( $args, [
115
+ 'email' => $this,
116
+ 'email_heading' => $this->heading,
117
+ 'email_body' => $email_body,
118
+ ] );
119
+ }
120
+ }
includes/Emails/Base_Email.php ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * WooCommerce Square
4
+ *
5
+ * This source file is subject to the GNU General Public License v3.0
6
+ * that is bundled with this package in the file license.txt.
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.gnu.org/licenses/gpl-3.0.html
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to license@woocommerce.com so we can send you a copy immediately.
12
+ *
13
+ * DISCLAIMER
14
+ *
15
+ * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
+ * versions in the future. If you wish to customize WooCommerce Square for your
17
+ * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
+ *
19
+ * @author WooCommerce
20
+ * @copyright Copyright: (c) 2019, Automattic, Inc.
21
+ * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
+ */
23
+
24
+ namespace WooCommerce\Square\Emails;
25
+
26
+ use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
+
28
+ defined( 'ABSPATH' ) or exit;
29
+
30
+ /**
31
+ * Base email class.
32
+ *
33
+ * @since 2.1.0
34
+ */
35
+ class Base_Email extends \WC_Email {
36
+ /**
37
+ * Whether the email is enabled by default.
38
+ *
39
+ * @var string
40
+ */
41
+ protected $enabled_default = 'no';
42
+
43
+ /**
44
+ * Plain text template path.
45
+ *
46
+ * @var string
47
+ */
48
+ public $template_plain = 'emails/plain/square-email.php';
49
+
50
+ /**
51
+ * HTML template path.
52
+ *
53
+ * @var string
54
+ */
55
+ public $template_html = 'emails/square-email.php';
56
+
57
+ /**
58
+ * Template path.
59
+ *
60
+ * @var string
61
+ */
62
+ public $template_base;
63
+
64
+ /**
65
+ * Email constructor.
66
+ *
67
+ * @since 2.1.0
68
+ */
69
+ public function __construct() {
70
+ $this->template_base = wc_square()->get_plugin_path() . '/templates/';
71
+
72
+ // call parent constructor
73
+ parent::__construct();
74
+
75
+ // set default recipient
76
+ $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
77
+ }
78
+
79
+ /**
80
+ * Initializes the email settings form fields.
81
+ *
82
+ * Extends and overrides parent method.
83
+ *
84
+ * @since 2.1.0
85
+ */
86
+ public function init_form_fields() {
87
+ // initialize the default fields from parent email object
88
+ parent::init_form_fields();
89
+
90
+ $form_fields = $this->form_fields;
91
+
92
+ // set email disabled by default
93
+ if ( isset( $form_fields['enabled'] ) ) {
94
+ $form_fields['enabled']['default'] = $this->enabled_default;
95
+ }
96
+
97
+ // the email has no customizable body or heading via input field
98
+ unset( $form_fields['body'], $form_fields['heading'] );
99
+
100
+ // adjust email subject field
101
+ if ( isset( $form_fields['subject'] ) ) {
102
+ /* translators: Placeholder: %s - default email subject text */
103
+ $form_fields['subject']['description'] = sprintf( __( 'This controls the email subject line. Leave blank to use the default subject: %s', 'woocommerce-square' ), '<code>' . $this->get_default_subject() . '</code>' );
104
+ $form_fields['subject']['desc_tip'] = false;
105
+ $form_fields['subject']['default'] = $this->subject;
106
+ }
107
+
108
+ // add a recipient field
109
+ $form_fields = Framework\SV_WC_Helper::array_insert_after( $form_fields, isset( $form_fields['enabled'] ) ? 'enabled' : key( $form_fields ), [
110
+ 'recipient' => [
111
+ 'title' => __( 'Recipient(s)', 'woocommerce-square' ),
112
+ 'type' => 'text',
113
+ /* translators: Placeholder: %s default email address */
114
+ 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to admin email: %s', 'woocommerce-square' ), '<code>' . esc_attr( get_option( 'admin_email' ) ) . '</code>' ),
115
+ 'placeholder' => get_bloginfo( 'admin_email' ),
116
+ 'default' => get_bloginfo( 'admin_email' ),
117
+ ],
118
+ ] );
119
+
120
+ // set the updated fields
121
+ $this->form_fields = $form_fields;
122
+ }
123
+
124
+ /**
125
+ * Gets the default email subject.
126
+ *
127
+ * @since 2.1.0
128
+ *
129
+ * @return string
130
+ */
131
+ public function get_default_subject() {
132
+ return $this->subject;
133
+ }
134
+
135
+ /**
136
+ * Gets the email body.
137
+ *
138
+ * @since 2.1.0
139
+ *
140
+ * @return string may contain HTML
141
+ */
142
+ protected function get_default_body() {
143
+ return $this->body;
144
+ }
145
+
146
+ /**
147
+ * Determines if the email has valid recipients.
148
+ *
149
+ * @since 2.1.0
150
+ *
151
+ * @return bool
152
+ */
153
+ protected function has_recipients() {
154
+ return ! empty( $this->get_recipient() );
155
+ }
156
+
157
+ /**
158
+ * Gets the arguments that should be passed to an email template.
159
+ *
160
+ * @since 2.1.0
161
+ *
162
+ * @param array $args optional associative array with additional arguments
163
+ * @return array
164
+ */
165
+ protected function get_template_args( $args = [] ) {
166
+ return array_merge( $args, [
167
+ 'email' => $this,
168
+ 'email_heading' => '',
169
+ 'email_body' => '',
170
+ ] );
171
+ }
172
+
173
+ /**
174
+ * Gets the email HTML content.
175
+ *
176
+ * @since 2.0.0
177
+ *
178
+ * @return string HTML
179
+ */
180
+ public function get_content_html() {
181
+ $args = [ 'plain_text' => false ];
182
+ return wc_get_template_html( $this->template_html, array_merge( $args, $this->get_template_args( $args ) ) );
183
+ }
184
+
185
+ /**
186
+ * Gets the email plain text content.
187
+ *
188
+ * @since 2.0.0
189
+ *
190
+ * @return string plain text
191
+ */
192
+ public function get_content_plain() {
193
+ $args = [ 'plain_text' => true ];
194
+ return wc_get_template_html( $this->template_plain, array_merge( $args, $this->get_template_args( $args ) ) );
195
+ }
196
+ }
includes/Emails/Sync_Completed.php CHANGED
@@ -32,30 +32,23 @@ defined( 'ABSPATH' ) or exit;
32
  *
33
  * @since 2.0.0
34
  */
35
- class Sync_Completed extends \WC_Email {
36
-
37
-
38
- /** @var string email body */
39
- protected $body;
40
-
41
-
42
  /**
43
  * Email constructor.
44
  *
45
  * @since 2.0.0
46
  */
47
  public function __construct() {
48
-
49
  // set properties
50
  $this->id = 'wc_square_sync_completed';
 
51
  $this->title = __( 'Square sync completed', 'woocommerce-square' );
52
  $this->description = __( 'This email is sent once a manual sync has been completed between WooCommerce and Square', 'woocommerce-square' );
53
  $this->subject = _x( '[WooCommerce] Square sync completed', 'Email subject', 'woocommerce-square');
54
  $this->heading = _x( 'Square sync completed for {product_count}', 'Email heading with merge tag placeholder', 'woocommerce-square');
55
  $this->body = _x( 'Square sync completed for {site_title} at {sync_completed_date} {sync_completed_time}.', 'Email body with merge tag placeholders', 'woocommerce-square' );
56
- $this->template_html = 'emails/square-sync-completed.php';
57
- $this->template_plain = 'emails/plain/square-sync-completed.php';
58
- $this->template_base = wc_square()->get_plugin_path() . '/templates/';
59
 
60
  // call parent constructor
61
  parent::__construct();
@@ -64,54 +57,6 @@ class Sync_Completed extends \WC_Email {
64
  $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
65
  }
66
 
67
-
68
- /**
69
- * Initializes the email settings form fields.
70
- *
71
- * Extends and overrides parent method.
72
- *
73
- * @since 2.0.0
74
- */
75
- public function init_form_fields() {
76
-
77
- // initialize the default fields from parent email object
78
- parent::init_form_fields();
79
-
80
- $form_fields = $this->form_fields;
81
-
82
- // set email disabled by default
83
- if ( isset( $form_fields['enabled'] ) ) {
84
- $form_fields['enabled']['default'] = 'no';
85
- }
86
-
87
- // the email has no customizable body or heading via input field
88
- unset( $form_fields['body'], $form_fields['heading'] );
89
-
90
- // adjust email subject field
91
- if ( isset( $form_fields['subject'] ) ) {
92
- /* translators: Placeholder: %s - default email subject text */
93
- $form_fields['subject']['description'] = sprintf( __( 'This controls the email subject line. Leave blank to use the default subject: %s', 'woocommerce-square' ), '<code>' . $this->get_default_subject() . '</code>' );
94
- $form_fields['subject']['desc_tip'] = false;
95
- $form_fields['subject']['default'] = $this->subject;
96
- }
97
-
98
- // add a recipient field
99
- $form_fields = Framework\SV_WC_Helper::array_insert_after( $form_fields, isset( $form_fields['enabled'] ) ? 'enabled' : key( $form_fields ), [
100
- 'recipient' => [
101
- 'title' => __( 'Recipient(s)', 'woocommerce-square' ),
102
- 'type' => 'text',
103
- /* translators: Placeholder: %s default email address */
104
- 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to admin email: %s', 'woocommerce-square' ), '<code>' . esc_attr( get_option( 'admin_email' ) ) . '</code>' ),
105
- 'placeholder' => get_bloginfo( 'admin_email' ),
106
- 'default' => get_bloginfo( 'admin_email' ),
107
- ],
108
- ] );
109
-
110
- // set the updated fields
111
- $this->form_fields = $form_fields;
112
- }
113
-
114
-
115
  /**
116
  * Gets the email heading, adjusted by sync job result status.
117
  *
@@ -121,7 +66,6 @@ class Sync_Completed extends \WC_Email {
121
  * @return string
122
  */
123
  private function get_heading_by_job_status( $status ) {
124
-
125
  if ( 'failed' === $status ) {
126
  $email_heading = esc_html__( 'Square sync failed', 'woocommerce-square' );
127
  } else {
@@ -132,56 +76,6 @@ class Sync_Completed extends \WC_Email {
132
  return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $email_heading ), $this->object );
133
  }
134
 
135
-
136
- /**
137
- * Gets the default email subject.
138
- *
139
- * @since 2.0.0
140
- *
141
- * @return string
142
- */
143
- public function get_default_subject() {
144
-
145
- return $this->subject;
146
- }
147
-
148
-
149
- /**
150
- * Gets the email body.
151
- *
152
- * @since 2.0.0
153
- *
154
- * @return string may contain HTML
155
- */
156
- protected function get_default_body() {
157
-
158
- return $this->body;
159
- }
160
-
161
-
162
- /**
163
- * Gets the email body.
164
- *
165
- * @since 2.0.0
166
- *
167
- * @return string may contain HTML
168
- */
169
- protected function get_body() {
170
-
171
- $email_body = $this->get_default_body();
172
-
173
- /**
174
- * Filters the sync completed email body.
175
- *
176
- * @since 2.0.0
177
- *
178
- * @param string $email_body the email body
179
- * @param Sync_Completed $email the email object
180
- */
181
- return $this->format_string( (string) apply_filters( "{$this->id}_body", $email_body, $this ) );
182
- }
183
-
184
-
185
  /**
186
  * Gets the email body adjusted by sync job result status.
187
  *
@@ -192,13 +86,10 @@ class Sync_Completed extends \WC_Email {
192
  * @return string may contain HTML
193
  */
194
  private function get_body_by_job_status( $status, $html ) {
195
-
196
  $email_body = $this->get_default_body();
197
 
198
  if ( 'failed' === $status ) {
199
-
200
  if ( true === $html ) {
201
-
202
  $square = wc_square();
203
  $settings_url = $square->get_settings_url();
204
  $records_url = add_query_arg( [ 'section' => 'update' ], $settings_url );
@@ -244,7 +135,6 @@ class Sync_Completed extends \WC_Email {
244
  return $this->format_string( (string) apply_filters( "{$this->id}_body", $email_body, $this ) );
245
  }
246
 
247
-
248
  /**
249
  * Gets the email's related sync job, if set.
250
  *
@@ -253,37 +143,9 @@ class Sync_Completed extends \WC_Email {
253
  * @return \stdClass|null
254
  */
255
  private function get_job() {
256
-
257
  return $this->object && is_object( $this->object ) ? $this->object : null;
258
  }
259
 
260
-
261
- /**
262
- * Determines if it's a customer email.
263
- *
264
- * @since 2.0.0
265
- *
266
- * @return false overrides parent method to always return false
267
- */
268
- public function is_customer_email() {
269
-
270
- return false;
271
- }
272
-
273
-
274
- /**
275
- * Determines if the email has valid recipients.
276
- *
277
- * @since 2.0.0
278
- *
279
- * @return bool
280
- */
281
- protected function has_recipients() {
282
-
283
- return ! empty( $this->get_recipient() );
284
- }
285
-
286
-
287
  /**
288
  * Triggers the email.
289
  *
@@ -292,15 +154,30 @@ class Sync_Completed extends \WC_Email {
292
  * @param string|object|\stdClass $job a sync job object or ID
293
  */
294
  public function trigger( $job ) {
295
-
296
  if ( $this->is_enabled() && $this->has_recipients() ) {
297
-
298
  if ( is_string( $job ) || is_numeric( $job ) ) {
299
  $job = wc_square()->get_background_job_handler()->get_job( $job );
300
  }
301
 
302
- if ( $job && is_object( $job ) && isset( $job->manual, $job->status ) && $job->manual && 'completed' === $job->status ) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
303
 
 
304
  $this->object = $job;
305
 
306
  $this->parse_merge_tags();
@@ -310,14 +187,12 @@ class Sync_Completed extends \WC_Email {
310
  }
311
  }
312
 
313
-
314
  /**
315
  * Parses the email's body merge tags.
316
  *
317
  * @since 2.0.0
318
  */
319
  protected function parse_merge_tags() {
320
-
321
  $job = $this->get_job();
322
 
323
  if ( ! $job ) {
@@ -328,18 +203,27 @@ class Sync_Completed extends \WC_Email {
328
  /* translators: Placeholder: %d products count */
329
  $product_count = sprintf( _n( '%d product', '%d products', $product_count, 'woocommerce-square' ), $product_count );
330
 
 
 
 
 
 
 
 
 
 
 
331
  // placeholders
332
  $email_merge_tags = [
333
  'product_count' => $product_count,
334
  'sync_started_date' => isset( $job->started_at ) ? date( wc_date_format(), strtotime( $job->started_at ) ) : '',
335
  'sync_started_time' => isset( $job->started_at ) ? date( wc_time_format(), strtotime( $job->started_at ) ) : '',
336
- 'sync_completed_date' => isset( $job->completed_at ) ? date( wc_date_format(), strtotime( $job->completed_at ) ) : '',
337
- 'sync_completed_time' => isset( $job->completed_at ) ? date( wc_time_format(), strtotime( $job->completed_at ) ) : '',
338
  ];
339
 
340
  // TODO update handling when WooCommerce 3.2 is the minimum required version {FN 2019-05-03}
341
  if ( Framework\SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.2' ) ) {
342
-
343
  foreach ( $email_merge_tags as $find => $replace ) {
344
  $this->placeholders[ '{' . $find . '}' ] = $replace;
345
  }
@@ -353,7 +237,6 @@ class Sync_Completed extends \WC_Email {
353
  }
354
  }
355
 
356
-
357
  /**
358
  * Gets the arguments that should be passed to an email template.
359
  *
@@ -363,7 +246,6 @@ class Sync_Completed extends \WC_Email {
363
  * @return array
364
  */
365
  protected function get_template_args( $args = [] ) {
366
-
367
  $sync_job = $this->get_job();
368
  $html = empty( $args['plain_text'] );
369
 
@@ -379,47 +261,6 @@ class Sync_Completed extends \WC_Email {
379
  'email' => $this,
380
  'email_heading' => $email_heading,
381
  'email_body' => $email_body,
382
- 'sync_job' => $sync_job,
383
  ] );
384
  }
385
-
386
-
387
- /**
388
- * Gets the email HTML content.
389
- *
390
- * @since 2.0.0
391
- *
392
- * @return string HTML
393
- */
394
- public function get_content_html() {
395
-
396
- $args = [ 'plain_text' => false ];
397
-
398
- ob_start();
399
-
400
- wc_get_template( $this->template_html, array_merge( $args, $this->get_template_args( $args ) ) );
401
-
402
- return ob_get_clean();
403
- }
404
-
405
-
406
- /**
407
- * Gets the email plain text content.
408
- *
409
- * @since 2.0.0
410
- *
411
- * @return string plain text
412
- */
413
- public function get_content_plain() {
414
-
415
- $args = [ 'plain_text' => true ];
416
-
417
- ob_start();
418
-
419
- wc_get_template( $this->template_html, array_merge( $args, $this->get_template_args( $args ) ) );
420
-
421
- return ob_get_clean();
422
- }
423
-
424
-
425
  }
32
  *
33
  * @since 2.0.0
34
  */
35
+ class Sync_Completed extends Base_Email {
 
 
 
 
 
 
36
  /**
37
  * Email constructor.
38
  *
39
  * @since 2.0.0
40
  */
41
  public function __construct() {
 
42
  // set properties
43
  $this->id = 'wc_square_sync_completed';
44
+ $this->customer_email = false;
45
  $this->title = __( 'Square sync completed', 'woocommerce-square' );
46
  $this->description = __( 'This email is sent once a manual sync has been completed between WooCommerce and Square', 'woocommerce-square' );
47
  $this->subject = _x( '[WooCommerce] Square sync completed', 'Email subject', 'woocommerce-square');
48
  $this->heading = _x( 'Square sync completed for {product_count}', 'Email heading with merge tag placeholder', 'woocommerce-square');
49
  $this->body = _x( 'Square sync completed for {site_title} at {sync_completed_date} {sync_completed_time}.', 'Email body with merge tag placeholders', 'woocommerce-square' );
50
+
51
+ $this->enabled_default = 'no';
 
52
 
53
  // call parent constructor
54
  parent::__construct();
57
  $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
58
  }
59
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
60
  /**
61
  * Gets the email heading, adjusted by sync job result status.
62
  *
66
  * @return string
67
  */
68
  private function get_heading_by_job_status( $status ) {
 
69
  if ( 'failed' === $status ) {
70
  $email_heading = esc_html__( 'Square sync failed', 'woocommerce-square' );
71
  } else {
76
  return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $email_heading ), $this->object );
77
  }
78
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
79
  /**
80
  * Gets the email body adjusted by sync job result status.
81
  *
86
  * @return string may contain HTML
87
  */
88
  private function get_body_by_job_status( $status, $html ) {
 
89
  $email_body = $this->get_default_body();
90
 
91
  if ( 'failed' === $status ) {
 
92
  if ( true === $html ) {
 
93
  $square = wc_square();
94
  $settings_url = $square->get_settings_url();
95
  $records_url = add_query_arg( [ 'section' => 'update' ], $settings_url );
135
  return $this->format_string( (string) apply_filters( "{$this->id}_body", $email_body, $this ) );
136
  }
137
 
 
138
  /**
139
  * Gets the email's related sync job, if set.
140
  *
143
  * @return \stdClass|null
144
  */
145
  private function get_job() {
 
146
  return $this->object && is_object( $this->object ) ? $this->object : null;
147
  }
148
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
149
  /**
150
  * Triggers the email.
151
  *
154
  * @param string|object|\stdClass $job a sync job object or ID
155
  */
156
  public function trigger( $job ) {
 
157
  if ( $this->is_enabled() && $this->has_recipients() ) {
 
158
  if ( is_string( $job ) || is_numeric( $job ) ) {
159
  $job = wc_square()->get_background_job_handler()->get_job( $job );
160
  }
161
 
162
+ if ( ! $job || ! is_object( $job ) || ! isset( $job->manual, $job->status ) ) {
163
+ return;
164
+ }
165
+
166
+ $should_send = false;
167
+ if ( $job->manual && ( 'completed' === $job->status || 'failed' === $job->status ) ) {
168
+ // for manual jobs, send an email if the job was either completed or failed
169
+ $should_send = true;
170
+ } else if ( ! $job->manual && 'failed' === $job->status ) {
171
+ // for automated jobs, send an email only if the job failed and it's been a day since the last email
172
+ $already_sent = get_transient( 'wc_square_failed_sync_email_sent' );
173
+ if ( false === $already_sent ) {
174
+ $should_send = true;
175
+
176
+ set_transient( 'wc_square_failed_sync_email_sent', true, DAY_IN_SECONDS );
177
+ }
178
+ }
179
 
180
+ if ( $should_send ) {
181
  $this->object = $job;
182
 
183
  $this->parse_merge_tags();
187
  }
188
  }
189
 
 
190
  /**
191
  * Parses the email's body merge tags.
192
  *
193
  * @since 2.0.0
194
  */
195
  protected function parse_merge_tags() {
 
196
  $job = $this->get_job();
197
 
198
  if ( ! $job ) {
203
  /* translators: Placeholder: %d products count */
204
  $product_count = sprintf( _n( '%d product', '%d products', $product_count, 'woocommerce-square' ), $product_count );
205
 
206
+ $sync_completed_date = '';
207
+ $sync_completed_time = '';
208
+ if ( isset( $job->completed_at ) ) {
209
+ $sync_completed_date = date( wc_date_format(), strtotime( $job->completed_at ) );
210
+ $sync_completed_time = date( wc_time_format(), strtotime( $job->completed_at ) );
211
+ } else if ( isset( $job->failed_at ) ) {
212
+ $sync_completed_date = date( wc_date_format(), strtotime( $job->failed_at ) );
213
+ $sync_completed_time = date( wc_time_format(), strtotime( $job->failed_at ) );
214
+ }
215
+
216
  // placeholders
217
  $email_merge_tags = [
218
  'product_count' => $product_count,
219
  'sync_started_date' => isset( $job->started_at ) ? date( wc_date_format(), strtotime( $job->started_at ) ) : '',
220
  'sync_started_time' => isset( $job->started_at ) ? date( wc_time_format(), strtotime( $job->started_at ) ) : '',
221
+ 'sync_completed_date' => $sync_completed_date,
222
+ 'sync_completed_time' => $sync_completed_time,
223
  ];
224
 
225
  // TODO update handling when WooCommerce 3.2 is the minimum required version {FN 2019-05-03}
226
  if ( Framework\SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.2' ) ) {
 
227
  foreach ( $email_merge_tags as $find => $replace ) {
228
  $this->placeholders[ '{' . $find . '}' ] = $replace;
229
  }
237
  }
238
  }
239
 
 
240
  /**
241
  * Gets the arguments that should be passed to an email template.
242
  *
246
  * @return array
247
  */
248
  protected function get_template_args( $args = [] ) {
 
249
  $sync_job = $this->get_job();
250
  $html = empty( $args['plain_text'] );
251
 
261
  'email' => $this,
262
  'email_heading' => $email_heading,
263
  'email_body' => $email_body,
 
264
  ] );
265
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
266
  }
includes/Gateway.php CHANGED
@@ -166,8 +166,6 @@ class Gateway extends Framework\SV_WC_Payment_Gateway_Direct {
166
  /**
167
  * Validates the entered payment fields.
168
  *
169
- * This only validates the nonce for now.
170
- *
171
  * @since 2.0.0
172
  *
173
  * @return bool
@@ -176,12 +174,16 @@ class Gateway extends Framework\SV_WC_Payment_Gateway_Direct {
176
 
177
  $is_valid = true;
178
 
179
- if ( Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-token' ) ) {
180
- return $is_valid;
181
- }
182
-
183
  try {
184
 
 
 
 
 
 
 
 
 
185
  if ( ! Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' ) ) {
186
  throw new Framework\SV_WC_Payment_Gateway_Exception( 'Payment nonce is missing' );
187
  }
@@ -211,6 +213,10 @@ class Gateway extends Framework\SV_WC_Payment_Gateway_Direct {
211
 
212
  $order = parent::get_order( $order_id );
213
 
 
 
 
 
214
  if ( empty( $order->payment->token ) ) {
215
 
216
  $order->payment->nonce = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' );
@@ -611,6 +617,27 @@ class Gateway extends Framework\SV_WC_Payment_Gateway_Direct {
611
  }
612
 
613
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
614
  /** Getter methods ************************************************************************************************/
615
 
616
 
166
  /**
167
  * Validates the entered payment fields.
168
  *
 
 
169
  * @since 2.0.0
170
  *
171
  * @return bool
174
 
175
  $is_valid = true;
176
 
 
 
 
 
177
  try {
178
 
179
+ if ( $this->is_3d_secure_enabled() && ! Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-buyer-verification-token' ) ) {
180
+ throw new Framework\SV_WC_Payment_Gateway_Exception( '3D Secure Verification Token is missing' );
181
+ }
182
+
183
+ if ( Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-token' ) ) {
184
+ return $is_valid;
185
+ }
186
+
187
  if ( ! Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' ) ) {
188
  throw new Framework\SV_WC_Payment_Gateway_Exception( 'Payment nonce is missing' );
189
  }
213
 
214
  $order = parent::get_order( $order_id );
215
 
216
+ if ( $this->is_3d_secure_enabled() ) {
217
+ $order->payment->verification_token = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-buyer-verification-token' );
218
+ }
219
+
220
  if ( empty( $order->payment->token ) ) {
221
 
222
  $order->payment->nonce = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' );
617
  }
618
 
619
 
620
+ /**
621
+ * Determines if 3d secure is enabled.
622
+ *
623
+ * @since 2.1.0
624
+ *
625
+ * @return bool
626
+ */
627
+ public function is_3d_secure_enabled() {
628
+
629
+ /**
630
+ * Filters whether or not 3d Secure should be enabled.
631
+ *
632
+ * @since 2.1.0
633
+ *
634
+ * @param bool $enabled
635
+ * @param Gateway $gateway_instance
636
+ */
637
+ return apply_filters( 'wc_square_is_3d_secure_enabled', true, $this );
638
+ }
639
+
640
+
641
  /** Getter methods ************************************************************************************************/
642
 
643
 
includes/Gateway/API/Requests/Customers.php CHANGED
@@ -103,6 +103,11 @@ class Customers extends API\Requests\Customers {
103
  $request->setBillingAddress( $this->get_address_from_order( $order ) );
104
  $request->setCardholderName( $order->get_formatted_billing_full_name() );
105
 
 
 
 
 
 
106
  $this->square_request = $request;
107
 
108
  $this->square_api_args = [
103
  $request->setBillingAddress( $this->get_address_from_order( $order ) );
104
  $request->setCardholderName( $order->get_formatted_billing_full_name() );
105
 
106
+ // 3DS / SCA verification token (from JS)
107
+ if ( ! empty( $order->payment->verification_token ) ) {
108
+ $request->setVerificationToken( $order->payment->verification_token );
109
+ }
110
+
111
  $this->square_request = $request;
112
 
113
  $this->square_api_args = [
includes/Gateway/API/Requests/Transactions.php CHANGED
@@ -109,6 +109,11 @@ class Transactions extends \WooCommerce\Square\API\Request {
109
  $this->square_request->setCardNonce( $order->payment->nonce );
110
  }
111
 
 
 
 
 
 
112
  $billing_address = new Address();
113
  $billing_address->setFirstName( $order->get_billing_first_name() );
114
  $billing_address->setLastName( $order->get_billing_last_name() );
109
  $this->square_request->setCardNonce( $order->payment->nonce );
110
  }
111
 
112
+ // 3DS / SCA verification token (from JS)
113
+ if ( ! empty( $order->payment->verification_token ) ) {
114
+ $this->square_request->setVerificationToken( $order->payment->verification_token );
115
+ }
116
+
117
  $billing_address = new Address();
118
  $billing_address->setFirstName( $order->get_billing_first_name() );
119
  $billing_address->setLastName( $order->get_billing_last_name() );
includes/Gateway/Card_Handler.php CHANGED
@@ -30,6 +30,29 @@ use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
30
  class Card_Handler extends Framework\SV_WC_Payment_Gateway_Payment_Tokens_Handler {
31
 
32
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  /**
34
  * Determines if a token should be deleted locally after a failed API attempt.
35
  *
30
  class Card_Handler extends Framework\SV_WC_Payment_Gateway_Payment_Tokens_Handler {
31
 
32
 
33
+ /**
34
+ * Tokenizes the current payment method and adds the standard transaction
35
+ * data to the order post record.
36
+ *
37
+ * @since 2.1.0
38
+ *
39
+ * @param \WC_Order $order order object
40
+ * @param Framework\SV_WC_Payment_Gateway_API_Create_Payment_Token_Response|null $response payment token API response, or null if the request should be made
41
+ * @param string $environment_id optional environment ID, defaults to the current environment
42
+ * @return \WC_Order order object
43
+ * @throws Framework\SV_WC_Plugin_Exception on transaction failure
44
+ */
45
+ public function create_token( \WC_Order $order, $response = null, $environment_id = null ) {
46
+
47
+ $order = parent::create_token( $order, $response, $environment_id );
48
+
49
+ // remove the verification token that was used to store the card so it's not also sent in the payment request
50
+ $order->payment->verification_token = null;
51
+
52
+ return $order;
53
+ }
54
+
55
+
56
  /**
57
  * Determines if a token should be deleted locally after a failed API attempt.
58
  *
includes/Gateway/Payment_Form.php CHANGED
@@ -31,10 +31,76 @@ use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
31
  * The payment form handler.
32
  *
33
  * @since 2.0.0
 
 
34
  */
35
  class Payment_Form extends Framework\SV_WC_Payment_Gateway_Payment_Form {
36
 
37
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
38
  /**
39
  * Renders the payment fields.
40
  *
@@ -53,26 +119,15 @@ class Payment_Form extends Framework\SV_WC_Payment_Gateway_Payment_Form {
53
  'payment-postcode',
54
  ];
55
 
56
- foreach ( $fields as $field_id ) {
57
- echo '<input type="hidden" name="wc-' . esc_attr( $this->get_gateway()->get_id_dasherized() ) . '-' . esc_attr( $field_id ) . '" />';
58
  }
59
 
60
- $postcode = '';
61
-
62
- if ( is_checkout_pay_page() ) {
63
-
64
- if ( $order = wc_get_order( $this->get_gateway()->get_checkout_pay_page_order_id() ) ) {
65
- $postcode = $order->get_billing_postcode();
66
- }
67
-
68
- } elseif ( WC()->customer && ! is_checkout() ) {
69
-
70
- $postcode = WC()->customer->get_billing_postcode();
71
  }
72
 
73
- if ( $postcode ) {
74
- echo '<input type="hidden" id="billing_postcode" value="' . esc_attr( $postcode ) . '" />';
75
- }
76
  }
77
 
78
 
@@ -140,14 +195,18 @@ class Payment_Form extends Framework\SV_WC_Payment_Gateway_Payment_Form {
140
  public function render_js() {
141
 
142
  $args = [
143
- 'id' => $this->get_gateway()->get_id(),
144
- 'id_dasherized' => $this->get_gateway()->get_id_dasherized(),
145
- 'csc_required' => $this->get_gateway()->csc_enabled(),
146
- 'logging_enabled' => $this->get_gateway()->debug_log(),
147
- 'general_error' => __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ),
148
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
149
- 'ajax_log_nonce' => wp_create_nonce( 'wc_' . $this->get_gateway()->get_id() . '_log_js_data' ),
150
- 'application_id' => $this->get_gateway()->get_application_id(),
 
 
 
 
151
  ];
152
 
153
  // map the unique square card type string to our framework standards
31
  * The payment form handler.
32
  *
33
  * @since 2.0.0
34
+ *
35
+ * @method \WooCommerce\Square\Gateway get_gateway()
36
  */
37
  class Payment_Form extends Framework\SV_WC_Payment_Gateway_Payment_Form {
38
 
39
 
40
+ /**
41
+ * Renders any additional billing information we need for processing on pages other than checkout
42
+ * e.g. pay page, add payment method page
43
+ *
44
+ * @since 2.1.0
45
+ */
46
+ public function render_supplementary_billing_info() {
47
+
48
+ $billing_data = [];
49
+ $billing_data_source = null;
50
+
51
+ if ( is_checkout_pay_page() ) {
52
+
53
+ if ( $order = wc_get_order( $this->get_gateway()->get_checkout_pay_page_order_id() ) ) {
54
+ $billing_data_source = $order;
55
+ }
56
+
57
+ } elseif ( WC()->customer && ! is_checkout() ) {
58
+
59
+ $billing_data_source = WC()->customer;
60
+ }
61
+
62
+ if ( $billing_data_source ) {
63
+
64
+ $billing_data = [ 'billing_postcode' => $billing_data_source->get_billing_postcode() ];
65
+
66
+ // 3d secure requires the full billing info
67
+ if ( $this->get_gateway()->is_3d_secure_enabled() ) {
68
+
69
+ $billing_data = array_merge( $billing_data, [
70
+ 'billing_first_name' => $billing_data_source->get_billing_first_name(),
71
+ 'billing_last_name' => $billing_data_source->get_billing_last_name(),
72
+ 'billing_email' => $billing_data_source->get_billing_email(),
73
+ 'billing_country' => $billing_data_source->get_billing_country(),
74
+ 'billing_address_1' => $billing_data_source->get_billing_address_1(),
75
+ 'billing_address_2' => $billing_data_source->get_billing_address_2(),
76
+ 'billing_state' => $billing_data_source->get_billing_state(),
77
+ 'billing_city' => $billing_data_source->get_billing_city(),
78
+ 'billing_phone' => $billing_data_source->get_billing_phone(),
79
+ ] );
80
+ }
81
+ }
82
+
83
+ foreach ( $billing_data as $key => $value ) {
84
+ echo '<input type="hidden" id="'. esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
85
+ }
86
+
87
+ if ( is_checkout_pay_page() ) {
88
+
89
+ $order = wc_get_order( $this->get_gateway()->get_checkout_pay_page_order_id() );
90
+
91
+ $total_amount = $order->get_total();
92
+
93
+ } else {
94
+
95
+ $total_amount = WC()->cart->total;
96
+ }
97
+
98
+ echo '<input type="hidden" name="wc-' . $this->get_gateway()->get_id_dasherized() . '-amount" value="' . esc_attr( $total_amount > 0 ? $total_amount : '' ) . '" />';
99
+
100
+ echo '<style> #sq-nudata-modal { z-index: 999999 !important; } </style>';
101
+ }
102
+
103
+
104
  /**
105
  * Renders the payment fields.
106
  *
119
  'payment-postcode',
120
  ];
121
 
122
+ if ( $this->get_gateway()->is_3d_secure_enabled() ) {
123
+ $fields[] = 'buyer-verification-token';
124
  }
125
 
126
+ foreach ( $fields as $field_id ) {
127
+ echo '<input type="hidden" name="wc-' . esc_attr( $this->get_gateway()->get_id_dasherized() ) . '-' . esc_attr( $field_id ) . '" />';
 
 
 
 
 
 
 
 
 
128
  }
129
 
130
+ $this->render_supplementary_billing_info();
 
 
131
  }
132
 
133
 
195
  public function render_js() {
196
 
197
  $args = [
198
+ 'application_id' => $this->get_gateway()->get_application_id(),
199
+ 'ajax_log_nonce' => wp_create_nonce( 'wc_' . $this->get_gateway()->get_id() . '_log_js_data' ),
200
+ 'ajax_url' => admin_url( 'admin-ajax.php' ),
201
+ 'csc_required' => $this->get_gateway()->csc_enabled(),
202
+ 'currency_code' => get_woocommerce_currency(),
203
+ 'general_error' => __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ),
204
+ 'id' => $this->get_gateway()->get_id(),
205
+ 'id_dasherized' => $this->get_gateway()->get_id_dasherized(),
206
+ 'is_3d_secure_enabled' => $this->get_gateway()->is_3d_secure_enabled(),
207
+ 'is_add_payment_method_page' => is_add_payment_method_page(),
208
+ 'location_id' => wc_square()->get_settings_handler()->get_location_id(),
209
+ 'logging_enabled' => $this->get_gateway()->debug_log(),
210
  ];
211
 
212
  // map the unique square card type string to our framework standards
includes/Handlers/Background_Job.php CHANGED
@@ -190,9 +190,7 @@ class Background_Job extends Framework\SV_WP_Background_Job_Handler {
190
 
191
  wc_square()->get_sync_handler()->record_sync( $job->processed_product_ids, $job );
192
 
193
- if ( ! empty( $job->manual ) ) {
194
- wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
195
- }
196
  }
197
 
198
 
@@ -210,9 +208,7 @@ class Background_Job extends Framework\SV_WP_Background_Job_Handler {
210
  'message' => 'Sync failed. Please try again',
211
  ] );
212
 
213
- if ( ! empty( $job->manual ) ) {
214
- wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
215
- }
216
  }
217
 
218
 
190
 
191
  wc_square()->get_sync_handler()->record_sync( $job->processed_product_ids, $job );
192
 
193
+ wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
 
 
194
  }
195
 
196
 
208
  'message' => 'Sync failed. Please try again',
209
  ] );
210
 
211
+ wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
 
 
212
  }
213
 
214
 
includes/Handlers/Connection.php CHANGED
@@ -253,6 +253,7 @@ class Connection {
253
  if ( ! $refresh_token ) {
254
  $this->get_plugin()->log( 'No refresh token stored, cannot refresh connection.' );
255
  update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
 
256
  return;
257
  }
258
 
@@ -299,6 +300,8 @@ class Connection {
299
  $this->get_plugin()->log( 'Unable to refresh connection: ' . $exception->getMessage() );
300
 
301
  update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
 
 
302
  }
303
 
304
  $this->schedule_refresh();
253
  if ( ! $refresh_token ) {
254
  $this->get_plugin()->log( 'No refresh token stored, cannot refresh connection.' );
255
  update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
256
+ wc_square()->get_email_handler()->get_access_token_email()->trigger();
257
  return;
258
  }
259
 
300
  $this->get_plugin()->log( 'Unable to refresh connection: ' . $exception->getMessage() );
301
 
302
  update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
303
+
304
+ wc_square()->get_email_handler()->get_access_token_email()->trigger();
305
  }
306
 
307
  $this->schedule_refresh();
includes/Handlers/Email.php CHANGED
@@ -34,11 +34,11 @@ defined( 'ABSPATH' ) or exit;
34
  * @since 2.0.0
35
  */
36
  class Email {
37
-
38
-
39
  /** @var Emails\Sync_Completed instance */
40
  private $square_sync_completed;
41
 
 
 
42
 
43
  /**
44
  * Sets up Square emails.
@@ -46,27 +46,23 @@ class Email {
46
  * @since 1.0.0
47
  */
48
  public function __construct() {
49
-
50
  // add email handlers to WooCommerce core
51
  add_action( 'woocommerce_loaded', [ $this, 'init_emails' ] );
52
  add_filter( 'woocommerce_email_classes', [ $this, 'get_email_classes' ] );
53
  }
54
 
55
-
56
  /**
57
  * Ensures the WooCommerce email handlers are loaded.
58
  *
59
  * @since 2.0.0
60
  */
61
  private function init_mailer() {
62
-
63
  // loads the base WooCommerce Email base class
64
  if ( ! class_exists( 'WC_Email' ) ) {
65
  WC()->mailer();
66
  }
67
  }
68
 
69
-
70
  /**
71
  * Initializes Square email classes.
72
  *
@@ -75,14 +71,16 @@ class Email {
75
  * @since 2.0.0
76
  */
77
  public function init_emails() {
78
-
79
  $this->init_mailer();
80
 
81
  if ( null === $this->square_sync_completed ) {
82
  $this->square_sync_completed = new Emails\Sync_Completed();
83
  }
84
- }
85
 
 
 
 
 
86
 
87
  /**
88
  * Adds WooCommerce Square email handlers.
@@ -95,7 +93,6 @@ class Email {
95
  * @return \WC_Email[]
96
  */
97
  public function get_email_classes( $emails = [] ) {
98
-
99
  // init emails if uninitialized
100
  $this->init_emails();
101
 
@@ -103,10 +100,13 @@ class Email {
103
  $emails['wc_square_sync_completed'] = $this->square_sync_completed;
104
  }
105
 
 
 
 
 
106
  return $emails;
107
  }
108
 
109
-
110
  /**
111
  * Gets the Square sync completed email instance.
112
  *
@@ -115,15 +115,19 @@ class Email {
115
  * @return Emails\Sync_Completed
116
  */
117
  public function get_sync_completed_email() {
118
-
119
- $this->init_mailer();
120
-
121
- if ( null === $this->square_sync_completed ) {
122
- $this->square_sync_completed = new Emails\Sync_Completed();
123
- }
124
-
125
  return $this->square_sync_completed;
126
  }
127
 
128
-
 
 
 
 
 
 
 
 
 
 
129
  }
34
  * @since 2.0.0
35
  */
36
  class Email {
 
 
37
  /** @var Emails\Sync_Completed instance */
38
  private $square_sync_completed;
39
 
40
+ /** @var Emails\Access_Token_Email instance */
41
+ private $square_access_token_email;
42
 
43
  /**
44
  * Sets up Square emails.
46
  * @since 1.0.0
47
  */
48
  public function __construct() {
 
49
  // add email handlers to WooCommerce core
50
  add_action( 'woocommerce_loaded', [ $this, 'init_emails' ] );
51
  add_filter( 'woocommerce_email_classes', [ $this, 'get_email_classes' ] );
52
  }
53
 
 
54
  /**
55
  * Ensures the WooCommerce email handlers are loaded.
56
  *
57
  * @since 2.0.0
58
  */
59
  private function init_mailer() {
 
60
  // loads the base WooCommerce Email base class
61
  if ( ! class_exists( 'WC_Email' ) ) {
62
  WC()->mailer();
63
  }
64
  }
65
 
 
66
  /**
67
  * Initializes Square email classes.
68
  *
71
  * @since 2.0.0
72
  */
73
  public function init_emails() {
 
74
  $this->init_mailer();
75
 
76
  if ( null === $this->square_sync_completed ) {
77
  $this->square_sync_completed = new Emails\Sync_Completed();
78
  }
 
79
 
80
+ if ( null === $this->square_access_token_email ) {
81
+ $this->square_access_token_email = new Emails\Access_Token_Email();
82
+ }
83
+ }
84
 
85
  /**
86
  * Adds WooCommerce Square email handlers.
93
  * @return \WC_Email[]
94
  */
95
  public function get_email_classes( $emails = [] ) {
 
96
  // init emails if uninitialized
97
  $this->init_emails();
98
 
100
  $emails['wc_square_sync_completed'] = $this->square_sync_completed;
101
  }
102
 
103
+ if ( ! array_key_exists( 'wc_square_access_token_email', $emails ) || ! $emails['wc_square_access_token_email'] instanceof Emails\Sync_Completed ) {
104
+ $emails['wc_square_access_token_email'] = $this->square_access_token_email;
105
+ }
106
+
107
  return $emails;
108
  }
109
 
 
110
  /**
111
  * Gets the Square sync completed email instance.
112
  *
115
  * @return Emails\Sync_Completed
116
  */
117
  public function get_sync_completed_email() {
118
+ $this->init_emails();
 
 
 
 
 
 
119
  return $this->square_sync_completed;
120
  }
121
 
122
+ /**
123
+ * Gets the Square access token email instance.
124
+ *
125
+ * @since 2.1.0
126
+ *
127
+ * @return Emails\Access_Token_Email
128
+ */
129
+ public function get_access_token_email() {
130
+ $this->init_emails();
131
+ return $this->square_access_token_email;
132
+ }
133
  }
includes/Plugin.php CHANGED
@@ -42,7 +42,7 @@ class Plugin extends Framework\SV_WC_Payment_Gateway_Plugin {
42
 
43
 
44
  /** plugin version number */
45
- const VERSION = '2.0.8';
46
 
47
  /** plugin ID */
48
  const PLUGIN_ID = 'square';
42
 
43
 
44
  /** plugin version number */
45
+ const VERSION = '2.1.0';
46
 
47
  /** plugin ID */
48
  const PLUGIN_ID = 'square';
includes/Sync/Manual_Synchronization.php CHANGED
@@ -192,7 +192,7 @@ class Manual_Synchronization extends Stepped_Job {
192
 
193
  $category_id = $mapped_category_audit[ $category->getId() ];
194
 
195
- $map[ $category_id ]['version'] = $category->getVersion();
196
  unset( $mapped_category_audit[ $category->getId() ] );
197
  }
198
  }
@@ -1584,26 +1584,22 @@ class Manual_Synchronization extends Stepped_Job {
1584
  *
1585
  * @since 2.0.0
1586
  *
1587
- * @param int[] $product_ids array of product IDs
1588
  * @return int[]
1589
  */
1590
  protected function get_shared_category_ids( $product_ids ) {
1591
- global $wpdb;
1592
 
1593
  if ( ! empty( $product_ids ) ) {
1594
-
1595
- $term_ids = $wpdb->get_col( " SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_cat' " );
1596
- $term_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $term_ids ) ) ) . ')';
1597
- $post_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $product_ids ) ) ) . ')';
1598
- $category_ids = $wpdb->get_results( "
1599
- SELECT term_taxonomy_id
1600
- FROM $wpdb->term_relationships
1601
- WHERE object_id IN $post_in
1602
- AND term_taxonomy_id IN $term_in
1603
- ", ARRAY_N );
1604
  }
1605
 
1606
- return ! empty( $category_ids ) ? array_unique( array_map( 'absint', array_merge( ...$category_ids ) ) ) : [];
1607
  }
1608
 
1609
 
192
 
193
  $category_id = $mapped_category_audit[ $category->getId() ];
194
 
195
+ $map[ $category_id ]['square_version'] = $category->getVersion();
196
  unset( $mapped_category_audit[ $category->getId() ] );
197
  }
198
  }
1584
  *
1585
  * @since 2.0.0
1586
  *
1587
+ * @param int[] $product_ids array of product IDs.
1588
  * @return int[]
1589
  */
1590
  protected function get_shared_category_ids( $product_ids ) {
 
1591
 
1592
  if ( ! empty( $product_ids ) ) {
1593
+ $category_ids = get_terms(
1594
+ [
1595
+ 'taxonomy' => 'product_cat',
1596
+ 'fields' => 'ids',
1597
+ 'object_ids' => $product_ids,
1598
+ ]
1599
+ );
 
 
 
1600
  }
1601
 
1602
+ return ! empty( $category_ids ) && ! is_wp_error( $category_ids ) ? $category_ids : [];
1603
  }
1604
 
1605
 
readme.txt CHANGED
@@ -4,7 +4,7 @@ Tags: credit card, square, woocommerce, inventory sync
4
  Requires at least: 4.6
5
  Tested up to: 5.3
6
  Requires PHP: 5.6
7
- Stable tag: 2.0.8
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
@@ -72,6 +72,12 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
72
 
73
  == Changelog ==
74
 
 
 
 
 
 
 
75
  = 2.0.8 - 2019.12.09 =
76
  * Fix - Inventory changes through payments and refunds from other gateways not reflected on Square.
77
  * Fix - Fatal error on versions of WooCommerce before 4.3.
@@ -80,16 +86,14 @@ If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.o
80
  * Fix - Verify if the product can be synced with Square before enabling sync when bulk/quick updating.
81
  * Fix - Disable sync for products that should not be synced after a REST API update.
82
  * Fix - Unable to create products during import.
83
- * Fix - Product inventory sync issuse when WooCommerce is set as the Source of Record.
84
  * Fix - Inventory not updated when purchased through another gateway.
85
  * Fix - Category and description data not updated in a sync from Square.
86
  * Fix - Transactions on multiple stores connected to the same Square account would appear to succeed without actually charging the customer.
87
  * Fix - When making multiple partial refunds on the same order, only the first one would work.
88
  * Tweak - Include product ID on failed sync record message.
89
- * Tweak - Remove notices for refresh token when sanbox is enabled.
90
- * Tweak - Prevent refreshing a token token when sanbox is enabled.
91
-
92
-
93
 
94
  = 2.0.7 - 2019.11.18 =
95
  * Fix - No longer automatically disconnect on unexpected authorization errors
4
  Requires at least: 4.6
5
  Tested up to: 5.3
6
  Requires PHP: 5.6
7
+ Stable tag: 2.1.0
8
  License: GPLv3
9
  License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
 
72
 
73
  == Changelog ==
74
 
75
+ = 2.1.0 - 2020.02.11 =
76
+ * Feature - Add support for SCA (3D Secure 2)
77
+ * Fix - Minor fixes to the Sync completed emails
78
+ * Tweak - Add email notifications when connection issues are detected
79
+ * Fix - Category sync when WooCommerce is the System of Record and there have been changes in Square
80
+
81
  = 2.0.8 - 2019.12.09 =
82
  * Fix - Inventory changes through payments and refunds from other gateways not reflected on Square.
83
  * Fix - Fatal error on versions of WooCommerce before 4.3.
86
  * Fix - Verify if the product can be synced with Square before enabling sync when bulk/quick updating.
87
  * Fix - Disable sync for products that should not be synced after a REST API update.
88
  * Fix - Unable to create products during import.
89
+ * Fix - Product inventory sync issue when WooCommerce is set as the Source of Record.
90
  * Fix - Inventory not updated when purchased through another gateway.
91
  * Fix - Category and description data not updated in a sync from Square.
92
  * Fix - Transactions on multiple stores connected to the same Square account would appear to succeed without actually charging the customer.
93
  * Fix - When making multiple partial refunds on the same order, only the first one would work.
94
  * Tweak - Include product ID on failed sync record message.
95
+ * Tweak - Remove notices for refresh token when sandbox is enabled.
96
+ * Tweak - Prevent refreshing a token token when sandbox is enabled.
 
 
97
 
98
  = 2.0.7 - 2019.11.18 =
99
  * Fix - No longer automatically disconnect on unexpected authorization errors
templates/emails/plain/{square-sync-completed.php → square-email.php} RENAMED
@@ -24,12 +24,11 @@
24
  defined( 'ABSPATH' ) or exit;
25
 
26
  /**
27
- * Square sync completed plain email template.
28
  *
29
  * @type string $email_heading email heading
30
  * @type string $email_body email body
31
  * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
32
- * @type \stdClass $sync_job background job object
33
  *
34
  * @version 2.0.0
35
  * @since 2.0.0
@@ -41,6 +40,6 @@ echo "----------\n\n";
41
 
42
  echo wptexturize( $email_body );
43
 
44
- echo "----------\n\n";
45
 
46
  echo (string) apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text', '' ) );
24
  defined( 'ABSPATH' ) or exit;
25
 
26
  /**
27
+ * Square plain email template.
28
  *
29
  * @type string $email_heading email heading
30
  * @type string $email_body email body
31
  * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
 
32
  *
33
  * @version 2.0.0
34
  * @since 2.0.0
40
 
41
  echo wptexturize( $email_body );
42
 
43
+ echo "\n\n----------\n\n";
44
 
45
  echo (string) apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text', '' ) );
trunk/templates/emails/square-sync-completed.php → templates/emails/square-email.php RENAMED
@@ -24,12 +24,11 @@
24
  defined( 'ABSPATH' ) or exit;
25
 
26
  /**
27
- * Square sync completed email template.
28
  *
29
  * @type string $email_heading email heading
30
  * @type string $email_body email body (may contain HTML)
31
  * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
32
- * @type \stdClass $sync_job background job object
33
  *
34
  * @version 2.0.0
35
  * @since 2.0.0
24
  defined( 'ABSPATH' ) or exit;
25
 
26
  /**
27
+ * Square html email template.
28
  *
29
  * @type string $email_heading email heading
30
  * @type string $email_body email body (may contain HTML)
31
  * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
 
32
  *
33
  * @version 2.0.0
34
  * @since 2.0.0
templates/emails/square-sync-completed.php DELETED
@@ -1,42 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- defined( 'ABSPATH' ) or exit;
25
-
26
- /**
27
- * Square sync completed email template.
28
- *
29
- * @type string $email_heading email heading
30
- * @type string $email_body email body (may contain HTML)
31
- * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
32
- * @type \stdClass $sync_job background job object
33
- *
34
- * @version 2.0.0
35
- * @since 2.0.0
36
- */
37
-
38
- do_action( 'woocommerce_email_header', $email_heading, $email );
39
-
40
- echo wpautop( wptexturize( $email_body ) );
41
-
42
- do_action( 'woocommerce_email_footer', $email );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/css/admin/wc-square-admin.min.css DELETED
@@ -1,2 +0,0 @@
1
- #wc-square-sync-page h2{margin-top:20px}#wc-square-sync-page #wc-square_clear-sync-records{margin-bottom:20px}.wc_square_table tr:nth-child(2n) td,.wc_square_table tr:nth-child(2n) th{background:#f9f9f9}.wc_square_table.sor{margin-bottom:20px}.wc_square_table.records .type{cursor:default}.wc_square_table.records .type mark{background:0 0;border:none;box-shadow:none;display:block;margin:5px 0;padding:0}.wc_square_table.records .type mark span{border-radius:3px;background:#c8d7e1;color:#2e4453;padding:6px 10px}.wc_square_table.records .type mark.alert span{background:#eba3a3;color:#761919}.wc_square_table.records .type mark.notice span{background:#f8dda7;color:#94660c}.wc_square_table.records .type mark.info span{background:#e5e5e5;color:#777}.wc_square_table.records .type mark.resolved span{background:#c6e1c6;color:#5b841b}.wc_square_table.records .actions .dashicons{margin-top:3px}
2
- /*# sourceMappingURL=wc-square-admin.min.css.map */
 
 
trunk/assets/css/admin/wc-square-admin.min.css.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["wc-square-admin.scss"],"names":[],"mappings":"AAEC,wBACC,WAAY,KAGb,mDACC,cAAe,KAMC,qCACA,qCAChB,WAAY,QAJE,qBAQd,cAAe,KAKf,+BAEC,OAAQ,QAER,oCAEC,WAAY,IACZ,OAAQ,KACR,WAAY,KACZ,QAAS,MACT,OAAQ,IAAA,EACR,QAAS,EAET,yCACC,cAAe,IACf,WAAY,QACZ,MAAO,QACP,QAAS,IAAA,KAGF,+CACP,WAAY,QACZ,MAAO,QAGC,gDACR,WAAY,QACZ,MAAO,QAGD,8CACN,WAAY,QACZ,MAAO,KAGG,kDACV,WAAY,QACZ,MAAO,QAOT,6CACC,WAAY"}
 
trunk/assets/css/admin/wc-square-admin.scss DELETED
@@ -1,74 +0,0 @@
1
- #wc-square-sync-page {
2
-
3
- h2 {
4
- margin-top: 20px;
5
- }
6
-
7
- #wc-square_clear-sync-records {
8
- margin-bottom: 20px;
9
- }
10
- }
11
-
12
- .wc_square_table {
13
-
14
- tr:nth-child(2n) td,
15
- tr:nth-child(2n) th {
16
- background: #F9F9F9;
17
- }
18
-
19
- &.sor {
20
- margin-bottom: 20px;
21
- }
22
-
23
- &.records {
24
-
25
- .type {
26
-
27
- cursor: default;
28
-
29
- mark {
30
-
31
- background: transparent;
32
- border: none;
33
- box-shadow: none;
34
- display: block;
35
- margin: 5px 0;
36
- padding: 0;
37
-
38
- span {
39
- border-radius: 3px;
40
- background: #C8D7E1;
41
- color: #2E4453;
42
- padding: 6px 10px;
43
- }
44
-
45
- &.alert span {
46
- background: #EBA3A3;
47
- color: #761919;
48
- }
49
-
50
- &.notice span {
51
- background: #F8DDA7;
52
- color: #94660c;
53
- }
54
-
55
- &.info span {
56
- background: #E5E5E5;
57
- color: #777777;
58
- }
59
-
60
- &.resolved span {
61
- background: #C6E1C6;
62
- color: #5B841B;
63
- }
64
- }
65
- }
66
-
67
- .actions {
68
-
69
- .dashicons {
70
- margin-top: 3px;
71
- }
72
- }
73
- }
74
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/css/frontend/wc-square.min.css DELETED
@@ -1,2 +0,0 @@
1
- .woocommerce #payment div.payment_method_square_credit_card div.form-row{padding:3px}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field{height:3em;padding:5px;border:1px solid #ccc;border-radius:3px;transition:border-color 160ms;-webkit-transition:border-color 160ms;background-color:#fff}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number{padding-right:55px;background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-cc-plain.svg);background-repeat:no-repeat;background-position:99%;background-size:50px 31px}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-visa{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-visa.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-mastercard{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-mastercard.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-amex{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-amex.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-diners-club{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-dinersclub.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-maestro{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-maestro.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-jcb{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-jcb.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-discover{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-discover.svg)}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number.card-type-invalid{background-image:url(../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images/card-cc-invalid.svg)}@media only screen and (max-width:320px){.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-hosted-field-card-number{background-image:none}}.woocommerce #payment div.payment_method_square_credit_card .wc-square-credit-card-payment-field--error{border-color:#a00}
2
- /*# sourceMappingURL=wc-square.min.css.map */
 
 
trunk/assets/css/frontend/wc-square.min.css.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["wc-square.scss"],"names":[],"mappings":"AASI,yEACF,QAAS,IAQV,gGACC,OAAQ,IACR,QAAS,IACT,OAAQ,IAAA,MAAA,KACR,cAAe,IACf,WAAY,aAAA,MACZ,mBAAoB,aAAA,MACpB,iBAAkB,KAGnB,4GACG,cAAe,KACjB,iBAAkB,8GAClB,kBAAmB,UACnB,oBAAqB,IACrB,gBAAiB,KAAA,KAL6B,2HAQ7C,iBAAkB,0GAR2B,iIAY7C,iBAAkB,gHAZ2B,2HAgB7C,iBAAkB,0GAhB2B,kIAoB7C,iBAAkB,gHApB2B,8HAwB7C,iBAAkB,6GAxB2B,0HA4B7C,iBAAkB,yGA5B2B,+HAgC7C,iBAAkB,8GAhC2B,8HAoC7C,iBAAkB,gHAGqB,yCAvCzC,4GAwCE,iBAAkB,MAIpB,wGACC,aAAc"}
 
trunk/assets/css/frontend/wc-square.scss DELETED
@@ -1,76 +0,0 @@
1
- $image_path: '../../../vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/assets/images';
2
-
3
- // checkout, Order > Pay, and Add Payment Method pages
4
- .woocommerce #payment div.payment_method_square_credit_card {
5
-
6
- iframe {
7
-
8
- }
9
-
10
- div.form-row {
11
- padding: 3px;
12
- }
13
-
14
- .wc-square-hosted-field-parent {
15
-
16
- }
17
-
18
- // general input styling
19
- .wc-square-credit-card-hosted-field {
20
- height: 3em;
21
- padding: 5px;
22
- border: 1px solid #ccc;
23
- border-radius: 3px;
24
- transition: border-color 160ms;
25
- -webkit-transition: border-color 160ms;
26
- background-color: white;
27
- }
28
-
29
- .wc-square-credit-card-hosted-field-card-number {
30
- padding-right: 55px;
31
- background-image: url('#{$image_path}/card-cc-plain.svg');
32
- background-repeat: no-repeat;
33
- background-position: 99%;
34
- background-size: 50px 31px;
35
-
36
- &.card-type-visa {
37
- background-image: url('#{$image_path}/card-visa.svg');
38
- }
39
-
40
- &.card-type-mastercard {
41
- background-image: url('#{$image_path}/card-mastercard.svg');
42
- }
43
-
44
- &.card-type-amex {
45
- background-image: url('#{$image_path}/card-amex.svg');
46
- }
47
-
48
- &.card-type-diners-club {
49
- background-image: url('#{$image_path}/card-dinersclub.svg');
50
- }
51
-
52
- &.card-type-maestro {
53
- background-image: url('#{$image_path}/card-maestro.svg');
54
- }
55
-
56
- &.card-type-jcb {
57
- background-image: url('#{$image_path}/card-jcb.svg');
58
- }
59
-
60
- &.card-type-discover {
61
- background-image: url('#{$image_path}/card-discover.svg');
62
- }
63
-
64
- &.card-type-invalid {
65
- background-image: url('#{$image_path}/card-cc-invalid.svg');
66
- }
67
-
68
- @media only screen and (max-width : 320px) {
69
- background-image: none;
70
- }
71
- }
72
-
73
- .wc-square-credit-card-payment-field--error {
74
- border-color: #a00;
75
- }
76
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/js/admin/wc-square-admin-products.coffee DELETED
@@ -1,355 +0,0 @@
1
- "use strict"
2
-
3
- ###*
4
- # WooCommerce Square admin general scripts for the settings page and update tab.
5
- #
6
- # @since 2.0.0
7
- ###
8
- jQuery( document ).ready ( $ ) ->
9
-
10
- typenow = window.typenow ? ''
11
- pagenow = window.pagenow ? ''
12
-
13
-
14
- # bail if not on product admin pages
15
- if 'product' isnt typenow
16
- return
17
-
18
- # bail if product sync is disabled
19
- if not wc_square_admin_products.is_product_sync_enabled
20
- return
21
-
22
-
23
- # products edit screen
24
- if 'edit-product' is pagenow
25
-
26
-
27
- # when clicking the quick edit button fetch the default Synced with Square checkbox
28
- $( 'button.editinline' ).on 'click', ( e ) ->
29
-
30
- $row = $( this ).closest( 'tr' )
31
- postID = $row.find( 'th.check-column input' ).val()
32
- data =
33
- action : 'wc_square_is_product_synced_with_square'
34
- security : wc_square_admin_products.is_product_synced_with_square_nonce
35
- product_id : $row.find( 'th.check-column input' ).val()
36
-
37
- $.post wc_square_admin_products.ajax_url, data, ( response ) ->
38
-
39
- $editRow = $( 'tr#edit-' + postID )
40
- $squareSynced = $editRow.find( 'select.square-synced' )
41
- $sku = $editRow.find( 'input[name=_sku]' )
42
- $manageStock = $editRow.find( 'input[name=_manage_stock]' )
43
- $stockStatus = $editRow.find( 'select[name=_stock_status]' )
44
- $stockQty = $editRow.find( 'input[name=_stock]' )
45
- $errors = $editRow.find( '.wc-square-sync-with-square-errors' )
46
-
47
- if response and response.data
48
- # if the product has multiple attributes we show an inline error message and bail
49
- if 'multiple_attributes' is response.data
50
- $squareSynced.prop( 'checked', false )
51
- $squareSynced.prop( 'disabled', true )
52
- $errors.find( '.multiple_attributes' ).show()
53
- return
54
- # if the product has variations without an SKU we show an inline error message and bail
55
- else if 'missing_variation_sku' is response.data
56
- $squareSynced.prop( 'checked', false )
57
- $squareSynced.prop( 'disabled', true )
58
- $errors.find( '.missing_variation_sku' ).show()
59
- return
60
- else
61
- # a missing sku can be recoverable instead, since the admin can enter one from the quick edit panel
62
- $squareSynced.val( if 'missing_sku' is response.data then 'no' else response.data )
63
-
64
- # if the SKU changes, enabled or disable Synced with Square checkbox accordingly
65
- $sku.on 'change keyup keypress', ( e ) ->
66
- if '' is $( this ).val()
67
- $squareSynced.val( 'no' )
68
- $squareSynced.prop( 'disabled', true )
69
- $errors.find( '.missing_sku' ).show()
70
- else
71
- $squareSynced.prop( 'disabled', false )
72
- $squareSynced.trigger 'change'
73
- $errors.find( '.missing_sku' ).hide()
74
- .trigger 'change'
75
-
76
- # if Synced with Square is enabled, we might as well disable stock management (without verbose explanations as in the product page)
77
- $squareSynced.on 'change', ( e ) ->
78
- if 'no' is $( this ).val()
79
- $manageStock.prop( 'disabled', false )
80
- $stockStatus.prop( 'disabled', false )
81
- $stockQty.prop( 'disabled', false )
82
- else
83
- $manageStock.prop( 'checked', true )
84
- $( '.stock_qty_field' ).show()
85
- $manageStock.prop( 'disabled', true )
86
- $stockStatus.prop( 'disabled', true )
87
- $stockQty.prop( 'disabled', true )
88
- .trigger 'change'
89
-
90
-
91
- # individual product edit screen
92
- if 'product' is pagenow
93
-
94
- syncCheckboxID = '#_' + wc_square_admin_products.synced_with_square_taxonomy
95
-
96
-
97
- isVariable = ->
98
- return $( '#product-type' ).val() in wc_square_admin_products.variable_product_types
99
-
100
-
101
- ###*
102
- # Checks whether the product has a SKU.
103
- #
104
- # @since 2.0.0
105
- ###
106
- hasSKU = ->
107
- return $( '#_sku' ).val() isnt ''
108
-
109
-
110
- ###*
111
- # Checks whether the product has more than one variation attribute.
112
- #
113
- # @since 2.0.0
114
- ###
115
- hasMultipleAttributes = ->
116
-
117
- $variation_attributes = $( '.woocommerce_attribute_data input[name^="attribute_variation"]:checked' )
118
-
119
- return isVariable() and $variation_attributes and $variation_attributes.length > 1
120
-
121
-
122
- ###*
123
- # Handle SKU.
124
- #
125
- # Disables the Sync with Square checkbox and toggles an inline notice when no SKU is set on a product.
126
- #
127
- # @since 2.0.0
128
- ###
129
- handleSKU = ( syncCheckboxID ) ->
130
-
131
- return if isVariable()
132
-
133
- $( '#_sku' ).on 'change keypress keyup', ( e ) ->
134
-
135
- if '' is $( this ).val()
136
- $( '.wc-square-sync-with-square-error.missing_sku' ).show()
137
- $( syncCheckboxID ).prop( 'disabled', true )
138
- $( syncCheckboxID ).prop( 'checked', false )
139
- else
140
- $( '.wc-square-sync-with-square-error.missing_sku' ).hide()
141
- if not hasMultipleAttributes()
142
- $( syncCheckboxID ).prop( 'disabled', false )
143
-
144
- $( syncCheckboxID ).trigger( 'change' )
145
-
146
- .trigger 'change'
147
-
148
-
149
- ###*
150
- # Handle attributes.
151
- #
152
- # Disables the Sync with Square checkbox and toggles an inline notice when more than one attribute is set on the product.
153
- #
154
- # @since 2.0.0
155
- ###
156
- handleAttributes = ( syncCheckboxID ) ->
157
-
158
- $( '#variable_product_options' ).on 'reload', ( e ) ->
159
-
160
- if hasMultipleAttributes()
161
- $( '.wc-square-sync-with-square-error.multiple_attributes' ).show()
162
- $( syncCheckboxID ).prop( 'disabled', true )
163
- $( syncCheckboxID ).prop( 'checked', false )
164
- else
165
- $( '.wc-square-sync-with-square-error.multiple_attributes' ).hide()
166
- if hasSKU()
167
- $( syncCheckboxID ).prop( 'disabled', false )
168
-
169
- $( syncCheckboxID ).trigger( 'change' )
170
-
171
- .trigger( 'reload' )
172
-
173
-
174
- # fire once on page load
175
- handleSKU( syncCheckboxID )
176
- handleAttributes( syncCheckboxID )
177
-
178
-
179
- ###*
180
- # Handle stock management.
181
- #
182
- # If product is managed by Square, handle stock fields according to chosen SoR.
183
- ###
184
- $stockFields = $( '.stock_fields' )
185
- $stockInput = $stockFields.find( '#_stock' )
186
- $manageField = $( '._manage_stock_field' )
187
- $manageInput = $manageField.find( '#_manage_stock' )
188
- $manageDesc = $manageField.find( '.description' )
189
- # keep note of the original manage stock checkbox description, if we need to restore it later
190
- manageDescOriginal = $manageDesc.text()
191
- # keep track of the original manage stock checkbox status, if we need to restore it later
192
- manageStockOriginal = $( '#_manage_stock' ).is( ':checked' )
193
-
194
- $( syncCheckboxID ).on 'change', ( e ) ->
195
-
196
- # only handle stock fields if inventory sync is enabled
197
- if not wc_square_admin_products.is_inventory_sync_enabled
198
- return
199
-
200
- variableProduct = $.inArray( $( '#product-type' ).val(), wc_square_admin_products.variable_product_types ) isnt -1
201
-
202
- if $( this ).is( ':checked' ) and $( '#_square_item_variation_id' ).length > 0
203
-
204
- useSquare = true
205
-
206
- $manageDesc.html( '<a href="' + wc_square_admin_products.settings_url + '">' + wc_square_admin_products.i18n.synced_with_square + '</a>' )
207
- $manageInput.prop( 'disabled', true ).prop( 'checked', not variableProduct ).change()
208
- $stockInput.prop( 'readonly', true )
209
-
210
- if not variableProduct
211
- $stockFields.show()
212
-
213
- # WooCommerce SoR - note: for variable products, the stock can be fetched for individual variations
214
- if wc_square_admin_products.is_woocommerce_sor and not variableProduct
215
-
216
- # add inline note with a toggle to fetch stock from Square manually via AJAX (sanity check to avoid appending multiple times)
217
- if $( 'p._stock_field span.description' ).length is 0
218
- $stockInput.after( '<span class="description" style="display:block;clear:both;"><a href="#" id="fetch-stock-with-square">' + wc_square_admin_products.i18n.fetch_stock_with_square + '</a><div class="spinner" style="float:none;"></div></span>' )
219
-
220
- $( '#fetch-stock-with-square' ).on 'click', ( e ) ->
221
- e.preventDefault()
222
-
223
- $spinner = $( 'p._stock_field span.description .spinner' )
224
- $spinner.css( 'visibility', 'visible' )
225
-
226
- data =
227
- action : 'wc_square_fetch_product_stock_with_square'
228
- security : wc_square_admin_products.fetch_product_stock_with_square_nonce
229
- product_id : $( '#post_ID' ).val()
230
-
231
- $.post wc_square_admin_products.ajax_url, data, ( response ) ->
232
-
233
- if response and response.success
234
-
235
- quantity = response.data
236
-
237
- $stockInput.val( quantity )
238
- $stockFields.find( 'input[name=_original_stock]' ).val( quantity )
239
- $stockInput.prop( 'readonly', false )
240
- $( 'p._stock_field span.description' ).remove()
241
-
242
- else
243
-
244
- if response.data
245
- $( '.inventory-fetch-error' ).remove()
246
- $spinner.after( '<span class="inventory-fetch-error" style="display:inline-block;color:red;">' + response.data + '</span>' )
247
-
248
- $spinner.css( 'visibility', 'hidden' )
249
- console.log( response )
250
-
251
- # Square SoR
252
- else if wc_square_admin_products.is_square_sor
253
-
254
- # add inline note explaining stock is managed by Square (sanity check to avoid appending multiple times)
255
- if $( 'p._stock_field span.description' ).length is 0
256
- $stockInput.after( '<span class="description" style="display:block;clear:both;">' + wc_square_admin_products.i18n.managed_by_square + '</span>' )
257
-
258
-
259
- # restore defaults when user chooses to disable Sync with Square checkbox
260
- else
261
-
262
- useSquare = false
263
-
264
- # remove any inline note to WooCommerce core stock fields that may have been added when Synced with Square is enabled
265
- $( 'p._stock_field span.description' ).remove()
266
-
267
- $stockInput.prop( 'readonly', false )
268
- $manageDesc.html( manageDescOriginal )
269
- $manageInput.prop( 'disabled', false ).prop( 'checked', manageStockOriginal )
270
-
271
- if manageStockOriginal
272
- $stockFields.show()
273
-
274
-
275
- # handle variations data separately (HTML differs from parent UI!)
276
- $( '.woocommerce_variation' ).each ->
277
-
278
- # fetch relevant variables for each variation
279
- variationID = $( this ).find( 'h3 > a' ).attr( 'rel' )
280
- $variationManageInput = $( '.variable_manage_stock' )
281
- $variationManageField = $variationManageInput.parent()
282
- $variationStockInput = $( this ).find( '.wc_input_stock' )
283
- $variationStockField = $variationStockInput.parent()
284
-
285
- # Square manages variations stock
286
- if useSquare
287
-
288
- # disable stock management inputs
289
- $variationManageInput.prop( 'disabled', true ).prop( 'checked', true ).change()
290
- $variationStockInput.prop( 'readonly', true )
291
- $( '#wc_square_variation_manage_stock' ).prop( 'disabled', false )
292
-
293
- # add a note that the variation stock is managed by square, but check if it wasn't added already to avoid duplicates
294
- if 0 is $variationManageField.find( '.description' ).length
295
- $variationManageInput.after( '<span class="description">(' + wc_square_admin_products.i18n.managed_by_square + ')</span>' )
296
-
297
- if wc_square_admin_products.is_woocommerce_sor
298
-
299
- fetchVariationStockActionID = 'fetch-stock-with-square-' + variationID
300
-
301
- # add inline note with a toggle to fetch stock from Square manually via AJAX (sanity check to avoid appending multiple times)
302
- if 0 is $variationStockField.find( 'span.description' ).length
303
- $variationStockInput.after( '<span class="description" style="display:block;clear:both;"><a href="#" id="' + fetchVariationStockActionID + '">' + wc_square_admin_products.i18n.fetch_stock_with_square + '</a><div class="spinner" style="float:none;"></div></span>' )
304
-
305
- # listen for requests to update stock with Square for the individual variation
306
- $( '#' + fetchVariationStockActionID ).on 'click', ( e ) ->
307
- e.preventDefault()
308
-
309
- $spinner = $( this ).next( '.spinner' )
310
- $spinner.css( 'visibility', 'visible' )
311
-
312
- data =
313
- action : 'wc_square_fetch_product_stock_with_square'
314
- security : wc_square_admin_products.fetch_product_stock_with_square_nonce
315
- product_id : variationID
316
-
317
- $.post wc_square_admin_products.ajax_url, data, ( response ) ->
318
-
319
- if response and response.success
320
-
321
- quantity = response.data
322
-
323
- $variationStockInput.val( quantity )
324
- $variationStockField.parent().find( 'input[name^="variable_original_stock"]' ).val( quantity )
325
- $variationStockInput.prop( 'readonly', false )
326
- $variationStockField.find( '.description' ).remove()
327
-
328
- else
329
-
330
- if response.data
331
- $( '.inventory-fetch-error' ).remove()
332
- $spinner.after( '<span class="inventory-fetch-error" style="display:inline-block;color:red;">' + response.data + '</span>' )
333
-
334
- $spinner.css( 'visibility', 'hidden' )
335
- console.log( response )
336
-
337
-
338
- # restore WooCommerce stock when user chooses to disable Sync with Square checkbox
339
- else
340
- $variationStockInput.prop( 'readonly', false )
341
- $variationManageInput.prop( 'disabled', false )
342
- $variationManageInput.next( '.description' ).remove()
343
- $( '#wc_square_variation_manage_stock' ).prop( 'disabled', true )
344
-
345
-
346
- # initial page load handling
347
- .trigger 'change'
348
-
349
- # trigger an update if the product type changes
350
- $( '#product-type' ).on 'change', ( e ) ->
351
- $( syncCheckboxID ).trigger 'change'
352
-
353
- # trigger an update for variable products when variations are loaded
354
- $( '#woocommerce-product-data' ).on 'woocommerce_variations_loaded', ( e ) ->
355
- $( syncCheckboxID ).trigger 'change'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/js/admin/wc-square-admin-products.min.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";(function(){var e=[].indexOf;jQuery(document).ready(function(r){var t,i,a,s,n,o,c,d,_,p,u,l,h,f,m,w,v;if(v=null!=(f=window.typenow)?f:"",h=null!=(m=window.pagenow)?m:"","product"===v&&wc_square_admin_products.is_product_sync_enabled)return"edit-product"===h&&r("button.editinline").on("click",function(e){var t,i,a;return t=r(this).closest("tr"),a=t.find("th.check-column input").val(),i={action:"wc_square_is_product_synced_with_square",security:wc_square_admin_products.is_product_synced_with_square_nonce,product_id:t.find("th.check-column input").val()},r.post(wc_square_admin_products.ajax_url,i,function(e){var t,i,s,n,o,c,d;if(t=r("tr#edit-"+a),o=t.find("select.square-synced"),n=t.find("input[name=_sku]"),s=t.find("input[name=_manage_stock]"),d=t.find("select[name=_stock_status]"),c=t.find("input[name=_stock]"),i=t.find(".wc-square-sync-with-square-errors"),e&&e.data)return"multiple_attributes"===e.data?(o.prop("checked",!1),o.prop("disabled",!0),void i.find(".multiple_attributes").show()):"missing_variation_sku"===e.data?(o.prop("checked",!1),o.prop("disabled",!0),void i.find(".missing_variation_sku").show()):(o.val("missing_sku"===e.data?"no":e.data),n.on("change keyup keypress",function(e){return""===r(this).val()?(o.val("no"),o.prop("disabled",!0),i.find(".missing_sku").show()):(o.prop("disabled",!1),o.trigger("change"),i.find(".missing_sku").hide())}).trigger("change"),o.on("change",function(e){return"no"===r(this).val()?(s.prop("disabled",!1),d.prop("disabled",!1),c.prop("disabled",!1)):(s.prop("checked",!0),r(".stock_qty_field").show(),s.prop("disabled",!0),d.prop("disabled",!0),c.prop("disabled",!0))}).trigger("change"))})}),"product"===h?(w="#_"+wc_square_admin_products.synced_with_square_taxonomy,p=function(){var t;return t=r("#product-type").val(),e.call(wc_square_admin_products.variable_product_types,t)>=0},_=function(){return""!==r("#_sku").val()},d=function(){var e;return e=r('.woocommerce_attribute_data input[name^="attribute_variation"]:checked'),p()&&e&&e.length>1},c=function(e){if(!p())return r("#_sku").on("change keypress keyup",function(t){return""===r(this).val()?(r(".wc-square-sync-with-square-error.missing_sku").show(),r(e).prop("disabled",!0),r(e).prop("checked",!1)):(r(".wc-square-sync-with-square-error.missing_sku").hide(),d()||r(e).prop("disabled",!1)),r(e).trigger("change")}).trigger("change")},o=function(e){return r("#variable_product_options").on("reload",function(t){return d()?(r(".wc-square-sync-with-square-error.multiple_attributes").show(),r(e).prop("disabled",!0),r(e).prop("checked",!1)):(r(".wc-square-sync-with-square-error.multiple_attributes").hide(),_()&&r(e).prop("disabled",!1)),r(e).trigger("change")}).trigger("reload")},c(w),o(w),s=r(".stock_fields"),n=s.find("#_stock"),i=r("._manage_stock_field"),a=i.find("#_manage_stock"),t=i.find(".description"),u=t.text(),l=r("#_manage_stock").is(":checked"),r(w).on("change",function(e){var i,o;if(wc_square_admin_products.is_inventory_sync_enabled)return o=-1!==r.inArray(r("#product-type").val(),wc_square_admin_products.variable_product_types),r(this).is(":checked")&&r("#_square_item_variation_id").length>0?(i=!0,t.html('<a href="'+wc_square_admin_products.settings_url+'">'+wc_square_admin_products.i18n.synced_with_square+"</a>"),a.prop("disabled",!0).prop("checked",!o).change(),n.prop("readonly",!0),o||s.show(),wc_square_admin_products.is_woocommerce_sor&&!o?(0===r("p._stock_field span.description").length&&n.after('<span class="description" style="display:block;clear:both;"><a href="#" id="fetch-stock-with-square">'+wc_square_admin_products.i18n.fetch_stock_with_square+'</a><div class="spinner" style="float:none;"></div></span>'),r("#fetch-stock-with-square").on("click",function(e){var t,i;return e.preventDefault(),(t=r("p._stock_field span.description .spinner")).css("visibility","visible"),i={action:"wc_square_fetch_product_stock_with_square",security:wc_square_admin_products.fetch_product_stock_with_square_nonce,product_id:r("#post_ID").val()},r.post(wc_square_admin_products.ajax_url,i,function(e){var i;return e&&e.success?(i=e.data,n.val(i),s.find("input[name=_original_stock]").val(i),n.prop("readonly",!1),r("p._stock_field span.description").remove()):(e.data&&(r(".inventory-fetch-error").remove(),t.after('<span class="inventory-fetch-error" style="display:inline-block;color:red;">'+e.data+"</span>")),t.css("visibility","hidden"),console.log(e))})})):wc_square_admin_products.is_square_sor&&0===r("p._stock_field span.description").length&&n.after('<span class="description" style="display:block;clear:both;">'+wc_square_admin_products.i18n.managed_by_square+"</span>")):(i=!1,r("p._stock_field span.description").remove(),n.prop("readonly",!1),t.html(u),a.prop("disabled",!1).prop("checked",l),l&&s.show()),r(".woocommerce_variation").each(function(){var e,t,a,s,n,o;return o=r(this).find("h3 > a").attr("rel"),t=r(".variable_manage_stock"),e=t.parent(),s=r(this).find(".wc_input_stock"),a=s.parent(),i?(t.prop("disabled",!0).prop("checked",!0).change(),s.prop("readonly",!0),r("#wc_square_variation_manage_stock").prop("disabled",!1),0===e.find(".description").length&&t.after('<span class="description">('+wc_square_admin_products.i18n.managed_by_square+")</span>"),wc_square_admin_products.is_woocommerce_sor?(n="fetch-stock-with-square-"+o,0===a.find("span.description").length&&s.after('<span class="description" style="display:block;clear:both;"><a href="#" id="'+n+'">'+wc_square_admin_products.i18n.fetch_stock_with_square+'</a><div class="spinner" style="float:none;"></div></span>'),r("#"+n).on("click",function(e){var t,i;return e.preventDefault(),(t=r(this).next(".spinner")).css("visibility","visible"),i={action:"wc_square_fetch_product_stock_with_square",security:wc_square_admin_products.fetch_product_stock_with_square_nonce,product_id:o},r.post(wc_square_admin_products.ajax_url,i,function(e){var i;return e&&e.success?(i=e.data,s.val(i),a.parent().find('input[name^="variable_original_stock"]').val(i),s.prop("readonly",!1),a.find(".description").remove()):(e.data&&(r(".inventory-fetch-error").remove(),t.after('<span class="inventory-fetch-error" style="display:inline-block;color:red;">'+e.data+"</span>")),t.css("visibility","hidden"),console.log(e))})})):void 0):(s.prop("readonly",!1),t.prop("disabled",!1),t.next(".description").remove(),r("#wc_square_variation_manage_stock").prop("disabled",!0))})}).trigger("change"),r("#product-type").on("change",function(e){return r(w).trigger("change")}),r("#woocommerce-product-data").on("woocommerce_variations_loaded",function(e){return r(w).trigger("change")})):void 0})}).call(void 0);
2
- //# sourceMappingURL=wc-square-admin-products.min.js.map
 
 
trunk/assets/js/admin/wc-square-admin-products.min.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["wc-square-admin-products.min.js"],"names":["indexOf","jQuery","document","ready","$","$manageDesc","$manageField","$manageInput","$stockFields","$stockInput","handleAttributes","handleSKU","hasMultipleAttributes","hasSKU","isVariable","manageDescOriginal","manageStockOriginal","pagenow","ref","ref1","syncCheckboxID","typenow","window","wc_square_admin_products","is_product_sync_enabled","on","e","$row","data","postID","this","closest","find","val","action","security","is_product_synced_with_square_nonce","product_id","post","ajax_url","response","$editRow","$errors","$manageStock","$sku","$squareSynced","$stockQty","$stockStatus","prop","show","trigger","hide","synced_with_square_taxonomy","ref2","call","variable_product_types","$variation_attributes","length","text","is","useSquare","variableProduct","is_inventory_sync_enabled","inArray","html","settings_url","i18n","synced_with_square","change","is_woocommerce_sor","after","fetch_stock_with_square","$spinner","preventDefault","css","fetch_product_stock_with_square_nonce","quantity","success","remove","console","log","is_square_sor","managed_by_square","each","$variationManageField","$variationManageInput","$variationStockField","$variationStockInput","fetchVariationStockActionID","variationID","attr","parent","next","undefined"],"mappings":"AAAA,cAEA,WAGE,IAAIA,KAAaA,QAOjBC,OAAOC,UAAUC,MAAM,SAAUC,GA8B/B,IAAIC,EAAaC,EAAcC,EAAcC,EAAcC,EAAaC,EAAkBC,EAAWC,EAAuBC,EAAQC,EAAYC,EAAoBC,EAAqBC,EAASC,EAAKC,EAAMC,EAAgBC,EAI7N,GAHAA,EAAoC,OAAzBH,EAAMI,OAAOD,SAAmBH,EAAM,GACjDD,EAAqC,OAA1BE,EAAOG,OAAOL,SAAmBE,EAAO,GAE/C,YAAcE,GAIbE,yBAAyBC,wBAwE9B,MApEI,iBAAmBP,GAErBb,EAAE,qBAAqBqB,GAAG,QAAS,SAAUC,GAC3C,IAAIC,EAAMC,EAAMC,EAQhB,OAPAF,EAAOvB,EAAE0B,MAAMC,QAAQ,MACvBF,EAASF,EAAKK,KAAK,yBAAyBC,MAC5CL,GACEM,OAAQ,0CACRC,SAAUZ,yBAAyBa,oCACnCC,WAAYV,EAAKK,KAAK,yBAAyBC,OAE1C7B,EAAEkC,KAAKf,yBAAyBgB,SAAUX,EAAM,SAAUY,GAC/D,IAAIC,EAAUC,EAASC,EAAcC,EAAMC,EAAeC,EAAWC,EAQrE,GAPAN,EAAWrC,EAAE,WAAayB,GAC1BgB,EAAgBJ,EAAST,KAAK,wBAC9BY,EAAOH,EAAST,KAAK,oBACrBW,EAAeF,EAAST,KAAK,6BAC7Be,EAAeN,EAAST,KAAK,8BAC7Bc,EAAYL,EAAST,KAAK,sBAC1BU,EAAUD,EAAST,KAAK,sCACpBQ,GAAYA,EAASZ,KAEvB,MAAI,wBAA0BY,EAASZ,MACrCiB,EAAcG,KAAK,WAAW,GAC9BH,EAAcG,KAAK,YAAY,QAC/BN,EAAQV,KAAK,wBAAwBiB,QAG5B,0BAA4BT,EAASZ,MAC9CiB,EAAcG,KAAK,WAAW,GAC9BH,EAAcG,KAAK,YAAY,QAC/BN,EAAQV,KAAK,0BAA0BiB,SAIvCJ,EAAcZ,IAAI,gBAAkBO,EAASZ,KAAO,KAAOY,EAASZ,MAGtEgB,EAAKnB,GAAG,wBAAyB,SAAUC,GACzC,MAAI,KAAOtB,EAAE0B,MAAMG,OACjBY,EAAcZ,IAAI,MAClBY,EAAcG,KAAK,YAAY,GACxBN,EAAQV,KAAK,gBAAgBiB,SAEpCJ,EAAcG,KAAK,YAAY,GAC/BH,EAAcK,QAAQ,UACfR,EAAQV,KAAK,gBAAgBmB,UAErCD,QAAQ,UAEJL,EAAcpB,GAAG,SAAU,SAAUC,GAC1C,MAAI,OAAStB,EAAE0B,MAAMG,OACnBU,EAAaK,KAAK,YAAY,GAC9BD,EAAaC,KAAK,YAAY,GACvBF,EAAUE,KAAK,YAAY,KAElCL,EAAaK,KAAK,WAAW,GAC7B5C,EAAE,oBAAoB6C,OACtBN,EAAaK,KAAK,YAAY,GAC9BD,EAAaC,KAAK,YAAY,GACvBF,EAAUE,KAAK,YAAY,MAEnCE,QAAQ,eAMf,YAAcjC,GAChBG,EAAiB,KAAOG,yBAAyB6B,4BACjDtC,EAAa,WACX,IAAIuC,EACJ,OAAOA,EAAOjD,EAAE,iBAAiB6B,MAAOjC,EAAQsD,KAAK/B,yBAAyBgC,uBAAwBF,IAAS,GAEjHxC,EAAS,WACP,MAA4B,KAArBT,EAAE,SAAS6B,OAEpBrB,EAAwB,WACtB,IAAI4C,EAEJ,OADAA,EAAwBpD,EAAE,0EACnBU,KAAgB0C,GAAyBA,EAAsBC,OAAS,GAEjF9C,EAAY,SAAmBS,GAC7B,IAAIN,IAGJ,OAAOV,EAAE,SAASqB,GAAG,wBAAyB,SAAUC,GAWtD,MAVI,KAAOtB,EAAE0B,MAAMG,OACjB7B,EAAE,iDAAiD6C,OACnD7C,EAAEgB,GAAgB4B,KAAK,YAAY,GACnC5C,EAAEgB,GAAgB4B,KAAK,WAAW,KAElC5C,EAAE,iDAAiD+C,OAC9CvC,KACHR,EAAEgB,GAAgB4B,KAAK,YAAY,IAGhC5C,EAAEgB,GAAgB8B,QAAQ,YAChCA,QAAQ,WAEbxC,EAAmB,SAA0BU,GAC3C,OAAOhB,EAAE,6BAA6BqB,GAAG,SAAU,SAAUC,GAW3D,OAVId,KACFR,EAAE,yDAAyD6C,OAC3D7C,EAAEgB,GAAgB4B,KAAK,YAAY,GACnC5C,EAAEgB,GAAgB4B,KAAK,WAAW,KAElC5C,EAAE,yDAAyD+C,OACvDtC,KACFT,EAAEgB,GAAgB4B,KAAK,YAAY,IAGhC5C,EAAEgB,GAAgB8B,QAAQ,YAChCA,QAAQ,WAGbvC,EAAUS,GACVV,EAAiBU,GACjBZ,EAAeJ,EAAE,iBACjBK,EAAcD,EAAawB,KAAK,WAChC1B,EAAeF,EAAE,wBACjBG,EAAeD,EAAa0B,KAAK,kBACjC3B,EAAcC,EAAa0B,KAAK,gBAEhCjB,EAAqBV,EAAYqD,OAEjC1C,EAAsBZ,EAAE,kBAAkBuD,GAAG,YAC7CvD,EAAEgB,GAAgBK,GAAG,SAAU,SAAUC,GACvC,IAAIkC,EAAWC,EAEf,GAAKtC,yBAAyBuC,0BAkE9B,OA/DAD,GAA4G,IAA1FzD,EAAE2D,QAAQ3D,EAAE,iBAAiB6B,MAAOV,yBAAyBgC,wBAC3EnD,EAAE0B,MAAM6B,GAAG,aAAevD,EAAE,8BAA8BqD,OAAS,GACrEG,GAAY,EACZvD,EAAY2D,KAAK,YAAczC,yBAAyB0C,aAAe,KAAO1C,yBAAyB2C,KAAKC,mBAAqB,QACjI5D,EAAayC,KAAK,YAAY,GAAMA,KAAK,WAAYa,GAAiBO,SACtE3D,EAAYuC,KAAK,YAAY,GACxBa,GACHrD,EAAayC,OAGX1B,yBAAyB8C,qBAAuBR,GAEE,IAAhDzD,EAAE,mCAAmCqD,QACvChD,EAAY6D,MAAM,wGAA0G/C,yBAAyB2C,KAAKK,wBAA0B,8DAEtLnE,EAAE,4BAA4BqB,GAAG,QAAS,SAAUC,GAClD,IAAI8C,EAAU5C,EASd,OARAF,EAAE+C,kBACFD,EAAWpE,EAAE,6CACJsE,IAAI,aAAc,WAC3B9C,GACEM,OAAQ,4CACRC,SAAUZ,yBAAyBoD,sCACnCtC,WAAYjC,EAAE,YAAY6B,OAErB7B,EAAEkC,KAAKf,yBAAyBgB,SAAUX,EAAM,SAAUY,GAC/D,IAAIoC,EACJ,OAAIpC,GAAYA,EAASqC,SACvBD,EAAWpC,EAASZ,KACpBnB,EAAYwB,IAAI2C,GAChBpE,EAAawB,KAAK,+BAA+BC,IAAI2C,GACrDnE,EAAYuC,KAAK,YAAY,GACtB5C,EAAE,mCAAmC0E,WAExCtC,EAASZ,OACXxB,EAAE,0BAA0B0E,SAC5BN,EAASF,MAAM,+EAAiF9B,EAASZ,KAAO,YAElH4C,EAASE,IAAI,aAAc,UACpBK,QAAQC,IAAIxC,SAKhBjB,yBAAyB0D,eAEkB,IAAhD7E,EAAE,mCAAmCqD,QACvChD,EAAY6D,MAAM,+DAAiE/C,yBAAyB2C,KAAKgB,kBAAoB,aAKzItB,GAAY,EAEZxD,EAAE,mCAAmC0E,SACrCrE,EAAYuC,KAAK,YAAY,GAC7B3C,EAAY2D,KAAKjD,GACjBR,EAAayC,KAAK,YAAY,GAAOA,KAAK,UAAWhC,GACjDA,GACFR,EAAayC,QAIV7C,EAAE,0BAA0B+E,KAAK,WACtC,IAAIC,EAAuBC,EAAuBC,EAAsBC,EAAsBC,EAA6BC,EAQ3H,OANAA,EAAcrF,EAAE0B,MAAME,KAAK,UAAU0D,KAAK,OAC1CL,EAAwBjF,EAAE,0BAC1BgF,EAAwBC,EAAsBM,SAC9CJ,EAAuBnF,EAAE0B,MAAME,KAAK,mBACpCsD,EAAuBC,EAAqBI,SAExC/B,GAEFyB,EAAsBrC,KAAK,YAAY,GAAMA,KAAK,WAAW,GAAMoB,SACnEmB,EAAqBvC,KAAK,YAAY,GACtC5C,EAAE,qCAAqC4C,KAAK,YAAY,GAEpD,IAAMoC,EAAsBpD,KAAK,gBAAgByB,QACnD4B,EAAsBf,MAAM,8BAAgC/C,yBAAyB2C,KAAKgB,kBAAoB,YAE5G3D,yBAAyB8C,oBAC3BmB,EAA8B,2BAA6BC,EAEvD,IAAMH,EAAqBtD,KAAK,oBAAoByB,QACtD8B,EAAqBjB,MAAM,+EAAiFkB,EAA8B,KAAOjE,yBAAyB2C,KAAKK,wBAA0B,8DAGpMnE,EAAE,IAAMoF,GAA6B/D,GAAG,QAAS,SAAUC,GAChE,IAAI8C,EAAU5C,EASd,OARAF,EAAE+C,kBACFD,EAAWpE,EAAE0B,MAAM8D,KAAK,aACflB,IAAI,aAAc,WAC3B9C,GACEM,OAAQ,4CACRC,SAAUZ,yBAAyBoD,sCACnCtC,WAAYoD,GAEPrF,EAAEkC,KAAKf,yBAAyBgB,SAAUX,EAAM,SAAUY,GAC/D,IAAIoC,EACJ,OAAIpC,GAAYA,EAASqC,SACvBD,EAAWpC,EAASZ,KACpB2D,EAAqBtD,IAAI2C,GACzBU,EAAqBK,SAAS3D,KAAK,0CAA0CC,IAAI2C,GACjFW,EAAqBvC,KAAK,YAAY,GAC/BsC,EAAqBtD,KAAK,gBAAgB8C,WAE7CtC,EAASZ,OACXxB,EAAE,0BAA0B0E,SAC5BN,EAASF,MAAM,+EAAiF9B,EAASZ,KAAO,YAElH4C,EAASE,IAAI,aAAc,UACpBK,QAAQC,IAAIxC,cA/B3B,IAsCA+C,EAAqBvC,KAAK,YAAY,GACtCqC,EAAsBrC,KAAK,YAAY,GACvCqC,EAAsBO,KAAK,gBAAgBd,SACpC1E,EAAE,qCAAqC4C,KAAK,YAAY,QAIlEE,QAAQ,UAEX9C,EAAE,iBAAiBqB,GAAG,SAAU,SAAUC,GACxC,OAAOtB,EAAEgB,GAAgB8B,QAAQ,YAG5B9C,EAAE,6BAA6BqB,GAAG,gCAAiC,SAAUC,GAClF,OAAOtB,EAAEgB,GAAgB8B,QAAQ,kBAtMrC,MA0MDI,UAAKuC","file":"wc-square-admin-products.min.js"}
 
trunk/assets/js/admin/wc-square-admin-settings.coffee DELETED
@@ -1,257 +0,0 @@
1
- "use strict"
2
-
3
- ###*
4
- # WooCommerce Square scripts for admin product pages.
5
- #
6
- # @since 2.0.0
7
- ###
8
- jQuery( document ).ready ( $ ) ->
9
-
10
- typenow = window.typenow ? ''
11
- pagenow = window.pagenow ? ''
12
-
13
-
14
- # bail if not on the admin settings page
15
- if ( 'woocommerce_page_wc-settings' isnt pagenow )
16
- return
17
-
18
-
19
- # toggle the "hide products" setting depending on the SOR
20
- $( '#wc_square_system_of_record' ).change( ->
21
-
22
- system_of_record = $( this ).val()
23
-
24
- $inventory_sync = $( '#wc_square_enable_inventory_sync' )
25
- $inventory_sync_row = $inventory_sync.closest( 'tr' )
26
-
27
- # toggle the "Sync inventory" setting depending on the SOR
28
- if system_of_record in [ 'square', 'woocommerce' ]
29
-
30
- $inventory_sync.next( 'span' ).html( wc_square_admin_settings.i18n.sync_inventory_label[system_of_record] )
31
-
32
- $inventory_sync_row.find( '.description' ).html( wc_square_admin_settings.i18n.sync_inventory_description[system_of_record] )
33
-
34
- $inventory_sync_row.show()
35
- else
36
- $inventory_sync_row.hide()
37
-
38
- # toggle the "Hide missing products" setting depending on the SOR
39
- if 'square' is system_of_record
40
- $( '#wc_square_hide_missing_products' ).closest( 'tr' ).show()
41
- else
42
- $( '#wc_square_hide_missing_products' ).closest( 'tr' ).hide()
43
-
44
- ).change()
45
-
46
- $( '.js-import-square-products' ).on 'click', ( e ) ->
47
- e.preventDefault()
48
-
49
- new $.WCBackboneModal.View
50
- target : 'wc-square-import-products'
51
-
52
- $( '#btn-close' ).on 'click', ( e ) ->
53
- e.preventDefault()
54
- $( 'button.modal-close' ).trigger( 'click' )
55
-
56
- $( '#btn-ok' ).on 'click', ( e ) ->
57
- e.preventDefault()
58
- $( this ).unbind()
59
-
60
- data =
61
- action : 'wc_square_import_products_from_square'
62
- dispatch : wc_square_admin_settings.sync_in_background
63
- security : wc_square_admin_settings.import_products_from_square
64
-
65
- $.post wc_square_admin_settings.ajax_url, data, ( response ) ->
66
-
67
- message = if response.data then response.data else null
68
-
69
- if response.success and message
70
- alert( message )
71
- else if not response.success and message
72
- alert( message )
73
-
74
- location.reload()
75
-
76
- # initiate a manual sync
77
- $( '#wc-square-sync' ).on 'click', ( e ) ->
78
- e.preventDefault()
79
-
80
- # open a modal dialog
81
- new $.WCBackboneModal.View
82
- target : 'wc-square-sync'
83
-
84
- # enable cancel sync button
85
- $( '#btn-close' ).on 'click', ( e ) ->
86
- e.preventDefault()
87
- $( 'button.modal-close' ).trigger( 'click' )
88
-
89
- # upon confirming, start a background process to sync products with Square
90
- $( '#btn-ok' ).on 'click', ( e ) ->
91
- e.preventDefault()
92
- $( this ).unbind()
93
-
94
- $( 'table.sync' ).block
95
- message : null
96
- overlayCSS :
97
- 'opacity' : '0.2'
98
- $( 'table.records' ).block
99
- message : null
100
- overlayCSS :
101
- 'opacity' : '0.2'
102
- $( '#wc-square_clear-sync-records' ).prop( 'disabled', true )
103
-
104
- data =
105
- action : 'wc_square_sync_products_with_square'
106
- dispatch : wc_square_admin_settings.sync_in_background
107
- security : wc_square_admin_settings.sync_products_with_square
108
-
109
- $.post wc_square_admin_settings.ajax_url, data, ( response ) ->
110
- if response and response.success
111
- location.reload()
112
- else
113
- $( '#wc-square_clear-sync-records' ).prop( 'disabled', false )
114
- $( 'table.sync' ).unblock()
115
- $( 'table.records' ).unblock()
116
- console.log( response )
117
-
118
-
119
- # sync record handling
120
- noRecordsFoundRow = '<tr><td colspan="4"><em>' + wc_square_admin_settings.i18n.no_records_found + '</em></td></tr>'
121
-
122
- # clear sync records history
123
- $( '#wc-square_clear-sync-records' ).on 'click', ( e ) ->
124
- e.preventDefault()
125
-
126
- $( 'table.records' ).block
127
- message : null
128
- overlayCSS :
129
- 'opacity' : '0.2'
130
-
131
- data =
132
- action : 'wc_square_handle_sync_records'
133
- id : 'all'
134
- handle : 'delete'
135
- security : wc_square_admin_settings.handle_sync_with_square_records
136
-
137
- $.post wc_square_admin_settings.ajax_url, data, ( response ) ->
138
- if response and response.success
139
- $( 'table.records tbody' ).html( noRecordsFoundRow )
140
- $( '#wc-square_clear-sync-records').prop( 'disabled', true )
141
- else
142
- if ( response.data )
143
- alert( response.data )
144
- console.log( response )
145
-
146
- $( 'table.records' ).unblock()
147
-
148
- # individual sync records actions
149
- $( '.records .actions button.action' ).on 'click', ( e ) ->
150
- e.preventDefault()
151
-
152
- $( 'table.records' ).block
153
- message : null
154
- overlayCSS :
155
- 'opacity' : '0.2'
156
-
157
- recordId = $( this ).data( 'id' )
158
- action = $( this ).data( 'action' )
159
- data =
160
- action : 'wc_square_handle_sync_records'
161
- id : recordId
162
- handle : action
163
- security : wc_square_admin_settings.handle_sync_with_square_records
164
-
165
- $.post wc_square_admin_settings.ajax_url, data, ( response ) ->
166
- if response and response.success
167
-
168
- rowId = '#record-' + recordId
169
-
170
- if 'delete' is action
171
-
172
- $( rowId ).remove()
173
-
174
- if not $( 'table.records tbody tr' ).length
175
- $( 'table.records tbody' ).html( noRecordsFoundRow )
176
- $( '#wc-square_clear-sync-records').prop( 'disabled', true )
177
-
178
- else if 'resolve' is action or 'unsync' is action
179
-
180
- $( rowId + ' .type' ).html( '<mark class="resolved"><span>' + wc_square_admin_settings.i18n.resolved + '</span></mark>' )
181
- $( rowId + ' .actions' ).html( '&mdash;' )
182
-
183
- else
184
- if response and response.data
185
- alert( response.data )
186
- console.log( {
187
- record : recordId
188
- action : action
189
- response : response
190
- } )
191
-
192
- $( 'table.records' ).unblock()
193
-
194
-
195
- ###*
196
- # Returns a job sync status.
197
- #
198
- # @since 2.0.0
199
- #
200
- # @param {string} job_id
201
- ###
202
- getSyncStatus = ( job_id ) ->
203
-
204
- $progress = $( 'span.progress' )
205
-
206
- if not $progress or $progress.length is 0
207
- # note: the space below in the inserted string is intended
208
- $( 'p.sync-result' ).append( ' <span class="progress" style="display:block"></span>' )
209
- $progress = $( 'span.progress' )
210
-
211
- data =
212
- action : 'wc_square_get_sync_with_square_status'
213
- security : wc_square_admin_settings.get_sync_with_square_status_nonce
214
- job_id : job_id
215
-
216
- $.post wc_square_admin_settings.ajax_url, data, ( response ) ->
217
- if response and response.data
218
- if response.success and response.data.id
219
-
220
- # start the progress spinner
221
- $( 'table.sync .spinner' ).css( 'visibility', 'visible' )
222
- # disable interacting with records as more could be added during a sync process
223
- $( '#wc-square_clear-sync-records' ).prop( 'disabled', true )
224
- $( 'table.records .actions button' ).prop( 'disabled', true )
225
-
226
- # continue if the job is in progression
227
- if response.data.status not in [ 'completed', 'failed' ]
228
-
229
- progress = ' '
230
-
231
- # update progress info in table cell
232
- if 'product_import' is response.data.action
233
- progress += wc_square_admin_settings.i18n.skipped + ': ' + parseInt( response.data.skipped_products_count, 10 ) + '<br/>'
234
- progress += wc_square_admin_settings.i18n.imported + ': ' + parseInt( response.data.processed_products_count, 10 )
235
- else if response.data.percentage
236
- progress += parseInt( response.data.percentage, 10 ) + '%'
237
-
238
- $progress.html( progress )
239
-
240
- # recursion update loop until we're 'completed' (add a long timeout to avoid missing callback return output)
241
- return setTimeout( ->
242
- getSyncStatus( response.data.id )
243
- , 30 * 1000 )
244
-
245
- # reload page, display updated sync dates and any sync records messages
246
- else
247
- location.reload()
248
-
249
- else # unlikely job processing exception
250
- $( '#wc-square_clear-sync-records' ).prop( 'disabled', false )
251
- $( 'table.records .actions button' ).prop( 'disabled', false )
252
- $( 'table.sync .spinner' ).css( 'visibility', 'hidden' )
253
- console.log( response )
254
-
255
- # run once on page load
256
- if wc_square_admin_settings.existing_sync_job_id
257
- getSyncStatus( wc_square_admin_settings.existing_sync_job_id )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/js/admin/wc-square-admin-settings.min.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";(function(){jQuery(document).ready(function(e){var s,t,r,n;if(null!=(r=window.typenow)?r:"","woocommerce_page_wc-settings"===(null!=(n=window.pagenow)?n:""))return e("#wc_square_system_of_record").change(function(){var s,t,r;return r=e(this).val(),s=e("#wc_square_enable_inventory_sync"),t=s.closest("tr"),"square"===r||"woocommerce"===r?(s.next("span").html(wc_square_admin_settings.i18n.sync_inventory_label[r]),t.find(".description").html(wc_square_admin_settings.i18n.sync_inventory_description[r]),t.show()):t.hide(),"square"===r?e("#wc_square_hide_missing_products").closest("tr").show():e("#wc_square_hide_missing_products").closest("tr").hide()}).change(),e(".js-import-square-products").on("click",function(s){return s.preventDefault(),new e.WCBackboneModal.View({target:"wc-square-import-products"}),e("#btn-close").on("click",function(s){return s.preventDefault(),e("button.modal-close").trigger("click")}),e("#btn-ok").on("click",function(s){var t;return s.preventDefault(),e(this).unbind(),t={action:"wc_square_import_products_from_square",dispatch:wc_square_admin_settings.sync_in_background,security:wc_square_admin_settings.import_products_from_square},e.post(wc_square_admin_settings.ajax_url,t,function(e){var s;return s=e.data?e.data:null,e.success&&s?alert(s):!e.success&&s&&alert(s),location.reload()})})}),e("#wc-square-sync").on("click",function(s){return s.preventDefault(),new e.WCBackboneModal.View({target:"wc-square-sync"}),e("#btn-close").on("click",function(s){return s.preventDefault(),e("button.modal-close").trigger("click")}),e("#btn-ok").on("click",function(s){var t;return s.preventDefault(),e(this).unbind(),e("table.sync").block({message:null,overlayCSS:{opacity:"0.2"}}),e("table.records").block({message:null,overlayCSS:{opacity:"0.2"}}),e("#wc-square_clear-sync-records").prop("disabled",!0),t={action:"wc_square_sync_products_with_square",dispatch:wc_square_admin_settings.sync_in_background,security:wc_square_admin_settings.sync_products_with_square},e.post(wc_square_admin_settings.ajax_url,t,function(s){return s&&s.success?location.reload():(e("#wc-square_clear-sync-records").prop("disabled",!1),e("table.sync").unblock(),e("table.records").unblock(),console.log(s))})})}),t='<tr><td colspan="4"><em>'+wc_square_admin_settings.i18n.no_records_found+"</em></td></tr>",e("#wc-square_clear-sync-records").on("click",function(s){var r;return s.preventDefault(),e("table.records").block({message:null,overlayCSS:{opacity:"0.2"}}),r={action:"wc_square_handle_sync_records",id:"all",handle:"delete",security:wc_square_admin_settings.handle_sync_with_square_records},e.post(wc_square_admin_settings.ajax_url,r,function(s){return s&&s.success?(e("table.records tbody").html(t),e("#wc-square_clear-sync-records").prop("disabled",!0)):(s.data&&alert(s.data),console.log(s)),e("table.records").unblock()})}),e(".records .actions button.action").on("click",function(s){var r,n,a;return s.preventDefault(),e("table.records").block({message:null,overlayCSS:{opacity:"0.2"}}),a=e(this).data("id"),r=e(this).data("action"),n={action:"wc_square_handle_sync_records",id:a,handle:r,security:wc_square_admin_settings.handle_sync_with_square_records},e.post(wc_square_admin_settings.ajax_url,n,function(s){var n;return s&&s.success?(n="#record-"+a,"delete"===r?(e(n).remove(),e("table.records tbody tr").length||(e("table.records tbody").html(t),e("#wc-square_clear-sync-records").prop("disabled",!0))):"resolve"!==r&&"unsync"!==r||(e(n+" .type").html('<mark class="resolved"><span>'+wc_square_admin_settings.i18n.resolved+"</span></mark>"),e(n+" .actions").html("&mdash;"))):(s&&s.data&&alert(s.data),console.log({record:a,action:r,response:s})),e("table.records").unblock()})}),s=function(t){var r,n;return(r=e("span.progress"))&&0!==r.length||(e("p.sync-result").append(' <span class="progress" style="display:block"></span>'),r=e("span.progress")),n={action:"wc_square_get_sync_with_square_status",security:wc_square_admin_settings.get_sync_with_square_status_nonce,job_id:t},e.post(wc_square_admin_settings.ajax_url,n,function(t){var n,a;if(t&&t.data)return t.success&&t.data.id?(e("table.sync .spinner").css("visibility","visible"),e("#wc-square_clear-sync-records").prop("disabled",!0),e("table.records .actions button").prop("disabled",!0),"completed"!==(a=t.data.status)&&"failed"!==a?(n=" ","product_import"===t.data.action?(n+=wc_square_admin_settings.i18n.skipped+": "+parseInt(t.data.skipped_products_count,10)+"<br/>",n+=wc_square_admin_settings.i18n.imported+": "+parseInt(t.data.processed_products_count,10)):t.data.percentage&&(n+=parseInt(t.data.percentage,10)+"%"),r.html(n),setTimeout(function(){return s(t.data.id)},3e4)):location.reload()):(e("#wc-square_clear-sync-records").prop("disabled",!1),e("table.records .actions button").prop("disabled",!1),e("table.sync .spinner").css("visibility","hidden"),console.log(t))})},wc_square_admin_settings.existing_sync_job_id?s(wc_square_admin_settings.existing_sync_job_id):void 0})}).call(void 0);
2
- //# sourceMappingURL=wc-square-admin-settings.min.js.map
 
 
trunk/assets/js/admin/wc-square-admin-settings.min.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["wc-square-admin-settings.min.js"],"names":["jQuery","document","ready","$","_getSyncStatus","noRecordsFoundRow","ref","ref1","window","typenow","pagenow","change","$inventory_sync","$inventory_sync_row","system_of_record","this","val","closest","next","html","wc_square_admin_settings","i18n","sync_inventory_label","find","sync_inventory_description","show","hide","on","e","preventDefault","WCBackboneModal","View","target","trigger","data","unbind","action","dispatch","sync_in_background","security","import_products_from_square","post","ajax_url","response","message","success","alert","location","reload","block","overlayCSS","opacity","prop","sync_products_with_square","unblock","console","log","no_records_found","id","handle","handle_sync_with_square_records","recordId","rowId","remove","length","resolved","record","job_id","$progress","append","get_sync_with_square_status_nonce","progress","ref2","css","status","skipped","parseInt","skipped_products_count","imported","processed_products_count","percentage","setTimeout","existing_sync_job_id","call","undefined"],"mappings":"AAAA,cAEA,WAQEA,OAAOC,UAAUC,MAAM,SAAUC,GAQ/B,IAAIC,EAAgBC,EAA4BC,EAAKC,EAIrD,GAHoC,OAAzBD,EAAME,OAAOC,SAAmBH,EAAM,GAG7C,kCAFiC,OAA1BC,EAAOC,OAAOE,SAAmBH,EAAO,IAsOnD,OAhOAJ,EAAE,+BAA+BQ,OAAO,WACtC,IAAIC,EAAiBC,EAAqBC,EAa1C,OAZAA,EAAmBX,EAAEY,MAAMC,MAC3BJ,EAAkBT,EAAE,oCACpBU,EAAsBD,EAAgBK,QAAQ,MAErB,WAArBH,GAAsD,gBAArBA,GACnCF,EAAgBM,KAAK,QAAQC,KAAKC,yBAAyBC,KAAKC,qBAAqBR,IACrFD,EAAoBU,KAAK,gBAAgBJ,KAAKC,yBAAyBC,KAAKG,2BAA2BV,IACvGD,EAAoBY,QAEpBZ,EAAoBa,OAGlB,WAAaZ,EACRX,EAAE,oCAAoCc,QAAQ,MAAMQ,OAEpDtB,EAAE,oCAAoCc,QAAQ,MAAMS,SAE5Df,SACHR,EAAE,8BAA8BwB,GAAG,QAAS,SAAUC,GASpD,OARAA,EAAEC,iBACF,IAAI1B,EAAE2B,gBAAgBC,MACpBC,OAAQ,8BAEV7B,EAAE,cAAcwB,GAAG,QAAS,SAAUC,GAEpC,OADAA,EAAEC,iBACK1B,EAAE,sBAAsB8B,QAAQ,WAElC9B,EAAE,WAAWwB,GAAG,QAAS,SAAUC,GACxC,IAAIM,EAQJ,OAPAN,EAAEC,iBACF1B,EAAEY,MAAMoB,SACRD,GACEE,OAAQ,wCACRC,SAAUjB,yBAAyBkB,mBACnCC,SAAUnB,yBAAyBoB,6BAE9BrC,EAAEsC,KAAKrB,yBAAyBsB,SAAUR,EAAM,SAAUS,GAC/D,IAAIC,EAOJ,OANAA,EAAUD,EAAST,KAAOS,EAAST,KAAO,KACtCS,EAASE,SAAWD,EACtBE,MAAMF,IACID,EAASE,SAAWD,GAC9BE,MAAMF,GAEDG,SAASC,eAKtB7C,EAAE,mBAAmBwB,GAAG,QAAS,SAAUC,GAYzC,OAXAA,EAAEC,iBAEF,IAAI1B,EAAE2B,gBAAgBC,MACpBC,OAAQ,mBAGV7B,EAAE,cAAcwB,GAAG,QAAS,SAAUC,GAEpC,OADAA,EAAEC,iBACK1B,EAAE,sBAAsB8B,QAAQ,WAGlC9B,EAAE,WAAWwB,GAAG,QAAS,SAAUC,GACxC,IAAIM,EAqBJ,OApBAN,EAAEC,iBACF1B,EAAEY,MAAMoB,SACRhC,EAAE,cAAc8C,OACdL,QAAS,KACTM,YACEC,QAAW,SAGfhD,EAAE,iBAAiB8C,OACjBL,QAAS,KACTM,YACEC,QAAW,SAGfhD,EAAE,iCAAiCiD,KAAK,YAAY,GACpDlB,GACEE,OAAQ,sCACRC,SAAUjB,yBAAyBkB,mBACnCC,SAAUnB,yBAAyBiC,2BAE9BlD,EAAEsC,KAAKrB,yBAAyBsB,SAAUR,EAAM,SAAUS,GAC/D,OAAIA,GAAYA,EAASE,QAChBE,SAASC,UAEhB7C,EAAE,iCAAiCiD,KAAK,YAAY,GACpDjD,EAAE,cAAcmD,UAChBnD,EAAE,iBAAiBmD,UACZC,QAAQC,IAAIb,UAM3BtC,EAAoB,2BAA6Be,yBAAyBC,KAAKoC,iBAAmB,kBAElGtD,EAAE,iCAAiCwB,GAAG,QAAS,SAAUC,GACvD,IAAIM,EAcJ,OAbAN,EAAEC,iBACF1B,EAAE,iBAAiB8C,OACjBL,QAAS,KACTM,YACEC,QAAW,SAGfjB,GACEE,OAAQ,gCACRsB,GAAI,MACJC,OAAQ,SACRpB,SAAUnB,yBAAyBwC,iCAE9BzD,EAAEsC,KAAKrB,yBAAyBsB,SAAUR,EAAM,SAAUS,GAU/D,OATIA,GAAYA,EAASE,SACvB1C,EAAE,uBAAuBgB,KAAKd,GAC9BF,EAAE,iCAAiCiD,KAAK,YAAY,KAEhDT,EAAST,MACXY,MAAMH,EAAST,MAEjBqB,QAAQC,IAAIb,IAEPxC,EAAE,iBAAiBmD,cAI9BnD,EAAE,mCAAmCwB,GAAG,QAAS,SAAUC,GACzD,IAAIQ,EAAQF,EAAM2B,EAgBlB,OAfAjC,EAAEC,iBACF1B,EAAE,iBAAiB8C,OACjBL,QAAS,KACTM,YACEC,QAAW,SAGfU,EAAW1D,EAAEY,MAAMmB,KAAK,MACxBE,EAASjC,EAAEY,MAAMmB,KAAK,UACtBA,GACEE,OAAQ,gCACRsB,GAAIG,EACJF,OAAQvB,EACRG,SAAUnB,yBAAyBwC,iCAE9BzD,EAAEsC,KAAKrB,yBAAyBsB,SAAUR,EAAM,SAAUS,GAC/D,IAAImB,EAuBJ,OAtBInB,GAAYA,EAASE,SACvBiB,EAAQ,WAAaD,EACjB,WAAazB,GACfjC,EAAE2D,GAAOC,SACJ5D,EAAE,0BAA0B6D,SAC/B7D,EAAE,uBAAuBgB,KAAKd,GAC9BF,EAAE,iCAAiCiD,KAAK,YAAY,KAE7C,YAAchB,GAAU,WAAaA,IAC9CjC,EAAE2D,EAAQ,UAAU3C,KAAK,gCAAkCC,yBAAyBC,KAAK4C,SAAW,kBACpG9D,EAAE2D,EAAQ,aAAa3C,KAAK,cAG1BwB,GAAYA,EAAST,MACvBY,MAAMH,EAAST,MAEjBqB,QAAQC,KACNU,OAAQL,EACRzB,OAAQA,EACRO,SAAUA,KAGPxC,EAAE,iBAAiBmD,cAG9BlD,EAAiB,SAAuB+D,GACtC,IAAIC,EAAWlC,EAYf,OAXAkC,EAAYjE,EAAE,mBACyB,IAArBiE,EAAUJ,SAE1B7D,EAAE,iBAAiBkE,OAAO,yDAC1BD,EAAYjE,EAAE,kBAEhB+B,GACEE,OAAQ,wCACRG,SAAUnB,yBAAyBkD,kCACnCH,OAAQA,GAEHhE,EAAEsC,KAAKrB,yBAAyBsB,SAAUR,EAAM,SAAUS,GAC/D,IAAI4B,EAAUC,EACd,GAAI7B,GAAYA,EAAST,KACvB,OAAIS,EAASE,SAAWF,EAAST,KAAKwB,IAEpCvD,EAAE,uBAAuBsE,IAAI,aAAc,WAE3CtE,EAAE,iCAAiCiD,KAAK,YAAY,GACpDjD,EAAE,iCAAiCiD,KAAK,YAAY,GAEd,eAAjCoB,EAAO7B,EAAST,KAAKwC,SAAoC,WAATF,GACnDD,EAAW,IAEP,mBAAqB5B,EAAST,KAAKE,QACrCmC,GAAYnD,yBAAyBC,KAAKsD,QAAU,KAAOC,SAASjC,EAAST,KAAK2C,uBAAwB,IAAM,QAChHN,GAAYnD,yBAAyBC,KAAKyD,SAAW,KAAOF,SAASjC,EAAST,KAAK6C,yBAA0B,KACpGpC,EAAST,KAAK8C,aACvBT,GAAYK,SAASjC,EAAST,KAAK8C,WAAY,IAAM,KAEvDZ,EAAUjD,KAAKoD,GAERU,WAAW,WAChB,OAAO7E,EAAeuC,EAAST,KAAKwB,KACnC,MAGIX,SAASC,WAGlB7C,EAAE,iCAAiCiD,KAAK,YAAY,GACpDjD,EAAE,iCAAiCiD,KAAK,YAAY,GACpDjD,EAAE,uBAAuBsE,IAAI,aAAc,UACpClB,QAAQC,IAAIb,OAMvBvB,yBAAyB8D,qBACpB9E,EAAegB,yBAAyB8D,2BADjD,MAIDC,UAAKC","file":"wc-square-admin-settings.min.js"}
 
trunk/assets/js/frontend/wc-square.coffee DELETED
@@ -1,451 +0,0 @@
1
- ###*
2
- # WooCommerce Square Payment Form handler.
3
- #
4
- # @since 2.0.0
5
- ###
6
-
7
- jQuery( document ).ready ( $ ) ->
8
-
9
- "use strict"
10
-
11
- # Square Credit Card Payment Form Handler class.
12
- #
13
- # @since 2.0.0
14
- class window.WC_Square_Payment_Form_Handler
15
-
16
-
17
- # Setup handler
18
- #
19
- # @since 2.3.2-1
20
- constructor: ( args ) ->
21
-
22
- @id = args.id
23
- @id_dasherized = args.id_dasherized
24
- @csc_required = args.csc_required
25
- @enabled_card_types = args.enabled_card_types
26
- @square_card_types = args.square_card_types
27
-
28
- @logging_enabled = args.logging_enabled
29
- @general_error = args.general_error
30
- @ajax_url = args.ajax_url
31
- @ajax_log_nonce = args.ajax_log_nonce
32
- @input_styles = args.input_styles
33
- @application_id = args.application_id
34
-
35
- # which payment form?
36
- if $( 'form.checkout' ).length
37
- @form = $( 'form.checkout' )
38
- this.handle_checkout_page()
39
-
40
- else if $( 'form#order_review' ).length
41
- @form = $( 'form#order_review' )
42
- this.handle_pay_page()
43
-
44
- else if $( 'form#add_payment_method' ).length
45
- @form = $( 'form#add_payment_method' )
46
- this.handle_add_payment_method_page()
47
-
48
- else
49
- console.log( 'No payment form found!' )
50
- return
51
-
52
- # localized error messages
53
- @params = window[ "sv_wc_payment_gateway_payment_form_params" ]
54
-
55
- # unblock the UI and clear any payment nonces when a server-side error occurs
56
- $( document.body ).on( 'checkout_error', ->
57
- $( "input[name=wc-square-credit-card-payment-nonce]" ).val( '' )
58
- )
59
-
60
-
61
- $( document.body ).on( 'click', "#payment_method_#{@id}", ->
62
-
63
- if @payment_form
64
-
65
- this.log 'Recalculating payment form size'
66
- @payment_form.recalculateSize()
67
- )
68
-
69
-
70
- # Public: Handle required actions on the checkout page
71
- #
72
- # Returns nothing.
73
- handle_checkout_page: ->
74
-
75
- # updated payment fields jQuery object on each checkout update (prevents stale data)
76
- $( document.body ).on( 'updated_checkout', => this.set_payment_fields() )
77
-
78
- # handle saved payment methods
79
- # note on the checkout page, this is bound to `updated_checkout` so it
80
- # fires even when other parts of the checkout are changed
81
- $( document.body ).on( 'updated_checkout', => this.handle_saved_payment_methods() )
82
-
83
- # validate payment data before order is submitted
84
- @form.on( "checkout_place_order_#{ @id }", => this.validate_payment_data() )
85
-
86
-
87
- # Public: Handle associated actions for saved payment methods
88
- #
89
- # Returns nothing.
90
- handle_saved_payment_methods: ->
91
-
92
- # make available inside change events
93
- id_dasherized = @id_dasherized
94
-
95
- $new_payment_method_selection = $( "div.js-wc-#{ id_dasherized }-new-payment-method-form" )
96
-
97
- # show/hide the saved payment methods when a saved payment method is de-selected/selected
98
- $( "input.js-wc-#{ @id_dasherized }-payment-token" ).change ->
99
-
100
- tokenized_payment_method_selected = $( "input.js-wc-#{ id_dasherized }-payment-token:checked" ).val()
101
-
102
- if tokenized_payment_method_selected
103
-
104
- # using an existing tokenized payment method, hide the 'new method' fields
105
- $new_payment_method_selection.slideUp( 200 )
106
-
107
- else
108
- # use new payment method, display the 'new method' fields
109
- $new_payment_method_selection.slideDown( 200 )
110
-
111
- .change()
112
-
113
- # display the 'save payment method' option for guest checkouts if the 'create account' option is checked
114
- # but only hide the input if there is a 'create account' checkbox (some themes just display the password)
115
- $( 'input#createaccount' ).change ->
116
- $parent_row = $( "input.js-wc-#{ id_dasherized }-tokenize-payment-method" ).closest( 'p.form-row' )
117
-
118
- if $( this ).is( ':checked' )
119
- $parent_row.slideDown()
120
- $parent_row.next().show()
121
- else
122
- $parent_row.hide()
123
- $parent_row.next().hide()
124
-
125
- $( 'input#createaccount' ).change() unless $( 'input#createaccount' ).is( ':checked' )
126
-
127
-
128
- # Public: Handle required actions on the Order > Pay page
129
- #
130
- # Returns nothing.
131
- handle_pay_page: ->
132
-
133
- this.set_payment_fields()
134
-
135
- # handle saved payment methods
136
- this.handle_saved_payment_methods()
137
-
138
- # validate payment data before order is submitted
139
- @form.submit =>
140
-
141
- # but only when one of our payment gateways is selected
142
- return this.validate_payment_data() if $( '#order_review input[name=payment_method]:checked' ).val() is @id
143
-
144
-
145
- # Public: Handle required actions on the Add Payment Method page
146
- #
147
- # Returns nothing.
148
- handle_add_payment_method_page: ->
149
-
150
- this.set_payment_fields()
151
-
152
- # validate payment data before order is submitted
153
- @form.submit =>
154
-
155
- # but only when one of our payment gateways is selected
156
- return this.validate_payment_data() if $( '#add_payment_method input[name=payment_method]:checked' ).val() is @id
157
-
158
-
159
- # Sets up the Square payment fields
160
- #
161
- # @since 2.0.0
162
- set_payment_fields: =>
163
-
164
- if @payment_form
165
-
166
- this.log 'Destroying payment form'
167
-
168
- @payment_form.destroy()
169
-
170
- this.log 'Building payment form'
171
-
172
- @payment_form = new SqPaymentForm( this.get_form_params() )
173
-
174
- @payment_form.build()
175
-
176
-
177
- # Gets the Square payment form params.
178
- #
179
- # @since 2.0.0
180
- #
181
- # @return Object
182
- get_form_params: =>
183
-
184
- $card_number = $( "#wc-#{@id_dasherized}-account-number-hosted" )
185
- $expiration = $( "#wc-#{@id_dasherized}-expiry-hosted" )
186
- $csc = $( "#wc-#{@id_dasherized}-csc-hosted" )
187
- $postal_code = $( "#wc-#{@id_dasherized}-postal-code-hosted" )
188
-
189
- return {
190
- applicationId: @application_id
191
- cardNumber: {
192
- elementId: $card_number.attr( 'id' )
193
- placeholder: $card_number.data( 'placeholder' )
194
- }
195
- expirationDate: {
196
- elementId: $expiration.attr( 'id' )
197
- placeholder: $expiration.data( 'placeholder' )
198
- }
199
- cvv: {
200
- elementId: $csc.attr( 'id' )
201
- placeholder: $csc.data( 'placeholder' )
202
- }
203
- postalCode: {
204
- elementId: $postal_code.attr( 'id' )
205
- placeholder: $postal_code.data( 'placeholder' )
206
- }
207
- inputClass: "wc-#{@id_dasherized}-payment-field"
208
- inputStyles: @input_styles
209
- callbacks: {
210
- inputEventReceived: ( event ) => this.handle_input_event( event )
211
- cardNonceResponseReceived: ( errors, nonce, cardData ) => this.handle_response( errors, nonce, cardData )
212
- unsupportedBrowserDetected: => this.handle_unsupported_browser()
213
- paymentFormLoaded: => this.handle_form_loaded()
214
- }
215
- }
216
-
217
-
218
- # Handles when the payment form is fully loaded.
219
- #
220
- # @since 2.0.0
221
- handle_form_loaded: ->
222
-
223
- this.log 'Payment form loaded'
224
-
225
- @payment_form.setPostalCode( $( '#billing_postcode' ).val() )
226
-
227
- # hide the postcode field on the checkout page or if it already has a value
228
- if $( 'form.checkout' ).length or $( '#billing_postcode' ).val()
229
- $( ".wc-square-credit-card-card-postal-code-parent" ).addClass( 'hidden' )
230
-
231
-
232
- # Handles payment form input changes.
233
- #
234
- # @since 2.0.0
235
- handle_input_event: ( event ) =>
236
-
237
- $input = $( '#' + event.elementId )
238
-
239
- if event.eventType is 'cardBrandChanged'
240
- this.handle_card_brand_change( event.cardBrand, $input )
241
-
242
-
243
- # Handles card number brand changes.
244
- #
245
- # @since 2.0.0
246
- handle_card_brand_change: ( brand, $input ) ->
247
-
248
- this.log "Card brand changed to #{brand}"
249
-
250
- # clear any existing card type class
251
- $input.attr( 'class', (i, c) -> c.replace( /(^|\s)card-type-\S+/g, '' ) )
252
-
253
- card_class = 'plain'
254
-
255
- if not brand? or brand is 'unknown'
256
- brand = ''
257
-
258
- if @square_card_types[brand]?
259
- brand = @square_card_types[brand]
260
-
261
- if brand and brand not in @enabled_card_types
262
- card_class = 'invalid'
263
- else
264
- card_class = brand
265
-
266
- $( "input[name=wc-#{@id_dasherized}-card-type]" ).val( brand )
267
-
268
- $input.addClass( "card-type-#{card_class}" )
269
-
270
-
271
- # Used to request a card nonce and submit the form.
272
- #
273
- # @since 2.0.0
274
- validate_payment_data: ->
275
-
276
- # bail when already processing
277
- return false if @form.is( '.processing' )
278
-
279
- # let through if nonce is already present
280
- if this.has_nonce()
281
- this.log 'Payment nonce present, placing order'
282
- return true
283
-
284
- return true if $( ".payment_method_#{ @id }" ).find( '.js-wc-square-credit-card-payment-token:checked' ).val()
285
-
286
- this.log 'Requesting payment nonce'
287
-
288
- this.block_ui()
289
-
290
- @payment_form.requestCardNonce()
291
-
292
- return false
293
-
294
-
295
- # Handles the Square payment form response.
296
- #
297
- # @since 2.0.0
298
- #
299
- # @param Object[] errors validation errors, if any
300
- # @param String nonce payment nonce
301
- handle_response: ( errors, nonce, cardData ) ->
302
-
303
- # if we have real errors to display from Square
304
- if errors
305
- return this.handle_errors( errors )
306
-
307
- # no errors, but also no payment data
308
- if not nonce
309
-
310
- message = 'Nonce is missing from the Square response'
311
-
312
- this.log message, 'error'
313
- this.log_data message, 'response'
314
-
315
- return this.handle_errors()
316
-
317
- # if we made it this far, we have payment data
318
- this.log 'Card data received'
319
- console.log cardData
320
- this.log_data( cardData, 'response' )
321
-
322
- if cardData.last_4
323
- $( "input[name=wc-#{@id_dasherized}-last-four]" ).val( cardData.last_4 )
324
-
325
- if cardData.exp_month
326
- $( "input[name=wc-#{@id_dasherized}-exp-month]" ).val( cardData.exp_month )
327
-
328
- if cardData.exp_year
329
- $( "input[name=wc-#{@id_dasherized}-exp-year]" ).val( cardData.exp_year )
330
-
331
- if cardData.billing_postal_code
332
- $( "input[name=wc-square-credit-card-payment-postcode]" ).val( cardData.billing_postal_code )
333
-
334
- # payment nonce data
335
- $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val( nonce )
336
-
337
- # now that we have a nonce, resubmit the form
338
- @form.submit()
339
-
340
-
341
- # Handles unsupported browsers.
342
- #
343
- # @since 2.0.0
344
- handle_unsupported_browser: ->
345
-
346
-
347
- # Handle error data.
348
- #
349
- # @since 2.0.0
350
- # @param Object[]
351
- handle_errors: ( errors = null ) ->
352
-
353
- this.log 'Error getting payment data', 'error'
354
-
355
- messages = []
356
-
357
- if errors
358
-
359
- console.error errors
360
-
361
- $( errors ).each ( index, error ) =>
362
-
363
- # only display the errors that can be helped by the customer
364
- if error.type in [ 'UNSUPPORTED_CARD_BRAND', 'VALIDATION_ERROR' ]
365
-
366
- messages.push( error.message )
367
-
368
- # otherwise, log more serious errors to the debug log
369
- else
370
- this.log_data( errors, 'response' )
371
-
372
- # if no specific messages are set, display a general error
373
- if messages.length is 0
374
- messages.push( @general_error )
375
-
376
- this.render_errors( messages )
377
-
378
- this.unblock_ui()
379
-
380
-
381
- # Public: Render any new errors and bring them into the viewport
382
- #
383
- # Returns nothing.
384
- render_errors: (errors) ->
385
-
386
- # hide and remove any previous errors
387
- $( '.woocommerce-error, .woocommerce-message' ).remove()
388
-
389
- # add errors
390
- @form.prepend '<ul class="woocommerce-error"><li>' + errors.join( '</li><li>' ) + '</li></ul>'
391
-
392
- # unblock UI
393
- @form.removeClass( 'processing' ).unblock()
394
- @form.find( '.input-text, select' ).blur()
395
-
396
- # scroll to top
397
- $( 'html, body' ).animate( { scrollTop: @form.offset().top - 100 }, 1000 )
398
-
399
-
400
- # Blocks the payment form UI
401
- #
402
- # @since 3.0.0
403
- block_ui: -> @form.block( message: null, overlayCSS: background: '#fff',opacity: 0.6 )
404
-
405
-
406
- # Unblocks the payment form UI
407
- #
408
- # @since 3.0.0
409
- unblock_ui: -> @form.unblock()
410
-
411
-
412
- # Determines if a nonce is present in the hidden input.
413
- #
414
- # @since 2.0.0
415
- # @return Bool
416
- has_nonce: -> $( "input[name=wc-#{@id_dasherized}-payment-nonce]" ).val()
417
-
418
-
419
- # Logs data to the debug log via AJAX.
420
- #
421
- # @since 2.0.0
422
- #
423
- # @param Object data request data
424
- # @param String type data type
425
- log_data: ( data, type ) ->
426
-
427
- # if logging is disabled, bail
428
- return unless @logging_enabled
429
-
430
- ajax_data = {
431
- 'action' : 'wc_' + @id + '_log_js_data',
432
- 'security' : @ajax_log_nonce,
433
- 'type' : type,
434
- 'data' : data
435
- }
436
-
437
- $.ajax( url: @ajax_url, data: ajax_data )
438
-
439
-
440
- # Logs any messages or errors to the console.
441
- #
442
- # @since 2.0.0
443
- log: ( message, type = 'notice' ) ->
444
-
445
- # if logging is disabled, bail
446
- return unless @logging_enabled
447
-
448
- if type is 'error'
449
- console.error 'Square Error: ' + message
450
- else
451
- console.log 'Square: ' + message
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/assets/js/frontend/wc-square.min.js DELETED
@@ -1,2 +0,0 @@
1
- "use strict";function _classCallCheck(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}var _createClass=function(){function e(e,t){for(var n=0;n<t.length;n++){var a=t[n];a.enumerable=a.enumerable||!1,a.configurable=!0,"value"in a&&(a.writable=!0),Object.defineProperty(e,a.key,a)}}return function(t,n,a){return n&&e(t.prototype,n),a&&e(t,a),t}}();(function(){var e=[].indexOf;jQuery(document).ready(function(t){return window.WC_Square_Payment_Form_Handler=function(){function n(e){if(_classCallCheck(this,n),this.set_payment_fields=this.set_payment_fields.bind(this),this.get_form_params=this.get_form_params.bind(this),this.handle_input_event=this.handle_input_event.bind(this),this.id=e.id,this.id_dasherized=e.id_dasherized,this.csc_required=e.csc_required,this.enabled_card_types=e.enabled_card_types,this.square_card_types=e.square_card_types,this.logging_enabled=e.logging_enabled,this.general_error=e.general_error,this.ajax_url=e.ajax_url,this.ajax_log_nonce=e.ajax_log_nonce,this.input_styles=e.input_styles,this.application_id=e.application_id,t("form.checkout").length)this.form=t("form.checkout"),this.handle_checkout_page();else if(t("form#order_review").length)this.form=t("form#order_review"),this.handle_pay_page();else{if(!t("form#add_payment_method").length)return void console.log("No payment form found!");this.form=t("form#add_payment_method"),this.handle_add_payment_method_page()}this.params=window.sv_wc_payment_gateway_payment_form_params,t(document.body).on("checkout_error",function(){return t("input[name=wc-square-credit-card-payment-nonce]").val("")}),t(document.body).on("click","#payment_method_"+this.id,function(){if(this.payment_form)return this.log("Recalculating payment form size"),this.payment_form.recalculateSize()})}return _createClass(n,[{key:"handle_checkout_page",value:function(){var e=this;return t(document.body).on("updated_checkout",function(){return e.set_payment_fields()}),t(document.body).on("updated_checkout",function(){return e.handle_saved_payment_methods()}),this.form.on("checkout_place_order_"+this.id,function(){return e.validate_payment_data()})}},{key:"handle_saved_payment_methods",value:function(){var e,n;if(n=this.id_dasherized,e=t("div.js-wc-"+n+"-new-payment-method-form"),t("input.js-wc-"+this.id_dasherized+"-payment-token").change(function(){return t("input.js-wc-"+n+"-payment-token:checked").val()?e.slideUp(200):e.slideDown(200)}).change(),t("input#createaccount").change(function(){var e;return e=t("input.js-wc-"+n+"-tokenize-payment-method").closest("p.form-row"),t(this).is(":checked")?(e.slideDown(),e.next().show()):(e.hide(),e.next().hide())}),!t("input#createaccount").is(":checked"))return t("input#createaccount").change()}},{key:"handle_pay_page",value:function(){var e=this;return this.set_payment_fields(),this.handle_saved_payment_methods(),this.form.submit(function(){if(t("#order_review input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"handle_add_payment_method_page",value:function(){var e=this;return this.set_payment_fields(),this.form.submit(function(){if(t("#add_payment_method input[name=payment_method]:checked").val()===e.id)return e.validate_payment_data()})}},{key:"set_payment_fields",value:function(){return this.payment_form&&(this.log("Destroying payment form"),this.payment_form.destroy()),this.log("Building payment form"),this.payment_form=new SqPaymentForm(this.get_form_params()),this.payment_form.build()}},{key:"get_form_params",value:function(){var e,n,a,r,i=this;return e=t("#wc-"+this.id_dasherized+"-account-number-hosted"),a=t("#wc-"+this.id_dasherized+"-expiry-hosted"),n=t("#wc-"+this.id_dasherized+"-csc-hosted"),r=t("#wc-"+this.id_dasherized+"-postal-code-hosted"),{applicationId:this.application_id,cardNumber:{elementId:e.attr("id"),placeholder:e.data("placeholder")},expirationDate:{elementId:a.attr("id"),placeholder:a.data("placeholder")},cvv:{elementId:n.attr("id"),placeholder:n.data("placeholder")},postalCode:{elementId:r.attr("id"),placeholder:r.data("placeholder")},inputClass:"wc-"+this.id_dasherized+"-payment-field",inputStyles:this.input_styles,callbacks:{inputEventReceived:function(e){return i.handle_input_event(e)},cardNonceResponseReceived:function(e,t,n){return i.handle_response(e,t,n)},unsupportedBrowserDetected:function(){return i.handle_unsupported_browser()},paymentFormLoaded:function(){return i.handle_form_loaded()}}}}},{key:"handle_form_loaded",value:function(){if(this.log("Payment form loaded"),this.payment_form.setPostalCode(t("#billing_postcode").val()),t("form.checkout").length||t("#billing_postcode").val())return t(".wc-square-credit-card-card-postal-code-parent").addClass("hidden")}},{key:"handle_input_event",value:function(e){var n;if(n=t("#"+e.elementId),"cardBrandChanged"===e.eventType)return this.handle_card_brand_change(e.cardBrand,n)}},{key:"handle_card_brand_change",value:function(n,a){var r;return this.log("Card brand changed to "+n),a.attr("class",function(e,t){return t.replace(/(^|\s)card-type-\S+/g,"")}),r="plain",null!=n&&"unknown"!==n||(n=""),null!=this.square_card_types[n]&&(n=this.square_card_types[n]),r=n&&e.call(this.enabled_card_types,n)<0?"invalid":n,t("input[name=wc-"+this.id_dasherized+"-card-type]").val(n),a.addClass("card-type-"+r)}},{key:"validate_payment_data",value:function(){return!this.form.is(".processing")&&(this.has_nonce()?(this.log("Payment nonce present, placing order"),!0):!!t(".payment_method_"+this.id).find(".js-wc-square-credit-card-payment-token:checked").val()||(this.log("Requesting payment nonce"),this.block_ui(),this.payment_form.requestCardNonce(),!1))}},{key:"handle_response",value:function(e,n,a){var r;return e?this.handle_errors(e):n?(this.log("Card data received"),console.log(a),this.log_data(a,"response"),a.last_4&&t("input[name=wc-"+this.id_dasherized+"-last-four]").val(a.last_4),a.exp_month&&t("input[name=wc-"+this.id_dasherized+"-exp-month]").val(a.exp_month),a.exp_year&&t("input[name=wc-"+this.id_dasherized+"-exp-year]").val(a.exp_year),a.billing_postal_code&&t("input[name=wc-square-credit-card-payment-postcode]").val(a.billing_postal_code),t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val(n),this.form.submit()):(r="Nonce is missing from the Square response",this.log(r,"error"),this.log_data(r,"response"),this.handle_errors())}},{key:"handle_unsupported_browser",value:function(){}},{key:"handle_errors",value:function(){var e,n=this,a=arguments.length>0&&void 0!==arguments[0]?arguments[0]:null;return this.log("Error getting payment data","error"),e=[],a&&(console.error(a),t(a).each(function(t,r){var i;return"UNSUPPORTED_CARD_BRAND"===(i=r.type)||"VALIDATION_ERROR"===i?e.push(r.message):n.log_data(a,"response")})),0===e.length&&e.push(this.general_error),this.render_errors(e),this.unblock_ui()}},{key:"render_errors",value:function(e){return t(".woocommerce-error, .woocommerce-message").remove(),this.form.prepend('<ul class="woocommerce-error"><li>'+e.join("</li><li>")+"</li></ul>"),this.form.removeClass("processing").unblock(),this.form.find(".input-text, select").blur(),t("html, body").animate({scrollTop:this.form.offset().top-100},1e3)}},{key:"block_ui",value:function(){return this.form.block({message:null,overlayCSS:{background:"#fff",opacity:.6}})}},{key:"unblock_ui",value:function(){return this.form.unblock()}},{key:"has_nonce",value:function(){return t("input[name=wc-"+this.id_dasherized+"-payment-nonce]").val()}},{key:"log_data",value:function(e,n){var a;if(this.logging_enabled)return a={action:"wc_"+this.id+"_log_js_data",security:this.ajax_log_nonce,type:n,data:e},t.ajax({url:this.ajax_url,data:a})}},{key:"log",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:"notice";if(this.logging_enabled)return"error"===t?console.error("Square Error: "+e):console.log("Square: "+e)}}]),n}()})}).call(void 0);
2
- //# sourceMappingURL=wc-square.min.js.map
 
 
trunk/assets/js/frontend/wc-square.min.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"sources":["wc-square.min.js"],"names":["_classCallCheck","instance","Constructor","TypeError","_createClass","defineProperties","target","props","i","length","descriptor","enumerable","configurable","writable","Object","defineProperty","key","protoProps","staticProps","prototype","indexOf","jQuery","document","ready","$","window","WC_Square_Payment_Form_Handler","args","this","set_payment_fields","bind","get_form_params","handle_input_event","id","id_dasherized","csc_required","enabled_card_types","square_card_types","logging_enabled","general_error","ajax_url","ajax_log_nonce","input_styles","application_id","form","handle_checkout_page","handle_pay_page","console","log","handle_add_payment_method_page","params","body","on","val","payment_form","recalculateSize","value","_this","handle_saved_payment_methods","validate_payment_data","$new_payment_method_selection","change","slideUp","slideDown","$parent_row","closest","is","next","show","hide","_this2","submit","_this3","destroy","SqPaymentForm","build","$card_number","$csc","$expiration","$postal_code","_this4","applicationId","cardNumber","elementId","attr","placeholder","data","expirationDate","cvv","postalCode","inputClass","inputStyles","callbacks","inputEventReceived","event","cardNonceResponseReceived","errors","nonce","cardData","handle_response","unsupportedBrowserDetected","handle_unsupported_browser","paymentFormLoaded","handle_form_loaded","setPostalCode","addClass","$input","eventType","handle_card_brand_change","cardBrand","brand","card_class","c","replace","call","has_nonce","find","block_ui","requestCardNonce","message","handle_errors","log_data","last_4","exp_month","exp_year","billing_postal_code","messages","_this5","arguments","undefined","error","each","index","ref","type","push","render_errors","unblock_ui","remove","prepend","join","removeClass","unblock","blur","animate","scrollTop","offset","top","block","overlayCSS","background","opacity","ajax_data","action","security","ajax","url"],"mappings":"AAAA,aAIA,SAASA,gBAAgBC,EAAUC,GAAe,KAAMD,aAAoBC,GAAgB,MAAM,IAAIC,UAAU,qCAFhH,IAAIC,aAAe,WAAc,SAASC,EAAiBC,EAAQC,GAAS,IAAK,IAAIC,EAAI,EAAGA,EAAID,EAAME,OAAQD,IAAK,CAAE,IAAIE,EAAaH,EAAMC,GAAIE,EAAWC,WAAaD,EAAWC,aAAc,EAAOD,EAAWE,cAAe,EAAU,UAAWF,IAAYA,EAAWG,UAAW,GAAMC,OAAOC,eAAeT,EAAQI,EAAWM,IAAKN,IAAiB,OAAO,SAAUR,EAAae,EAAYC,GAAiJ,OAA9HD,GAAYZ,EAAiBH,EAAYiB,UAAWF,GAAiBC,GAAab,EAAiBH,EAAagB,GAAqBhB,GAA7gB,IAInB,WAME,IAAIkB,KAAaA,QAEjBC,OAAOC,UAAUC,MAAM,SAAUC,GAM/B,OAAOC,OAAOC,+BAAiC,WAI7C,SAASA,EAA+BC,GA6BtC,GA5BA3B,gBAAgB4B,KAAMF,GAKtBE,KAAKC,mBAAqBD,KAAKC,mBAAmBC,KAAKF,MAMvDA,KAAKG,gBAAkBH,KAAKG,gBAAgBD,KAAKF,MAIjDA,KAAKI,mBAAqBJ,KAAKI,mBAAmBF,KAAKF,MACvDA,KAAKK,GAAKN,EAAKM,GACfL,KAAKM,cAAgBP,EAAKO,cAC1BN,KAAKO,aAAeR,EAAKQ,aACzBP,KAAKQ,mBAAqBT,EAAKS,mBAC/BR,KAAKS,kBAAoBV,EAAKU,kBAC9BT,KAAKU,gBAAkBX,EAAKW,gBAC5BV,KAAKW,cAAgBZ,EAAKY,cAC1BX,KAAKY,SAAWb,EAAKa,SACrBZ,KAAKa,eAAiBd,EAAKc,eAC3Bb,KAAKc,aAAef,EAAKe,aACzBd,KAAKe,eAAiBhB,EAAKgB,eAEvBnB,EAAE,iBAAiBf,OACrBmB,KAAKgB,KAAOpB,EAAE,iBACdI,KAAKiB,4BACA,GAAIrB,EAAE,qBAAqBf,OAChCmB,KAAKgB,KAAOpB,EAAE,qBACdI,KAAKkB,sBACA,CAAA,IAAItB,EAAE,2BAA2Bf,OAKtC,YADAsC,QAAQC,IAAI,0BAHZpB,KAAKgB,KAAOpB,EAAE,2BACdI,KAAKqB,iCAMPrB,KAAKsB,OAASzB,OAAkD,0CAEhED,EAAEF,SAAS6B,MAAMC,GAAG,iBAAkB,WACpC,OAAO5B,EAAE,mDAAmD6B,IAAI,MAElE7B,EAAEF,SAAS6B,MAAMC,GAAG,QAAS,mBAAqBxB,KAAKK,GAAI,WACzD,GAAIL,KAAK0B,aAEP,OADA1B,KAAKoB,IAAI,mCACFpB,KAAK0B,aAAaC,oBAwb/B,OA9aAnD,aAAasB,IACXV,IAAK,uBACLwC,MAAO,WACL,IAAIC,EAAQ7B,KAaZ,OAVAJ,EAAEF,SAAS6B,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAM5B,uBAKfL,EAAEF,SAAS6B,MAAMC,GAAG,mBAAoB,WACtC,OAAOK,EAAMC,iCAGR9B,KAAKgB,KAAKQ,GAAG,wBAA0BxB,KAAKK,GAAI,WACrD,OAAOwB,EAAME,6BASjB3C,IAAK,+BACLwC,MAAO,WACL,IAAII,EAA+B1B,EA6BnC,GA3BAA,EAAgBN,KAAKM,cACrB0B,EAAgCpC,EAAE,aAAeU,EAAgB,4BAEjEV,EAAE,eAAiBI,KAAKM,cAAgB,kBAAkB2B,OAAO,WAG/D,OADoCrC,EAAE,eAAiBU,EAAgB,0BAA0BmB,MAGxFO,EAA8BE,QAAQ,KAGtCF,EAA8BG,UAAU,OAEhDF,SAGHrC,EAAE,uBAAuBqC,OAAO,WAC9B,IAAIG,EAEJ,OADAA,EAAcxC,EAAE,eAAiBU,EAAgB,4BAA4B+B,QAAQ,cACjFzC,EAAEI,MAAMsC,GAAG,aACbF,EAAYD,YACLC,EAAYG,OAAOC,SAE1BJ,EAAYK,OACLL,EAAYG,OAAOE,WAGzB7C,EAAE,uBAAuB0C,GAAG,YAC/B,OAAO1C,EAAE,uBAAuBqC,YASpC7C,IAAK,kBACLwC,MAAO,WACL,IAAIc,EAAS1C,KAMb,OAJAA,KAAKC,qBAELD,KAAK8B,+BAEE9B,KAAKgB,KAAK2B,OAAO,WACtB,GAAI/C,EAAE,oDAAoD6B,QAAUiB,EAAOrC,GAEzE,OAAOqC,EAAOX,6BAUpB3C,IAAK,iCACLwC,MAAO,WACL,IAAIgB,EAAS5C,KAIb,OAFAA,KAAKC,qBAEED,KAAKgB,KAAK2B,OAAO,WACtB,GAAI/C,EAAE,0DAA0D6B,QAAUmB,EAAOvC,GAE/E,OAAOuC,EAAOb,6BAKpB3C,IAAK,qBACLwC,MAAO,WAOL,OANI5B,KAAK0B,eACP1B,KAAKoB,IAAI,2BACTpB,KAAK0B,aAAamB,WAEpB7C,KAAKoB,IAAI,yBACTpB,KAAK0B,aAAe,IAAIoB,cAAc9C,KAAKG,mBACpCH,KAAK0B,aAAaqB,WAG3B3D,IAAK,kBACLwC,MAAO,WACL,IAEIoB,EAAcC,EAAMC,EAAaC,EAFjCC,EAASpD,KAOb,OAJAgD,EAAepD,EAAE,OAASI,KAAKM,cAAgB,0BAC/C4C,EAActD,EAAE,OAASI,KAAKM,cAAgB,kBAC9C2C,EAAOrD,EAAE,OAASI,KAAKM,cAAgB,eACvC6C,EAAevD,EAAE,OAASI,KAAKM,cAAgB,wBAE7C+C,cAAerD,KAAKe,eACpBuC,YACEC,UAAWP,EAAaQ,KAAK,MAC7BC,YAAaT,EAAaU,KAAK,gBAEjCC,gBACEJ,UAAWL,EAAYM,KAAK,MAC5BC,YAAaP,EAAYQ,KAAK,gBAEhCE,KACEL,UAAWN,EAAKO,KAAK,MACrBC,YAAaR,EAAKS,KAAK,gBAEzBG,YACEN,UAAWJ,EAAaK,KAAK,MAC7BC,YAAaN,EAAaO,KAAK,gBAEjCI,WAAY,MAAQ9D,KAAKM,cAAgB,iBACzCyD,YAAa/D,KAAKc,aAClBkD,WACEC,mBAAoB,SAA4BC,GAC9C,OAAOd,EAAOhD,mBAAmB8D,IAEnCC,0BAA2B,SAAmCC,EAAQC,EAAOC,GAC3E,OAAOlB,EAAOmB,gBAAgBH,EAAQC,EAAOC,IAE/CE,2BAA4B,WAC1B,OAAOpB,EAAOqB,8BAEhBC,kBAAmB,WACjB,OAAOtB,EAAOuB,2BAWtBvF,IAAK,qBACLwC,MAAO,WAIL,GAHA5B,KAAKoB,IAAI,uBACTpB,KAAK0B,aAAakD,cAAchF,EAAE,qBAAqB6B,OAEnD7B,EAAE,iBAAiBf,QAAUe,EAAE,qBAAqB6B,MACtD,OAAO7B,EAAE,kDAAkDiF,SAAS,aAIxEzF,IAAK,qBACLwC,MAAO,SAA4BsC,GACjC,IAAIY,EAEJ,GADAA,EAASlF,EAAE,IAAMsE,EAAMX,WACC,qBAApBW,EAAMa,UACR,OAAO/E,KAAKgF,yBAAyBd,EAAMe,UAAWH,MAS1D1F,IAAK,2BACLwC,MAAO,SAAkCsD,EAAOJ,GAC9C,IAAIK,EAmBJ,OAlBAnF,KAAKoB,IAAI,yBAA2B8D,GAEpCJ,EAAOtB,KAAK,QAAS,SAAU5E,EAAGwG,GAChC,OAAOA,EAAEC,QAAQ,uBAAwB,MAE3CF,EAAa,QACA,MAATD,GAA2B,YAAVA,IACnBA,EAAQ,IAE2B,MAAjClF,KAAKS,kBAAkByE,KACzBA,EAAQlF,KAAKS,kBAAkByE,IAG/BC,EADED,GAAS1F,EAAQ8F,KAAKtF,KAAKQ,mBAAoB0E,GAAS,EAC7C,UAEAA,EAEftF,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAIyD,GACtDJ,EAAOD,SAAS,aAAeM,MAQxC/F,IAAK,wBACLwC,MAAO,WACL,OAAI5B,KAAKgB,KAAKsB,GAAG,iBAKbtC,KAAKuF,aACPvF,KAAKoB,IAAI,yCACF,KAELxB,EAAE,mBAAqBI,KAAKK,IAAImF,KAAK,mDAAmD/D,QAG5FzB,KAAKoB,IAAI,4BACTpB,KAAKyF,WACLzF,KAAK0B,aAAagE,oBACX,OAWTtG,IAAK,kBACLwC,MAAO,SAAyBwC,EAAQC,EAAOC,GAC7C,IAAIqB,EAEJ,OAAIvB,EACKpE,KAAK4F,cAAcxB,GAGvBC,GAOLrE,KAAKoB,IAAI,sBACTD,QAAQC,IAAIkD,GACZtE,KAAK6F,SAASvB,EAAU,YACpBA,EAASwB,QACXlG,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAI6C,EAASwB,QAEpExB,EAASyB,WACXnG,EAAE,iBAAmBI,KAAKM,cAAgB,eAAemB,IAAI6C,EAASyB,WAEpEzB,EAAS0B,UACXpG,EAAE,iBAAmBI,KAAKM,cAAgB,cAAcmB,IAAI6C,EAAS0B,UAEnE1B,EAAS2B,qBACXrG,EAAE,sDAAsD6B,IAAI6C,EAAS2B,qBAGvErG,EAAE,iBAAmBI,KAAKM,cAAgB,mBAAmBmB,IAAI4C,GAE1DrE,KAAKgB,KAAK2B,WAxBfgD,EAAU,4CACV3F,KAAKoB,IAAIuE,EAAS,SAClB3F,KAAK6F,SAASF,EAAS,YAChB3F,KAAK4F,oBA6BhBxG,IAAK,6BACLwC,MAAO,eAQPxC,IAAK,gBACLwC,MAAO,WACL,IAIIsE,EAJAC,EAASnG,KAEToE,EAASgC,UAAUvH,OAAS,QAAsBwH,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,KAuBjF,OApBApG,KAAKoB,IAAI,6BAA8B,SACvC8E,KACI9B,IACFjD,QAAQmF,MAAMlC,GACdxE,EAAEwE,GAAQmC,KAAK,SAAUC,EAAOF,GAC9B,IAAIG,EAEJ,MAA2B,4BAAtBA,EAAMH,EAAMI,OAA8C,qBAARD,EAC9CP,EAASS,KAAKL,EAAMX,SAGpBQ,EAAON,SAASzB,EAAQ,eAKb,IAApB8B,EAASrH,QACXqH,EAASS,KAAK3G,KAAKW,eAErBX,KAAK4G,cAAcV,GACZlG,KAAK6G,gBAQdzH,IAAK,gBACLwC,MAAO,SAAuBwC,GAS5B,OAPAxE,EAAE,4CAA4CkH,SAE9C9G,KAAKgB,KAAK+F,QAAQ,qCAAuC3C,EAAO4C,KAAK,aAAe,cAEpFhH,KAAKgB,KAAKiG,YAAY,cAAcC,UACpClH,KAAKgB,KAAKwE,KAAK,uBAAuB2B,OAE/BvH,EAAE,cAAcwH,SACrBC,UAAWrH,KAAKgB,KAAKsG,SAASC,IAAM,KACnC,QAQLnI,IAAK,WACLwC,MAAO,WACL,OAAO5B,KAAKgB,KAAKwG,OACf7B,QAAS,KACT8B,YACEC,WAAY,OACZC,QAAS,SAUfvI,IAAK,aACLwC,MAAO,WACL,OAAO5B,KAAKgB,KAAKkG,aASnB9H,IAAK,YACLwC,MAAO,WACL,OAAOhC,EAAE,iBAAmBI,KAAKM,cAAgB,mBAAmBmB,SAWtErC,IAAK,WACLwC,MAAO,SAAkB8B,EAAMgD,GAC7B,IAAIkB,EAEJ,GAAK5H,KAAKU,gBASV,OANAkH,GACEC,OAAU,MAAQ7H,KAAKK,GAAK,eAC5ByH,SAAY9H,KAAKa,eACjB6F,KAAQA,EACRhD,KAAQA,GAEH9D,EAAEmI,MACPC,IAAKhI,KAAKY,SACV8C,KAAMkE,OASVxI,IAAK,MACLwC,MAAO,SAAa+D,GAClB,IAAIe,EAAON,UAAUvH,OAAS,QAAsBwH,IAAjBD,UAAU,GAAmBA,UAAU,GAAK,SAG/E,GAAKpG,KAAKU,gBAGV,MAAa,UAATgG,EACKvF,QAAQmF,MAAM,iBAAmBX,GAEjCxE,QAAQC,IAAI,WAAauE,OAK/B7F,EA/esC,OAkfhDwF,UAAKe","file":"wc-square.min.js"}
 
trunk/i18n/languages/woocommerce-square.pot DELETED
@@ -1,3215 +0,0 @@
1
- # Copyright (C) 2019 WooCommerce
2
- # This file is distributed under the GNU General Public License v3.0.
3
- msgid ""
4
- msgstr ""
5
- "Project-Id-Version: WooCommerce Square 2.0.8\n"
6
- "Report-Msgid-Bugs-To: "
7
- "https://github.com/woocommerce/woocommerce-square/issues\n"
8
- "POT-Creation-Date: 2019-12-09 08:50:47+00:00\n"
9
- "MIME-Version: 1.0\n"
10
- "Content-Type: text/plain; charset=utf-8\n"
11
- "Content-Transfer-Encoding: 8bit\n"
12
- "PO-Revision-Date: 2019-MO-DA HO:MI+ZONE\n"
13
- "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
- "Language-Team: LANGUAGE <EMAIL@ADDRESS>\n"
15
- "X-Generator: grunt-wp-i18n 1.0.3\n"
16
-
17
- #: includes/AJAX.php:109
18
- msgid "Please mark product as un-synced and save, then synced again."
19
- msgstr ""
20
-
21
- #: includes/AJAX.php:122
22
- #. translators: Placeholders: %1$s = error message, %2$s = help text
23
- msgid "Unable to fetch inventory: %1$s. %2$s"
24
- msgstr ""
25
-
26
- #: includes/AJAX.php:127
27
- #. translators: Placeholders: %s = help text
28
- msgid "Error finding item in Square. %s"
29
- msgstr ""
30
-
31
- #: includes/AJAX.php:145
32
- msgid "Could not start import. Please try again."
33
- msgstr ""
34
-
35
- #: includes/AJAX.php:148
36
- msgid ""
37
- "Your products are being imported in the background! This may take some time "
38
- "to complete."
39
- msgstr ""
40
-
41
- #: includes/AJAX.php:194
42
- msgid "Could not delete records."
43
- msgstr ""
44
-
45
- #: includes/AJAX.php:203
46
- msgid "Could not delete record."
47
- msgstr ""
48
-
49
- #: includes/AJAX.php:214
50
- msgid "Could not resolve record."
51
- msgstr ""
52
-
53
- #: includes/AJAX.php:227
54
- msgid "Could not unsync product."
55
- msgstr ""
56
-
57
- #: includes/AJAX.php:239
58
- #. translators: Placeholder: %s - error message
59
- msgid "An error occurred. %s"
60
- msgstr ""
61
-
62
- #: includes/AJAX.php:284
63
- #. translators: Placeholder: %s - sync job ID
64
- msgid "No sync job in progress found %s"
65
- msgstr ""
66
-
67
- #: includes/Admin/Privacy.php:46 includes/Admin/Settings_Page.php:55
68
- #: includes/Gateway.php:58 includes/Settings.php:183 includes/Settings.php:666
69
- msgid "Square"
70
- msgstr ""
71
-
72
- #: includes/Admin/Privacy.php:48
73
- msgid "WooCommerce Square Customer Data"
74
- msgstr ""
75
-
76
- #: includes/Admin/Privacy.php:62
77
- #. translators: Placeholder: %1$s - <a> tag, %2$s - </a> tag
78
- msgid ""
79
- "By using this extension, you may be storing personal data or sharing data "
80
- "with an external service. %1$sLearn more about how this works, including "
81
- "what you may want to include in your privacy policy.%2$s"
82
- msgstr ""
83
-
84
- #: includes/Admin/Privacy.php:93
85
- msgid "Square User Data Erased."
86
- msgstr ""
87
-
88
- #: includes/Admin/Settings_Page.php:145
89
- msgid "Settings"
90
- msgstr ""
91
-
92
- #: includes/Admin/Settings_Page.php:146 includes/Admin/Sync_Page.php:50
93
- msgid "Update"
94
- msgstr ""
95
-
96
- #: includes/Admin/Settings_Page.php:173
97
- msgid "Import Products From Square"
98
- msgstr ""
99
-
100
- #: includes/Admin/Settings_Page.php:175 includes/Admin/Sync_Page.php:334
101
- msgid "Close modal window"
102
- msgstr ""
103
-
104
- #: includes/Admin/Settings_Page.php:180
105
- #. translators: Placeholders: %1$s - <strong>, %2%s - </strong>
106
- msgid ""
107
- "You are about to import all products from Square. This will create a new "
108
- "product in WooCommerce for every product retrieved from Square. If you have "
109
- "products in the trash from the previous imports, these will be ignored in "
110
- "the import. %1$sOnly use this action to perform a one-time import!%2$s"
111
- msgstr ""
112
-
113
- #: includes/Admin/Settings_Page.php:184 includes/Admin/Sync_Page.php:366
114
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:133
115
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:66
116
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:227
117
- msgid "Cancel"
118
- msgstr ""
119
-
120
- #: includes/Admin/Settings_Page.php:185 includes/Settings.php:204
121
- msgid "Import Products"
122
- msgstr ""
123
-
124
- #: includes/Admin/Sync_Page.php:54
125
- msgid "Sync records"
126
- msgstr ""
127
-
128
- #: includes/Admin/Sync_Page.php:79
129
- #. translators: Placeholders: %1$s, %3$s - opening <strong> HTML tag, %2$s,
130
- #. $4%s - closing </strong> HTML tag
131
- msgid ""
132
- "%1$sSquare%2$s is the system of record. The following data from Square will "
133
- "overwrite WooCommerce data for synced products: %3$sname, price, "
134
- "description, category, inventory%4$s."
135
- msgstr ""
136
-
137
- #: includes/Admin/Sync_Page.php:88
138
- #. translators: Placeholders: %1$s - opening <strong> HTML tag, %2$s closing
139
- #. </strong> HTML tag
140
- msgid ""
141
- "%1$sProduct images%2$s will be imported from Square if no featured image is "
142
- "set in WooCommerce."
143
- msgstr ""
144
-
145
- #: includes/Admin/Sync_Page.php:100
146
- #. translators: Placeholders: %1$s, %3$s - opening <strong> HTML tag, %2$s,
147
- #. %4$s - closing </strong> HTML tag
148
- msgid ""
149
- "%1$sWooCommerce%2$s is the system of record. The following data from "
150
- "WooCommerce will overwrite Square data for synced products: %3$sname, "
151
- "price, inventory, category, image%4$s."
152
- msgstr ""
153
-
154
- #: includes/Admin/Sync_Page.php:112
155
- #. translators: Placeholders: %1$s - opening <strong> HTML tag, %2$s closing
156
- #. </strong> HTML tag
157
- msgid ""
158
- "%1$sNo chosen system of record.%2$s Products will not be synced between "
159
- "Square and WooCommerce."
160
- msgstr ""
161
-
162
- #: includes/Admin/Sync_Page.php:145
163
- msgid "Please connect to Square to enable product sync."
164
- msgstr ""
165
-
166
- #: includes/Admin/Sync_Page.php:147
167
- msgid "There are currently no products marked to be synced with Square."
168
- msgstr ""
169
-
170
- #: includes/Admin/Sync_Page.php:149
171
- msgid "A sync is currently in progress. Please try again later."
172
- msgstr ""
173
-
174
- #: includes/Admin/Sync_Page.php:154
175
- #. translators: Placeholder: %s - reason text
176
- msgid "Product sync between WooCommerce and Square is currently unavailable. %s"
177
- msgstr ""
178
-
179
- #: includes/Admin/Sync_Page.php:161
180
- msgid "Synced products"
181
- msgstr ""
182
-
183
- #: includes/Admin/Sync_Page.php:162
184
- msgid "Latest sync"
185
- msgstr ""
186
-
187
- #: includes/Admin/Sync_Page.php:163
188
- msgid "Next sync"
189
- msgstr ""
190
-
191
- #: includes/Admin/Sync_Page.php:164 includes/Admin/Sync_Page.php:270
192
- #: includes/Admin/Sync_Page.php:311
193
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:426
194
- msgid "Actions"
195
- msgstr ""
196
-
197
- #: includes/Admin/Sync_Page.php:173 includes/Emails/Sync_Completed.php:329
198
- #. translators: Placeholder: %d number of products synced with Square
199
- #. translators: Placeholder: %d products count
200
- msgid "%d product"
201
- msgid_plural "%d products"
202
- msgstr[0] ""
203
- msgstr[1] ""
204
-
205
- #: includes/Admin/Sync_Page.php:190
206
- msgid "Importing now&hellip;"
207
- msgstr ""
208
-
209
- #: includes/Admin/Sync_Page.php:192
210
- msgid "Syncing now&hellip;"
211
- msgstr ""
212
-
213
- #: includes/Admin/Sync_Page.php:207
214
- msgid "Not synced yet."
215
- msgstr ""
216
-
217
- #: includes/Admin/Sync_Page.php:239
218
- msgid "Sync now"
219
- msgstr ""
220
-
221
- #: includes/Admin/Sync_Page.php:268 includes/Admin/Sync_Page.php:309
222
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:97
223
- msgid "Status"
224
- msgstr ""
225
-
226
- #: includes/Admin/Sync_Page.php:269 includes/Admin/Sync_Page.php:310
227
- msgid "Message"
228
- msgstr ""
229
-
230
- #: includes/Admin/Sync_Page.php:300
231
- msgid "No records found."
232
- msgstr ""
233
-
234
- #: includes/Admin/Sync_Page.php:332
235
- msgid "Sync products with Square"
236
- msgstr ""
237
-
238
- #: includes/Admin/Sync_Page.php:342
239
- msgid ""
240
- "If a match is found in Square, product data in WooCommerce will be "
241
- "overwritten with Square data."
242
- msgstr ""
243
-
244
- #: includes/Admin/Sync_Page.php:344
245
- msgid ""
246
- "If a match is found in WooCommerce, product data in Square will be "
247
- "overwritten with WooCommerce data."
248
- msgstr ""
249
-
250
- #: includes/Admin/Sync_Page.php:348
251
- msgid ""
252
- "If a match is not found in Square, the product will be hidden from the "
253
- "catalog in WooCommerce."
254
- msgstr ""
255
-
256
- #: includes/Admin/Sync_Page.php:350
257
- msgid "If a match is not found in Square, the product will be skipped in the sync."
258
- msgstr ""
259
-
260
- #: includes/Admin/Sync_Page.php:353
261
- msgid "If a match is not found, a new product will be created in Square."
262
- msgstr ""
263
-
264
- #: includes/Admin/Sync_Page.php:359
265
- #. translators: Placeholders: %1$s - the system of record name (e.g. Square or
266
- #. WooCommerce), %3%s - unordered HTML list of additional information item(s)
267
- msgid ""
268
- "You are about to sync products with Square. %1$s is your system of record. "
269
- "For all products synced with Square: %2$s"
270
- msgstr ""
271
-
272
- #: includes/Admin/Sync_Page.php:367
273
- msgid "Start sync"
274
- msgstr ""
275
-
276
- #: includes/Admin.php:116 includes/Handlers/Products.php:176
277
- msgid "Synced with Square"
278
- msgstr ""
279
-
280
- #: includes/Admin.php:117
281
- msgid "Managed by Square"
282
- msgstr ""
283
-
284
- #: includes/Admin.php:118
285
- msgid "Fetch stock from Square"
286
- msgstr ""
287
-
288
- #: includes/Admin.php:150 includes/Sync/Records/Record.php:206
289
- msgid "Resolved"
290
- msgstr ""
291
-
292
- #: includes/Admin.php:151
293
- msgid "No records found"
294
- msgstr ""
295
-
296
- #: includes/Admin.php:152
297
- msgid "Skipped"
298
- msgstr ""
299
-
300
- #: includes/Admin.php:153
301
- msgid "Imported"
302
- msgstr ""
303
-
304
- #: includes/Admin.php:155
305
- msgid "Enable to fetch inventory changes from Square"
306
- msgstr ""
307
-
308
- #: includes/Admin.php:156
309
- msgid "Enable to push inventory changes to Square"
310
- msgstr ""
311
-
312
- #: includes/Admin.php:159 includes/Settings.php:193
313
- msgid "Inventory is fetched from Square periodically and updated in WooCommerce"
314
- msgstr ""
315
-
316
- #: includes/Admin.php:162
317
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag
318
- msgid ""
319
- "Inventory is %1$salways fetched from Square%2$s periodically to account for "
320
- "sales from other channels."
321
- msgstr ""
322
-
323
- #: includes/Emails/Sync_Completed.php:51
324
- msgid "Square sync completed"
325
- msgstr ""
326
-
327
- #: includes/Emails/Sync_Completed.php:52
328
- msgid ""
329
- "This email is sent once a manual sync has been completed between "
330
- "WooCommerce and Square"
331
- msgstr ""
332
-
333
- #: includes/Emails/Sync_Completed.php:93
334
- #. translators: Placeholder: %s - default email subject text
335
- msgid ""
336
- "This controls the email subject line. Leave blank to use the default "
337
- "subject: %s"
338
- msgstr ""
339
-
340
- #: includes/Emails/Sync_Completed.php:101
341
- msgid "Recipient(s)"
342
- msgstr ""
343
-
344
- #: includes/Emails/Sync_Completed.php:104
345
- #. translators: Placeholder: %s default email address
346
- msgid ""
347
- "Enter recipients (comma separated) for this email. Defaults to admin email: "
348
- "%s"
349
- msgstr ""
350
-
351
- #: includes/Emails/Sync_Completed.php:126
352
- msgid "Square sync failed"
353
- msgstr ""
354
-
355
- #: includes/Emails/Sync_Completed.php:209
356
- #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
357
- #. </a> HTML link tag
358
- msgid "%1$sInspect status logs%2$s"
359
- msgstr ""
360
-
361
- #: includes/Emails/Sync_Completed.php:215
362
- #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
363
- #. </a> HTML link tag
364
- msgid "%1$sEnable logging%2$s"
365
- msgstr ""
366
-
367
- #: includes/Emails/Sync_Completed.php:222
368
- #. translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing
369
- #. </a> HTML link tag, %3$s - additional action
370
- msgid "The sync job has failed. %1$sClick for more details%2$s, or %3$s."
371
- msgstr ""
372
-
373
- #: includes/Emails/Sync_Completed.php:230
374
- msgid "Inspect status logs"
375
- msgstr ""
376
-
377
- #: includes/Emails/Sync_Completed.php:232 includes/Settings.php:229
378
- msgid "Enable Logging"
379
- msgstr ""
380
-
381
- #: includes/Emails/Sync_Completed.php:237
382
- #. translators: Placeholders: %s - additional action
383
- msgid "The sync job has failed. Check sync records, or %s."
384
- msgstr ""
385
-
386
- #: includes/Gateway/API/Requests/Orders.php:82
387
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:555
388
- msgid "Discount"
389
- msgstr ""
390
-
391
- #: includes/Gateway/API/Requests/Orders.php:281
392
- #: includes/Gateway/API/Requests/Orders.php:319
393
- msgid "Adjustment"
394
- msgstr ""
395
-
396
- #: includes/Gateway/Payment_Form.php:95
397
- msgid "Postal code"
398
- msgstr ""
399
-
400
- #: includes/Gateway/Payment_Form.php:147 includes/Gateway.php:193
401
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:216
402
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2758
403
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:376
404
- msgid "An error occurred, please try again or try an alternate form of payment."
405
- msgstr ""
406
-
407
- #: includes/Gateway.php:59
408
- msgid "Allow customers to use Square to securely pay with their credit cards"
409
- msgstr ""
410
-
411
- #: includes/Gateway.php:379
412
- msgid "Refunds must be made within 120 days of the original payment date."
413
- msgstr ""
414
-
415
- #: includes/Gateway.php:404
416
- msgid ""
417
- "Could not find original transaction tender. Please refund this transaction "
418
- "from your Square dashboard."
419
- msgstr ""
420
-
421
- #: includes/Gateway.php:519
422
- msgid "Customer Profiles"
423
- msgstr ""
424
-
425
- #: includes/Handlers/Background_Job.php:340
426
- msgid "Clear Square Sync"
427
- msgstr ""
428
-
429
- #: includes/Handlers/Background_Job.php:341
430
- msgid "Clear"
431
- msgstr ""
432
-
433
- #: includes/Handlers/Background_Job.php:342
434
- msgid "This tool will clear any ongoing Square product syncs."
435
- msgstr ""
436
-
437
- #: includes/Handlers/Background_Job.php:361
438
- msgid "Success! You can now sync your products."
439
- msgstr ""
440
-
441
- #: includes/Handlers/Connection.php:103 includes/Handlers/Connection.php:168
442
- msgid "Sorry, you do not have permission to manage the Square connection."
443
- msgstr ""
444
-
445
- #: includes/Handlers/Connection.php:113
446
- msgid "Square Error: We could not connect to Square. No access token was given.!"
447
- msgstr ""
448
-
449
- #: includes/Handlers/Connection.php:176
450
- msgid "Disconnected successfully"
451
- msgstr ""
452
-
453
- #: includes/Handlers/Connection.php:382
454
- msgid "Connect with Square"
455
- msgstr ""
456
-
457
- #: includes/Handlers/Connection.php:402
458
- msgid "Disconnect from Square"
459
- msgstr ""
460
-
461
- #: includes/Handlers/Product.php:179
462
- #. translators: Placeholder: %s category ID
463
- msgid ""
464
- "Square category with id (%s) was not imported to your Store. Please run "
465
- "Import Products from Square settings."
466
- msgstr ""
467
-
468
- #: includes/Handlers/Product.php:344
469
- msgid "Product not synced with Square"
470
- msgstr ""
471
-
472
- #: includes/Handlers/Products.php:68
473
- #. translators: Placeholder: %s - product name
474
- msgid ""
475
- "Please add an SKU to sync %s with Square. The SKU must match the item's SKU "
476
- "in your Square account."
477
- msgstr ""
478
-
479
- #: includes/Handlers/Products.php:70
480
- #. translators: Placeholder: %s - product name
481
- msgid ""
482
- "Please add an SKU to every variation of %s for syncing with Square. Each "
483
- "SKU must match the corresponding item's SKU in your Square account."
484
- msgstr ""
485
-
486
- #: includes/Handlers/Products.php:72
487
- #. translators: Placeholder: %s - product name
488
- msgid "%s has multiple variation attributes and cannot be synced with Square."
489
- msgstr ""
490
-
491
- #: includes/Handlers/Products.php:249
492
- msgid "Update product data with Square data"
493
- msgstr ""
494
-
495
- #: includes/Handlers/Products.php:249
496
- msgid "Send product data to Square"
497
- msgstr ""
498
-
499
- #: includes/Handlers/Products.php:253
500
- msgid "Sync with Square"
501
- msgstr ""
502
-
503
- #: includes/Handlers/Products.php:288
504
- msgid "Sync with Square?"
505
- msgstr ""
506
-
507
- #: includes/Handlers/Products.php:292
508
- msgid "No change"
509
- msgstr ""
510
-
511
- #: includes/Handlers/Products.php:294
512
- msgid "No"
513
- msgstr ""
514
-
515
- #: includes/Handlers/Products.php:295
516
- msgid "Yes"
517
- msgstr ""
518
-
519
- #: includes/Handlers/Products.php:301
520
- msgid "This product"
521
- msgstr ""
522
-
523
- #: includes/Handlers/Products.php:655
524
- #. translators: Placeholder: %1$s - date (localized), %2$s - time (localized),
525
- #. %3$s - opening <a> HTML link tag, %4$s closing </a> HTML link tag
526
- msgid ""
527
- "The product catalog visibility has been set to \"hidden\", as a matching "
528
- "product could not be found in Square on %1$s at %2$s. %3$sCheck sync "
529
- "records%4$s."
530
- msgstr ""
531
-
532
- #: includes/Handlers/Sync.php:318
533
- #. translators: Placeholder: %d number of products processed
534
- msgid "Updated data for %d product."
535
- msgid_plural "Updated data for %d products."
536
- msgstr[0] ""
537
- msgstr[1] ""
538
-
539
- #: includes/Plugin.php:273
540
- msgid ""
541
- "Heads up! There may be a problem with your connection to Square. In order "
542
- "to continue accepting payments, please %1$sdisconnect and re-connect your "
543
- "site%2$s."
544
- msgstr ""
545
-
546
- #: includes/Plugin.php:285
547
- msgid "You are connected to Square!"
548
- msgstr ""
549
-
550
- #: includes/Plugin.php:292
551
- msgid "To get started, set your business location."
552
- msgstr ""
553
-
554
- #: includes/Plugin.php:298
555
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
556
- msgid "Visit the %1$splugin settings%2$s to set your business location."
557
- msgstr ""
558
-
559
- #: includes/Plugin.php:307
560
- msgid "You are ready to sync products!"
561
- msgstr ""
562
-
563
- #: includes/Plugin.php:313
564
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - product count, %3$s -
565
- #. </strong> tag, %4$s - <a> tag, %5$s - </a> tag
566
- msgid ""
567
- "%1$s%2$d products%3$s are marked \"sync with Square\". %4$sStart a new sync "
568
- "now &raquo;%5$s"
569
- msgstr ""
570
-
571
- #: includes/Plugin.php:322
572
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
573
- #. <a> tag, %4$s - </a> tag
574
- msgid ""
575
- "%1$sNo products%2$s are marked \"sync with Square\". %3$sUpdate your "
576
- "products to sync data &raquo;%4$s"
577
- msgstr ""
578
-
579
- #: includes/Plugin.php:335
580
- msgid ""
581
- "Heads up! Square is configured to sync product inventory, but WooCommerce "
582
- "stock management is disabled. Please %1$senable stock management%2$s to "
583
- "ensure product inventory counts are kept in sync."
584
- msgstr ""
585
-
586
- #: includes/Plugin.php:348
587
- msgid "To get started, connect with Square."
588
- msgstr ""
589
-
590
- #: includes/Plugin.php:354
591
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
592
- msgid "To get started, %1$sconnect with Square &raquo;%2$s"
593
- msgstr ""
594
-
595
- #: includes/Plugin.php:361
596
- #. translators: Placeholders: %1$s - plugin name
597
- msgid "Thanks for installing %1$s!"
598
- msgstr ""
599
-
600
- #: includes/Plugin.php:385
601
- #. translators: Placeholders: %1$s - plugin name, %2$ - plugin version number,
602
- #. %3$s - opening <a> HTML link tag, %4$s - closing </a> HTML link tag, %5$s -
603
- #. opening <a> HTML link tag, %6$s - closing </a> HTML link tag
604
- msgid ""
605
- "%1$s has been updated to version %2$s. In order to continue syncing product "
606
- "inventory, please make sure to disconnect and reconnect with Square from "
607
- "the %3$splugin settings%4$s and re-sync your products. Read more in the "
608
- "%5$supdated documentation%6$s."
609
- msgstr ""
610
-
611
- #: includes/Plugin.php:419
612
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
613
- #. 2-character country code, %4$s - comma separated list of 2-character country
614
- #. codes
615
- msgid ""
616
- "%1$sWooCommerce Square:%2$s Your base country is %3$s, but Square can’t "
617
- "accept transactions from merchants outside of %4$s."
618
- msgstr ""
619
-
620
- #: includes/Plugin.php:441
621
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
622
- #. <a> tag, %4$s - </a> tag
623
- msgid ""
624
- "%1$sWooCommerce Square:%2$s It looks like your site does not support "
625
- "background processing, which means large numbers of products may not sync "
626
- "successfully with Square. %3$sRead more here%4$s on how to resolve this."
627
- msgstr ""
628
-
629
- #: includes/Plugin.php:479
630
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
631
- #. <a> tag, %4$s - </a> tag
632
- msgid ""
633
- "%1$sWooCommerce Square:%2$s Automatic refreshing of the connection to "
634
- "Square is inactive. Please disconnect and reconnect to resolve."
635
- msgstr ""
636
-
637
- #: includes/Plugin.php:510
638
- msgid ""
639
- "%1$sWooCommerce Square:%2$s Product prices are entered inclusive of tax, "
640
- "but Square does not support syncing tax-inclusive prices. Please make sure "
641
- "your Square tax rates match your WooCommerce tax rates."
642
- msgstr ""
643
-
644
- #: includes/Plugin.php:536
645
- msgid ""
646
- "Heads up! Your store currency is %1$s but your configured Square business "
647
- "location currency is %2$s, so payments cannot be processed. Please "
648
- "%3$schoose a different business location%4$s or change your %5$sshop "
649
- "currency%6$s."
650
- msgstr ""
651
-
652
- #. Plugin Name of the plugin/theme
653
- msgid "WooCommerce Square"
654
- msgstr ""
655
-
656
- #: includes/Settings.php:117
657
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
658
- msgid ""
659
- "Sync your products and inventory and also accept credit and debit card "
660
- "payments at checkout. %1$sClick here%2$s to configure payments."
661
- msgstr ""
662
-
663
- #: includes/Settings.php:123
664
- msgid ""
665
- "Connect with Square to start syncing your products and inventory and also "
666
- "accept credit and debit card payments at checkout."
667
- msgstr ""
668
-
669
- #: includes/Settings.php:136
670
- msgid "Sandbox settings"
671
- msgstr ""
672
-
673
- #: includes/Settings.php:139
674
- #. translators: Placeholders: %1$s - URL
675
- msgid "Sandbox details can be created at: %s"
676
- msgstr ""
677
-
678
- #: includes/Settings.php:145
679
- msgid "Sandbox Application ID"
680
- msgstr ""
681
-
682
- #: includes/Settings.php:146
683
- msgid ""
684
- "Application ID for the Sandbox Application, see the details in the My "
685
- "Applications section."
686
- msgstr ""
687
-
688
- #: includes/Settings.php:150
689
- msgid "Sandbox Access Token"
690
- msgstr ""
691
-
692
- #: includes/Settings.php:151
693
- msgid ""
694
- "Access Token for the Sandbox Test Account, see the details in the Sandbox "
695
- "Test Account section. Make sure you use the correct Sandbox Access Token "
696
- "for your application. For a given Sandbox Test Account, each Authorized "
697
- "Application is assigned a different Access Token."
698
- msgstr ""
699
-
700
- #: includes/Settings.php:159
701
- msgid "Business location"
702
- msgstr ""
703
-
704
- #: includes/Settings.php:164
705
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
706
- #. <a> tag, %4$s - </a> tag
707
- msgid ""
708
- "Select a location to link to this site. Only %1$sactive%2$s "
709
- "%3$slocations%4$s that support credit card processing in Square can be "
710
- "linked."
711
- msgstr ""
712
-
713
- #: includes/Settings.php:172
714
- msgid "Product system of record"
715
- msgstr ""
716
-
717
- #: includes/Settings.php:177
718
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s -
719
- #. <a> tag, %4$s - </a> tag
720
- msgid ""
721
- "Choose where you will update data for synced products. Inventory in Square "
722
- "is %1$salways%2$s checked for adjustments when sync is enabled. %3$sClick "
723
- "here%4$s to read more about choosing a system of record."
724
- msgstr ""
725
-
726
- #: includes/Settings.php:182
727
- msgid "Do not sync product data"
728
- msgstr ""
729
-
730
- #. Author of the plugin/theme
731
- msgid "WooCommerce"
732
- msgstr ""
733
-
734
- #: includes/Settings.php:190
735
- msgid "Sync inventory"
736
- msgstr ""
737
-
738
- #: includes/Settings.php:191
739
- msgid "Enable to sync product inventory with Square"
740
- msgstr ""
741
-
742
- #: includes/Settings.php:197
743
- msgid "Handle missing products"
744
- msgstr ""
745
-
746
- #: includes/Settings.php:198
747
- msgid "Hide synced products when not found in Square"
748
- msgstr ""
749
-
750
- #: includes/Settings.php:200
751
- msgid ""
752
- "Products not found in Square will be hidden in the WooCommerce product "
753
- "catalog."
754
- msgstr ""
755
-
756
- #: includes/Settings.php:206
757
- msgid ""
758
- "Run an import to create new products in this WooCommerce store for each new "
759
- "product created in Square that has a unique SKU not existing in here. Needs "
760
- "to be run each time new items are created in Square."
761
- msgstr ""
762
-
763
- #: includes/Settings.php:216
764
- msgid "Connection"
765
- msgstr ""
766
-
767
- #: includes/Settings.php:233
768
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
769
- msgid "Log debug messages to the %1$sWooCommerce status log%2$s"
770
- msgstr ""
771
-
772
- #: includes/Settings.php:260
773
- msgid "Please choose a location"
774
- msgstr ""
775
-
776
- #: includes/Settings.php:290
777
- msgid "Import all products from Square"
778
- msgstr ""
779
-
780
- #: includes/Sync/Interval_Polling.php:96
781
- msgid "Updated data for %d category."
782
- msgid_plural "Updated data for %d categories."
783
- msgstr[0] ""
784
- msgstr[1] ""
785
-
786
- #: includes/Sync/Manual_Synchronization.php:1086
787
- #. translators: Placeholder: %s - product ID
788
- msgid "Product %s could not be updated in Square."
789
- msgstr ""
790
-
791
- #: includes/Sync/Product_Import.php:264
792
- msgid "You do not have permission to create products"
793
- msgstr ""
794
-
795
- #: includes/Sync/Product_Import.php:269
796
- msgid "Invalid data"
797
- msgstr ""
798
-
799
- #: includes/Sync/Product_Import.php:287
800
- msgid "Missing parameter %s"
801
- msgstr ""
802
-
803
- #: includes/Sync/Product_Import.php:302
804
- msgid "Invalid product type - the product type must be any of these: %s"
805
- msgstr ""
806
-
807
- #: includes/Sync/Product_Import.php:365
808
- #. translators: Placeholders: %1$s - Square item name, %2$s - failure reason
809
- msgid "Could not import \"%1$s\" from Square. %2$s"
810
- msgstr ""
811
-
812
- #: includes/Sync/Product_Import.php:375
813
- #. translators: Placeholders: %s - failure reason
814
- msgid "Could not import item from Square. %s"
815
- msgstr ""
816
-
817
- #: includes/Sync/Product_Import.php:453
818
- #. translators: Placeholders: %1$s - Square item name, %2$s - Square item
819
- #. variation name, %3$s - failure reason
820
- msgid "Could not import \"%1$s - %2$s\" from Square. %3$s"
821
- msgstr ""
822
-
823
- #: includes/Sync/Product_Import.php:504
824
- msgid "Items with variable pricing cannot be imported."
825
- msgstr ""
826
-
827
- #: includes/Sync/Product_Import.php:602 includes/Sync/Product_Import.php:866
828
- msgid "The SKU already exists on another product"
829
- msgstr ""
830
-
831
- #: includes/Sync/Product_Import.php:790
832
- msgid "Variation #%1$s of %2$s"
833
- msgstr ""
834
-
835
- #: includes/Sync/Records/Record.php:203
836
- msgid "Info"
837
- msgstr ""
838
-
839
- #: includes/Sync/Records/Record.php:204
840
- msgid "Notice"
841
- msgstr ""
842
-
843
- #: includes/Sync/Records/Record.php:205
844
- msgid "Alert"
845
- msgstr ""
846
-
847
- #: includes/Sync/Records/Record.php:371
848
- #. translators: Placeholder: %s - product name
849
- msgid "%s not found in Square."
850
- msgstr ""
851
-
852
- #: includes/Sync/Records/Record.php:542
853
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:92
854
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:819
855
- msgid "Delete"
856
- msgstr ""
857
-
858
- #: includes/Sync/Records/Record.php:550
859
- msgid "Ignore"
860
- msgstr ""
861
-
862
- #: includes/Sync/Records/Record.php:559
863
- msgid "Unlink"
864
- msgstr ""
865
-
866
- #: includes/Utilities/Encryption_Utility.php:56
867
- msgid "Encryption is not supported on this site."
868
- msgstr ""
869
-
870
- #: includes/Utilities/Encryption_Utility.php:74
871
- msgid "%1$s encryption is not available on this site. %2$s will be used instead."
872
- msgstr ""
873
-
874
- #: includes/Utilities/Encryption_Utility.php:99
875
- msgid "No encryption method available"
876
- msgstr ""
877
-
878
- #: includes/Utilities/Encryption_Utility.php:103
879
- msgid "Data must be a non-empty string or array"
880
- msgstr ""
881
-
882
- #: includes/Utilities/Encryption_Utility.php:107
883
- #: includes/Utilities/Encryption_Utility.php:150
884
- msgid "Encryption key must be a string"
885
- msgstr ""
886
-
887
- #: includes/Utilities/Encryption_Utility.php:119
888
- msgid "Could not generate encryption vector."
889
- msgstr ""
890
-
891
- #: includes/Utilities/Encryption_Utility.php:142
892
- msgid "No decryption method available"
893
- msgstr ""
894
-
895
- #: includes/Utilities/Encryption_Utility.php:146
896
- msgid "Data must be a non-empty string"
897
- msgstr ""
898
-
899
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_AdminView.php:48
900
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_AdminView.php:63
901
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_AdminView.php:64
902
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:89
903
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:19
904
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:30
905
- msgid "Scheduled Actions"
906
- msgstr ""
907
-
908
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_InvalidActionException.php:22
909
- msgid "Action [%s] has invalid arguments. It cannot be JSON decoded to an array."
910
- msgstr ""
911
-
912
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:96
913
- msgid "Hook"
914
- msgstr ""
915
-
916
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:98
917
- msgid "Arguments"
918
- msgstr ""
919
-
920
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:99
921
- msgid "Group"
922
- msgstr ""
923
-
924
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:100
925
- msgid "Recurrence"
926
- msgstr ""
927
-
928
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:101
929
- msgid "Scheduled Date"
930
- msgstr ""
931
-
932
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:102
933
- msgid "Log"
934
- msgstr ""
935
-
936
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:122
937
- msgid "Claim ID"
938
- msgstr ""
939
-
940
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:129
941
- msgid "Run"
942
- msgstr ""
943
-
944
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:130
945
- msgid "Process the action now as if it were run as part of a queue"
946
- msgstr ""
947
-
948
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:134
949
- msgid "Cancel the action now to avoid it being run in future"
950
- msgstr ""
951
-
952
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:143
953
- msgid "%s year"
954
- msgid_plural "%s years"
955
- msgstr[0] ""
956
- msgstr[1] ""
957
-
958
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:147
959
- msgid "%s month"
960
- msgid_plural "%s months"
961
- msgstr[0] ""
962
- msgstr[1] ""
963
-
964
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:151
965
- msgid "%s week"
966
- msgid_plural "%s weeks"
967
- msgstr[0] ""
968
- msgstr[1] ""
969
-
970
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:155
971
- msgid "%s day"
972
- msgid_plural "%s days"
973
- msgstr[0] ""
974
- msgstr[1] ""
975
-
976
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:159
977
- msgid "%s hour"
978
- msgid_plural "%s hours"
979
- msgstr[0] ""
980
- msgstr[1] ""
981
-
982
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:163
983
- msgid "%s minute"
984
- msgid_plural "%s minutes"
985
- msgstr[0] ""
986
- msgstr[1] ""
987
-
988
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:167
989
- msgid "%s second"
990
- msgid_plural "%s seconds"
991
- msgstr[0] ""
992
- msgstr[1] ""
993
-
994
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:194
995
- msgid "Now!"
996
- msgstr ""
997
-
998
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:227
999
- msgid "Every %s"
1000
- msgstr ""
1001
-
1002
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:231
1003
- msgid "Cron %s"
1004
- msgstr ""
1005
-
1006
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:235
1007
- msgid "Non-repeating"
1008
- msgstr ""
1009
-
1010
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:321
1011
- msgid ""
1012
- "Maximum simultaneous batches already in progress (%s queues). No actions "
1013
- "will be processed until the current batches are complete."
1014
- msgstr ""
1015
-
1016
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:336
1017
- msgid "Successfully executed action: %s"
1018
- msgstr ""
1019
-
1020
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:339
1021
- msgid "Successfully canceled action: %s"
1022
- msgstr ""
1023
-
1024
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:342
1025
- msgid "Successfully processed change for action: %s"
1026
- msgstr ""
1027
-
1028
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:347
1029
- msgid "Could not process change for action: \"%s\" (ID: %d). Error: %s"
1030
- msgstr ""
1031
-
1032
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:392
1033
- msgid " (%s ago)"
1034
- msgstr ""
1035
-
1036
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:394
1037
- msgid " (%s)"
1038
- msgstr ""
1039
-
1040
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php:531
1041
- msgid "Search hook, args and claim ID"
1042
- msgstr ""
1043
-
1044
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:61
1045
- msgid "action created"
1046
- msgstr ""
1047
-
1048
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:65
1049
- msgid "action canceled"
1050
- msgstr ""
1051
-
1052
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:69
1053
- msgid "action started"
1054
- msgstr ""
1055
-
1056
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:73
1057
- msgid "action complete"
1058
- msgstr ""
1059
-
1060
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:77
1061
- msgid "action failed: %s"
1062
- msgstr ""
1063
-
1064
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:81
1065
- msgid "action timed out after %s seconds"
1066
- msgstr ""
1067
-
1068
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:86
1069
- msgid "unexpected shutdown: PHP Fatal error %s in %s on line %s"
1070
- msgstr ""
1071
-
1072
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:91
1073
- msgid "action reset"
1074
- msgstr ""
1075
-
1076
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php:95
1077
- msgid "action ignored"
1078
- msgstr ""
1079
-
1080
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_QueueRunner.php:110
1081
- msgid "Every minute"
1082
- msgstr ""
1083
-
1084
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:152
1085
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:169
1086
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:268
1087
- msgid "Invalid schedule. Cannot save action."
1088
- msgstr ""
1089
-
1090
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:181
1091
- msgid "Complete"
1092
- msgstr ""
1093
-
1094
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:182
1095
- msgid "Pending"
1096
- msgstr ""
1097
-
1098
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:183
1099
- msgid "In-progress"
1100
- msgstr ""
1101
-
1102
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:184
1103
- msgid "Failed"
1104
- msgstr ""
1105
-
1106
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php:185
1107
- msgid "Canceled"
1108
- msgstr ""
1109
-
1110
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:31
1111
- #. translators: %s php class name
1112
- msgid "The %s class can only be run within WP CLI."
1113
- msgstr ""
1114
-
1115
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:59
1116
- msgid "There are too many concurrent batches, but the run is forced to continue."
1117
- msgstr ""
1118
-
1119
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:61
1120
- msgid "There are too many concurrent batches."
1121
- msgstr ""
1122
-
1123
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:92
1124
- msgid "Running %d action"
1125
- msgid_plural "Running %d actions"
1126
- msgstr[0] ""
1127
- msgstr[1] ""
1128
-
1129
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:109
1130
- msgid "The claim has been lost. Aborting current batch."
1131
- msgstr ""
1132
-
1133
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:139
1134
- #. translators: %s refers to the action ID
1135
- msgid "Started processing action %s"
1136
- msgstr ""
1137
-
1138
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:156
1139
- #. translators: %s refers to the action ID
1140
- msgid "Completed processing action %s with hook: %s"
1141
- msgstr ""
1142
-
1143
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:171
1144
- #. translators: %1$s refers to the action ID, %2$s refers to the Exception
1145
- #. message
1146
- msgid "Error processing action %1$s: %2$s"
1147
- msgstr ""
1148
-
1149
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:183
1150
- msgid "second"
1151
- msgid_plural "seconds"
1152
- msgstr[0] ""
1153
- msgstr[1] ""
1154
-
1155
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php:187
1156
- msgid "Attempting to reduce used memory..."
1157
- msgstr ""
1158
-
1159
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php:87
1160
- #. translators: %d refers to how many scheduled taks were found to run
1161
- msgid "Found %d scheduled task"
1162
- msgid_plural "Found %d scheduled tasks"
1163
- msgstr[0] ""
1164
- msgstr[1] ""
1165
-
1166
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php:104
1167
- #. translators: %d refers to the total number of batches executed
1168
- msgid "%d batch executed."
1169
- msgid_plural "%d batches executed."
1170
- msgstr[0] ""
1171
- msgstr[1] ""
1172
-
1173
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php:123
1174
- #. translators: %s refers to the exception error message.
1175
- msgid "There was an error running the action scheduler: %s"
1176
- msgstr ""
1177
-
1178
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php:140
1179
- #. translators: %d refers to the total number of taskes completed
1180
- msgid "%d scheduled task completed."
1181
- msgid_plural "%d scheduled tasks completed."
1182
- msgstr[0] ""
1183
- msgstr[1] ""
1184
-
1185
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:27
1186
- msgid "Error saving action: %s"
1187
- msgstr ""
1188
-
1189
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:51
1190
- msgid "Unable to save action."
1191
- msgstr ""
1192
-
1193
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:441
1194
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:452
1195
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:478
1196
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:755
1197
- msgid "Unidentified action %s"
1198
- msgstr ""
1199
-
1200
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:590
1201
- msgid "Unable to claim actions. Database error."
1202
- msgstr ""
1203
-
1204
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:610
1205
- msgid "The group \"%s\" does not exist."
1206
- msgstr ""
1207
-
1208
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:678
1209
- msgid "Unable to unlock claim %s. Database error."
1210
- msgstr ""
1211
-
1212
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:692
1213
- msgid "Unable to unlock claim on action %s. Database error."
1214
- msgstr ""
1215
-
1216
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:703
1217
- msgid "Unable to mark failure on action %s. Database error."
1218
- msgstr ""
1219
-
1220
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php:727
1221
- msgid "Invalid action ID. No status found."
1222
- msgstr ""
1223
-
1224
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:37
1225
- msgid "Failed <span class=\"count\">(%s)</span>"
1226
- msgid_plural "Failed <span class=\"count\">(%s)</span>"
1227
- msgstr[0] ""
1228
- msgstr[1] ""
1229
-
1230
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:51
1231
- msgid "In-Progress <span class=\"count\">(%s)</span>"
1232
- msgid_plural "In-Progress <span class=\"count\">(%s)</span>"
1233
- msgstr[0] ""
1234
- msgstr[1] ""
1235
-
1236
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:20
1237
- msgid "Scheduled actions are hooks triggered on a cetain date and time."
1238
- msgstr ""
1239
-
1240
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:31
1241
- msgid "Scheduled Action"
1242
- msgstr ""
1243
-
1244
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:33
1245
- msgid "Add"
1246
- msgstr ""
1247
-
1248
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:34
1249
- msgid "Add New Scheduled Action"
1250
- msgstr ""
1251
-
1252
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:35
1253
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:226
1254
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:758
1255
- msgid "Edit"
1256
- msgstr ""
1257
-
1258
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:36
1259
- msgid "Edit Scheduled Action"
1260
- msgstr ""
1261
-
1262
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:37
1263
- msgid "New Scheduled Action"
1264
- msgstr ""
1265
-
1266
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:38
1267
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:39
1268
- msgid "View Action"
1269
- msgstr ""
1270
-
1271
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:40
1272
- msgid "Search Scheduled Actions"
1273
- msgstr ""
1274
-
1275
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:41
1276
- msgid "No actions found"
1277
- msgstr ""
1278
-
1279
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:42
1280
- msgid "No actions found in trash"
1281
- msgstr ""
1282
-
1283
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_TaxonomyRegistrar.php:14
1284
- msgid "Action Group"
1285
- msgstr ""
1286
-
1287
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:374
1288
- msgid "Awesome"
1289
- msgstr ""
1290
-
1291
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:375
1292
- msgid "Fantastic"
1293
- msgstr ""
1294
-
1295
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:376
1296
- msgid "Cowabunga"
1297
- msgstr ""
1298
-
1299
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:377
1300
- msgid "Congratulations"
1301
- msgstr ""
1302
-
1303
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:378
1304
- msgid "Hot dog"
1305
- msgstr ""
1306
-
1307
- #: vendor/skyverge/wc-plugin-framework/woocommerce/Lifecycle.php:385
1308
- #. translators: Placeholders: %1$s - plugin name, %2$s - <a> tag, %3$s - </a>
1309
- #. tag, %4$s - <a> tag, %5$s - </a> tag
1310
- msgid ""
1311
- "Are you having a great experience with %1$s so far? Please consider "
1312
- "%2$sleaving a review%3$s! If things aren't going quite as expected, we're "
1313
- "happy to help -- please %4$sreach out to our support team%5$s."
1314
- msgstr ""
1315
-
1316
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:183
1317
- msgid ""
1318
- "Thanks for installing %1$s! To get started, take a minute to %2$sread the "
1319
- "documentation%3$s :)"
1320
- msgstr ""
1321
-
1322
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:211
1323
- msgid ""
1324
- "Thanks for installing %1$s! To get started, take a minute to complete these "
1325
- "%2$squick and easy setup steps%3$s :)"
1326
- msgstr ""
1327
-
1328
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:236
1329
- msgid "Setup"
1330
- msgstr ""
1331
-
1332
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:304
1333
- #. translators: Placeholders: %s - plugin name
1334
- msgid "%s &rsaquo; Setup"
1335
- msgstr ""
1336
-
1337
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:352
1338
- msgid "Oops! An error occurred, please try again."
1339
- msgstr ""
1340
-
1341
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:490
1342
- msgid "Ready!"
1343
- msgstr ""
1344
-
1345
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:583
1346
- #. translators: Placeholder: %s - plugin name
1347
- msgid "Welcome to %s!"
1348
- msgstr ""
1349
-
1350
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:596
1351
- msgid ""
1352
- "This quick setup wizard will help you configure the basic settings and get "
1353
- "you started."
1354
- msgstr ""
1355
-
1356
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:610
1357
- msgid "%s is ready!"
1358
- msgstr ""
1359
-
1360
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:662
1361
- msgid "Next step"
1362
- msgstr ""
1363
-
1364
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:688
1365
- msgid "You can also:"
1366
- msgstr ""
1367
-
1368
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:732
1369
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:762
1370
- msgid "View the Docs"
1371
- msgstr ""
1372
-
1373
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:733
1374
- msgid "See more setup options"
1375
- msgstr ""
1376
-
1377
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:734
1378
- msgid "Learn more about customizing the plugin"
1379
- msgstr ""
1380
-
1381
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:758
1382
- msgid "Review Your Settings"
1383
- msgstr ""
1384
-
1385
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:766
1386
- msgid "Leave a Review"
1387
- msgstr ""
1388
-
1389
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:790
1390
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:660
1391
- msgid "Continue"
1392
- msgstr ""
1393
-
1394
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:950
1395
- msgid "Return to the WordPress Dashboard"
1396
- msgstr ""
1397
-
1398
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:952
1399
- msgid "Not right now"
1400
- msgstr ""
1401
-
1402
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:954
1403
- msgid "Skip this step"
1404
- msgstr ""
1405
-
1406
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:268
1407
- msgid ""
1408
- "The following plugin is disabled because it is out of date and incompatible "
1409
- "with newer plugins on your site:"
1410
- msgid_plural ""
1411
- "The following plugins are disabled because they are out of date and "
1412
- "incompatible with newer plugins on your site:"
1413
- msgstr[0] ""
1414
- msgstr[1] ""
1415
-
1416
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:282
1417
- msgid ""
1418
- "To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s "
1419
- "%5$sdeactivate%6$s the above plugin, or %7$sdeactivate the following%8$s:"
1420
- msgid_plural ""
1421
- "To resolve this, please %1$supdate%2$s (recommended) %3$sor%4$s "
1422
- "%5$sdeactivate%6$s the above plugins, or %7$sdeactivate the following%8$s:"
1423
- msgstr[0] ""
1424
- msgstr[1] ""
1425
-
1426
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:303
1427
- msgid ""
1428
- "The following plugins are inactive because they require a newer version of "
1429
- "WooCommerce:"
1430
- msgstr ""
1431
-
1432
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:303
1433
- msgid ""
1434
- "The following plugin is inactive because it requires a newer version of "
1435
- "WooCommerce:"
1436
- msgstr ""
1437
-
1438
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:308
1439
- #. translators: Placeholders: %1$s - plugin name, %2$s - WooCommerce version
1440
- #. number
1441
- msgid "%1$s requires WooCommerce %2$s or newer"
1442
- msgstr ""
1443
-
1444
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-framework-bootstrap.php:312
1445
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
1446
- msgid "Please %1$supdate WooCommerce%2$s"
1447
- msgstr ""
1448
-
1449
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:148
1450
- #. translators: Placeholders: %1$s - plugin name, %2$s - a PHP
1451
- #. extension/comma-separated list of PHP extensions
1452
- msgid ""
1453
- "%1$s requires the %2$s PHP extension to function. Contact your host or "
1454
- "server administrator to install and configure the missing extension."
1455
- msgid_plural ""
1456
- "%1$s requires the following PHP extensions to function: %2$s. Contact your "
1457
- "host or server administrator to install and configure the missing "
1458
- "extensions."
1459
- msgstr[0] ""
1460
- msgstr[1] ""
1461
-
1462
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:176
1463
- #. translators: Placeholders: %1$s - plugin name, %2$s - a PHP
1464
- #. function/comma-separated list of PHP functions
1465
- msgid ""
1466
- "%1$s requires the %2$s PHP function to exist. Contact your host or server "
1467
- "administrator to install and configure the missing function."
1468
- msgid_plural ""
1469
- "%1$s requires the following PHP functions to exist: %2$s. Contact your "
1470
- "host or server administrator to install and configure the missing functions."
1471
- msgstr[0] ""
1472
- msgstr[1] ""
1473
-
1474
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:206
1475
- #. translators: Placeholders: %s - plugin name
1476
- msgid ""
1477
- "%s may behave unexpectedly because the following PHP configuration settings "
1478
- "are required:"
1479
- msgstr ""
1480
-
1481
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:220
1482
- msgid "%s or higher"
1483
- msgstr ""
1484
-
1485
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:230
1486
- msgid ""
1487
- "Please contact your hosting provider or server administrator to configure "
1488
- "these settings."
1489
- msgstr ""
1490
-
1491
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:252
1492
- #. translators: Placeholders: %1$s - <strong>, %2$s - </strong>
1493
- msgid ""
1494
- "Hey there! We've noticed that your server is running %1$san outdated "
1495
- "version of PHP%2$s, which is the programming language that WooCommerce and "
1496
- "its extensions are built on.\n"
1497
- "\t\t\t\t\tThe PHP version that is currently used for your site is no longer "
1498
- "maintained, nor %1$sreceives security updates%2$s; newer versions are "
1499
- "faster and more secure.\n"
1500
- "\t\t\t\t\tAs a result, %3$s no longer supports this version and you should "
1501
- "upgrade PHP as soon as possible.\n"
1502
- "\t\t\t\t\tYour hosting provider can do this for you. %4$sHere are some "
1503
- "resources to help you upgrade%5$s and to explain PHP versions further."
1504
- msgstr ""
1505
-
1506
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin-dependencies.php:271
1507
- #. translators: Placeholders: %1$s - WooCommerce version number, %2$s -
1508
- #. <strong>, %3$s - </strong>, %4$s - Plugin name, %5$s - <a> tag, %6$s - </a>
1509
- #. tag
1510
- msgid ""
1511
- "Hey there! We've noticed that your site is running version %1$s of "
1512
- "WooCommerce, but %2$sWooCommerce 3.0 or higher will soon be required%3$s by "
1513
- "%4$s. We recommend you %5$supdate WooCommerce%6$s to the latest version as "
1514
- "soon as possible."
1515
- msgstr ""
1516
-
1517
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:297
1518
- #. translators: Placeholders: %s - plugin name
1519
- msgid "You cannot clone instances of %s."
1520
- msgstr ""
1521
-
1522
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:308
1523
- #. translators: Placeholders: %s - plugin name
1524
- msgid "You cannot unserialize instances of %s."
1525
- msgstr ""
1526
-
1527
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:529
1528
- #. translators: Docs as in Documentation
1529
- msgid "Docs"
1530
- msgstr ""
1531
-
1532
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:622
1533
- msgid "%1$s - A minimum of %2$s is required."
1534
- msgstr ""
1535
-
1536
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:631
1537
- msgid "Set as %1$s - %2$s is required."
1538
- msgstr ""
1539
-
1540
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:854
1541
- msgid "Configure"
1542
- msgstr ""
1543
-
1544
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:178
1545
- msgid ""
1546
- "There was a problem processing your order and it is being placed on hold "
1547
- "for review. Please contact us to complete the transaction."
1548
- msgstr ""
1549
-
1550
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Hosted_Payment_Handler.php:319
1551
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:444
1552
- #. translators: Placeholders: %s - a WooCommerce order ID
1553
- msgid "Could not find order %s"
1554
- msgstr ""
1555
-
1556
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:151
1557
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2351
1558
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:163
1559
- #. translators: Placeholders: %1$s - status code, %2$s - status message
1560
- #. translators: Placeholders: %1$s - payment request response status code, %2$s
1561
- #. - payment request response status message
1562
- msgid "Status code %1$s: %2$s"
1563
- msgstr ""
1564
-
1565
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:154
1566
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2354
1567
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:166
1568
- #. translators: Placeholders: %s - status code
1569
- #. translators: Placeholders: %s - payment request response status code
1570
- msgid "Status code: %s"
1571
- msgstr ""
1572
-
1573
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:157
1574
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2357
1575
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:169
1576
- #. translators: Placeholders; %s - status message
1577
- #. translators: Placeholders: %s - payment request response status message
1578
- msgid "Status message: %s"
1579
- msgstr ""
1580
-
1581
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:162
1582
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2362
1583
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:176
1584
- msgid "Transaction ID %s"
1585
- msgstr ""
1586
-
1587
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:203
1588
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:508
1589
- #. translators: Placeholders: %s - payment gateway title (such as
1590
- #. Authorize.net, Braintree, etc)
1591
- msgid "%s duplicate transaction received"
1592
- msgstr ""
1593
-
1594
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:206
1595
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:511
1596
- msgid "Order %s is already paid for."
1597
- msgstr ""
1598
-
1599
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:266
1600
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2694
1601
- msgid ""
1602
- "Your order has been received and is being reviewed. Thank you for your "
1603
- "business."
1604
- msgstr ""
1605
-
1606
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:273
1607
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:851
1608
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1732
1609
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:363
1610
- #. translators: This is a message describing that the transaction in question
1611
- #. only performed a credit card authorization and did not capture any funds.
1612
- msgid "Authorization only transaction"
1613
- msgstr ""
1614
-
1615
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:361
1616
- #. translators: Placeholders: %s - payment gateway title
1617
- msgid "%s Transaction Held for Review"
1618
- msgstr ""
1619
-
1620
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:432
1621
- #. translators: Placeholders: %s - payment gateway title
1622
- msgid "%s Payment Failed"
1623
- msgstr ""
1624
-
1625
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Abstract_Payment_Handler.php:459
1626
- #. translators: Placeholders: %s - payment gateway title
1627
- msgid "%s Transaction Cancelled"
1628
- msgstr ""
1629
-
1630
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:157
1631
- msgid "Order cannot be captured"
1632
- msgstr ""
1633
-
1634
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:162
1635
- msgid "Transaction authorization has expired"
1636
- msgstr ""
1637
-
1638
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:167
1639
- msgid "Transaction has already been fully captured"
1640
- msgstr ""
1641
-
1642
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:172
1643
- msgid "Transaction cannot be captured"
1644
- msgstr ""
1645
-
1646
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:188
1647
- #. translators: Placeholders: %1$s - payment gateway title (such as
1648
- #. Authorize.net, Braintree, etc), %2$s - transaction amount. Definitions:
1649
- #. Capture, as in capture funds from a credit card.
1650
- msgid "%1$s Capture of %2$s Approved"
1651
- msgstr ""
1652
-
1653
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:195
1654
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:670
1655
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:755
1656
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2030
1657
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2261
1658
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2575
1659
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2620
1660
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:346
1661
- #. translators: Placeholders: %s - transaction ID
1662
- msgid "(Transaction ID %s)"
1663
- msgstr ""
1664
-
1665
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/Handlers/Capture.php:226
1666
- #. translators: Placeholders: %1$s - payment gateway title (such as
1667
- #. Authorize.net, Braintree, etc), %2$s - failure message. Definitions:
1668
- #. "capture" as in capturing funds from a credit card.
1669
- msgid "%1$s Capture Failed: %2$s"
1670
- msgstr ""
1671
-
1672
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:119
1673
- msgid "Are you sure you wish to process this capture? The action cannot be undone."
1674
- msgstr ""
1675
-
1676
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:122
1677
- msgid ""
1678
- "Something went wrong, and the capture could no be completed. Please try "
1679
- "again."
1680
- msgstr ""
1681
-
1682
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:166
1683
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:241
1684
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:304
1685
- #. translators: verb, as in "Capture credit card charge". Used when an
1686
- #. amount has been pre-authorized before, but funds have not yet been captured
1687
- #. (taken) from the card. Capturing the charge will take the money from the
1688
- #. credit card and put it in the merchant's pockets.
1689
- msgid "Capture Charge"
1690
- msgstr ""
1691
-
1692
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:294
1693
- msgid "This charge has been fully captured."
1694
- msgstr ""
1695
-
1696
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:296
1697
- msgid "This charge can no longer be captured."
1698
- msgstr ""
1699
-
1700
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-order.php:298
1701
- msgid "This charge cannot be captured."
1702
- msgstr ""
1703
-
1704
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:90
1705
- msgid "Are you sure you want to remove this token?"
1706
- msgstr ""
1707
-
1708
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:100
1709
- msgid "Invalid token data"
1710
- msgstr ""
1711
-
1712
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:104
1713
- msgid "An error occurred. Please try again."
1714
- msgstr ""
1715
-
1716
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:453
1717
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:302
1718
- msgid "(%s)"
1719
- msgstr ""
1720
-
1721
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:483
1722
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:664
1723
- msgid "Default"
1724
- msgstr ""
1725
-
1726
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:519
1727
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:552
1728
- msgid "Token ID"
1729
- msgstr ""
1730
-
1731
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:524
1732
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:299
1733
- msgid "Card Type"
1734
- msgstr ""
1735
-
1736
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:529
1737
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:565
1738
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:191
1739
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:297
1740
- msgid "Last Four"
1741
- msgstr ""
1742
-
1743
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:536
1744
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:320
1745
- msgid "Expiration (MM/YY)"
1746
- msgstr ""
1747
-
1748
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:557
1749
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:427
1750
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:298
1751
- #. translators: e-check account type, HTML form field label
1752
- msgid "Account Type"
1753
- msgstr ""
1754
-
1755
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:560
1756
- msgid "Checking"
1757
- msgstr ""
1758
-
1759
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:561
1760
- msgid "Savings"
1761
- msgstr ""
1762
-
1763
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:662
1764
- msgid "Refresh"
1765
- msgstr ""
1766
-
1767
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:664
1768
- msgid "Add New"
1769
- msgstr ""
1770
-
1771
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:667
1772
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:759
1773
- msgid "Save"
1774
- msgstr ""
1775
-
1776
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-payment-token-editor.php:690
1777
- msgid "Remove"
1778
- msgstr ""
1779
-
1780
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:221
1781
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:208
1782
- msgid "%s Payment Tokens"
1783
- msgstr ""
1784
-
1785
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/class-sv-wc-payment-gateway-admin-user-handler.php:299
1786
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:663
1787
- msgid "Customer ID"
1788
- msgstr ""
1789
-
1790
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:32
1791
- msgid "This section contains configuration settings for this gateway."
1792
- msgstr ""
1793
-
1794
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:53
1795
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1267
1796
- #. translators: environment as in a software environment (test/production)
1797
- msgid "Environment"
1798
- msgstr ""
1799
-
1800
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:54
1801
- msgid "The transaction environment for this gateway."
1802
- msgstr ""
1803
-
1804
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:61
1805
- msgid "Tokenization Enabled"
1806
- msgstr ""
1807
-
1808
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:62
1809
- msgid "Displays whether or not tokenization is enabled for this gateway."
1810
- msgstr ""
1811
-
1812
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:75
1813
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1197
1814
- msgid "Debug Mode"
1815
- msgstr ""
1816
-
1817
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:76
1818
- msgid "Displays whether or not debug logging is enabled for this gateway."
1819
- msgstr ""
1820
-
1821
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:79
1822
- msgid "Display at Checkout & Log"
1823
- msgstr ""
1824
-
1825
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:81
1826
- msgid "Display at Checkout"
1827
- msgstr ""
1828
-
1829
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:83
1830
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1205
1831
- msgid "Save to Log"
1832
- msgstr ""
1833
-
1834
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-admin-gateway-status.php:85
1835
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1203
1836
- msgid "Off"
1837
- msgstr ""
1838
-
1839
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:30
1840
- msgid "Authorization total"
1841
- msgstr ""
1842
-
1843
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:34
1844
- msgid "Amount already captured"
1845
- msgstr ""
1846
-
1847
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:40
1848
- msgid "Remaining order total"
1849
- msgstr ""
1850
-
1851
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:46
1852
- msgid "Capture amount"
1853
- msgstr ""
1854
-
1855
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:53
1856
- msgid "Comment (optional):"
1857
- msgstr ""
1858
-
1859
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-order-partial-capture.php:65
1860
- msgid "Capture %s"
1861
- msgstr ""
1862
-
1863
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-user-payment-token-editor-token.php:48
1864
- msgid "-- Select an option --"
1865
- msgstr ""
1866
-
1867
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-user-payment-token-editor.php:59
1868
- msgid "No saved payment tokens"
1869
- msgstr ""
1870
-
1871
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/admin/views/html-user-profile-field-customer-id.php:30
1872
- msgid "The gateway customer ID for the user. Only edit this if necessary."
1873
- msgstr ""
1874
-
1875
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:98
1876
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:131
1877
- msgid "An error occurred, please try again or try an alternate form of payment"
1878
- msgstr ""
1879
-
1880
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:99
1881
- msgid ""
1882
- "We cannot process your order with the payment information that you "
1883
- "provided. Please use a different payment account or an alternate payment "
1884
- "method."
1885
- msgstr ""
1886
-
1887
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:100
1888
- msgid ""
1889
- "This order is being placed on hold for review. Please contact us to "
1890
- "complete the transaction."
1891
- msgstr ""
1892
-
1893
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:105
1894
- msgid ""
1895
- "This order is being placed on hold for review due to an incorrect card "
1896
- "verification number. You may contact the store to complete the transaction."
1897
- msgstr ""
1898
-
1899
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:106
1900
- msgid "The card verification number is invalid, please try again."
1901
- msgstr ""
1902
-
1903
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:107
1904
- msgid "Please enter your card verification number and try again."
1905
- msgstr ""
1906
-
1907
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:110
1908
- msgid ""
1909
- "That card type is not accepted, please use an alternate card or other form "
1910
- "of payment."
1911
- msgstr ""
1912
-
1913
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:111
1914
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:115
1915
- msgid ""
1916
- "The card type is invalid or does not correlate with the credit card number. "
1917
- " Please try again or use an alternate card or other form of payment."
1918
- msgstr ""
1919
-
1920
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:112
1921
- msgid "Please select the card type and try again."
1922
- msgstr ""
1923
-
1924
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:116
1925
- msgid "The card number is invalid, please re-enter and try again."
1926
- msgstr ""
1927
-
1928
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:117
1929
- msgid "Please enter your card number and try again."
1930
- msgstr ""
1931
-
1932
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:120
1933
- msgid "The card expiration date is invalid, please re-enter and try again."
1934
- msgstr ""
1935
-
1936
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:121
1937
- msgid "The card expiration month is invalid, please re-enter and try again."
1938
- msgstr ""
1939
-
1940
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:122
1941
- msgid "The card expiration year is invalid, please re-enter and try again."
1942
- msgstr ""
1943
-
1944
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:123
1945
- msgid "Please enter your card expiration date and try again."
1946
- msgstr ""
1947
-
1948
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:126
1949
- msgid "The bank routing number is invalid, please re-enter and try again."
1950
- msgstr ""
1951
-
1952
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:127
1953
- msgid "The bank account number is invalid, please re-enter and try again."
1954
- msgstr ""
1955
-
1956
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:130
1957
- msgid ""
1958
- "The provided card is expired, please use an alternate card or other form of "
1959
- "payment."
1960
- msgstr ""
1961
-
1962
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:131
1963
- msgid ""
1964
- "The provided card was declined, please use an alternate card or other form "
1965
- "of payment."
1966
- msgstr ""
1967
-
1968
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:132
1969
- msgid ""
1970
- "Insufficient funds in account, please use an alternate card or other form "
1971
- "of payment."
1972
- msgstr ""
1973
-
1974
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:133
1975
- msgid ""
1976
- "The card is inactivate or not authorized for card-not-present transactions, "
1977
- "please use an alternate card or other form of payment."
1978
- msgstr ""
1979
-
1980
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:134
1981
- msgid ""
1982
- "The credit limit for the card has been reached, please use an alternate "
1983
- "card or other form of payment."
1984
- msgstr ""
1985
-
1986
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:135
1987
- msgid "The card verification number does not match. Please re-enter and try again."
1988
- msgstr ""
1989
-
1990
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/api/class-sv-wc-payment-gateway-api-response-message-helper.php:136
1991
- msgid ""
1992
- "The provided address does not match the billing address for cardholder. "
1993
- "Please verify the address and try again."
1994
- msgstr ""
1995
-
1996
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:83
1997
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:101
1998
- msgid "Apple Pay"
1999
- msgstr ""
2000
-
2001
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:107
2002
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1143
2003
- msgid "Enable / Disable"
2004
- msgstr ""
2005
-
2006
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:108
2007
- msgid "Accept Apple Pay"
2008
- msgstr ""
2009
-
2010
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:115
2011
- msgid "Allow Apple Pay on"
2012
- msgstr ""
2013
-
2014
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:125
2015
- msgid "Button Style"
2016
- msgstr ""
2017
-
2018
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:128
2019
- msgid "Black"
2020
- msgstr ""
2021
-
2022
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:129
2023
- msgid "White"
2024
- msgstr ""
2025
-
2026
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:130
2027
- msgid "White with outline"
2028
- msgstr ""
2029
-
2030
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:142
2031
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1318
2032
- msgid "Connection Settings"
2033
- msgstr ""
2034
-
2035
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:148
2036
- msgid "Apple Merchant ID"
2037
- msgstr ""
2038
-
2039
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:152
2040
- msgid "This is found in your %1$sApple developer account%2$s"
2041
- msgstr ""
2042
-
2043
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:159
2044
- msgid "Certificate Path"
2045
- msgstr ""
2046
-
2047
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:164
2048
- #. translators: Placeholders: %s - the server's web root path
2049
- msgid "For reference, your current web root path is: %s"
2050
- msgstr ""
2051
-
2052
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:177
2053
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:187
2054
- msgid "Processing Gateway"
2055
- msgstr ""
2056
-
2057
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:195
2058
- msgid "Test Mode"
2059
- msgstr ""
2060
-
2061
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:196
2062
- msgid ""
2063
- "Enable to test Apple Pay functionality throughout your sites without "
2064
- "processing real payments."
2065
- msgstr ""
2066
-
2067
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:305
2068
- msgid "Your site must be served over HTTPS with a valid SSL certificate."
2069
- msgstr ""
2070
-
2071
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:315
2072
- #. translators: Placeholders: %1$s - plugin name, %2$s - a
2073
- #. currency/comma-separated list of currencies, %3$s - <a> tag, %4$s - </a> tag
2074
- msgid ""
2075
- "Accepts payment in %1$s only. %2$sConfigure%3$s WooCommerce to accept %1$s "
2076
- "to enable Apple Pay."
2077
- msgid_plural ""
2078
- "Accepts payment in one of %1$s only. %2$sConfigure%3$s WooCommerce to "
2079
- "accept one of %1$s to enable Apple Pay."
2080
- msgstr[0] ""
2081
- msgstr[1] ""
2082
-
2083
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:334
2084
- msgid ""
2085
- "Your %1$sMerchant Identity Certificate%2$s cannot be found. Please check "
2086
- "your path configuration."
2087
- msgstr ""
2088
-
2089
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:341
2090
- msgid "Apple Pay is disabled."
2091
- msgstr ""
2092
-
2093
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:380
2094
- msgid "Single products"
2095
- msgstr ""
2096
-
2097
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:381
2098
- msgid "Cart"
2099
- msgstr ""
2100
-
2101
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-admin.php:382
2102
- msgid "Checkout"
2103
- msgstr ""
2104
-
2105
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:168
2106
- msgid "Buy with"
2107
- msgstr ""
2108
-
2109
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:302
2110
- msgid "Pay with"
2111
- msgstr ""
2112
-
2113
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-frontend.php:308
2114
- msgid "or"
2115
- msgstr ""
2116
-
2117
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:86
2118
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:93
2119
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:106
2120
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:115
2121
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:127
2122
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:171
2123
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:181
2124
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay-orders.php:183
2125
- msgid "Error %d: Unable to create order. Please try again."
2126
- msgstr ""
2127
-
2128
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:120
2129
- msgid "Apple Pay payment authorized."
2130
- msgstr ""
2131
-
2132
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:156
2133
- msgid "Apple Pay payment failed. %s"
2134
- msgstr ""
2135
-
2136
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:545
2137
- msgid "Subtotal"
2138
- msgstr ""
2139
-
2140
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:565
2141
- msgid "Shipping"
2142
- msgstr ""
2143
-
2144
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:575
2145
- msgid "Fees"
2146
- msgstr ""
2147
-
2148
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/apple-pay/class-sv-wc-payment-gateway-apple-pay.php:585
2149
- msgid "Taxes"
2150
- msgstr ""
2151
-
2152
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:60
2153
- msgid ""
2154
- "Payment error, please try another payment method or contact us to complete "
2155
- "your transaction."
2156
- msgstr ""
2157
-
2158
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:160
2159
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:479
2160
- msgid "Card expiration date is invalid"
2161
- msgstr ""
2162
-
2163
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:184
2164
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:472
2165
- msgid "Card number is missing"
2166
- msgstr ""
2167
-
2168
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:190
2169
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:475
2170
- msgid "Card number is invalid (wrong length)"
2171
- msgstr ""
2172
-
2173
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:195
2174
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:474
2175
- msgid "Card number is invalid (only digits allowed)"
2176
- msgstr ""
2177
-
2178
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:200
2179
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:473
2180
- msgid "Card number is invalid"
2181
- msgstr ""
2182
-
2183
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:227
2184
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:477
2185
- msgid "Card security code is invalid (only digits are allowed)"
2186
- msgstr ""
2187
-
2188
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:233
2189
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:478
2190
- msgid "Card security code is invalid (must be 3 or 4 digits)"
2191
- msgstr ""
2192
-
2193
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:239
2194
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:476
2195
- msgid "Card security code is missing"
2196
- msgstr ""
2197
-
2198
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:266
2199
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:488
2200
- msgid "Routing Number is missing"
2201
- msgstr ""
2202
-
2203
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:273
2204
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:489
2205
- msgid "Routing Number is invalid (only digits are allowed)"
2206
- msgstr ""
2207
-
2208
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:279
2209
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:490
2210
- msgid "Routing number is invalid (must be 9 digits)"
2211
- msgstr ""
2212
-
2213
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:288
2214
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:485
2215
- msgid "Account Number is missing"
2216
- msgstr ""
2217
-
2218
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:295
2219
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:486
2220
- msgid "Account Number is invalid (only digits are allowed)"
2221
- msgstr ""
2222
-
2223
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:301
2224
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:487
2225
- msgid "Account number is invalid (must be between 5 and 17 digits)"
2226
- msgstr ""
2227
-
2228
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:308
2229
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:484
2230
- msgid "Drivers license number is invalid"
2231
- msgstr ""
2232
-
2233
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:314
2234
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:480
2235
- msgid "Check Number is invalid (only digits are allowed)"
2236
- msgstr ""
2237
-
2238
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:484
2239
- msgid "Unknown error"
2240
- msgstr ""
2241
-
2242
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:493
2243
- msgid "Payment method address could not be updated. %s"
2244
- msgstr ""
2245
-
2246
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:660
2247
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2610
2248
- #. translators: Placeholders: %1$s - payment method title, %2$s - payment
2249
- #. account type (savings/checking) (may or may not be available), %3$s - last
2250
- #. four digits of the account
2251
- msgid "%1$s Check Transaction Approved: %2$s account ending in %3$s"
2252
- msgstr ""
2253
-
2254
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:665
2255
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2615
2256
- #. translators: Placeholders: %s - check number
2257
- msgid "Check number %s"
2258
- msgstr ""
2259
-
2260
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:734
2261
- #. translators: Placeholders: %1$s - payment method title, %2$s - environment
2262
- #. ("Test"), %3$s - transaction type (authorization/charge), %4$s - card type
2263
- #. (mastercard, visa, ...), %5$s - last four digits of the card
2264
- msgid "%1$s %2$s %3$s Approved: %4$s ending in %5$s"
2265
- msgstr ""
2266
-
2267
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:747
2268
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:675
2269
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2567
2270
- #. translators: Placeholders: %s - expiry date
2271
- msgid "(expires %s)"
2272
- msgstr ""
2273
-
2274
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:819
2275
- #. translators: Placeholders: %s - failure message
2276
- msgid "Tokenization Request Failed: %s"
2277
- msgstr ""
2278
-
2279
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:830
2280
- #. translators: Placeholders: %1$s - payment method title, %2$s - failure
2281
- #. message
2282
- msgid "%1$s Tokenization Request Failed: %2$s"
2283
- msgstr ""
2284
-
2285
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:888
2286
- #. translators: Placeholders: %s - failure message. Payment method as in a
2287
- #. specific credit card, e-check or bank account
2288
- msgid "Oops, adding your new payment method failed: %s"
2289
- msgstr ""
2290
-
2291
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:929
2292
- #. translators: Payment method as in a specific credit card. Placeholders: %1$s
2293
- #. - card type (visa, mastercard, ...), %2$s - last four digits of the card,
2294
- #. %3$s - card expiry date
2295
- msgid "Nice! New payment method added: %1$s ending in %2$s (expires %3$s)"
2296
- msgstr ""
2297
-
2298
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:939
2299
- #. translators: Payment method as in a specific e-check account. Placeholders:
2300
- #. %1$s - account type (checking/savings), %2$s - last four digits of the
2301
- #. account
2302
- msgid "Nice! New payment method added: %1$s account ending in %2$s"
2303
- msgstr ""
2304
-
2305
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:946
2306
- #. translators: Payment method as in a specific credit card, e-check or bank
2307
- #. account
2308
- msgid "Nice! New payment method added."
2309
- msgstr ""
2310
-
2311
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:1066
2312
- #. translators: Placeholders: %1$s - site title, %2$s - customer email. Payment
2313
- #. method as in a specific credit card, e-check or bank account
2314
- msgid "%1$s - Add Payment Method for %2$s"
2315
- msgstr ""
2316
-
2317
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:179
2318
- msgid "PayPal"
2319
- msgstr ""
2320
-
2321
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:180
2322
- msgid "Checking Account"
2323
- msgstr ""
2324
-
2325
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:181
2326
- msgid "Savings Account"
2327
- msgstr ""
2328
-
2329
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:182
2330
- msgid "Credit / Debit Card"
2331
- msgstr ""
2332
-
2333
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:183
2334
- msgid "Bank Account"
2335
- msgstr ""
2336
-
2337
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:296
2338
- msgid "Thank you for your order, please click the button below to pay."
2339
- msgstr ""
2340
-
2341
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:297
2342
- msgid "Thank you for your order. We are now redirecting you to complete payment."
2343
- msgstr ""
2344
-
2345
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:298
2346
- msgid "Pay Now"
2347
- msgstr ""
2348
-
2349
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:299
2350
- msgid "Cancel Order"
2351
- msgstr ""
2352
-
2353
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:596
2354
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:832
2355
- #. translators: Placeholders: %1$s - payment gateway title (such as
2356
- #. Authorize.net, Braintree, etc), %2$s - payment method name (mastercard, bank
2357
- #. account, etc), %3$s - last four digits of the card/account, %4$s -
2358
- #. card/account expiry date
2359
- msgid "%1$s Payment Method Saved: %2$s ending in %3$s (expires %4$s)"
2360
- msgstr ""
2361
-
2362
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:607
2363
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:843
2364
- #. translators: Placeholders: %1$s - payment gateway title (such as CyberSouce,
2365
- #. NETbilling, etc), %2$s - account type (checking/savings - may or may not be
2366
- #. available), %3$s - last four digits of the account
2367
- msgid "%1$s eCheck Payment Method Saved: %2$s account ending in %3$s"
2368
- msgstr ""
2369
-
2370
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:616
2371
- #. translators: Placeholders: %s - payment gateway title (such as CyberSouce,
2372
- #. NETbilling, etc)
2373
- msgid "%s Payment Method Saved"
2374
- msgstr ""
2375
-
2376
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-hosted.php:625
2377
- #. translators: Placeholders: %s - a failed tokenization API error
2378
- msgid "Tokenization failed. %s"
2379
- msgstr ""
2380
-
2381
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:228
2382
- msgid "Oops, there was an error updating your payment method. Please try again."
2383
- msgstr ""
2384
-
2385
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:229
2386
- msgid "Are you sure you want to delete this payment method?"
2387
- msgstr ""
2388
-
2389
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:287
2390
- #. translators: Payment method as in a specific credit card, eCheck or bank
2391
- #. account
2392
- msgid "You do not have any saved payment methods."
2393
- msgstr ""
2394
-
2395
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:326
2396
- #. translators: Payment method as in a specific credit card, eCheck or bank
2397
- #. account
2398
- msgid "My Payment Methods"
2399
- msgstr ""
2400
-
2401
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:334
2402
- #. translators: Payment method as in a specific credit card, e-check or bank
2403
- #. account
2404
- msgid "Add New Payment Method"
2405
- msgstr ""
2406
-
2407
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:422
2408
- msgid "Method"
2409
- msgstr ""
2410
-
2411
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:423
2412
- msgid "Details"
2413
- msgstr ""
2414
-
2415
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:424
2416
- msgid "Expires"
2417
- msgstr ""
2418
-
2419
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:425
2420
- msgid "Default?"
2421
- msgstr ""
2422
-
2423
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:462
2424
- msgid "Credit/Debit Cards"
2425
- msgstr ""
2426
-
2427
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:471
2428
- msgid "Bank Accounts"
2429
- msgstr ""
2430
-
2431
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:526
2432
- msgid "N/A"
2433
- msgstr ""
2434
-
2435
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:638
2436
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:199
2437
- msgid "Nickname"
2438
- msgstr ""
2439
-
2440
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:973
2441
- msgid "Oops, you took too long, please try again."
2442
- msgstr ""
2443
-
2444
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:986
2445
- msgid "There was an error with your request, please try again."
2446
- msgstr ""
2447
-
2448
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:999
2449
- #. translators: Payment method as in a specific credit card, e-check or bank
2450
- #. account
2451
- msgid "Error removing payment method"
2452
- msgstr ""
2453
-
2454
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-my-payment-methods.php:1004
2455
- #. translators: Payment method as in a specific credit card, e-check or bank
2456
- #. account
2457
- msgid "Payment method deleted."
2458
- msgstr ""
2459
-
2460
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:302
2461
- msgid "Card Number"
2462
- msgstr ""
2463
-
2464
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:323
2465
- msgid "MM / YY"
2466
- msgstr ""
2467
-
2468
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:341
2469
- msgid "Card Security Code"
2470
- msgstr ""
2471
-
2472
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:344
2473
- msgid "CSC"
2474
- msgstr ""
2475
-
2476
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:384
2477
- msgid "Where do I find this?"
2478
- msgstr ""
2479
-
2480
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:390
2481
- #. translators: e-check routing number, HTML form field label,
2482
- #. https:en.wikipedia.org/wiki/Routing_transit_number
2483
- msgid "Routing Number"
2484
- msgstr ""
2485
-
2486
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:409
2487
- #. translators: e-check account number, HTML form field label
2488
- msgid "Account Number"
2489
- msgstr ""
2490
-
2491
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:475
2492
- #. translators: Test mode refers to the current software environment
2493
- msgid "TEST MODE ENABLED"
2494
- msgstr ""
2495
-
2496
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:577
2497
- #. translators: Payment method as in a specific credit card, eCheck or bank
2498
- #. account
2499
- msgid "Manage Payment Methods"
2500
- msgstr ""
2501
-
2502
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:714
2503
- msgid "Use a new card"
2504
- msgstr ""
2505
-
2506
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:714
2507
- msgid "Use a new bank account"
2508
- msgstr ""
2509
-
2510
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:777
2511
- #. translators: account as in customer's account on the eCommerce site
2512
- msgid "Securely Save to Account"
2513
- msgstr ""
2514
-
2515
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:603
2516
- #. translators: Placeholders: %1$s - plugin name, %2$s - <a> tag, %3$s - </a>
2517
- #. tag
2518
- msgid ""
2519
- "%1$s: WooCommerce is not being forced over SSL; your customers' payment "
2520
- "data may be at risk. %2$sVerify your site URLs here%3$s"
2521
- msgstr ""
2522
-
2523
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:620
2524
- #. translators: Placeholders: %s - payment gateway name
2525
- msgid ""
2526
- "%s will soon require TLS 1.2 support to process transactions and your "
2527
- "server environment may need to be updated. Please contact your hosting "
2528
- "provider to confirm that your site can send and receive TLS 1.2 connections "
2529
- "and request they make any necessary updates."
2530
- msgstr ""
2531
-
2532
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:676
2533
- #. translators: Placeholders: %1$s - plugin name, %2$s - a
2534
- #. currency/comma-separated list of currencies, %3$s - <a> tag, %4$s - </a> tag
2535
- msgid ""
2536
- "%1$s accepts payment in %2$s only. %3$sConfigure%4$s WooCommerce to accept "
2537
- "%2$s to enable this gateway for checkout."
2538
- msgid_plural ""
2539
- "%1$s accepts payment in one of %2$s only. %3$sConfigure%4$s WooCommerce to "
2540
- "accept one of %2$s to enable this gateway for checkout."
2541
- msgstr[0] ""
2542
- msgstr[1] ""
2543
-
2544
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:711
2545
- #. translators: Placeholders: %1$s - payment gateway name, %2$s - opening <a>
2546
- #. tag, %3$s - closing </a> tag
2547
- msgid ""
2548
- "Heads up! %1$s is currently configured to log transaction data for "
2549
- "debugging purposes. If you are not experiencing any problems with payment "
2550
- "processing, we recommend %2$sturning off Debug Mode%3$s"
2551
- msgstr ""
2552
-
2553
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:750
2554
- #. translators: Placeholders: %1$s - payment gateway title (such as
2555
- #. Authorize.net, Braintree, etc), %2$s - <a> tag, %3$s - </a> tag
2556
- msgid ""
2557
- "%1$s is inactive for subscription transactions. Please %2$senable "
2558
- "tokenization%3$s to activate %1$s for Subscriptions."
2559
- msgstr ""
2560
-
2561
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:768
2562
- #. translators: Placeholders: %1$s - payment gateway title (such as
2563
- #. Authorize.net, Braintree, etc), %2$s - <a> tag, %3$s - </a> tag
2564
- msgid ""
2565
- "%1$s is inactive for pre-order transactions. Please %2$senable "
2566
- "tokenization%3$s to activate %1$s for Pre-Orders."
2567
- msgstr ""
2568
-
2569
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:805
2570
- msgid ""
2571
- "You must enable tokenization for this gateway in order to support automatic "
2572
- "renewal payments with the WooCommerce Subscriptions extension."
2573
- msgstr ""
2574
-
2575
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-plugin.php:806
2576
- msgid "Inactive"
2577
- msgstr ""
2578
-
2579
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:114
2580
- msgid "%s Customer ID"
2581
- msgstr ""
2582
-
2583
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:183
2584
- msgid "Type"
2585
- msgstr ""
2586
-
2587
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:253
2588
- msgid "Removed payment token \"%d\""
2589
- msgstr ""
2590
-
2591
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-privacy.php:300
2592
- msgid "Expiry Date"
2593
- msgstr ""
2594
-
2595
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:340
2596
- msgid "you successfully processed a payment!"
2597
- msgstr ""
2598
-
2599
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:345
2600
- msgid "you successfully processed a refund!"
2601
- msgstr ""
2602
-
2603
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:481
2604
- msgid "Check Number is missing"
2605
- msgstr ""
2606
-
2607
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:482
2608
- msgid "Drivers license state is missing"
2609
- msgstr ""
2610
-
2611
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:483
2612
- msgid "Drivers license number is missing"
2613
- msgstr ""
2614
-
2615
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:660
2616
- msgid "Place order"
2617
- msgstr ""
2618
-
2619
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:692
2620
- msgid "Thank you for your order."
2621
- msgstr ""
2622
-
2623
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1102
2624
- msgid "Credit Card"
2625
- msgstr ""
2626
-
2627
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1104
2628
- msgid "eCheck"
2629
- msgstr ""
2630
-
2631
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1122
2632
- msgid "Pay securely using your credit card."
2633
- msgstr ""
2634
-
2635
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1124
2636
- msgid "Pay securely using your checking account."
2637
- msgstr ""
2638
-
2639
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1144
2640
- msgid "Enable this gateway"
2641
- msgstr ""
2642
-
2643
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1150
2644
- msgid "Title"
2645
- msgstr ""
2646
-
2647
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1152
2648
- msgid "Payment method title that the customer will see during checkout."
2649
- msgstr ""
2650
-
2651
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1157
2652
- msgid "Description"
2653
- msgstr ""
2654
-
2655
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1159
2656
- msgid "Payment method description that the customer will see during checkout."
2657
- msgstr ""
2658
-
2659
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1188
2660
- msgid "Detailed Decline Messages"
2661
- msgstr ""
2662
-
2663
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1190
2664
- msgid ""
2665
- "Check to enable detailed decline messages to the customer during checkout "
2666
- "when possible, rather than a generic decline message."
2667
- msgstr ""
2668
-
2669
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1200
2670
- #. translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag
2671
- msgid ""
2672
- "Show Detailed Error Messages and API requests/responses on the checkout "
2673
- "page and/or save them to the %1$sdebug log%2$s"
2674
- msgstr ""
2675
-
2676
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1204
2677
- msgid "Show on Checkout Page"
2678
- msgstr ""
2679
-
2680
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1207
2681
- #. translators: show debugging information on both checkout page and in the log
2682
- msgid "Both"
2683
- msgstr ""
2684
-
2685
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1270
2686
- msgid "Select the gateway environment to use for transactions."
2687
- msgstr ""
2688
-
2689
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1324
2690
- msgid "Share connection settings"
2691
- msgstr ""
2692
-
2693
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1326
2694
- msgid "Use connection/authentication settings from other gateway"
2695
- msgstr ""
2696
-
2697
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1329
2698
- msgid "Disabled because the other gateway is using these settings"
2699
- msgstr ""
2700
-
2701
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1346
2702
- msgid "Card Verification (CSC)"
2703
- msgstr ""
2704
-
2705
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1347
2706
- msgid "Display the Card Security Code (CV2) field on checkout"
2707
- msgstr ""
2708
-
2709
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1355
2710
- msgid "Saved Card Verification"
2711
- msgstr ""
2712
-
2713
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1356
2714
- msgid "Display the Card Security Code field when paying with a saved card"
2715
- msgstr ""
2716
-
2717
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1685
2718
- #. translators: Placeholders: %1$s - site title, %2$s - order number
2719
- msgid "%1$s - Order %2$s"
2720
- msgstr ""
2721
-
2722
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1813
2723
- #. translators: Placeholders: %1$s - site title, %2$s - order number.
2724
- #. Definitions: Capture as in capture funds from a credit card.
2725
- msgid "%1$s - Capture for Order %2$s"
2726
- msgstr ""
2727
-
2728
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:1956
2729
- #. translators: Placeholders: %1$s - site title, %2$s - order number
2730
- msgid "%1$s - Refund for Order %2$s"
2731
- msgstr ""
2732
-
2733
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2023
2734
- #. translators: Placeholders: %1$s - payment gateway title (such as
2735
- #. Authorize.net, Braintree, etc), %2$s - a monetary amount
2736
- msgid "%1$s Refund in the amount of %2$s approved."
2737
- msgstr ""
2738
-
2739
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2051
2740
- #. translators: Placeholders: %1$s - payment gateway title (such as
2741
- #. Authorize.net, Braintree, etc), %2$s - error code, %3$s - error message
2742
- msgid "%1$s Refund Failed: %2$s - %3$s"
2743
- msgstr ""
2744
-
2745
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2059
2746
- #. translators: Placeholders: %1$s - payment gateway title (such as
2747
- #. Authorize.net, Braintree, etc), %2$s - error message
2748
- msgid "%1$s Refund Failed: %2$s"
2749
- msgstr ""
2750
-
2751
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2080
2752
- #. translators: Placeholders: %s - payment gateway title (such as
2753
- #. Authorize.net, Braintree, etc)
2754
- msgid "%s Order completely refunded."
2755
- msgstr ""
2756
-
2757
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2135
2758
- msgid ""
2759
- "Oops, you cannot partially void this order. Please use the full order "
2760
- "amount."
2761
- msgstr ""
2762
-
2763
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2222
2764
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - error code,
2765
- #. %3$s - error message. Void as in to void an order.
2766
- msgid "%1$s Void Failed: %2$s - %3$s"
2767
- msgstr ""
2768
-
2769
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2230
2770
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - error
2771
- #. message. Void as in to void an order.
2772
- msgid "%1$s Void Failed: %2$s"
2773
- msgstr ""
2774
-
2775
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2254
2776
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - a monetary
2777
- #. amount. Void as in to void an order.
2778
- msgid "%1$s Void in the amount of %2$s approved."
2779
- msgstr ""
2780
-
2781
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2546
2782
- #. translators: Placeholders: %1$s - payment method title, %2$s - environment
2783
- #. ("Test"), %3$s - transaction type (authorization/charge)
2784
- msgid "%1$s %2$s %3$s Approved"
2785
- msgstr ""
2786
-
2787
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2556
2788
- #. translators: Placeholders: %1$s - credit card type (MasterCard, Visa,
2789
- #. etc...), %2$s - last four digits of the card
2790
- msgid "%1$s ending in %2$s"
2791
- msgstr ""
2792
-
2793
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2652
2794
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - message
2795
- #. (probably reason for the transaction being held for review)
2796
- msgid "%1$s Transaction Held for Review (%2$s)"
2797
- msgstr ""
2798
-
2799
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2741
2800
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - error
2801
- #. message; e.g. Order Note: [Payment method] Payment failed [error]
2802
- msgid "%1$s Payment Failed (%2$s)"
2803
- msgstr ""
2804
-
2805
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2776
2806
- #. translators: Placeholders: %1$s - payment gateway title, %2$s -
2807
- #. message/error
2808
- msgid "%1$s Transaction Cancelled (%2$s)"
2809
- msgstr ""
2810
-
2811
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3021
2812
- msgid "Transaction Type"
2813
- msgstr ""
2814
-
2815
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3023
2816
- msgid ""
2817
- "Select how transactions should be processed. Charge submits all "
2818
- "transactions for settlement, Authorization simply authorizes the order "
2819
- "total for capture later."
2820
- msgstr ""
2821
-
2822
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3034
2823
- msgid "Charge Virtual-Only Orders"
2824
- msgstr ""
2825
-
2826
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3036
2827
- msgid ""
2828
- "If the order contains exclusively virtual items, enable this to immediately "
2829
- "charge, rather than authorize, the transaction."
2830
- msgstr ""
2831
-
2832
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3044
2833
- msgid "Enable Partial Capture"
2834
- msgstr ""
2835
-
2836
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3046
2837
- msgid "Allow orders to be partially captured multiple times."
2838
- msgstr ""
2839
-
2840
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3058
2841
- msgid "Capture Paid Orders"
2842
- msgstr ""
2843
-
2844
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3061
2845
- msgid "Automatically capture orders when they are changed to %s."
2846
- msgstr ""
2847
-
2848
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3062
2849
- msgid "a paid status"
2850
- msgstr ""
2851
-
2852
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3252
2853
- msgid "Accepted Card Logos"
2854
- msgstr ""
2855
-
2856
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3254
2857
- msgid ""
2858
- "These are the card logos that are displayed to customers as accepted during "
2859
- "checkout."
2860
- msgstr ""
2861
-
2862
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3257
2863
- #. translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag
2864
- msgid ""
2865
- "This setting %1$sdoes not%2$s change which card types the gateway will "
2866
- "accept. Accepted cards are configured from your payment processor account."
2867
- msgstr ""
2868
-
2869
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3348
2870
- #. translators:
2871
- #. http:www.cybersource.com/products/payment_security/payment_tokenization/ and
2872
- #. https:en.wikipedia.org/wiki/Tokenization_(data_security)
2873
- msgid "Tokenization"
2874
- msgstr ""
2875
-
2876
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3349
2877
- msgid "Allow customers to securely save their payment details for future checkout."
2878
- msgstr ""
2879
-
2880
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:254
2881
- msgid "Pre-Order Tokenization attempt failed (%s)"
2882
- msgstr ""
2883
-
2884
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:300
2885
- msgid "%s - Pre-Order Release Payment for Order %s"
2886
- msgstr ""
2887
-
2888
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:304
2889
- msgid "Payment token missing/invalid."
2890
- msgstr ""
2891
-
2892
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:329
2893
- msgid "%s %s Pre-Order Release Payment Approved: %s ending in %s (expires %s)"
2894
- msgstr ""
2895
-
2896
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:340
2897
- msgid "%s eCheck Pre-Order Release Payment Approved: %s ending in %s"
2898
- msgstr ""
2899
-
2900
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-pre-orders.php:382
2901
- msgid "Pre-Order Release Payment Failed: %s"
2902
- msgstr ""
2903
-
2904
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:213
2905
- msgid "Subscription Renewal: payment token is missing/invalid."
2906
- msgstr ""
2907
-
2908
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:239
2909
- msgid "%1$s - Subscription Renewal Order %2$s"
2910
- msgstr ""
2911
-
2912
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:371
2913
- #. translators: Placeholders: %1$s - payment gateway title, %2$s - error
2914
- #. message; e.g. Order Note: [Payment method] Payment Change failed [error]
2915
- msgid "%1$s Payment Change Failed (%2$s)"
2916
- msgstr ""
2917
-
2918
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:511
2919
- msgid "Via %s ending in %s"
2920
- msgstr ""
2921
-
2922
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:538
2923
- msgid "Subscriptions"
2924
- msgstr ""
2925
-
2926
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:607
2927
- msgid ""
2928
- "This payment method is tied to a subscription and cannot be deleted. Please "
2929
- "switch the subscription to another method first."
2930
- msgstr ""
2931
-
2932
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:659
2933
- msgid "Payment Token"
2934
- msgstr ""
2935
-
2936
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:688
2937
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:693
2938
- msgid "%s is required."
2939
- msgstr ""
2940
-
2941
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/payment-tokens/class-sv-wc-payment-gateway-payment-tokens-handler.php:171
2942
- msgid "Unknown Error"
2943
- msgstr ""
2944
-
2945
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:643
2946
- msgid "Job data key \"%s\" not set"
2947
- msgstr ""
2948
-
2949
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:647
2950
- msgid "Job data key \"%s\" is not an array"
2951
- msgstr ""
2952
-
2953
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:883
2954
- msgid "Every %d Minutes"
2955
- msgstr ""
2956
-
2957
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:1047
2958
- msgid "Background Processing Test"
2959
- msgstr ""
2960
-
2961
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:1048
2962
- msgid "Run Test"
2963
- msgstr ""
2964
-
2965
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:1049
2966
- msgid ""
2967
- "This tool will test whether your server is capable of processing background "
2968
- "jobs."
2969
- msgstr ""
2970
-
2971
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:1067
2972
- msgid "Success! You should be able to process background jobs."
2973
- msgstr ""
2974
-
2975
- #: vendor/skyverge/wc-plugin-framework/woocommerce/utilities/class-sv-wp-background-job-handler.php:1070
2976
- msgid ""
2977
- "Could not connect. Please ask your hosting company to ensure your server "
2978
- "has loopback connections enabled."
2979
- msgstr ""
2980
-
2981
- #. Plugin URI of the plugin/theme
2982
- msgid "https://woocommerce.com/products/square/"
2983
- msgstr ""
2984
-
2985
- #. Description of the plugin/theme
2986
- msgid ""
2987
- "Adds ability to sync inventory between WooCommerce and Square POS. In "
2988
- "addition, you can also make purchases through the Square payment gateway."
2989
- msgstr ""
2990
-
2991
- #. Author URI of the plugin/theme
2992
- msgid "https://www.woocommerce.com/"
2993
- msgstr ""
2994
-
2995
- #: includes/Admin/Sync_Page.php:262
2996
- msgctxt "Delete all records"
2997
- msgid "Clear history"
2998
- msgstr ""
2999
-
3000
- #: includes/Admin/Sync_Page.php:267 includes/Admin/Sync_Page.php:308
3001
- msgctxt "Date - Time"
3002
- msgid "Time"
3003
- msgstr ""
3004
-
3005
- #: includes/Emails/Sync_Completed.php:53
3006
- msgctxt "Email subject"
3007
- msgid "[WooCommerce] Square sync completed"
3008
- msgstr ""
3009
-
3010
- #: includes/Emails/Sync_Completed.php:54
3011
- msgctxt "Email heading with merge tag placeholder"
3012
- msgid "Square sync completed for {product_count}"
3013
- msgstr ""
3014
-
3015
- #: includes/Emails/Sync_Completed.php:55
3016
- msgctxt "Email body with merge tag placeholders"
3017
- msgid ""
3018
- "Square sync completed for {site_title} at {sync_completed_date} "
3019
- "{sync_completed_time}."
3020
- msgstr ""
3021
-
3022
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:36
3023
- msgctxt "post"
3024
- msgid "Failed"
3025
- msgstr ""
3026
-
3027
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostStatusRegistrar.php:50
3028
- msgctxt "post"
3029
- msgid "In-Progress"
3030
- msgstr ""
3031
-
3032
- #: vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore_PostTypeRegistrar.php:32
3033
- msgctxt "Admin menu name"
3034
- msgid "Scheduled Actions"
3035
- msgstr ""
3036
-
3037
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:397
3038
- msgctxt "enhanced select"
3039
- msgid "No matches found"
3040
- msgstr ""
3041
-
3042
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:398
3043
- msgctxt "enhanced select"
3044
- msgid "Loading failed"
3045
- msgstr ""
3046
-
3047
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:399
3048
- msgctxt "enhanced select"
3049
- msgid "Please enter 1 or more characters"
3050
- msgstr ""
3051
-
3052
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:400
3053
- msgctxt "enhanced select"
3054
- msgid "Please enter %qty% or more characters"
3055
- msgstr ""
3056
-
3057
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:401
3058
- msgctxt "enhanced select"
3059
- msgid "Please delete 1 character"
3060
- msgstr ""
3061
-
3062
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:402
3063
- msgctxt "enhanced select"
3064
- msgid "Please delete %qty% characters"
3065
- msgstr ""
3066
-
3067
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:403
3068
- msgctxt "enhanced select"
3069
- msgid "You can only select 1 item"
3070
- msgstr ""
3071
-
3072
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:404
3073
- msgctxt "enhanced select"
3074
- msgid "You can only select %qty% items"
3075
- msgstr ""
3076
-
3077
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:405
3078
- msgctxt "enhanced select"
3079
- msgid "Loading more results&hellip;"
3080
- msgstr ""
3081
-
3082
- #: vendor/skyverge/wc-plugin-framework/woocommerce/admin/abstract-sv-wc-plugin-admin-setup-wizard.php:406
3083
- msgctxt "enhanced select"
3084
- msgid "Searching&hellip;"
3085
- msgstr ""
3086
-
3087
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-helper.php:408
3088
- msgctxt "coordinating conjunction for a list of items: a, b, and c"
3089
- msgid "and"
3090
- msgstr ""
3091
-
3092
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:534
3093
- msgctxt "noun"
3094
- msgid "Support"
3095
- msgstr ""
3096
-
3097
- #: vendor/skyverge/wc-plugin-framework/woocommerce/class-sv-wc-plugin.php:539
3098
- msgctxt "verb"
3099
- msgid "Review"
3100
- msgstr ""
3101
-
3102
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:736
3103
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2548
3104
- msgctxt "noun, software environment"
3105
- msgid "Test"
3106
- msgstr ""
3107
-
3108
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:737
3109
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2549
3110
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3027
3111
- msgctxt "credit card transaction type"
3112
- msgid "Authorization"
3113
- msgstr ""
3114
-
3115
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-direct.php:737
3116
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2549
3117
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3026
3118
- msgctxt "noun, credit card transaction type"
3119
- msgid "Charge"
3120
- msgstr ""
3121
-
3122
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:192
3123
- msgctxt "payment method type"
3124
- msgid "Account"
3125
- msgstr ""
3126
-
3127
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:228
3128
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3285
3129
- msgctxt "credit card type"
3130
- msgid "Visa"
3131
- msgstr ""
3132
-
3133
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:232
3134
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3286
3135
- msgctxt "credit card type"
3136
- msgid "MasterCard"
3137
- msgstr ""
3138
-
3139
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:236
3140
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3287
3141
- msgctxt "credit card type"
3142
- msgid "American Express"
3143
- msgstr ""
3144
-
3145
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:240
3146
- msgctxt "credit card type"
3147
- msgid "Diners Club"
3148
- msgstr ""
3149
-
3150
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:244
3151
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3288
3152
- msgctxt "credit card type"
3153
- msgid "Discover"
3154
- msgstr ""
3155
-
3156
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:248
3157
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3290
3158
- msgctxt "credit card type"
3159
- msgid "JCB"
3160
- msgstr ""
3161
-
3162
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:252
3163
- msgctxt "credit card type"
3164
- msgid "CarteBleue"
3165
- msgstr ""
3166
-
3167
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:256
3168
- msgctxt "credit card type"
3169
- msgid "Maestro"
3170
- msgstr ""
3171
-
3172
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-helper.php:260
3173
- msgctxt "credit card type"
3174
- msgid "Laser"
3175
- msgstr ""
3176
-
3177
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3289
3178
- msgctxt "credit card type"
3179
- msgid "Diners"
3180
- msgstr ""
3181
-
3182
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:435
3183
- #. translators: http:www.investopedia.com/terms/c/checkingaccount.asp
3184
- msgctxt "account type"
3185
- msgid "Checking"
3186
- msgstr ""
3187
-
3188
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway-payment-form.php:437
3189
- #. translators: http:www.investopedia.com/terms/s/savingsaccount.asp
3190
- msgctxt "account type"
3191
- msgid "Savings"
3192
- msgstr ""
3193
-
3194
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:2329
3195
- msgctxt "hash before order number"
3196
- msgid "#"
3197
- msgstr ""
3198
-
3199
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/integrations/class-sv-wc-payment-gateway-integration-subscriptions.php:568
3200
- msgctxt "hash before order number"
3201
- msgid "#%s"
3202
- msgstr ""
3203
-
3204
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3055
3205
- msgctxt ""
3206
- "coordinating conjunction for a list of order statuses: on-hold, processing, "
3207
- "or completed"
3208
- msgid "or"
3209
- msgstr ""
3210
-
3211
- #: vendor/skyverge/wc-plugin-framework/woocommerce/payment-gateway/class-sv-wc-payment-gateway.php:3891
3212
- #. translators: https:www.skyverge.com/for-translators-environments/
3213
- msgctxt "software environment"
3214
- msgid "Production"
3215
- msgstr ""
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/AJAX.php DELETED
@@ -1,288 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Product;
30
- use WooCommerce\Square\Handlers\Sync;
31
- use WooCommerce\Square\Sync\Records;
32
-
33
- /**
34
- * AJAX handler.
35
- *
36
- * @since 2.0.0
37
- */
38
- class AJAX {
39
-
40
-
41
- /**
42
- * Adds AJAX action callbacks.
43
- *
44
- * @since 2.0.0
45
- */
46
- public function __construct() {
47
-
48
- // check an individual product sync status
49
- add_action( 'wp_ajax_wc_square_is_product_synced_with_square', [ $this, 'is_product_synced_with_square' ] );
50
-
51
- // fetch product stock from Square
52
- add_action( 'wp_ajax_wc_square_fetch_product_stock_with_square', [ $this, 'fetch_product_stock_with_square' ] );
53
-
54
- add_action( 'wp_ajax_wc_square_import_products_from_square', [ $this, 'import_products_from_square' ] );
55
-
56
- // sync all products with Square
57
- add_action( 'wp_ajax_wc_square_sync_products_with_square', [ $this, 'sync_products_with_square' ] );
58
-
59
- // handle sync records
60
- add_action( 'wp_ajax_wc_square_handle_sync_records', [ $this, 'handle_sync_records' ] );
61
-
62
- // get the status of a sync job
63
- add_action( 'wp_ajax_wc_square_get_sync_with_square_status', [ $this, 'get_sync_with_square_job_status' ] );
64
- }
65
-
66
-
67
- /**
68
- * Checks if a product is set to be synced with Square.
69
- *
70
- * @internal
71
- *
72
- * @since 2.0.0
73
- */
74
- public function is_product_synced_with_square() {
75
-
76
- check_ajax_referer( 'is-product-synced-with-square', 'security' );
77
-
78
- if ( isset( $_POST['product_id'] ) && ( $product = wc_get_product( $_POST['product_id'] ) ) ) {
79
-
80
- if ( $product->is_type( 'variable' ) && $product->has_child() ) {
81
- if ( Product::has_multiple_variation_attributes( $product ) ) {
82
- wp_send_json_error( 'multiple_attributes' );
83
- } else if ( ! Product::has_sku( $product ) ) {
84
- wp_send_json_error( 'missing_variation_sku' );
85
- }
86
- } else {
87
- if ( ! Product::has_sku( $product ) ) {
88
- wp_send_json_error( 'missing_sku' );
89
- }
90
- }
91
- wp_send_json_success( Product::is_synced_with_square( $product ) ? 'yes' : 'no' );
92
- }
93
-
94
- wp_send_json_error( 'invalid_product' );
95
- }
96
-
97
-
98
- /**
99
- * Fetches product stock data from Square.
100
- *
101
- * @internal
102
- *
103
- * @since 2.0.0
104
- */
105
- public function fetch_product_stock_with_square() {
106
-
107
- check_ajax_referer( 'fetch-product-stock-with-square', 'security' );
108
-
109
- $fix_error = __( 'Please mark product as un-synced and save, then synced again.', 'woocommerce-square' );
110
-
111
- if ( isset( $_REQUEST['product_id'] ) && ( $product = wc_get_product( $_REQUEST['product_id'] ) ) ) {
112
-
113
- try {
114
-
115
- $product = Product::update_stock_from_square( $product );
116
-
117
- wp_send_json_success( $product->get_stock_quantity() );
118
-
119
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
120
-
121
- /* translators: Placeholders: %1$s = error message, %2$s = help text */
122
- wp_send_json_error( sprintf( __( 'Unable to fetch inventory: %1$s. %2$s', 'woocommerce-square' ), $exception->getMessage(), $fix_error ) );
123
- }
124
- }
125
-
126
- /* translators: Placeholders: %s = help text */
127
- wp_send_json_error( sprintf( __( 'Error finding item in Square. %s', 'woocommerce-square' ), $fix_error ) );
128
- }
129
-
130
-
131
- /**
132
- * Starts importing products from Square.
133
- *
134
- * @internal
135
- *
136
- * @since 2.0.0
137
- */
138
- public function import_products_from_square() {
139
-
140
- check_ajax_referer( 'import-products-from-square', 'security' );
141
-
142
- $started = wc_square()->get_sync_handler()->start_product_import( ! empty( $_POST['dispatch'] ) );
143
-
144
- if ( ! $started ) {
145
- wp_send_json_error( __( 'Could not start import. Please try again.', 'woocommerce-square' ) );
146
- }
147
-
148
- wp_send_json_success( __( 'Your products are being imported in the background! This may take some time to complete.', 'woocommerce-square' ) );
149
- }
150
-
151
-
152
- /**
153
- * Starts syncing products with Square.
154
- *
155
- * @internal
156
- *
157
- * @since 2.0.0
158
- */
159
- public function sync_products_with_square() {
160
-
161
- check_ajax_referer( 'sync-products-with-square', 'security' );
162
-
163
- $started = wc_square()->get_sync_handler()->start_manual_sync( ! empty( $_POST['dispatch'] ) );
164
-
165
- if ( ! $started ) {
166
- wp_send_json_error();
167
- }
168
-
169
- wp_send_json_success();
170
- }
171
-
172
-
173
- /**
174
- * Handles sync records actions.
175
- *
176
- * @internal
177
- *
178
- * @since 2.0.0
179
- */
180
- public function handle_sync_records() {
181
-
182
- check_ajax_referer( 'handle-sync-with-square-records', 'security' );
183
-
184
- $error = '';
185
-
186
- if ( isset( $_POST['id'], $_POST['handle'] ) ) {
187
-
188
- $id = $_POST['id'];
189
- $action = $_POST['handle'];
190
-
191
- if ( 'all' === $id && 'delete' === $action ) {
192
-
193
- $outcome = Records::clean_records();
194
- $error = esc_html__( 'Could not delete records.', 'woocommerce-square' );
195
-
196
- } elseif ( is_string( $id ) && '' !== $id ) {
197
-
198
- switch ( $action ) {
199
-
200
- case 'delete' :
201
-
202
- $outcome = Records::delete_record( $id );
203
- $error = esc_html__( 'Could not delete record.', 'woocommerce-square' );
204
-
205
- break;
206
-
207
- case 'resolve' :
208
-
209
- if ( $record = Records::get_record( $id) ) {
210
- $record->resolve();
211
- $outcome = $record->save();
212
- }
213
-
214
- $error = esc_html__( 'Could not resolve record.', 'woocommerce-square' );
215
-
216
- break;
217
-
218
- case 'unsync' :
219
-
220
- $record = Records::get_record( $id );
221
-
222
- if ( $record && ( $product = $record->get_product() ) ) {
223
- $record->resolve();
224
- $outcome = Product::unset_synced_with_square( $product ) && $record->save();
225
- }
226
-
227
- $error = esc_html__( 'Could not unsync product.', 'woocommerce-square' );
228
-
229
- break;
230
- }
231
- }
232
-
233
- if ( ! empty( $outcome ) ) {
234
- wp_send_json_success( $outcome );
235
- }
236
- }
237
-
238
- /* translators: Placeholder: %s - error message */
239
- wp_send_json_error( sprintf( __( 'An error occurred. %s', 'woocommerce-square' ), $error ) );
240
- }
241
-
242
-
243
- /**
244
- * Gets a sync job status.
245
- *
246
- * Also bumps the job progression (useful for when background processing isn't available).
247
- *
248
- * @internal
249
- *
250
- * @since 2.0.0
251
- */
252
- public function get_sync_with_square_job_status() {
253
-
254
- check_ajax_referer( 'get-sync-with-square-status', 'security' );
255
-
256
- $job_id = isset( $_POST['job_id'] ) ? $_POST['job_id'] : null;
257
-
258
- if ( $job_id && ( $handler = wc_square()->get_background_job_handler() ) ) {
259
-
260
- try {
261
-
262
- if ( $job_in_progress = $handler->get_job( $job_id ) ) {
263
-
264
- $result = [
265
- 'action' => $job_in_progress->action,
266
- 'id' => $job_in_progress->id,
267
- 'job_products_count' => count( $job_in_progress->product_ids ),
268
- 'percentage' => ( (float) count( $job_in_progress->processed_product_ids ) / max( 1, count( $job_in_progress->product_ids ) ) ) * 100,
269
- 'processed_products_count' => count( $job_in_progress->processed_product_ids ),
270
- 'skipped_products_count' => count( $job_in_progress->skipped_products ),
271
- 'status' => $job_in_progress->status,
272
- ];
273
-
274
- wp_send_json_success( $result );
275
- }
276
-
277
- } catch ( \Exception $e ) {
278
-
279
- wp_send_json_error( $e->getMessage() );
280
- }
281
- }
282
-
283
- /* translators: Placeholder: %s - sync job ID */
284
- wp_send_json_error( sprintf( esc_html__( 'No sync job in progress found %s', 'woocommerce-square' ), is_string( $job_id ) ? $job_id : null ) );
285
- }
286
-
287
-
288
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API.php DELETED
@@ -1,885 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect;
28
- use WooCommerce\Square\API\Requests;
29
- use WooCommerce\Square\API\Responses;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * WooCommerce Square API class
35
- *
36
- * @since 2.0.0
37
- */
38
- class API extends Framework\SV_WC_API_Base {
39
-
40
-
41
- /** catalog request type */
42
- const REQUEST_TYPE_CATALOG = 'catalog';
43
-
44
- /** inventory request type */
45
- const REQUEST_TYPE_INVENTORY = 'inventory';
46
-
47
-
48
- /** @var SquareConnect\ApiClient Square API client instance */
49
- protected $client;
50
-
51
-
52
- /**
53
- * Constructs the main Square API wrapper class.
54
- *
55
- * @since 2.0.0
56
- *
57
- * @param string $access_token Square API access token
58
- * @param bool $is_sandbox If sandbox access is desired
59
- */
60
- public function __construct( $access_token, $is_sandbox = null ) {
61
- $api_config = SquareConnect\Configuration::getDefaultConfiguration();
62
- $api_config->setAccessToken( $access_token );
63
-
64
- // Set sandbox URL if enabled.
65
- if ( $is_sandbox ) {
66
- $api_config->setHost( 'https://connect.squareupsandbox.com' );
67
- }
68
-
69
- $this->client = new SquareConnect\ApiClient( $api_config );
70
- }
71
-
72
-
73
- /** Catalog API Methods *******************************************************************************************/
74
-
75
-
76
- /**
77
- * Batch-deletes an array of catalog objects.
78
- *
79
- * @since 2.0.0
80
- *
81
- * @param string[] $object_ids array of square catalog object IDs
82
- * @return Responses\Catalog
83
- * @throws Framework\SV_WC_API_Exception
84
- */
85
- public function batch_delete_catalog_objects( array $object_ids ) {
86
-
87
- $request = $this->get_catalog_request();
88
- $request->set_batch_delete_catalog_objects_data( $object_ids );
89
-
90
- return $this->perform_request( $request );
91
- }
92
-
93
-
94
- /**
95
- * Batch-retrieves an array of catalog objects.
96
- *
97
- * @since 2.0.0
98
- *
99
- * @param string[] $object_ids array of square catalog object IDs
100
- * @param bool $include_related_objects whether or not to include related objects in the response
101
- * @return Responses\Catalog
102
- * @throws Framework\SV_WC_API_Exception
103
- */
104
- public function batch_retrieve_catalog_objects( array $object_ids, $include_related_objects = false ) {
105
-
106
- $request = $this->get_catalog_request();
107
- $request->set_batch_retrieve_catalog_objects_data( $object_ids, (bool) $include_related_objects );
108
-
109
- return $this->perform_request( $request );
110
- }
111
-
112
-
113
- /**
114
- * Batch-upserts an array of catalog objects.
115
- *
116
- * @since 2.0.0
117
- *
118
- * @param string $idempotency_key a UUID for this request
119
- * @param array $batches an array of batches to upsert
120
- * @return Responses\Catalog
121
- * @throws Framework\SV_WC_API_Exception
122
- */
123
- public function batch_upsert_catalog_objects( $idempotency_key, array $batches ) {
124
-
125
- $request = $this->get_catalog_request();
126
- $request->set_batch_upsert_catalog_objects_data( $idempotency_key, $batches );
127
-
128
- return $this->perform_request( $request );
129
- }
130
-
131
-
132
- /**
133
- * Returns info about the Catalog API, including helpful info like request size limits.
134
- *
135
- * @since 2.0.0
136
- * @return Responses\Catalog
137
- * @throws Framework\SV_WC_API_Exception
138
- */
139
- public function catalog_info() {
140
-
141
- $request = $this->get_catalog_request();
142
- $request->set_catalog_info_data();
143
-
144
- return $this->perform_request( $request );
145
- }
146
-
147
-
148
- /**
149
- * Deletes an object from the Square catalog.
150
- *
151
- * @since 2.0.0
152
- *
153
- * @param string $object_id Square catalog object ID
154
- * @return Responses\Catalog
155
- * @throws Framework\SV_WC_API_Exception
156
- */
157
- public function delete_catalog_object( $object_id ) {
158
-
159
- $request = $this->get_catalog_request();
160
- $request->set_delete_catalog_object_data( $object_id );
161
-
162
- return $this->perform_request( $request );
163
- }
164
-
165
-
166
- /**
167
- * Returns a list of Square catalog items.
168
- *
169
- * @since 2.0.0
170
- *
171
- * @param string $cursor the cursor to list from
172
- * @param string[] $types the item types to filter by
173
- * @return Responses\Catalog
174
- * @throws Framework\SV_WC_API_Exception
175
- */
176
- public function list_catalog( $cursor = '', $types = [] ) {
177
-
178
- $request = $this->get_catalog_request();
179
- $request->set_list_catalog_data( $cursor, $types );
180
-
181
- return $this->perform_request( $request );
182
- }
183
-
184
-
185
- /**
186
- * Retrieves a single catalog object.
187
- *
188
- * @since 2.0.0
189
- *
190
- * @param string $object_id the Square catalog object ID
191
- * @param bool $include_related_objects whether or not to include related objects (such as categories)
192
- * @return Responses\Catalog
193
- * @throws Framework\SV_WC_API_Exception
194
- */
195
- public function retrieve_catalog_object( $object_id, $include_related_objects = false ) {
196
-
197
- $request = $this->get_catalog_request();
198
- $request->set_retrieve_catalog_object_data( $object_id, $include_related_objects );
199
-
200
- return $this->perform_request( $request );
201
- }
202
-
203
-
204
- /**
205
- * Searches the catalog for objects.
206
- *
207
- * @since 2.0.0
208
- *
209
- * @param array $args see Catalog::set_search_catalog_objects_data() for list of args
210
- * @return Responses\Catalog
211
- * @throws Framework\SV_WC_API_Exception
212
- */
213
- public function search_catalog_objects( $args = [] ) {
214
-
215
- $request = $this->get_catalog_request();
216
- $request->set_search_catalog_objects_data( $args );
217
-
218
- return $this->perform_request( $request );
219
- }
220
-
221
-
222
- /**
223
- * Updates the modifier lists that apply to given items.
224
- *
225
- * @since 2.0.0
226
- *
227
- * @param string[] $item_ids array of Square catalog item IDs
228
- * @param string[] $modifier_lists_to_enable (optional) modifier list IDs to enable
229
- * @param string[] $modifier_lists_to_disable (optional) modifier list IDs to disable
230
- * @return Responses\Catalog
231
- * @throws Framework\SV_WC_API_Exception
232
- */
233
- public function update_item_modifier_lists( array $item_ids, array $modifier_lists_to_enable = [], array $modifier_lists_to_disable = [] ) {
234
-
235
- $request = $this->get_catalog_request();
236
- $request->set_update_item_modifier_lists_data( $item_ids, $modifier_lists_to_enable, $modifier_lists_to_disable );
237
-
238
- return $this->perform_request( $request );
239
- }
240
-
241
-
242
- /**
243
- * Updates an item's applied taxes.
244
- *
245
- * @since 2.0.0
246
- *
247
- * @param string[] $item_ids array of Square catalog item IDs
248
- * @param string[] $taxes_to_enable (optional) tax IDs to enable
249
- * @param string[] $taxes_to_disable (optional) tax IDs to disable
250
- * @return Responses\Catalog
251
- * @throws Framework\SV_WC_API_Exception
252
- */
253
- public function update_item_taxes( array $item_ids, array $taxes_to_enable = [], array $taxes_to_disable = [] ) {
254
-
255
- $request = $this->get_catalog_request();
256
- $request->set_update_item_taxes_data( $item_ids, $taxes_to_enable, $taxes_to_disable );
257
-
258
- return $this->perform_request( $request );
259
- }
260
-
261
-
262
- /**
263
- * Upserts an object into the catalog.
264
- *
265
- * @since 2.0.0
266
- *
267
- * @param string $idempotency_key UUID for this request
268
- * @param SquareConnect\Model\CatalogObject $object the object to upsert
269
- * @return Responses\Catalog
270
- * @throws Framework\SV_WC_API_Exception
271
- */
272
- public function upsert_catalog_object( $idempotency_key, $object ) {
273
-
274
- $request = $this->get_catalog_request();
275
- $request->set_upsert_catalog_object_data( $idempotency_key, $object );
276
-
277
- return $this->perform_request( $request );
278
- }
279
-
280
-
281
- /**
282
- * Creates an image in Square.
283
- *
284
- * Note that this method uses a custom request, since the Square SDK does not yet provide a method for image creation.
285
- *
286
- * @since 2.0.0
287
- *
288
- * @param $image_path
289
- * @param string $square_item_id
290
- * @param string $caption optional image caption
291
- * @return string
292
- * @throws Framework\SV_WC_API_Exception
293
- */
294
- public function create_image( $image_path, $square_item_id = '', $caption = '' ) {
295
-
296
- if ( ! is_readable( $image_path ) ) {
297
- throw new Framework\SV_WC_API_Exception( 'Image file is not readable' );
298
- }
299
-
300
- $image = file_get_contents( $image_path );
301
-
302
- $headers = [
303
- 'accept' => 'application/json',
304
- 'content-type' => 'multipart/form-data; boundary="boundary"',
305
- 'Square-Version' => '2019-05-08',
306
- 'Authorization' => 'Bearer ' . wc_square()->get_settings_handler()->get_access_token(),
307
- ];
308
-
309
- $body = '--boundary' . "\r\n";
310
- $body .= 'Content-Disposition: form-data; name="request"' . "\r\n";
311
- $body .= 'Content-Type: application/json' . "\r\n\r\n";
312
-
313
- $request = [
314
- 'idempotency_key' => wc_square()->get_idempotency_key(),
315
- 'image' => [
316
- 'type' => 'IMAGE',
317
- 'id' => '#TEMP_ID',
318
- 'image_data' => [
319
- 'caption' => esc_attr( $caption ),
320
- ],
321
- ],
322
- ];
323
-
324
- if ( $square_item_id ) {
325
- $request['object_id'] = $square_item_id;
326
- }
327
-
328
- $body .= json_encode( $request );
329
-
330
- $body .= "\r\n";
331
-
332
- $body .= '--boundary' . "\r\n";
333
- $body .= 'Content-Disposition: form-data; name="image"; filename="' . esc_attr( basename( $image_path ) ) . '"' . "\r\n";
334
- $body .= 'Content-Type: image/jpeg' . "\r\n\r\n";
335
- $body .= $image . "\r\n";
336
- $body .= '--boundary--';
337
-
338
- $response = wp_remote_post( 'https://connect.squareup.com/v2/catalog/images', [
339
- 'headers' => $headers,
340
- 'body' => $body,
341
- ] );
342
-
343
- if ( is_wp_error( $response ) ) {
344
- throw new Framework\SV_WC_API_Exception( $response->get_error_message() );
345
- }
346
-
347
- $body = wp_remote_retrieve_body( $response );
348
- $body = json_decode( $body, true );
349
-
350
- if ( ! is_array( $body ) ) {
351
- throw new Framework\SV_WC_API_Exception( 'Response was malformed' );
352
- }
353
-
354
- if ( ! empty( $body['errors'] ) || empty( $body['image']['id'] ) ) {
355
-
356
- if ( ! empty( $body['errors'][0]['detail'] ) ) {
357
- $message = $body['errors'][0]['detail'];
358
- } else {
359
- $message = 'Unknown error';
360
- }
361
-
362
- throw new Framework\SV_WC_API_Exception( $message );
363
- }
364
-
365
- return $body['image']['id'];
366
- }
367
-
368
-
369
- /** Inventory API Methods *****************************************************************************************/
370
-
371
-
372
- /**
373
- * Adds a count of inventory as "in-stock" to the given Square item variation ID as a result of a refund.
374
- *
375
- * @since 2.0.0
376
- *
377
- * @param string $square_id Square object ID
378
- * @param int $amount amount of inventory to add
379
- * @return Responses\Inventory
380
- * @throws Framework\SV_WC_API_Exception
381
- */
382
- public function add_inventory_from_refund( $square_id, $amount ) {
383
-
384
- return $this->add_inventory( $square_id, $amount, 'NONE' );
385
- }
386
-
387
-
388
- /**
389
- * Adds a count of inventory as "in-stock" to the given Square item variation ID.
390
- *
391
- * @since 2.0.0
392
- *
393
- * @param string $square_id Square object ID
394
- * @param int $amount amount of inventory to add
395
- * @param string $from_state the API state the inventory is coming from
396
- * @return Responses\Inventory
397
- * @throws Framework\SV_WC_API_Exception
398
- */
399
- public function add_inventory( $square_id, $amount, $from_state = 'NONE' ) {
400
-
401
- return $this->adjust_inventory( $square_id, $amount, $from_state, 'IN_STOCK' );
402
- }
403
-
404
-
405
- /**
406
- * Removes a count of inventory as "in-stock" to the given Square item variation ID.
407
- *
408
- * @since 2.0.0
409
- *
410
- * @param string $square_id Square object ID
411
- * @param int $amount amount of inventory to remove
412
- * @return Responses\Inventory
413
- * @throws Framework\SV_WC_API_Exception
414
- */
415
- public function remove_inventory( $square_id, $amount ) {
416
-
417
- return $this->adjust_inventory( $square_id, $amount, 'IN_STOCK', 'SOLD' );
418
- }
419
-
420
-
421
- /**
422
- * Performs an inventory adjustment.
423
- *
424
- * @since 2.0.0
425
- *
426
- * @param string $square_id Square object ID
427
- * @param int $amount amount of inventory to add
428
- * @param string $from_state the API state the inventory is coming from
429
- * @param string $to_state the API state the inventory is changing to
430
- * @return Responses\Inventory
431
- * @throws Framework\SV_WC_API_Exception
432
- */
433
- protected function adjust_inventory( $square_id, $amount, $from_state, $to_state ) {
434
-
435
- $date = new \DateTime();
436
-
437
- $change = new SquareConnect\Model\InventoryChange();
438
- $change->setType( 'ADJUSTMENT' );
439
- $change->setAdjustment( new SquareConnect\Model\InventoryAdjustment( [
440
- 'catalog_object_id' => $square_id,
441
- 'location_id' => $this->get_plugin()->get_settings_handler()->get_location_id(),
442
- 'quantity' => (string) absint( $amount ),
443
- 'from_state' => $from_state,
444
- 'to_state' => $to_state,
445
- 'occurred_at' => $date->format( DATE_ATOM ),
446
- ] ) );
447
-
448
- return $this->batch_change_inventory( uniqid( '', false ), [
449
- $change,
450
- ] );
451
- }
452
-
453
-
454
- /**
455
- * Performs a Batch Change Inventory request.
456
- *
457
- * @since 2.0.0
458
- *
459
- * @param string $idempotency_key UUID for this request
460
- * @param SquareConnect\Model\InventoryChange[] $changes array of Inventory Changes
461
- * @param bool $ignore_unchanged_counts whether the current physical count should be ignored if the quantity is unchanged since the last physical count
462
- * @return Responses\Inventory
463
- * @throws Framework\SV_WC_API_Exception
464
- */
465
- public function batch_change_inventory( $idempotency_key, $changes, $ignore_unchanged_counts = true ) {
466
-
467
- $request = $this->get_inventory_request();
468
- $request->set_batch_change_inventory_data( $idempotency_key, $changes, $ignore_unchanged_counts );
469
-
470
- return $this->perform_request( $request );
471
- }
472
-
473
-
474
- /**
475
- * Performs a Batch Retrieve Inventory Changes request.
476
- *
477
- * @since 2.0.0
478
- *
479
- * @param array $args see Requests\Inventory::set_batch_retrieve_inventory_changes_data() for accepted arguments
480
- *
481
- * @return Responses\Inventory
482
- * @throws Framework\SV_WC_API_Exception
483
- */
484
- public function batch_retrieve_inventory_changes( array $args = [] ) {
485
-
486
- $request = $this->get_inventory_request();
487
- $request->set_batch_retrieve_inventory_changes_data( $args );
488
-
489
- return $this->perform_request( $request );
490
- }
491
-
492
-
493
- /**
494
- * Performs a Batch Retrieve Inventory Counts request.
495
- *
496
- * @since 2.0.0
497
- *
498
- * @param array $args see Requests\Inventory::set_batch_retrieve_inventory_counts_data() for accepted arguments
499
- *
500
- * @return Responses\Inventory
501
- * @throws Framework\SV_WC_API_Exception
502
- */
503
- public function batch_retrieve_inventory_counts( array $args = [] ) {
504
-
505
- $request = $this->get_inventory_request();
506
- $request->set_batch_retrieve_inventory_counts_data( $args );
507
-
508
- return $this->perform_request( $request );
509
- }
510
-
511
-
512
- /**
513
- * Performs a Retrieve Inventory Adjustment request.
514
- *
515
- * @since 2.0.0
516
- *
517
- * @param string $adjustment_id the InventoryAdjustment ID to retrieve
518
- *
519
- * @return Responses\Inventory
520
- * @throws Framework\SV_WC_API_Exception
521
- */
522
- public function retrieve_inventory_adjustment( $adjustment_id ) {
523
-
524
- $request = $this->get_inventory_request();
525
- $request->set_retrieve_inventory_adjustment_data( $adjustment_id );
526
-
527
- return $this->perform_request( $request );
528
- }
529
-
530
-
531
- /**
532
- * Performs a Retrieve Inventory Changes request.
533
- *
534
- * @since 2.0.0
535
- *
536
- * @param string $catalog_object_id the CatalogObject ID to retrieve
537
- *
538
- * @return Responses\Inventory
539
- * @throws Framework\SV_WC_API_Exception
540
- */
541
- public function retrieve_inventory_changes( $catalog_object_id ) {
542
-
543
- $request = $this->get_inventory_request();
544
- $request->set_retrieve_inventory_changes_data( $catalog_object_id );
545
-
546
- return $this->perform_request( $request );
547
- }
548
-
549
-
550
- /**
551
- * Performs a Retrieve Inventory Count request.
552
- *
553
- * @since 2.0.0
554
- *
555
- * @param string $catalog_object_id the CatalogObject ID to retrieve
556
- * @return Responses\Inventory
557
- * @throws Framework\SV_WC_API_Exception
558
- */
559
- public function retrieve_inventory_count( $catalog_object_id ) {
560
-
561
- $request = $this->get_inventory_request();
562
- $request->set_retrieve_inventory_count_data( $catalog_object_id, [ $this->get_plugin()->get_settings_handler()->get_location_id() ] );
563
-
564
- return $this->perform_request( $request );
565
- }
566
-
567
-
568
- /**
569
- * Performs a Retrieve Inventory Physical Count request.
570
- *
571
- * @since 2.0.0
572
- *
573
- * @param string $physical_count_id the InventoryPhysicalCount ID to retrieve
574
- *
575
- * @return Responses\Inventory
576
- * @throws Framework\SV_WC_API_Exception
577
- */
578
- public function retrieve_inventory_physical_count( $physical_count_id ) {
579
-
580
- $request = $this->get_inventory_request();
581
- $request->set_retrieve_inventory_physical_count_data( $physical_count_id );
582
-
583
- return $this->perform_request( $request );
584
- }
585
-
586
-
587
- /** Locations methods *********************************************************************************************/
588
-
589
-
590
- /**
591
- * Gets the available locations.
592
- *
593
- * @since 2.0.0
594
- *
595
- * @return SquareConnect\Model\Location[]
596
- * @throws Framework\SV_WC_API_Exception
597
- */
598
- public function get_locations() {
599
-
600
- $request = new API\Requests\Locations( $this->client );
601
-
602
- $request->set_list_locations_data();
603
-
604
- $this->set_response_handler( API\Responses\Locations::class );
605
-
606
- /* @type API\Responses\Locations $response */
607
- $response = $this->perform_request( $request );
608
-
609
- return $response->get_locations();
610
- }
611
-
612
-
613
- /** Customer methods **********************************************************************************************/
614
-
615
-
616
- /**
617
- * Gets all customers.
618
- *
619
- * @since 2.0.0
620
- *
621
- * @param string $cursor pagination cursor
622
- * @return API\Response
623
- * @throws Framework\SV_WC_API_Exception
624
- */
625
- public function get_customers( $cursor = '' ) {
626
-
627
- $request = new API\Requests\Customers( $this->client );
628
-
629
- $request->set_get_customers_data( $cursor );
630
-
631
- $this->set_response_handler( API\Response::class );
632
-
633
- return $this->perform_request( $request );
634
- }
635
-
636
-
637
- /** Request Helper Methods ****************************************************************************************/
638
-
639
-
640
- /**
641
- * Gets a new Catalog API request.
642
- *
643
- * @since 2.0.0
644
- *
645
- * @return Requests\Catalog
646
- * @throws Framework\SV_WC_API_Exception
647
- */
648
- protected function get_catalog_request() {
649
-
650
- return $this->get_new_request( self::REQUEST_TYPE_CATALOG );
651
- }
652
-
653
-
654
- /**
655
- * Gets a new Inventory API request.
656
- *
657
- * @since 2.0.0
658
- *
659
- * @return Requests\Inventory
660
- * @throws Framework\SV_WC_API_Exception
661
- */
662
- protected function get_inventory_request() {
663
-
664
- return $this->get_new_request( self::REQUEST_TYPE_INVENTORY );
665
- }
666
-
667
-
668
- /**
669
- * Gets a new request object.
670
- *
671
- * @since 2.0.0
672
- *
673
- * @param string $type desired request type
674
- * @return Requests\Catalog|Requests\Inventory
675
- * @throws Framework\SV_WC_API_Exception
676
- */
677
- protected function get_new_request( $type = '' ) {
678
-
679
- switch ( $type ) {
680
-
681
- case self::REQUEST_TYPE_CATALOG:
682
- $request = new Requests\Catalog( $this->client );
683
- $response_handler = Responses\Catalog::class;
684
- break;
685
-
686
- case self::REQUEST_TYPE_INVENTORY:
687
- $request = new Requests\Inventory( $this->client );
688
- $response_handler = Responses\Inventory::class;
689
- break;
690
-
691
- default:
692
- throw new Framework\SV_WC_API_Exception( 'Invalid request type.' );
693
- }
694
-
695
- $this->set_response_handler( $response_handler );
696
-
697
- return $request;
698
- }
699
-
700
-
701
- /**
702
- * Performs an API request.
703
- *
704
- * @see Framework\SV_WC_API_Base::perform_request()
705
- *
706
- * @since 2.0.0
707
- *
708
- * @param API\Request $request request object
709
- * @return Framework\SV_WC_API_Response
710
- * @throws Framework\SV_WC_API_Exception
711
- */
712
- protected function perform_request( $request ) {
713
-
714
- // ensure API is in its default state
715
- $this->reset_response();
716
-
717
- // save the request object
718
- $this->request = $request;
719
-
720
- $start_time = microtime( true );
721
-
722
- try {
723
-
724
- // set the request URI to the Square SDK method for better logging
725
- $this->request_uri = $this->get_request()->get_square_api_method();
726
- $this->request_method = '';
727
-
728
- // add any query args to the logged request URI for easier debugging
729
- foreach ( $this->get_request()->get_square_api_args() as $arg ) {
730
-
731
- if ( is_string( $arg ) ) {
732
- $this->request_uri .= "/{$arg}";
733
- }
734
- }
735
-
736
- // perform the request
737
- $response = $this->do_square_request( $this->get_request()->get_square_api(), $this->get_request()->get_square_api_method(), $this->get_request()->get_square_api_args() );
738
-
739
- // calculate request duration
740
- $this->request_duration = round( microtime( true ) - $start_time, 5 );
741
-
742
- // parse & validate response
743
- $response = $this->handle_response( $response );
744
-
745
- } catch ( Framework\SV_WC_API_Exception $e ) {
746
-
747
- // alert other actors that a request has been made
748
- $this->broadcast_request();
749
-
750
- throw $e;
751
- }
752
-
753
- return $response;
754
- }
755
-
756
-
757
- /**
758
- * Handles and parses the response.
759
- *
760
- * @since 2.0.0
761
- *
762
- * @param array|\WP_Error $response response data
763
- * @throws Framework\SV_WC_API_Exception
764
- * @return Framework\SV_WC_API_Response|object request class instance that implements SV_WC_API_Request
765
- */
766
- protected function handle_response( $response ) {
767
-
768
- // allow child classes to validate response prior to parsing
769
- $this->do_pre_parse_response_validation();
770
-
771
- // parse the response body and tie it to the request
772
- $this->response = $this->get_parsed_response( $this->raw_response_body );
773
-
774
- // allow child classes to validate response after parsing -- this is useful
775
- // for checking error codes/messages included in a parsed response
776
- $this->do_post_parse_response_validation();
777
-
778
- // fire do_action() so other actors can act on request/response data,
779
- // primarily used for logging
780
- $this->broadcast_request();
781
-
782
- return $this->response;
783
- }
784
-
785
-
786
- /**
787
- * Validates the response data after it's been parsed.
788
- *
789
- * @since 2.0.0
790
- *
791
- * @return bool
792
- * @throws Framework\SV_WC_API_Exception
793
- */
794
- protected function do_post_parse_response_validation() {
795
-
796
- if ( ! $this->get_response()->has_errors() ) {
797
- return true;
798
- }
799
-
800
- $errors = [];
801
-
802
- foreach ( $this->get_response()->get_errors() as $error ) {
803
- if ( empty( $error->code ) ) {
804
- continue;
805
- }
806
-
807
- $errors[] = trim( "[{$error->code}] {$error->detail}" );
808
-
809
- // Last attempt to refresh access token.
810
- if ( 'ACCESS_TOKEN_EXPIRED' == $error->code ) {
811
- $this->get_plugin()->log( 'Access Token Expired, attempting a refresh.' );
812
- $this->get_plugin()->get_connection_handler()->refresh_connection();
813
-
814
- $failure_value = get_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
815
-
816
- if ( empty( $failure_value ) ) {
817
- // Successfully refreshed on the last attempt
818
- $this->get_plugin()->log( 'Connection successfully refreshed.' );
819
- return true;
820
- }
821
- }
822
-
823
- // if the error indicates that access token is bad, disconnect the plugin to prevent further attempts
824
- if ( in_array( $error->code, [ 'ACCESS_TOKEN_EXPIRED', 'ACCESS_TOKEN_REVOKED' ], true ) ) {
825
- $this->get_plugin()->get_connection_handler()->disconnect();
826
- $this->get_plugin()->log( 'Disconnected due to invalid authorization. Please try connecting again.' );
827
- }
828
- }
829
-
830
- // At this point we could not validate the response and assume a failed attempt.
831
- throw new Framework\SV_WC_API_Exception( implode( ' | ', $errors ) );
832
- }
833
-
834
- /**
835
- * Performs a remote request with the Square API class.
836
- *
837
- * @since 2.0.0
838
- *
839
- * @param Object $square_api the square API class instance
840
- * @param string $method the class method to call
841
- * @param array $args the args to send with the method call
842
- * @throws Framework\SV_WC_API_Exception
843
- */
844
- protected function do_square_request( $square_api, $method, $args ) {
845
-
846
- if ( ! is_callable( [ $square_api, $method ] ) ) {
847
- throw new Framework\SV_WC_API_Exception( 'Invalid API method' );
848
- }
849
-
850
- try {
851
-
852
- // perform the request
853
- $response = call_user_func_array( [ $square_api, $method ], $args );
854
-
855
- if ( is_array( $response ) && $this->request->get_with_http_info() ) {
856
- $this->response_code = isset( $response[1] ) ? (int) $response[1] : 400;
857
- $this->response_headers = isset( $response[2] ) ? (array) $response[2] : [];
858
- $this->raw_response_body = isset( $response[0] ) ? $response[0] : [];
859
- } else {
860
- $this->raw_response_body = $response;
861
- }
862
-
863
- } catch ( SquareConnect\ApiException $exception ) {
864
-
865
- $this->response_code = $exception->getCode();
866
- $this->response_headers = $exception->getResponseHeaders();
867
- $this->raw_response_body = $exception->getResponseBody();
868
- }
869
- }
870
-
871
-
872
- /**
873
- * Gets the main plugin instance.
874
- *
875
- * @since 2.0.0
876
- *
877
- * @return \WooCommerce\Square\Plugin
878
- */
879
- public function get_plugin() {
880
-
881
- return wc_square();
882
- }
883
-
884
-
885
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Request.php DELETED
@@ -1,206 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Configuration;
28
-
29
- defined( 'ABSPATH' ) or exit;
30
-
31
- /**
32
- * Base WooCommerce Square API request object.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Request implements Framework\SV_WC_API_Request {
37
-
38
-
39
- /** @var Configuration the configuration object */
40
- protected $configuration;
41
-
42
- /** @var mixed the Square API class instance being used for this request */
43
- protected $square_api;
44
-
45
- /** @var string method name on the square API to call */
46
- protected $square_api_method;
47
-
48
- /** @var array arguments for the method call */
49
- protected $square_api_args = [];
50
-
51
- /** @var null|object the square API request model */
52
- protected $square_request;
53
-
54
- /** @var bool whether the request is being made 'WithHTTPInfo' or not */
55
- protected $with_http_info = true;
56
-
57
-
58
- /**
59
- * Gets the Square API instance to use for this request.
60
- *
61
- * @since 2.0.0
62
- *
63
- * @return mixed
64
- */
65
- public function get_square_api() {
66
-
67
- return $this->square_api;
68
- }
69
-
70
-
71
- /**
72
- * Get the method to call on the Square API instance.
73
- *
74
- * @since 2.0.0
75
- *
76
- * @return string
77
- */
78
- public function get_square_api_method() {
79
-
80
- $method = $this->square_api_method;
81
-
82
- return $this->with_http_info ? $method . 'WithHttpInfo' : $method;
83
- }
84
-
85
-
86
- /**
87
- * Gets the arguments to call the Square API method with.
88
- *
89
- * @since 2.0.0
90
- *
91
- * @return array
92
- */
93
- public function get_square_api_args() {
94
-
95
- return $this->square_api_args;
96
- }
97
-
98
-
99
- /**
100
- * Returns whether this request is set to get HTTP info.
101
- *
102
- * @since 2.0.0
103
- *
104
- * @return bool
105
- */
106
- public function get_with_http_info() {
107
-
108
- return $this->with_http_info;
109
- }
110
-
111
-
112
- /**
113
- * Gets the HTTP method.
114
- *
115
- * @since 2.0.0
116
- *
117
- * @return string
118
- */
119
- public function get_method() {
120
- // TODO: Implement get_method() method.
121
- }
122
-
123
-
124
- /**
125
- * Gets the query parameters.
126
- *
127
- * @since 2.0.0
128
- *
129
- * @return array
130
- */
131
- public function get_params() {
132
- // TODO: Implement get_params() method.
133
- }
134
-
135
-
136
- /**
137
- * Gets the path.
138
- *
139
- * @since 2.0.0
140
- *
141
- * @return string
142
- */
143
- public function get_path() {
144
- // TODO: Implement get_path() method.
145
- }
146
-
147
-
148
- /**
149
- * Gets the request data.
150
- *
151
- * @since 2.0.0
152
- *
153
- * @return array
154
- */
155
- public function get_data() {
156
- // TODO: Implement get_data() method.
157
- }
158
-
159
-
160
- /**
161
- * Gets the request data as a string.
162
- *
163
- * @since 2.0.0
164
- *
165
- * @return string
166
- */
167
- public function to_string() {
168
-
169
- $body = '';
170
-
171
- if ( is_callable( [ $this->square_request, '__toString' ] ) ) {
172
-
173
- $body = $this->square_request->__toString();
174
-
175
- } elseif ( is_array( $this->square_api_args ) ) {
176
-
177
- $body = [];
178
-
179
- foreach ( $this->square_api_args as $key => $arg ) {
180
-
181
- if ( is_callable( [ $arg, '__toString' ] ) ) {
182
- $body[ $key ] = $arg->__toString();
183
- }
184
- }
185
-
186
- $body = implode( ',', $body );
187
- }
188
-
189
- return $body;
190
- }
191
-
192
-
193
- /**
194
- * Gets the request data as a string with all sensitive information masked.
195
- *
196
- * @since 2.0.0
197
- *
198
- * @return string
199
- */
200
- public function to_string_safe() {
201
-
202
- return $this->to_string();
203
- }
204
-
205
-
206
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Requests/Catalog.php DELETED
@@ -1,288 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Requests;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model as SquareModel;
28
- use SquareConnect\Api\CatalogApi;
29
- use WooCommerce\Square\API\Request;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * WooCommerce Square Catalog API Request class.
35
- *
36
- * @since 2.0.0
37
- */
38
- class Catalog extends Request {
39
-
40
-
41
- /**
42
- * Initializes a new Catalog request.
43
- *
44
- * @since 2.0.0
45
- *
46
- * @param \SquareConnect\ApiClient $api_client the API client
47
- */
48
- public function __construct( $api_client ) {
49
-
50
- $this->square_api = new CatalogApi( $api_client );
51
- }
52
-
53
-
54
- /**
55
- * Sets the data for a batchDeleteCatalogObjects request.
56
- *
57
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-batchdeletecatalogobjects
58
- * @see \SquareConnect\Api\CatalogApi::batchDeleteCatalogObjects()
59
- *
60
- * @since 2.0.0
61
- *
62
- * @param string[] $object_ids the square catalog object IDs to delete
63
- */
64
- public function set_batch_delete_catalog_objects_data( array $object_ids ) {
65
-
66
- $this->square_api_method = 'batchDeleteCatalogObjects';
67
- $this->square_api_args = [ new SquareModel\BatchDeleteCatalogObjectsRequest( [ 'object_ids' => $object_ids ] ) ];
68
- }
69
-
70
-
71
- /**
72
- * Sets the data for a batchRetrieveCatalogObjects request.
73
- *
74
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-batchretrievecatalogobjects
75
- * @see \SquareConnect\Api\CatalogApi::batchRetrieveCatalogObjects()
76
- *
77
- * @since 2.0.0
78
- *
79
- * @param string[] $object_ids the square catalog object IDs to delete
80
- * @param bool $include_related_objects whether or not to include related objects in the response
81
- */
82
- public function set_batch_retrieve_catalog_objects_data( array $object_ids, $include_related_objects = false ) {
83
-
84
- $this->square_api_method = 'batchRetrieveCatalogObjects';
85
- $this->square_api_args = [ new SquareModel\BatchRetrieveCatalogObjectsRequest( [
86
- 'object_ids' => $object_ids,
87
- 'include_related_objects' => (bool) $include_related_objects
88
- ] ) ];
89
- }
90
-
91
-
92
- /**
93
- * Sets the data for a batchUpsertCatalogObjects request.
94
- *
95
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-batchupsertcatalogobjects
96
- * @see \SquareConnect\Api\CatalogApi::batchUpsertCatalogObjects()
97
- *
98
- * @since 2.0.0
99
- *
100
- * @param string $idempotency_key the UUID for this request
101
- * @param SquareModel\CatalogObjectBatch[] $batches array of catalog object batches
102
- */
103
- public function set_batch_upsert_catalog_objects_data( $idempotency_key, array $batches ) {
104
-
105
- $this->square_api_method = 'batchUpsertCatalogObjects';
106
- $this->square_api_args = [ new SquareModel\BatchUpsertCatalogObjectsRequest( [
107
- 'idempotency_key' => $idempotency_key,
108
- 'batches' => $batches,
109
- ] ) ];
110
- }
111
-
112
-
113
- /**
114
- * Sets the data for a catalogInfo request.
115
- *
116
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-cataloginfo
117
- * @see \SquareConnect\Api\CatalogApi::catalogInfo()
118
- *
119
- * @since 2.0.0
120
- *
121
- * @param string $cursor
122
- * @param array $types
123
- */
124
- public function set_catalog_info_data( $cursor = '', $types = [] ) {
125
-
126
- $this->square_api_method = 'catalogInfo';
127
- }
128
-
129
-
130
- /**
131
- * Sets the data for a deleteCatalogObject request.
132
- *
133
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-deletecatalogobject
134
- * @see \SquareConnect\Api\CatalogApi::deleteCatalogObject()
135
- *
136
- * @since 2.0.0
137
- *
138
- * @param string $object_id the Square catalog object ID to delete
139
- */
140
- public function set_delete_catalog_object_data( $object_id ) {
141
-
142
- $this->square_api_method = 'deleteCatalogObject';
143
- $this->square_api_args = [ $object_id ];
144
- }
145
-
146
-
147
- /**
148
- * Sets the data for a listCatalog request.
149
- *
150
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-listcatalog
151
- * @see \SquareConnect\Api\CatalogApi::listCatalog()
152
- *
153
- * @since 2.0.0
154
- *
155
- * @param string $cursor (optional) the pagination cursor
156
- * @param array $types (optional) the catalog item types to filter by
157
- */
158
- public function set_list_catalog_data( $cursor = '', $types = [] ) {
159
-
160
- $this->square_api_method = 'listCatalog';
161
- $this->square_api_args = [
162
- 'cursor' => $cursor,
163
- 'types' => is_array( $types ) ? implode( ',', array_map( 'strtoupper', $types ) ) : ''
164
- ];
165
- }
166
-
167
-
168
- /**
169
- * Sets the data for a retrieveCatalogObject request.
170
- *
171
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-retrievecatalogobject
172
- * @see \SquareConnect\Api\CatalogApi::retrieveCatalogObject()
173
- *
174
- * @since 2.0.0
175
- *
176
- * @param string $object_id the Square catalog object ID to retrieve
177
- * @param bool whether or not to include related objects (such as categories)
178
- */
179
- public function set_retrieve_catalog_object_data( $object_id, $include_related_objects = false ) {
180
-
181
- $this->square_api_method = 'retrieveCatalogObject';
182
- $this->square_api_args = [ $object_id, (bool) $include_related_objects ];
183
- }
184
-
185
-
186
- /**
187
- * Sets the data for a searchCatalogObjects request.
188
- *
189
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-searchcatalogobjects
190
- * @see \SquareConnect\Api\CatalogApi::searchCatalogObjects()
191
- *
192
- * @since 2.0.0
193
- *
194
- * @param array $args see Square documentation for full list of args allowed
195
- */
196
- public function set_search_catalog_objects_data( array $args = [] ) {
197
-
198
- // convert object types to array
199
- if ( isset( $args['object_types'] ) && ! is_array( $args['object_types'] ) ) {
200
- $args['object_types'] = [ $args['object_types'] ];
201
- }
202
-
203
- $defaults = [
204
- 'cursor' => null,
205
- 'object_types' => null,
206
- 'include_deleted_objects' => null,
207
- 'include_related_objects' => null,
208
- 'begin_time' => null,
209
- 'query' => null,
210
- 'limit' => null,
211
- ];
212
-
213
- // apply defaults and remove any keys that aren't recognized
214
- $args = array_intersect_key( wp_parse_args( $args, $defaults ), $defaults );
215
-
216
- $this->square_api_method = 'searchCatalogObjects';
217
- $this->square_api_args = [ new SquareModel\SearchCatalogObjectsRequest( $args ) ];
218
- }
219
-
220
-
221
- /**
222
- * Sets the data for a updateItemModifierLists request.
223
- *
224
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-updateitemmodifierlists
225
- * @see \SquareConnect\Api\CatalogApi::updateItemModifierLists()
226
- *
227
- * @since 2.0.0
228
- *
229
- * @param string[] $item_ids array of item IDs to update
230
- * @param string[] $modifier_lists_to_enable array of list IDs to enable
231
- * @param string[] $modifier_lists_to_disable array of list IDs to disable
232
- */
233
- public function set_update_item_modifier_lists_data( array $item_ids, array $modifier_lists_to_enable = [], array $modifier_lists_to_disable = [] ) {
234
-
235
- $this->square_api_method = 'updateItemModifierLists';
236
- $this->square_api_args = [ new SquareModel\UpdateItemModifierListsRequest( [
237
- 'item_ids' => $item_ids,
238
- 'modifier_lists_to_enable' => $modifier_lists_to_enable,
239
- 'modifier_lists_to_disable' => $modifier_lists_to_disable,
240
- ] ) ];
241
- }
242
-
243
-
244
- /**
245
- * Sets the data for an updateItemTaxes request.
246
- *
247
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-updateitemtaxes
248
- * @see \SquareConnect\Api\CatalogApi::updateItemTaxes()
249
- *
250
- * @since 2.0.0
251
- *
252
- * @param string[] $item_ids array of item IDs to update
253
- * @param string[] $taxes_to_enable array of catalog tax IDs to enable
254
- * @param string[] $taxes_to_disable array of catalog tax IDs to disable
255
- */
256
- public function set_update_item_taxes_data( array $item_ids, array $taxes_to_enable = [], array $taxes_to_disable = [] ) {
257
-
258
- $this->square_api_method = 'updateItemTaxes';
259
- $this->square_api_args = [ new SquareModel\UpdateItemTaxesRequest( [
260
- 'item_ids' => $item_ids,
261
- 'taxes_to_enable' => $taxes_to_enable,
262
- 'taxes_to_disable' => $taxes_to_disable,
263
- ] ) ];
264
- }
265
-
266
-
267
- /**
268
- * Sets the data for an upsertCatalogObject request.
269
- *
270
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-catalog-upsertcatalogobject
271
- * @see \SquareConnect\Api\CatalogApi::upsertCatalogObject()
272
- *
273
- * @since 2.0.0
274
- *
275
- * @param string $idempotency_key a UUID for this request
276
- * @param SquareModel\CatalogObject $object the object to update
277
- */
278
- public function set_upsert_catalog_object_data( $idempotency_key, $object ) {
279
-
280
- $this->square_api_method = 'upsertCatalogObject';
281
- $this->square_api_args = [ new SquareModel\UpsertCatalogObjectRequest( [
282
- 'idempotency_key' => $idempotency_key,
283
- 'object' => $object,
284
- ] ) ];
285
- }
286
-
287
-
288
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Requests/Customers.php DELETED
@@ -1,84 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Requests;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SquareConnect\Api\CustomersApi;
29
- use WooCommerce\Square\API;
30
-
31
- /**
32
- * The customers API request class.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Customers extends API\Request {
37
-
38
-
39
- /**
40
- * Initializes a new customer request.
41
- *
42
- * @since 2.0.0
43
- *
44
- * @param \SquareConnect\ApiClient $api_client the API client
45
- */
46
- public function __construct( $api_client ) {
47
-
48
- $this->square_api = new CustomersApi( $api_client );
49
- }
50
-
51
-
52
- /**
53
- * Sets the data for getting an existing customer.
54
- *
55
- * @since 2.0.0
56
- *
57
- * @param string $customer_id customer ID
58
- */
59
- public function set_get_customer_data( $customer_id ) {
60
-
61
- $this->square_api_method = 'retrieveCustomer';
62
-
63
- $this->square_api_args = [ $customer_id ];
64
- }
65
-
66
-
67
- /**
68
- * Sets the data for getting all existing customer.
69
- *
70
- * @since 2.0.0
71
- *
72
- * @param string $cursor pagination cursor
73
- */
74
- public function set_get_customers_data( $cursor = '' ) {
75
-
76
- $this->square_api_method = 'listCustomers';
77
-
78
- if ( $cursor ) {
79
- $this->square_api_args = [ 'cursor' => $cursor ];
80
- }
81
- }
82
-
83
-
84
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Requests/Inventory.php DELETED
@@ -1,214 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Requests;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model as SquareModel;
28
- use SquareConnect\Api\InventoryApi;
29
- use WooCommerce\Square\API\Request;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * WooCommerce Square Inventory API Request class
35
- *
36
- * @since 2.0.0
37
- */
38
- class Inventory extends Request {
39
-
40
-
41
- /**
42
- * Initializes a new Inventory request.
43
- *
44
- * @since 2.0.0
45
- *
46
- * @param \SquareConnect\ApiClient $api_client the API client
47
- */
48
- public function __construct( $api_client ) {
49
-
50
- $this->square_api = new InventoryApi( $api_client );
51
- }
52
-
53
-
54
- /**
55
- * Sets the data for a batchChangeInventory request.
56
- *
57
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-batchchangeinventory
58
- * @see InventoryApi::batchChangeInventory()
59
- *
60
- * @since 2.0.0
61
- *
62
- * @param string $idempotency_key a UUID for this request
63
- * @param SquareModel\InventoryChange[] $changes array of inventory changes to be made
64
- * @param bool $ignore_unchanged_counts whether the current physical count should be ignored if the quantity is unchanged since the last physical count
65
- */
66
- public function set_batch_change_inventory_data( $idempotency_key, $changes, $ignore_unchanged_counts = true ) {
67
-
68
- $this->square_api_method = 'batchChangeInventory';
69
- $this->square_api_args = [ new SquareModel\BatchChangeInventoryRequest( [
70
- 'idempotency_key' => $idempotency_key,
71
- 'changes' => $changes,
72
- 'ignore_unchanged_counts' => (bool) $ignore_unchanged_counts
73
- ] ) ];
74
- }
75
-
76
-
77
- /**
78
- * Sets the data for a batchRetrieveInventoryChanges request.
79
- *
80
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-batchretrieveinventorychanges
81
- * @see InventoryApi::batchRetrieveInventoryChanges()
82
- *
83
- * @since 2.0.0
84
- *
85
- * @param array $args
86
- * @type string[] $catalog_object_ids filters results by CatalogObject ID
87
- * @type string[] $location_ids filters results by Location ID
88
- * @type string[] $types filters results by InventoryChangeType
89
- * @type string[] $states filters ADJUSTMENT query results by InventoryState
90
- * @type string $updated_after filters any changes updated after this time
91
- * @type string $updated_before filters any changes updated before this time
92
- * @type string $cursor pagination cursor
93
- */
94
- public function set_batch_retrieve_inventory_changes_data( $args = [] ) {
95
-
96
- $defaults = [
97
- 'catalog_object_ids' => null,
98
- 'location_ids' => null,
99
- 'types' => null,
100
- 'states' => null,
101
- 'updated_after' => null,
102
- 'updated_before' => null,
103
- 'cursor' => null,
104
- ];
105
-
106
- // apply defaults and remove any keys that aren't recognized
107
- $args = array_intersect_key( wp_parse_args( $args, $defaults ), $defaults );
108
-
109
- $this->square_api_method = 'batchRetrieveInventoryChanges';
110
- $this->square_api_args = [ new SquareModel\BatchRetrieveInventoryChangesRequest( $args ) ];
111
- }
112
-
113
-
114
- /**
115
- * Sets the data for a batchRetrieveInventoryCounts request.
116
- *
117
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-batchretrieveinventorycounts
118
- * @see InventoryApi::batchRetrieveInventoryCounts()
119
- *
120
- * @since 2.0.0
121
- *
122
- * @param array $args
123
- * @type string[] $catalog_object_ids filters results by CatalogObject ID
124
- * @type string[] $location_ids filters results by Location ID
125
- * @type string $updated_after filters any changes updated after this time
126
- * @type string $cursor pagination cursor
127
- */
128
- public function set_batch_retrieve_inventory_counts_data( $args = [] ) {
129
-
130
- $defaults = [
131
- 'catalog_object_ids' => null,
132
- 'location_ids' => null,
133
- 'updated_after' => null,
134
- 'cursor' => null,
135
- ];
136
-
137
- // apply defaults and remove any keys that aren't recognized
138
- $args = array_intersect_key( wp_parse_args( $args, $defaults ), $defaults );
139
-
140
- $this->square_api_method = 'batchRetrieveInventoryCounts';
141
- $this->square_api_args = [ new SquareModel\BatchRetrieveInventoryCountsRequest( $args ) ];
142
- }
143
-
144
-
145
- /**
146
- * Sets the data for a retrieveInventoryAdjustment request.
147
- *
148
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-retrieveinventoryadjustment
149
- * @see InventoryApi::retrieveInventoryAdjustment()
150
- *
151
- * @since 2.0.0
152
- *
153
- * @param string $adjustment_id the InventoryAdjustment ID to retrieve
154
- */
155
- public function set_retrieve_inventory_adjustment_data( $adjustment_id ) {
156
-
157
- $this->square_api_method = 'retrieveInventoryAdjustment';
158
- $this->square_api_args = [ $adjustment_id ];
159
- }
160
-
161
-
162
- /**
163
- * Sets the data for a retrieveInventoryChanges request.
164
- *
165
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-retrieveinventorychanges
166
- * @see InventoryApi::retrieveInventoryChanges()
167
- *
168
- * @since 2.0.0
169
- *
170
- * @param string $catalog_object_id the CatalogObject ID to retrieve
171
- */
172
- public function set_retrieve_inventory_changes_data( $catalog_object_id ) {
173
-
174
- $this->square_api_method = 'retrieveInventoryChanges';
175
- $this->square_api_args = [ $catalog_object_id ];
176
- }
177
-
178
-
179
- /**
180
- * Sets the data for a retrieveInventoryCount request.
181
- *
182
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-retrieveinventorycount
183
- * @see InventoryApi::retrieveInventoryCount()
184
- *
185
- * @since 2.0.0
186
- *
187
- * @param string $catalog_object_id the CatalogObject ID to retrieve
188
- * @param string[] $location_ids location IDs
189
- */
190
- public function set_retrieve_inventory_count_data( $catalog_object_id, array $location_ids = [] ) {
191
-
192
- $this->square_api_method = 'retrieveInventoryCount';
193
- $this->square_api_args = [ $catalog_object_id, $location_ids ];
194
- }
195
-
196
-
197
- /**
198
- * Sets the data for a retrieveInventoryPhysicalCount request.
199
- *
200
- * @see https://docs.connect.squareup.com/api/connect/v2#endpoint-inventory-retrieveinventoryphysicalcount
201
- * @see InventoryApi::retrieveInventoryPhysicalCount()
202
- *
203
- * @since 2.0.0
204
- *
205
- * @param string $physical_count_id the InventoryPhysicalCount ID to retrieve
206
- */
207
- public function set_retrieve_inventory_physical_count_data( $physical_count_id ) {
208
-
209
- $this->square_api_method = 'retrieveInventoryPhysicalCount';
210
- $this->square_api_args = [ $physical_count_id ];
211
- }
212
-
213
-
214
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Requests/Locations.php DELETED
@@ -1,65 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Requests;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model as SquareModel;
28
- use SquareConnect\Api\LocationsApi;
29
- use WooCommerce\Square\API\Request;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * WooCommerce Square locations API Request class.
35
- *
36
- * @since 2.0.0
37
- */
38
- class Locations extends Request {
39
-
40
-
41
- /**
42
- * Initializes a new locations request.
43
- *
44
- * @since 2.0.0
45
- *
46
- * @param \SquareConnect\ApiClient $api_client the API client
47
- */
48
- public function __construct( $api_client ) {
49
-
50
- $this->square_api = new LocationsApi( $api_client );
51
- }
52
-
53
-
54
- /**
55
- * Sets API method.
56
- *
57
- * @since 2.0.0
58
- */
59
- public function set_list_locations_data() {
60
-
61
- $this->square_api_method = 'listLocations';
62
- }
63
-
64
-
65
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Response.php DELETED
@@ -1,120 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
- defined( 'ABSPATH' ) or exit;
29
-
30
- /**
31
- * Base WooCommerce Square API response object.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Response implements Framework\SV_WC_API_Response {
36
-
37
-
38
- /** @var mixed raw response data */
39
- protected $raw_response_data;
40
-
41
-
42
- /**
43
- * Constructs the response object.
44
- *
45
- * @since 2.0.0
46
- *
47
- * @param Object|array $raw_response_data
48
- */
49
- public function __construct( $raw_response_data ) {
50
-
51
- $this->raw_response_data = $raw_response_data;
52
- }
53
-
54
-
55
- /**
56
- * Gets the response data.
57
- *
58
- * @since 2.0.0
59
- *
60
- * @return Object
61
- */
62
- public function get_data() {
63
-
64
- return $this->raw_response_data ?: null;
65
- }
66
-
67
-
68
- /**
69
- * Gets errors returned by the Square API.
70
- *
71
- * @since 2.0.0
72
- *
73
- * @return \stdClass[]
74
- */
75
- public function get_errors() {
76
-
77
- return ! empty( $this->raw_response_data->errors ) && is_array( $this->raw_response_data->errors ) ? $this->raw_response_data->errors : [];
78
- }
79
-
80
-
81
- /**
82
- * Determines if the API response contains errors.
83
- *
84
- * @since 2.0.0
85
- *
86
- * @return bool
87
- */
88
- public function has_errors() {
89
-
90
- return ! empty( $this->get_errors() );
91
- }
92
-
93
-
94
- /**
95
- * Gets the response data as a string.
96
- *
97
- * @since 2.0.0
98
- *
99
- * @return string
100
- */
101
- public function to_string() {
102
-
103
- return is_callable( [ $this->get_data(), '__toString' ] ) ? $this->get_data() : '';
104
- }
105
-
106
-
107
- /**
108
- * Gets the response data a string with all sensitive information masked.
109
- *
110
- * @since 2.0.0
111
- *
112
- * @return string
113
- */
114
- public function to_string_safe() {
115
-
116
- return $this->to_string();
117
- }
118
-
119
-
120
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Responses/Catalog.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Responses;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\API\Response;
28
-
29
- defined( 'ABSPATH' ) or exit;
30
-
31
- /**
32
- * Catalog response object
33
- *
34
- * @since 2.0.0
35
- *
36
- * @method \SquareConnect\Model\ListCatalogResponse|\SquareConnect\Model\BatchUpsertCatalogObjectsResponse|\SquareConnect\Model\SearchCatalogObjectsResponse|\SquareConnect\Model\RetrieveCatalogObjectResponse|\SquareConnect\Model\CatalogInfoResponse get_data()
37
- */
38
- class Catalog extends Response {
39
-
40
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Responses/Connection_Refresh_Response.php DELETED
@@ -1,100 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * The connection refresh response class.
32
- *
33
- * Note that this is handled by Woo's proxy connection server, not Square's API.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Connection_Refresh_Response extends Framework\SV_WC_API_JSON_Response {
38
-
39
-
40
- /**
41
- * Gets the access token, if any.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return string|null
46
- */
47
- public function get_token() {
48
-
49
- return $this->access_token;
50
- }
51
-
52
- /**
53
- * Gets the refresh token, if any.
54
- *
55
- * @since 2.0.0
56
- *
57
- * @return string|null
58
- */
59
- public function get_refresh_token() {
60
- return $this->refresh_token;
61
- }
62
-
63
-
64
- /**
65
- * Gets the error message, if any.
66
- *
67
- * @since 2.0.0
68
- *
69
- * @return string|null
70
- */
71
- public function get_error_message() {
72
-
73
- $message = $this->reason;
74
-
75
- if ( empty( $message ) ) {
76
- $message = $this->type;
77
- }
78
-
79
- if ( empty( $message ) ) {
80
- $message = 'Unknown error';
81
- }
82
-
83
- return $message;
84
- }
85
-
86
-
87
- /**
88
- * Determines if there was an error returned.
89
- *
90
- * @since 2.0.0
91
- *
92
- * @return bool
93
- */
94
- public function has_error() {
95
-
96
- return ! empty( $this->response_data->error );
97
- }
98
-
99
-
100
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Responses/Inventory.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Responses;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\BatchRetrieveInventoryCountsResponse;
28
- use WooCommerce\Square\API\Response;
29
-
30
- defined( 'ABSPATH' ) or exit;
31
-
32
- /**
33
- * Inventory response object
34
- *
35
- * @since 2.0.0
36
- */
37
- class Inventory extends Response {
38
-
39
-
40
- /**
41
- * Gets inventory counts.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return \SquareConnect\Model\InventoryCount[] array of inventory count objects
46
- */
47
- public function get_counts() {
48
-
49
- $counts = [];
50
-
51
- if ( $this->get_data() instanceof BatchRetrieveInventoryCountsResponse && is_array( $this->get_data()->getCounts() ) ) {
52
- $counts = $this->get_data()->getCounts();
53
- }
54
-
55
- return $counts;
56
- }
57
-
58
-
59
- /**
60
- * Checks if there are inventory counts.
61
- *
62
- * @since 2.0.0
63
- *
64
- * @return bool
65
- */
66
- public function has_counts() {
67
-
68
- return ! empty( $this->get_counts() );
69
- }
70
-
71
-
72
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/API/Responses/Locations.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\API\Responses;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model as SquareModel;
28
- use WooCommerce\Square\API\Response;
29
-
30
- defined( 'ABSPATH' ) or exit;
31
-
32
- /**
33
- * Catalog response object
34
- *
35
- * @since 2.0.0
36
- *
37
- * @method SquareModel\ListLocationsResponse get_data()
38
- */
39
- class Locations extends Response {
40
-
41
-
42
- /**
43
- * Gets the returned locations.
44
- *
45
- * @since 2.0.0
46
- *
47
- * @return SquareModel\Location[]
48
- */
49
- public function get_locations() {
50
-
51
- return $this->get_data() ? $this->get_data()->getLocations() : [];
52
- }
53
-
54
-
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Admin.php DELETED
@@ -1,219 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use WooCommerce\Square\Handlers\Product;
29
-
30
- /**
31
- * The base admin handler class.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Admin {
36
-
37
-
38
- /** @var Handlers\Products */
39
- private $products_handler;
40
-
41
- /** @var Admin\Privacy */
42
- private $privacy_handler;
43
-
44
- /** @var Plugin plugin instance */
45
- private $plugin;
46
-
47
-
48
- /**
49
- * Constructs the class.
50
- *
51
- * @since 2.0.0
52
- *
53
- * @param Plugin $plugin plugin instance
54
- */
55
- public function __construct( Plugin $plugin ) {
56
-
57
- $this->plugin = $plugin;
58
-
59
- $this->products_handler = $this->plugin->get_products_handler();
60
-
61
- // privacy
62
- if ( version_compare( WC_VERSION, '3.4', '>=' ) ) {
63
- $this->privacy_handler = new Admin\Privacy();
64
- }
65
-
66
- $this->add_hooks();
67
- }
68
-
69
-
70
- /**
71
- * Adds the action & filter hooks.
72
- *
73
- * @since 2.0.0
74
- */
75
- private function add_hooks() {
76
-
77
- // add the settings page
78
- add_filter( 'woocommerce_get_settings_pages', function ( $pages ) {
79
-
80
- $pages[] = new Admin\Settings_Page( $this->get_plugin()->get_settings_handler() );
81
-
82
- return $pages;
83
- } );
84
-
85
- // load admin scripts
86
- add_action( 'admin_enqueue_scripts', function() { $this->load_scripts_styles(); } );
87
- }
88
-
89
-
90
- /**
91
- * Loads and enqueues admin scripts and styles.
92
- *
93
- * @since 2.0.0
94
- */
95
- private function load_scripts_styles() {
96
- global $typenow;
97
-
98
- if ( 'product' === $typenow ) {
99
-
100
- wp_enqueue_script( 'wc-square-admin-products', $this->get_plugin()->get_plugin_url() . '/assets/js/admin/wc-square-admin-products.min.js', [ 'jquery' ], Plugin::VERSION, true );
101
-
102
- wp_localize_script( 'wc-square-admin-products', 'wc_square_admin_products', [
103
-
104
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
105
- 'settings_url' => esc_url( $this->get_plugin()->get_settings_url() ),
106
- 'variable_product_types' => $this->get_variable_product_types(),
107
- 'synced_with_square_taxonomy' => Product::SYNCED_WITH_SQUARE_TAXONOMY,
108
- 'is_product_sync_enabled' => $this->get_plugin()->get_settings_handler()->is_product_sync_enabled(),
109
- 'is_woocommerce_sor' => $this->get_plugin()->get_settings_handler()->is_system_of_record_woocommerce(),
110
- 'is_square_sor' => $this->get_plugin()->get_settings_handler()->is_system_of_record_square(),
111
- 'is_inventory_sync_enabled' => $this->get_plugin()->get_settings_handler()->is_inventory_sync_enabled(),
112
- 'is_product_synced_with_square_nonce' => wp_create_nonce( 'is-product-synced-with-square' ),
113
- 'fetch_product_stock_with_square_nonce' => wp_create_nonce( 'fetch-product-stock-with-square' ),
114
-
115
- 'i18n' => [
116
- 'synced_with_square' => __( 'Synced with Square', 'woocommerce-square' ),
117
- 'managed_by_square' => __( 'Managed by Square', 'woocommerce-square' ),
118
- 'fetch_stock_with_square' => __( 'Fetch stock from Square', 'woocommerce-square' ),
119
- ],
120
-
121
- ] );
122
-
123
- } elseif ( $this->get_plugin()->is_plugin_settings() ) {
124
-
125
- wp_enqueue_style( 'wc-square-admin', $this->get_plugin()->get_plugin_url() . '/assets/css/admin/wc-square-admin.min.css', [], Plugin::VERSION );
126
-
127
- wp_enqueue_script( 'wc-square-admin-settings', $this->get_plugin()->get_plugin_url() . '/assets/js/admin/wc-square-admin-settings.min.js', [ 'jquery', 'jquery-blockui', 'backbone', 'wc-backbone-modal' ], Plugin::VERSION, true );
128
-
129
- if ( $sync_job = $this->get_plugin()->get_sync_handler()->get_job_in_progress() ) {
130
- $existing_sync_id = $sync_job->id;
131
- } else {
132
- $existing_sync_id = false;
133
- }
134
-
135
- wp_localize_script( 'wc-square-admin-settings', 'wc_square_admin_settings', [
136
-
137
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
138
- 'is_product_sync_enabled' => $this->get_plugin()->get_settings_handler()->is_product_sync_enabled(),
139
- 'is_woocommerce_sor' => $this->get_plugin()->get_settings_handler()->is_system_of_record_woocommerce(),
140
- 'is_square_sor' => $this->get_plugin()->get_settings_handler()->is_system_of_record_square(),
141
- 'is_inventory_sync_enabled' => $this->get_plugin()->get_settings_handler()->is_inventory_sync_enabled(),
142
- 'existing_sync_job_id' => $existing_sync_id,
143
- 'sync_in_background' => $this->get_plugin()->get_sync_handler()->should_sync_in_background(),
144
- 'import_products_from_square' => wp_create_nonce( 'import-products-from-square' ),
145
- 'sync_products_with_square' => wp_create_nonce( 'sync-products-with-square' ),
146
- 'get_sync_with_square_status_nonce' => wp_create_nonce( 'get-sync-with-square-status' ),
147
- 'handle_sync_with_square_records' => wp_create_nonce( 'handle-sync-with-square-records' ),
148
-
149
- 'i18n' => [
150
- 'resolved' => __( 'Resolved', 'woocommerce-square' ),
151
- 'no_records_found' => __( 'No records found', 'woocommerce-square' ),
152
- 'skipped' => __( 'Skipped', 'woocommerce-square' ),
153
- 'imported' => __( 'Imported', 'woocommerce-square' ),
154
- 'sync_inventory_label' => [
155
- 'square' => __( 'Enable to fetch inventory changes from Square', 'woocommerce-square' ),
156
- 'woocommerce' => __( 'Enable to push inventory changes to Square', 'woocommerce-square' ),
157
- ],
158
- 'sync_inventory_description' => [
159
- 'square' => __( 'Inventory is fetched from Square periodically and updated in WooCommerce', 'woocommerce-square' ),
160
- 'woocommerce' => sprintf(
161
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag */
162
- __( 'Inventory is %1$salways fetched from Square%2$s periodically to account for sales from other channels.', 'woocommerce-square' ),
163
- '<strong>', '</strong>'
164
- ),
165
- ],
166
- ],
167
-
168
- ] );
169
- }
170
- }
171
-
172
-
173
- /**
174
- * Gets a list of variable product types.
175
- *
176
- * @since 2.0.0
177
- *
178
- * @return string[]
179
- */
180
- private function get_variable_product_types() {
181
-
182
- /**
183
- * Filters the variable product types.
184
- *
185
- * @since 2.0.0
186
- *
187
- * @param string[] array of product types
188
- */
189
- return (array) apply_filters( 'wc_square_variable_product_types', [ 'variable', 'variable-subscription' ] );
190
- }
191
-
192
-
193
- /**
194
- * Gets the products handler.
195
- *
196
- * @since 2.0.0
197
- *
198
- * @return Admin\Products
199
- */
200
- public function get_products_handler() {
201
-
202
- return $this->products_handler;
203
- }
204
-
205
-
206
- /**
207
- * Gets the plugin instance.
208
- *
209
- * @since 2.0.0
210
- *
211
- * @return Plugin
212
- */
213
- protected function get_plugin() {
214
-
215
- return $this->plugin;
216
- }
217
-
218
-
219
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Admin/Privacy.php DELETED
@@ -1,106 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Admin;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * Privacy admin handler.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Privacy extends \WC_Abstract_Privacy {
36
-
37
-
38
- /**
39
- * Privacy class constructor.
40
- *
41
- * @since 2.0.0
42
- */
43
- public function __construct() {
44
-
45
-
46
- parent::__construct( __( 'Square', 'woocommerce-square' ) );
47
-
48
- $this->add_eraser( 'woocommerce-square-customer-data', __( 'WooCommerce Square Customer Data', 'woocommerce-square' ), [ $this, 'customer_data_eraser' ] );
49
- }
50
-
51
-
52
- /**
53
- * Gets the message to display.
54
- *
55
- * @since 2.0.0
56
- */
57
- public function get_message() {
58
-
59
- return wpautop(
60
- sprintf(
61
- /* translators: Placeholder: %1$s - <a> tag, %2$s - </a> tag */
62
- __( 'By using this extension, you may be storing personal data or sharing data with an external service. %1$sLearn more about how this works, including what you may want to include in your privacy policy.%2$s', 'woocommerce-square' ),
63
- '<a href="https://docs.woocommerce.com/document/privacy-payments/#woocommerce-square" target="_blank">', '</a>'
64
- )
65
- );
66
- }
67
-
68
-
69
- /**
70
- * Finds and erases customer data by email address.
71
- *
72
- * @since 2.0.0
73
- *
74
- * @param string $email_address the user email address
75
- * @param int $page page
76
- * @return array an array of personal data in name => value pairs
77
- */
78
- public function customer_data_eraser( $email_address, $page ) {
79
-
80
- // check if user has an ID to load stored personal data
81
- $user = get_user_by( 'email', $email_address );
82
- $square_customer_id = get_user_meta( $user->ID, 'wc_square_customer_id', true );
83
-
84
- $items_removed = false;
85
- $messages = [];
86
-
87
- if ( ! empty( $square_customer_id ) ) {
88
-
89
- $items_removed = true;
90
-
91
- delete_user_meta( $user->ID, 'wc_square_customer_id' );
92
-
93
- $messages[] = __( 'Square User Data Erased.', 'woocommerce-square' );
94
- }
95
-
96
- return [
97
- 'items_removed' => $items_removed,
98
- 'items_retained' => false,
99
- 'messages' => $messages,
100
- 'done' => true,
101
- ];
102
- }
103
-
104
-
105
- }
106
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Admin/Settings_Page.php DELETED
@@ -1,197 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Admin;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square;
30
-
31
- /**
32
- * The settings page class.
33
- *
34
- * @see \WooCommerce\Square\Settings handles settings registration
35
- *
36
- * @since 2.0.0
37
- */
38
- class Settings_Page extends \WC_Settings_Page {
39
-
40
-
41
- /** @var Square\Settings settings handler instance */
42
- protected $settings_handler;
43
-
44
-
45
- /**
46
- * Constructs the settings page.
47
- *
48
- * @since 2.0.0
49
- *
50
- * @param Square\Settings $settings_handler a settings handler instance, for displaying and saving the settings
51
- */
52
- public function __construct( Square\Settings $settings_handler ) {
53
-
54
- $this->id = Square\Plugin::PLUGIN_ID;
55
- $this->label = __( 'Square', 'woocommerce-square' );
56
- $this->settings_handler = $settings_handler;
57
-
58
- parent::__construct();
59
- }
60
-
61
-
62
- /**
63
- * Outputs the settings page.
64
- *
65
- * @internal
66
- *
67
- * @since 2.0.0
68
- */
69
- public function output() {
70
- global $current_section;
71
-
72
- if ( 'update' === $current_section ) {
73
- $this->output_update_section();
74
- } else {
75
- $this->output_general_section();
76
- }
77
- }
78
-
79
-
80
- /**
81
- * Outputs the general settings section.
82
- *
83
- * @since 2.0.0
84
- */
85
- private function output_general_section() {
86
-
87
- $this->settings_handler->admin_options();
88
- self::output_import_products_modal_template();
89
- }
90
-
91
-
92
- /**
93
- * Outputs the "Update" settings section.
94
- *
95
- * @since 2.0.0
96
- */
97
- private function output_update_section() {
98
- global $hide_save_button;
99
-
100
- // removes the save/update button from the screen
101
- $hide_save_button = true;
102
-
103
- Sync_Page::output();
104
- }
105
-
106
-
107
- /**
108
- * Saves the settings.
109
- *
110
- * @internal
111
- *
112
- * @since 2.0.0
113
- */
114
- public function save() {
115
-
116
- $this->settings_handler->process_admin_options();
117
- }
118
-
119
-
120
- /**
121
- * Gets the settings.
122
- *
123
- * @since 2.0.0
124
- *
125
- * @return array
126
- */
127
- public function get_settings() {
128
-
129
- return (array) apply_filters( 'woocommerce_get_settings_' . $this->get_id(), $this->settings_handler->get_form_fields() );
130
- }
131
-
132
-
133
- /**
134
- * Gets the settings sections.
135
- *
136
- * @internal
137
- *
138
- * @since 2.0.0
139
- *
140
- * @return array
141
- */
142
- public function get_sections() {
143
-
144
- $sections = [
145
- '' => __( 'Settings', 'woocommerce-square' ), // this key is intentionally blank
146
- 'update' => __( 'Update', 'woocommerce-square' ),
147
- ];
148
-
149
- /**
150
- * Filters the WooCommerce Square settings sections.
151
- *
152
- * @since 2.0.0
153
- *
154
- * @param array $sections settings sections
155
- */
156
- return (array) apply_filters( 'woocommerce_get_sections_' . $this->get_id(), $sections );
157
- }
158
-
159
-
160
- /**
161
- * Outputs a backbone modal template for importing products from Square.
162
- *
163
- * @since 2.0.0
164
- */
165
- private static function output_import_products_modal_template() {
166
-
167
- ?>
168
- <script type="text/template" id="tmpl-wc-square-import-products">
169
- <div class="wc-backbone-modal">
170
- <div class="wc-backbone-modal-content">
171
- <section class="wc-backbone-modal-main" role="main">
172
- <header class="wc-backbone-modal-header">
173
- <h1><?php esc_html_e( 'Import Products From Square', 'woocommerce-square' ); ?></h1>
174
- <button class="modal-close modal-close-link dashicons dashicons-no-alt">
175
- <span class="screen-reader-text"><?php esc_html_e( 'Close modal window', 'woocommerce-square' ); ?></span>
176
- </button>
177
- </header>
178
- <article>
179
- <?php /* translators: Placeholders: %1$s - <strong>, %2%s - </strong> */ ?>
180
- <?php printf( esc_html__( 'You are about to import all products from Square. This will create a new product in WooCommerce for every product retrieved from Square. If you have products in the trash from the previous imports, these will be ignored in the import. %1$sOnly use this action to perform a one-time import!%2$s', 'woocommerce-square' ), '<strong>', '</strong>' ); ?>
181
- </article>
182
- <footer>
183
- <div class="inner">
184
- <button id="btn-close" class="button button-large"><?php esc_html_e( 'Cancel', 'woocommerce-square' ); ?></button>
185
- <button id="btn-ok" class="button button-large button-primary"><?php esc_html_e( 'Import Products', 'woocommerce-square' ); ?></button>
186
- </div>
187
- </footer>
188
- </section>
189
- </div>
190
- </div>
191
- <div class="wc-backbone-modal-backdrop modal-close"></div>
192
- </script>
193
- <?php
194
- }
195
-
196
-
197
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Admin/Sync_Page.php DELETED
@@ -1,379 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Admin;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Product;
30
- use WooCommerce\Square\Sync\Records;
31
-
32
- /**
33
- * Handles HTML output for the "Update" section of the Settings page with sync status handling and UI.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Sync_Page {
38
-
39
-
40
- /**
41
- * Outputs the page HTML.
42
- *
43
- * @since 2.0.0
44
- */
45
- public static function output() {
46
-
47
- ?>
48
- <div id="wc-square-sync-page">
49
-
50
- <h2><?php esc_html_e( 'Update', 'woocommerce-square' ); ?></h2>
51
- <?php self::output_system_record_of_data_info(); ?>
52
- <?php self::output_sync_status(); ?>
53
-
54
- <h2><?php esc_html_e( 'Sync records', 'woocommerce-square' ); ?></h2>
55
- <?php self::output_sync_records(); ?>
56
- <?php self::output_sync_with_square_modal_template(); ?>
57
-
58
- </div>
59
- <?php
60
- }
61
-
62
-
63
- /**
64
- * Outputs notice-like tabular HTML with information on the current system of record handling.
65
- *
66
- * @since 2.0.0
67
- */
68
- private static function output_system_record_of_data_info() {
69
-
70
- ?>
71
- <table class="wc_square_table sor widefat" cellspacing="0">
72
- <tbody>
73
- <?php if ( wc_square()->get_settings_handler()->is_system_of_record_square() ) : ?>
74
-
75
- <tr>
76
- <td>
77
- <?php printf(
78
- /* translators: Placeholders: %1$s, %3$s - opening <strong> HTML tag, %2$s, $4%s - closing </strong> HTML tag */
79
- esc_html__( '%1$sSquare%2$s is the system of record. The following data from Square will overwrite WooCommerce data for synced products: %3$sname, price, description, category, inventory%4$s.', 'woocommerce-square' ),
80
- '<strong>', '</strong>', '<strong>', '</strong>'
81
- ); ?>
82
- </td>
83
- </tr>
84
- <tr>
85
- <td>
86
- <?php printf(
87
- /* translators: Placeholders: %1$s - opening <strong> HTML tag, %2$s closing </strong> HTML tag */
88
- esc_html__( '%1$sProduct images%2$s will be imported from Square if no featured image is set in WooCommerce.', 'woocommerce-square' ),
89
- '<strong>', '</strong>'
90
- );?>
91
- </td>
92
- </tr>
93
-
94
- <?php elseif ( wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) : ?>
95
-
96
- <tr>
97
- <td>
98
- <?php printf(
99
- /* translators: Placeholders: %1$s, %3$s - opening <strong> HTML tag, %2$s, %4$s - closing </strong> HTML tag */
100
- esc_html__( '%1$sWooCommerce%2$s is the system of record. The following data from WooCommerce will overwrite Square data for synced products: %3$sname, price, inventory, category, image%4$s.', 'woocommerce-square' ),
101
- '<strong>', '</strong>', '<strong>', '</strong>'
102
- ); ?>
103
- </td>
104
- </tr>
105
-
106
- <?php else : ?>
107
-
108
- <tr>
109
- <td>
110
- <?php printf(
111
- /* translators: Placeholders: %1$s - opening <strong> HTML tag, %2$s closing </strong> HTML tag*/
112
- esc_html__( '%1$sNo chosen system of record.%2$s Products will not be synced between Square and WooCommerce.', 'woocommerce-square' ),
113
- '<strong>', '</strong>'
114
- ); ?>
115
- </td>
116
- </tr>
117
-
118
- <?php endif; ?>
119
- </tbody>
120
- </table>
121
- <?php
122
- }
123
-
124
-
125
- /**
126
- * Outputs tabular HTML with information on sync status and a button to trigger a manual sync.
127
- *
128
- * @since 2.0.0
129
- */
130
- private static function output_sync_status() {
131
-
132
- $is_connected = wc_square()->get_settings_handler()->is_connected();
133
- $sync_in_progress = $is_connected ? wc_square()->get_sync_handler()->is_sync_in_progress() : false;
134
- $synced_products = wc_square()->get_settings_handler()->is_product_sync_enabled() ? Product::get_products_synced_with_square() : [];
135
- $synced_count = count( $synced_products );
136
- $is_product_import = false;
137
-
138
- if ( $sync_in_progress ) {
139
-
140
- $current_job = wc_square()->get_sync_handler()->get_job_in_progress();
141
- $is_product_import = isset( $current_job->action ) && 'product_import' === $current_job->action;
142
- }
143
-
144
- if ( ! $is_connected ) {
145
- $disabled_reason = esc_html__( 'Please connect to Square to enable product sync.', 'woocommerce-square' );
146
- } elseif ( 0 === $synced_count ) {
147
- $disabled_reason = esc_html__( 'There are currently no products marked to be synced with Square.', 'woocommerce-square' );
148
- } elseif ( $sync_in_progress ) {
149
- $disabled_reason = esc_html__( 'A sync is currently in progress. Please try again later.', 'woocommerce-square' );
150
- }
151
-
152
- if ( ! empty( $disabled_reason ) ) {
153
- /* translators: Placeholder: %s - reason text */
154
- $disabled_reason = sprintf( esc_html__( 'Product sync between WooCommerce and Square is currently unavailable. %s', 'woocommerce-square' ), $disabled_reason );
155
- }
156
-
157
- ?>
158
- <table class="wc_square_table sync widefat" cellspacing="0">
159
- <thead>
160
- <tr>
161
- <th class="synced-products"><?php esc_html_e( 'Synced products', 'woocommerce-square' ); ?></th>
162
- <th class="latest-sync"><?php esc_html_e( 'Latest sync', 'woocommerce-square' ); ?></th>
163
- <th class="next-sync"><?php esc_html_e( 'Next sync', 'woocommerce-square' ); ?></th>
164
- <th class="actions"><?php esc_html_e( 'Actions', 'woocommerce-square' ); ?></th>
165
- </tr>
166
- </thead>
167
- <tbody>
168
- <tr>
169
- <td class="synced-products">
170
- <a href="<?php echo esc_url( admin_url( 'edit.php?s&post_status=all&post_type=product&product_type=synced-with-square&stock_status&paged=1' ) ); ?>">
171
- <?php printf(
172
- /* translators: Placeholder: %d number of products synced with Square */
173
- _n( '%d product', '%d products', $synced_count, 'woocommerce-square' ),
174
- $synced_count
175
- ); ?>
176
- </a>
177
- <input
178
- type="hidden"
179
- id="wc-square-sync-products-count"
180
- value="<?php echo esc_attr( $synced_count ); ?>"
181
- />
182
- </td>
183
-
184
- <?php $date_time_format = wc_date_format() . ' ' . wc_time_format(); ?>
185
-
186
- <td class="latest-sync">
187
- <p class="sync-result">
188
- <?php if ( $sync_in_progress ) : ?>
189
- <?php if ( $is_product_import ) : ?>
190
- <em><?php esc_html_e( 'Importing now&hellip;', 'woocommerce-square' ); ?></em>
191
- <?php else : ?>
192
- <em><?php esc_html_e( 'Syncing now&hellip;', 'woocommerce-square' ); ?></em>
193
- <?php endif; ?>
194
- <?php else : ?>
195
-
196
- <?php if ( $last_synced_at = wc_square()->get_sync_handler()->get_last_synced_at() ) : ?>
197
-
198
- <?php
199
- $last_synced_date = new \DateTime();
200
- $last_synced_date->setTimestamp( $last_synced_at );
201
- $last_synced_date->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
202
- ?>
203
-
204
- <?php echo esc_html( $last_synced_date->format( $date_time_format ) ); ?>
205
-
206
- <?php else : ?>
207
- <em><?php esc_html_e( 'Not synced yet.', 'woocommerce-square' ); ?></em>
208
- <?php endif; ?>
209
- <?php endif; ?>
210
- </p>
211
- </td>
212
- <td class="next-sync">
213
- <p>
214
- <?php if ( $sync_in_progress ) : ?>
215
- &mdash;
216
- <?php else : ?>
217
-
218
- <?php if ( $next_sync_at = wc_square()->get_sync_handler()->get_next_sync_at() ) : ?>
219
-
220
- <?php
221
- $next_sync_date = new \DateTime();
222
- $next_sync_date->setTimestamp( $next_sync_at );
223
- $next_sync_date->setTimezone( new \DateTimeZone( wc_timezone_string() ) );
224
- ?>
225
-
226
- <?php echo esc_html( $next_sync_date->format( $date_time_format ) ); ?>
227
-
228
- <?php else : ?>
229
- &mdash;
230
- <?php endif; ?>
231
- <?php endif; ?>
232
- </p>
233
- </td>
234
- <td class="actions">
235
- <button
236
- id="wc-square-sync"
237
- class="button button-large"
238
- <?php echo ! empty( $disabled_reason ) ? sprintf( 'disabled="disabled" title="%s"', esc_attr( $disabled_reason ) ) : ''; ?>
239
- ><?php esc_html_e( 'Sync now', 'woocommerce-square' ); ?></span></button>
240
- <div id="wc-square-sync-progress-spinner" class="spinner" style="float:none; <?php echo $sync_in_progress ? 'visibility:visible;' : ''; ?>"></div>
241
- </td>
242
- </tr>
243
- </tbody>
244
- </table>
245
- <?php
246
- }
247
-
248
-
249
- /**
250
- * Outputs tabular HTML with sync record logs and UI.
251
- *
252
- * @since 2.0.0
253
- */
254
- private static function output_sync_records() {
255
-
256
- $records = Records::get_records(); ?>
257
-
258
- <button
259
- id="wc-square_clear-sync-records"
260
- class="button button-large"
261
- <?php if ( empty( $records ) ) { echo 'disabled="disabled"'; } ?>
262
- ><?php echo esc_html_x( 'Clear history', 'Delete all records', 'woocommerce-square' ); ?></button>
263
-
264
- <table class="wc_square_table records widefat" cellspacing="0">
265
- <thead>
266
- <tr>
267
- <th class="date-time"><?php echo esc_html_x( 'Time', 'Date - Time', 'woocommerce-square' ); ?></th>
268
- <th class="type"><?php esc_html_e( 'Status', 'woocommerce-square' ); ?></th>
269
- <th class="message"><?php esc_html_e( 'Message', 'woocommerce-square' ); ?></th>
270
- <th class="actions"><?php esc_html_e( 'Actions', 'woocommerce-square' ); ?></th>
271
- </tr>
272
- </thead>
273
- <tbody>
274
- <?php if ( ! empty( $records ) ) : ?>
275
-
276
- <?php foreach ( $records as $record ) : ?>
277
-
278
- <tr id="record-<?php echo esc_attr( $record->get_id() ); ?>">
279
- <td class="date-time"><?php echo $record->get_local_date(); ?></td>
280
- <td class="type"><mark class="<?php echo esc_attr( sanitize_html_class( $record->get_type() ) ); ?>"><span><?php echo esc_html( $record->get_label() ); ?></span></mark></td>
281
- <td class="message"><?php echo wp_kses_post( $record->get_message() ); ?></td>
282
- <td class="actions">
283
- <?php foreach ( $record->get_actions() as $action ) : ?>
284
- <button
285
- class="button action <?php echo sanitize_html_class( $action->name ); ?> tips"
286
- data-id="<?php echo esc_attr( $record->get_id() ); ?>"
287
- data-action="<?php echo esc_attr( $action->name ); ?>"
288
- data-tip="<?php echo esc_attr( $action->label ); ?>"
289
- ><?php echo $action->icon; ?></button>
290
- <?php endforeach; ?>
291
- </td>
292
- </tr>
293
-
294
- <?php endforeach; ?>
295
-
296
- <?php else : ?>
297
-
298
- <tr>
299
- <td colspan="4">
300
- <em><?php esc_html_e( 'No records found.', 'woocommerce-square' ) ?></em>
301
- </td>
302
- </tr>
303
-
304
- <?php endif; ?>
305
- </tbody>
306
- <tfoot>
307
- <tr>
308
- <th class="date-time"><?php echo esc_html_x( 'Time', 'Date - Time', 'woocommerce-square' ); ?></th>
309
- <th class="type"><?php esc_html_e( 'Status', 'woocommerce-square' ); ?></th>
310
- <th class="message"><?php esc_html_e( 'Message', 'woocommerce-square' ); ?></th>
311
- <th class="actions"><?php esc_html_e( 'Actions', 'woocommerce-square' ); ?></th>
312
- </tr>
313
- </tfoot>
314
- </table>
315
- <?php
316
- }
317
-
318
-
319
- /**
320
- * Outputs a backbone modal template for starting a manual sync process.
321
- *
322
- * @since 2.0.0
323
- */
324
- private static function output_sync_with_square_modal_template() {
325
-
326
- ?>
327
- <script type="text/template" id="tmpl-wc-square-sync">
328
- <div class="wc-backbone-modal">
329
- <div class="wc-backbone-modal-content">
330
- <section class="wc-backbone-modal-main" role="main">
331
- <header class="wc-backbone-modal-header">
332
- <h1><?php esc_html_e( 'Sync products with Square', 'woocommerce-square' ); ?></h1>
333
- <button class="modal-close modal-close-link dashicons dashicons-no-alt">
334
- <span class="screen-reader-text"><?php esc_html_e( 'Close modal window', 'woocommerce-square' ); ?></span>
335
- </button>
336
- </header>
337
- <article>
338
- <?php $square_settings = wc_square()->get_settings_handler(); ?>
339
- <?php ob_start(); ?>
340
- <ul>
341
- <?php if ( $square_settings->is_system_of_record_square() ) : ?>
342
- <li><?php esc_html_e( 'If a match is found in Square, product data in WooCommerce will be overwritten with Square data.', 'woocommerce-square' ); ?></li>
343
- <?php elseif ( $square_settings->is_system_of_record_woocommerce() ) : ?>
344
- <li><?php esc_html_e( 'If a match is found in WooCommerce, product data in Square will be overwritten with WooCommerce data.', 'woocommerce-square' ); ?></li>
345
- <?php endif; ?>
346
- <?php if ( $square_settings->is_system_of_record_square() ) : ?>
347
- <?php if ( $square_settings->hide_missing_square_products() ) : ?>
348
- <li><?php esc_html_e( 'If a match is not found in Square, the product will be hidden from the catalog in WooCommerce.', 'woocommerce-square' ); ?></li>
349
- <?php else : ?>
350
- <li><?php esc_html_e( 'If a match is not found in Square, the product will be skipped in the sync.', 'woocommerce-square' ); ?></li>
351
- <?php endif; ?>
352
- <?php else : ?>
353
- <li><?php esc_html_e( 'If a match is not found, a new product will be created in Square.', 'woocommerce-square' ); ?></li>
354
- <?php endif; ?>
355
- </ul>
356
- <?php $additional_info = ob_get_clean(); ?>
357
- <?php printf(
358
- /* translators: Placeholders: %1$s - the system of record name (e.g. Square or WooCommerce), %3%s - unordered HTML list of additional information item(s) */
359
- esc_html__( 'You are about to sync products with Square. %1$s is your system of record. For all products synced with Square: %2$s', 'woocommerce-square' ),
360
- $square_settings->get_system_of_record_name(),
361
- $additional_info
362
- ); ?>
363
- </article>
364
- <footer>
365
- <div class="inner">
366
- <button id="btn-close" class="button button-large"><?php esc_html_e( 'Cancel', 'woocommerce-square' ); ?></button>
367
- <button id="btn-ok" class="button button-large button-primary"><?php esc_html_e( 'Start sync', 'woocommerce-square' ); ?></button>
368
- </div>
369
- </footer>
370
- </section>
371
- </div>
372
- </div>
373
- <div class="wc-backbone-modal-backdrop modal-close"></div>
374
- </script>
375
- <?php
376
- }
377
-
378
-
379
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Emails/Sync_Completed.php DELETED
@@ -1,425 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Emails;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
- defined( 'ABSPATH' ) or exit;
29
-
30
- /**
31
- * Sync completed email.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Sync_Completed extends \WC_Email {
36
-
37
-
38
- /** @var string email body */
39
- protected $body;
40
-
41
-
42
- /**
43
- * Email constructor.
44
- *
45
- * @since 2.0.0
46
- */
47
- public function __construct() {
48
-
49
- // set properties
50
- $this->id = 'wc_square_sync_completed';
51
- $this->title = __( 'Square sync completed', 'woocommerce-square' );
52
- $this->description = __( 'This email is sent once a manual sync has been completed between WooCommerce and Square', 'woocommerce-square' );
53
- $this->subject = _x( '[WooCommerce] Square sync completed', 'Email subject', 'woocommerce-square');
54
- $this->heading = _x( 'Square sync completed for {product_count}', 'Email heading with merge tag placeholder', 'woocommerce-square');
55
- $this->body = _x( 'Square sync completed for {site_title} at {sync_completed_date} {sync_completed_time}.', 'Email body with merge tag placeholders', 'woocommerce-square' );
56
- $this->template_html = 'emails/square-sync-completed.php';
57
- $this->template_plain = 'emails/plain/square-sync-completed.php';
58
- $this->template_base = wc_square()->get_plugin_path() . '/templates/';
59
-
60
- // call parent constructor
61
- parent::__construct();
62
-
63
- // set default recipient
64
- $this->recipient = $this->get_option( 'recipient', get_option( 'admin_email' ) );
65
- }
66
-
67
-
68
- /**
69
- * Initializes the email settings form fields.
70
- *
71
- * Extends and overrides parent method.
72
- *
73
- * @since 2.0.0
74
- */
75
- public function init_form_fields() {
76
-
77
- // initialize the default fields from parent email object
78
- parent::init_form_fields();
79
-
80
- $form_fields = $this->form_fields;
81
-
82
- // set email disabled by default
83
- if ( isset( $form_fields['enabled'] ) ) {
84
- $form_fields['enabled']['default'] = 'no';
85
- }
86
-
87
- // the email has no customizable body or heading via input field
88
- unset( $form_fields['body'], $form_fields['heading'] );
89
-
90
- // adjust email subject field
91
- if ( isset( $form_fields['subject'] ) ) {
92
- /* translators: Placeholder: %s - default email subject text */
93
- $form_fields['subject']['description'] = sprintf( __( 'This controls the email subject line. Leave blank to use the default subject: %s', 'woocommerce-square' ), '<code>' . $this->get_default_subject() . '</code>' );
94
- $form_fields['subject']['desc_tip'] = false;
95
- $form_fields['subject']['default'] = $this->subject;
96
- }
97
-
98
- // add a recipient field
99
- $form_fields = Framework\SV_WC_Helper::array_insert_after( $form_fields, isset( $form_fields['enabled'] ) ? 'enabled' : key( $form_fields ), [
100
- 'recipient' => [
101
- 'title' => __( 'Recipient(s)', 'woocommerce-square' ),
102
- 'type' => 'text',
103
- /* translators: Placeholder: %s default email address */
104
- 'description' => sprintf( __( 'Enter recipients (comma separated) for this email. Defaults to admin email: %s', 'woocommerce-square' ), '<code>' . esc_attr( get_option( 'admin_email' ) ) . '</code>' ),
105
- 'placeholder' => get_bloginfo( 'admin_email' ),
106
- 'default' => get_bloginfo( 'admin_email' ),
107
- ],
108
- ] );
109
-
110
- // set the updated fields
111
- $this->form_fields = $form_fields;
112
- }
113
-
114
-
115
- /**
116
- * Gets the email heading, adjusted by sync job result status.
117
- *
118
- * @since 2.0.0
119
- *
120
- * @param string $status sync job status
121
- * @return string
122
- */
123
- private function get_heading_by_job_status( $status ) {
124
-
125
- if ( 'failed' === $status ) {
126
- $email_heading = esc_html__( 'Square sync failed', 'woocommerce-square' );
127
- } else {
128
- $email_heading = parent::get_default_heading();
129
- }
130
-
131
- /** @see Sync_Completed::get_heading() for filter documentation */
132
- return apply_filters( 'woocommerce_email_heading_' . $this->id, $this->format_string( $email_heading ), $this->object );
133
- }
134
-
135
-
136
- /**
137
- * Gets the default email subject.
138
- *
139
- * @since 2.0.0
140
- *
141
- * @return string
142
- */
143
- public function get_default_subject() {
144
-
145
- return $this->subject;
146
- }
147
-
148
-
149
- /**
150
- * Gets the email body.
151
- *
152
- * @since 2.0.0
153
- *
154
- * @return string may contain HTML
155
- */
156
- protected function get_default_body() {
157
-
158
- return $this->body;
159
- }
160
-
161
-
162
- /**
163
- * Gets the email body.
164
- *
165
- * @since 2.0.0
166
- *
167
- * @return string may contain HTML
168
- */
169
- protected function get_body() {
170
-
171
- $email_body = $this->get_default_body();
172
-
173
- /**
174
- * Filters the sync completed email body.
175
- *
176
- * @since 2.0.0
177
- *
178
- * @param string $email_body the email body
179
- * @param Sync_Completed $email the email object
180
- */
181
- return $this->format_string( (string) apply_filters( "{$this->id}_body", $email_body, $this ) );
182
- }
183
-
184
-
185
- /**
186
- * Gets the email body adjusted by sync job result status.
187
- *
188
- * @since 2.0.0
189
- *
190
- * @param string $status sync job status
191
- * @param bool $html whether output should be HTML (true) or plain text (false)
192
- * @return string may contain HTML
193
- */
194
- private function get_body_by_job_status( $status, $html ) {
195
-
196
- $email_body = $this->get_default_body();
197
-
198
- if ( 'failed' === $status ) {
199
-
200
- if ( true === $html ) {
201
-
202
- $square = wc_square();
203
- $settings_url = $square->get_settings_url();
204
- $records_url = add_query_arg( [ 'section' => 'update' ], $settings_url );
205
-
206
- if ( $square->get_settings_handler()->is_debug_enabled() ) {
207
- $action = sprintf(
208
- /* translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing </a> HTML link tag */
209
- esc_html__( '%1$sInspect status logs%2$s', 'woocommerce-square' ),
210
- '<a href="' . esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) . '">', '</a>'
211
- );
212
- } else {
213
- $action = sprintf(
214
- /* translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing </a> HTML link tag */
215
- esc_html__( '%1$sEnable logging%2$s', 'woocommerce-square' ),
216
- '<a href="' . esc_url( $settings_url ) .'">', '</a>'
217
- );
218
- }
219
-
220
- $email_body .= sprintf(
221
- /* translators: Placeholders: %1$s - opening <a> HTML link tag, %2$s - closing </a> HTML link tag, %3$s - additional action */
222
- '<br>' . esc_html__( 'The sync job has failed. %1$sClick for more details%2$s, or %3$s.', 'woocommerce-square' ),
223
- '<a href="' . esc_url( $records_url ) .'">', '</a>',
224
- strtolower( $action )
225
- );
226
-
227
- } else { // plain text
228
-
229
- if ( wc_square()->get_settings_handler()->is_debug_enabled() ) {
230
- $action = esc_html__( 'Inspect status logs', 'woocommerce-square' );
231
- } else {
232
- $action = esc_html__( 'Enable Logging', 'woocommerce-square' );
233
- }
234
-
235
- $email_body .= sprintf(
236
- /* translators: Placeholders: %s - additional action */
237
- esc_html__( 'The sync job has failed. Check sync records, or %s.', 'woocommerce-square' ),
238
- strtolower( $action )
239
- );
240
- }
241
- }
242
-
243
- /** @see Sync_Completed::get_body() for filter documentation */
244
- return $this->format_string( (string) apply_filters( "{$this->id}_body", $email_body, $this ) );
245
- }
246
-
247
-
248
- /**
249
- * Gets the email's related sync job, if set.
250
- *
251
- * @since 2.0.0
252
- *
253
- * @return \stdClass|null
254
- */
255
- private function get_job() {
256
-
257
- return $this->object && is_object( $this->object ) ? $this->object : null;
258
- }
259
-
260
-
261
- /**
262
- * Determines if it's a customer email.
263
- *
264
- * @since 2.0.0
265
- *
266
- * @return false overrides parent method to always return false
267
- */
268
- public function is_customer_email() {
269
-
270
- return false;
271
- }
272
-
273
-
274
- /**
275
- * Determines if the email has valid recipients.
276
- *
277
- * @since 2.0.0
278
- *
279
- * @return bool
280
- */
281
- protected function has_recipients() {
282
-
283
- return ! empty( $this->get_recipient() );
284
- }
285
-
286
-
287
- /**
288
- * Triggers the email.
289
- *
290
- * @since 2.0.0
291
- *
292
- * @param string|object|\stdClass $job a sync job object or ID
293
- */
294
- public function trigger( $job ) {
295
-
296
- if ( $this->is_enabled() && $this->has_recipients() ) {
297
-
298
- if ( is_string( $job ) || is_numeric( $job ) ) {
299
- $job = wc_square()->get_background_job_handler()->get_job( $job );
300
- }
301
-
302
- if ( $job && is_object( $job ) && isset( $job->manual, $job->status ) && $job->manual && 'completed' === $job->status ) {
303
-
304
- $this->object = $job;
305
-
306
- $this->parse_merge_tags();
307
-
308
- $this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
309
- }
310
- }
311
- }
312
-
313
-
314
- /**
315
- * Parses the email's body merge tags.
316
- *
317
- * @since 2.0.0
318
- */
319
- protected function parse_merge_tags() {
320
-
321
- $job = $this->get_job();
322
-
323
- if ( ! $job ) {
324
- return;
325
- }
326
-
327
- $product_count = is_array( $job->processed_product_ids ) ? count( $job->processed_product_ids ) : absint( $job->processed_product_ids );
328
- /* translators: Placeholder: %d products count */
329
- $product_count = sprintf( _n( '%d product', '%d products', $product_count, 'woocommerce-square' ), $product_count );
330
-
331
- // placeholders
332
- $email_merge_tags = [
333
- 'product_count' => $product_count,
334
- 'sync_started_date' => isset( $job->started_at ) ? date( wc_date_format(), strtotime( $job->started_at ) ) : '',
335
- 'sync_started_time' => isset( $job->started_at ) ? date( wc_time_format(), strtotime( $job->started_at ) ) : '',
336
- 'sync_completed_date' => isset( $job->completed_at ) ? date( wc_date_format(), strtotime( $job->completed_at ) ) : '',
337
- 'sync_completed_time' => isset( $job->completed_at ) ? date( wc_time_format(), strtotime( $job->completed_at ) ) : '',
338
- ];
339
-
340
- // TODO update handling when WooCommerce 3.2 is the minimum required version {FN 2019-05-03}
341
- if ( Framework\SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.2' ) ) {
342
-
343
- foreach ( $email_merge_tags as $find => $replace ) {
344
- $this->placeholders[ '{' . $find . '}' ] = $replace;
345
- }
346
-
347
- } else {
348
-
349
- foreach ( $email_merge_tags as $find => $replace ) {
350
- $this->find[ $find ] = '{' . $find . '}';
351
- $this->replace[ $find ] = $replace;
352
- }
353
- }
354
- }
355
-
356
-
357
- /**
358
- * Gets the arguments that should be passed to an email template.
359
- *
360
- * @since 2.0.0
361
- *
362
- * @param array $args optional associative array with additional arguments
363
- * @return array
364
- */
365
- protected function get_template_args( $args = [] ) {
366
-
367
- $sync_job = $this->get_job();
368
- $html = empty( $args['plain_text'] );
369
-
370
- if ( $sync_job && isset( $sync_job->status ) && 'failed' === $sync_job->status ) {
371
- $email_heading = $this->get_heading_by_job_status( 'failed' );
372
- $email_body = $this->get_body_by_job_status( 'failed', $html );
373
- } else {
374
- $email_heading = $this->get_heading_by_job_status( 'completed' );
375
- $email_body = $this->get_body_by_job_status( 'completed', $html );
376
- }
377
-
378
- return array_merge( $args, [
379
- 'email' => $this,
380
- 'email_heading' => $email_heading,
381
- 'email_body' => $email_body,
382
- 'sync_job' => $sync_job,
383
- ] );
384
- }
385
-
386
-
387
- /**
388
- * Gets the email HTML content.
389
- *
390
- * @since 2.0.0
391
- *
392
- * @return string HTML
393
- */
394
- public function get_content_html() {
395
-
396
- $args = [ 'plain_text' => false ];
397
-
398
- ob_start();
399
-
400
- wc_get_template( $this->template_html, array_merge( $args, $this->get_template_args( $args ) ) );
401
-
402
- return ob_get_clean();
403
- }
404
-
405
-
406
- /**
407
- * Gets the email plain text content.
408
- *
409
- * @since 2.0.0
410
- *
411
- * @return string plain text
412
- */
413
- public function get_content_plain() {
414
-
415
- $args = [ 'plain_text' => true ];
416
-
417
- ob_start();
418
-
419
- wc_get_template( $this->template_html, array_merge( $args, $this->get_template_args( $args ) ) );
420
-
421
- return ob_get_clean();
422
- }
423
-
424
-
425
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Functions.php DELETED
@@ -1,40 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- defined( 'ABSPATH' ) or exit;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
-
29
- /**
30
- * Gets the singleton instance of WooCommerce Square.
31
- *
32
- * @since 2.0.0
33
- *
34
- * return \WooCommerce\Square\Plugin
35
- */
36
- function wc_square() {
37
-
38
- return \WooCommerce\Square\Plugin::instance();
39
- }
40
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway.php DELETED
@@ -1,783 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Model\Customer;
30
- use WooCommerce\Square\Gateway\Card_Handler;
31
- use WooCommerce\Square\Gateway\Customer_Helper;
32
- use WooCommerce\Square\Gateway\Payment_Form;
33
- use WooCommerce\Square\Handlers\Product;
34
- use WooCommerce\Square\Utilities\Money_Utility;
35
-
36
- /**
37
- * The Square payment gateway class.
38
- *
39
- * @since 2.0.0
40
- *
41
- * @method Plugin get_plugin()
42
- */
43
- class Gateway extends Framework\SV_WC_Payment_Gateway_Direct {
44
-
45
-
46
- /** @var Gateway\API API base instance */
47
- private $api;
48
-
49
-
50
- /**
51
- * Constructs the class.
52
- *
53
- * @since 2.0.0
54
- */
55
- public function __construct() {
56
-
57
- parent::__construct( Plugin::GATEWAY_ID, wc_square(), [
58
- 'method_title' => __( 'Square', 'woocommerce-square' ),
59
- 'method_description' => __( 'Allow customers to use Square to securely pay with their credit cards', 'woocommerce-square' ),
60
- 'payment_type' => self::PAYMENT_TYPE_CREDIT_CARD,
61
- 'supports' => [
62
- self::FEATURE_PRODUCTS,
63
- self::FEATURE_CARD_TYPES,
64
- self::FEATURE_DETAILED_CUSTOMER_DECLINE_MESSAGES,
65
- self::FEATURE_PAYMENT_FORM,
66
- self::FEATURE_CREDIT_CARD_AUTHORIZATION,
67
- self::FEATURE_CREDIT_CARD_CHARGE,
68
- self::FEATURE_CREDIT_CARD_CHARGE_VIRTUAL,
69
- self::FEATURE_CREDIT_CARD_CAPTURE,
70
- self::FEATURE_REFUNDS,
71
- self::FEATURE_VOIDS,
72
- self::FEATURE_CUSTOMER_ID,
73
- self::FEATURE_TOKENIZATION,
74
- self::FEATURE_ADD_PAYMENT_METHOD,
75
- self::FEATURE_TOKEN_EDITOR,
76
- ],
77
- ] );
78
-
79
- $this->view_transaction_url = 'https://squareup.com/dashboard/sales/transactions/%s';
80
-
81
- // log accept.js requests and responses
82
- add_action( 'wp_ajax_wc_' . $this->get_id() . '_log_js_data', [ $this, 'log_js_data' ] );
83
- add_action( 'wp_ajax_nopriv_wc_' . $this->get_id() . '_log_js_data', [ $this, 'log_js_data' ] );
84
-
85
- // store the Square item variation ID to order items
86
- add_action( 'woocommerce_new_order_item', [ $this, 'store_new_order_item_square_meta' ], 10, 3 );
87
-
88
- // restore refunded Square inventory
89
- add_action( 'woocommerce_order_fully_refunded', [ $this, 'restore_refunded_inventory' ], 10, 2 );
90
- }
91
-
92
-
93
- /**
94
- * Logs any data sent by the payment form JS via AJAX.
95
- *
96
- * @since 2.0.0
97
- */
98
- public function log_js_data() {
99
-
100
- check_ajax_referer( 'wc_' . $this->get_id() . '_log_js_data', 'security' );
101
-
102
- $message = sprintf( "Square.js %1\$s:\n ", ! empty( $_REQUEST['type'] ) ? ucfirst( wc_clean( $_REQUEST['type'] ) ) : 'Request' );
103
-
104
- // add the data
105
- if ( ! empty( $_REQUEST['data'] ) ) {
106
- $message .= print_r( wc_clean( $_REQUEST['data'] ), true );
107
- }
108
-
109
- $this->get_plugin()->log( $message, $this->get_id() );
110
- }
111
-
112
-
113
- /**
114
- * Stores the Square item variation ID to order items when added to orders.
115
- *
116
- * @internal
117
- *
118
- * @since 2.0.0
119
- *
120
- * @param int $item_id order item ID
121
- * @param \WC_Order_Item $item order item object
122
- * @param int $order_id order ID
123
- */
124
- public function store_new_order_item_square_meta( $item_id, $item, $order_id ) {
125
-
126
- if ( ! $item instanceof \WC_Order_Item_Product ) {
127
- return;
128
- }
129
-
130
- $product = $item->get_product();
131
-
132
- if ( ! $product instanceof \WC_Product ) {
133
- return;
134
- }
135
-
136
- if ( ! Product::is_synced_with_square( $product ) ) {
137
- return;
138
- }
139
-
140
- if ( $square_id = $product->get_meta( Product::SQUARE_VARIATION_ID_META_KEY ) ) {
141
- $item->update_meta_data( Product::SQUARE_VARIATION_ID_META_KEY, $square_id );
142
- }
143
-
144
- $item->save_meta_data();
145
- }
146
-
147
-
148
- /**
149
- * Enqueues the gateway JS.
150
- *
151
- * @since 2.0.0
152
- */
153
- protected function enqueue_gateway_assets() {
154
- if ( $this->get_plugin()->get_settings_handler()->is_sandbox() ) {
155
- $url = 'https://js.squareupsandbox.com/v2/paymentform';
156
- } else {
157
- $url = 'https://js.squareup.com/v2/paymentform';
158
- }
159
-
160
- wp_enqueue_script( 'wc-' . $this->get_plugin()->get_id_dasherized() . '-payment-form', $url, [], Plugin::VERSION );
161
-
162
- parent::enqueue_gateway_assets();
163
- }
164
-
165
-
166
- /**
167
- * Validates the entered payment fields.
168
- *
169
- * This only validates the nonce for now.
170
- *
171
- * @since 2.0.0
172
- *
173
- * @return bool
174
- */
175
- public function validate_fields() {
176
-
177
- $is_valid = true;
178
-
179
- if ( Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-token' ) ) {
180
- return $is_valid;
181
- }
182
-
183
- try {
184
-
185
- if ( ! Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' ) ) {
186
- throw new Framework\SV_WC_Payment_Gateway_Exception( 'Payment nonce is missing' );
187
- }
188
-
189
- } catch ( Framework\SV_WC_Payment_Gateway_Exception $exception ) {
190
-
191
- $is_valid = false;
192
-
193
- Framework\SV_WC_Helper::wc_add_notice( __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ), 'error' );
194
-
195
- $this->add_debug_message( $exception->getMessage(), 'error' );
196
- }
197
-
198
- return $is_valid;
199
- }
200
-
201
-
202
- /**
203
- * Gets the order object with payment information added.
204
- *
205
- * @since 2.0.0
206
- *
207
- * @param int|\WC_Order $order_id order ID or object
208
- * @return \WC_Order
209
- */
210
- public function get_order( $order_id ) {
211
-
212
- $order = parent::get_order( $order_id );
213
-
214
- if ( empty( $order->payment->token ) ) {
215
-
216
- $order->payment->nonce = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-payment-nonce' );
217
-
218
- $order->payment->card_type = Framework\SV_WC_Payment_Gateway_Helper::normalize_card_type( Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-card-type' ) );
219
- $order->payment->account_number = $order->payment->last_four = substr( Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-last-four' ), -4 );
220
- $order->payment->exp_month = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-exp-month' );
221
- $order->payment->exp_year = Framework\SV_WC_Helper::get_post( 'wc-' . $this->get_id_dasherized() . '-exp-year' );
222
- }
223
-
224
- $order->square_order_id = $this->get_order_meta( $order, 'square_order_id' );
225
- $order->square_customer_id = $order->customer_id;
226
-
227
- // look up in the index for guest customers
228
- if ( ! $order->get_user_id() ) {
229
-
230
- $indexed_customers = Gateway\Customer_Helper::get_customers_by_email( $order->get_billing_email() );
231
-
232
- // only use an indexed customer ID if there was a single one returned, otherwise we can't know which to use
233
- if ( ! empty( $indexed_customers ) && count( $indexed_customers ) === 1 ) {
234
- $order->square_customer_id = $order->customer_id = $indexed_customers[0];
235
- }
236
- }
237
-
238
- // if no previous customer could be found, always create a new customer
239
- if ( empty( $order->square_customer_id ) ) {
240
-
241
- try {
242
-
243
- $response = $this->get_api()->create_customer( $order );
244
-
245
- $order->square_customer_id = $order->customer_id = $response->get_customer_id(); // set $customer_id since we know this customer can be associated with this user
246
-
247
- // store the guests customers in our index to avoid future duplicates
248
- if ( ! $order->get_user_id() ) {
249
- Gateway\Customer_Helper::add_customer( $order->square_customer_id, $order->get_billing_email() );
250
- }
251
-
252
- } catch ( \Exception $exception ) {
253
-
254
- // log the error, but continue with payment
255
- if ( $this->debug_log() ) {
256
- $this->get_plugin()->log( $exception->getMessage(), $this->get_id() );
257
- }
258
- }
259
- }
260
-
261
- return $order;
262
- }
263
-
264
-
265
- /**
266
- * Do the transaction.
267
- *
268
- * @since 2.0.0
269
- *
270
- * @param \WC_Order $order
271
- * @return bool
272
- * @throws Framework\SV_WC_Plugin_Exception
273
- */
274
- protected function do_transaction( $order ) {
275
-
276
- // if there is no associated Square order ID, create one
277
- if ( empty( $order->square_order_id ) ) {
278
-
279
- try {
280
-
281
- $location_id = $this->get_plugin()->get_settings_handler()->get_location_id();
282
- $response = $this->get_api()->create_order( $location_id, $order );
283
-
284
- $order->square_order_id = $response->getId();
285
-
286
- // adjust order by difference between WooCommerce and Square order totals
287
- $wc_total = Money_Utility::amount_to_cents( $order->get_total() );
288
- $square_total = $response->getTotalMoney()->getAmount();
289
- $delta_total = $wc_total - $square_total;
290
-
291
- if ( abs( $delta_total ) > 0 ) {
292
- $response = $this->get_api()->adjust_order( $location_id, $order, $response->getVersion(), $delta_total );
293
-
294
- // since a downward adjustment causes (downward) tax recomputation, perform an additional (untaxed) upward adjustment if necessary
295
- $square_total = $response->getTotalMoney()->getAmount();
296
- $delta_total = $wc_total - $square_total;
297
-
298
- if ( $delta_total > 0 ) {
299
- $response = $this->get_api()->adjust_order( $location_id, $order, $response->getVersion(), $delta_total );
300
- }
301
- }
302
-
303
- // reset the payment total to the total calculated by Square to prevent errors
304
- $order->payment_total = Framework\SV_WC_Helper::number_format( Money_Utility::cents_to_float( $response->getTotalMoney()->getAmount() ) );
305
-
306
- } catch ( Framework\SV_WC_API_Exception $exception ) {
307
-
308
- // log the error, but continue with payment
309
- if ( $this->debug_log() ) {
310
- $this->get_plugin()->log( $exception->getMessage(), $this->get_id() );
311
- }
312
- }
313
- }
314
-
315
- return parent::do_transaction( $order );
316
- }
317
-
318
-
319
- /**
320
- * Adds transaction data to the order.
321
- *
322
- * @since 2.0.0
323
- *
324
- * @param \WC_Order $order order object
325
- * @param \WooCommerce\Square\Gateway\API\Responses\Charge $response API response object
326
- */
327
- public function add_payment_gateway_transaction_data( $order, $response ) {
328
-
329
- $location_id = $response->get_location_id() ?: $this->get_plugin()->get_settings_handler()->get_location_id();
330
-
331
- if ( $location_id ) {
332
- $this->update_order_meta( $order, 'square_location_id', $location_id );
333
- }
334
-
335
- if ( $response->get_square_order_id() ) {
336
- $this->update_order_meta( $order, 'square_order_id', $response->get_square_order_id() );
337
- }
338
- }
339
-
340
-
341
- /**
342
- * Gets an order with capture data attached.
343
- *
344
- * @since 2.0.0
345
- *
346
- * @param int|\WC_Order $order order object
347
- * @param null|float $amount amount to capture
348
- * @return \WC_Order
349
- */
350
- public function get_order_for_capture( $order, $amount = null ) {
351
-
352
- $order = parent::get_order_for_capture( $order, $amount );
353
-
354
- $order->capture->location_id = $this->get_order_meta( $order, 'square_location_id' );
355
-
356
- return $order;
357
- }
358
-
359
-
360
- /**
361
- * Gets an order with refund data attached.
362
- *
363
- * @since 2.0.0
364
- *
365
- * @param int|\WC_Order $order order object
366
- * @param float $amount amount to refund
367
- * @param string $reason response for the refund
368
- *
369
- * @return \WC_Order|\WP_Error
370
- */
371
- protected function get_order_for_refund( $order, $amount, $reason ) {
372
-
373
- $order = parent::get_order_for_refund( $order, $amount, $reason );
374
-
375
- if ( $transaction_date = $this->get_order_meta( $order, 'trans_date' ) ) {
376
-
377
- // throw an error if the payment is > 120 days old
378
- if ( current_time( 'timestamp' ) - strtotime( $transaction_date ) > 120 * DAY_IN_SECONDS ) {
379
- return new \WP_Error( 'wc_square_refund_age_exceeded', __( 'Refunds must be made within 120 days of the original payment date.', 'woocommerce-square' ) );
380
- }
381
- }
382
-
383
- $order->refund->location_id = $this->get_order_meta( $order, 'square_location_id' );
384
- $order->refund->tender_id = $this->get_order_meta( $order, 'authorization_code' );
385
-
386
- if ( ! $order->refund->tender_id ) {
387
-
388
- try {
389
-
390
- $response = $this->get_api()->get_transaction( $order->refund->trans_id, $order->refund->location_id );
391
-
392
- if ( ! $response->get_authorization_code() ) {
393
- throw new Framework\SV_WC_Plugin_Exception( 'Tender missing' );
394
- }
395
-
396
- $this->update_order_meta( $order, 'authorization_code', $response->get_authorization_code() );
397
- $this->update_order_meta( $order, 'square_location_id', $response->get_location_id() );
398
-
399
- $order->refund->location_id = $response->get_location_id();
400
- $order->refund->tender_id = $response->get_authorization_code();
401
-
402
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
403
-
404
- return new \WP_Error( 'wc_square_refund_tender_missing', __( 'Could not find original transaction tender. Please refund this transaction from your Square dashboard.', 'woocommerce-square' ) );
405
- }
406
- }
407
-
408
- return $order;
409
- }
410
-
411
-
412
- /**
413
- * Restores refunded Square inventory.
414
- *
415
- * @internal
416
- *
417
- * @since 2.0.0
418
- *
419
- * @param int $order_id order ID
420
- * @param int $refund_id refund ID
421
- */
422
- public function restore_refunded_inventory( $order_id, $refund_id ) {
423
-
424
- // no handling if inventory sync is disabled
425
- if ( ! $this->get_plugin()->get_settings_handler()->is_inventory_sync_enabled() ) {
426
- return;
427
- }
428
-
429
- $order = wc_get_order( $order_id );
430
-
431
- if ( ! $order instanceof \WC_Order ) {
432
- return;
433
- }
434
-
435
- // check that the order was paid using our gateway
436
- if ( $order->get_payment_method() !== $this->get_id() ) {
437
- return;
438
- }
439
-
440
- $refund = wc_get_order( $refund_id );
441
-
442
- if ( ! $refund instanceof \WC_Order_Refund ) {
443
- return;
444
- }
445
-
446
- foreach ( $order->get_items() as $item ) {
447
-
448
- if ( ! $item instanceof \WC_Order_Item_Product ) {
449
- continue;
450
- }
451
-
452
- // if this item has an associated Square ID, send a stock adjustment
453
- if ( $square_id = $item->get_meta( Product::SQUARE_VARIATION_ID_META_KEY ) ) {
454
-
455
- try {
456
-
457
- $this->get_plugin()->get_api()->add_inventory_from_refund( $square_id, $item->get_quantity() );
458
-
459
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
460
-
461
- $this->get_plugin()->log( 'Could not send refund inventory adjustment. ' . $exception->getMessage() );
462
- }
463
- }
464
- }
465
- }
466
-
467
-
468
- /**
469
- * Gets a mock order for adding a new payment method.
470
- *
471
- * @since 2.0.0
472
- *
473
- * @return \WC_Order
474
- */
475
- protected function get_order_for_add_payment_method() {
476
-
477
- $order = parent::get_order_for_add_payment_method();
478
-
479
- // if the customer doesn't have a postcode yet, use the value returned by Square JS
480
- if ( ! $order->get_billing_postcode() && $postcode = Framework\SV_WC_Helper::get_post( 'wc-square-credit-card-payment-postcode') ) {
481
- $order->set_billing_postcode( $postcode );
482
- }
483
-
484
- return $order;
485
- }
486
-
487
-
488
- /**
489
- * Builds the payment tokens handler instance.
490
- *
491
- * @since 2.0.0
492
- *
493
- * @return Card_Handler
494
- */
495
- public function build_payment_tokens_handler() {
496
-
497
- return new Card_Handler( $this );
498
- }
499
-
500
-
501
- /** Admin methods *************************************************************************************************/
502
-
503
-
504
- /**
505
- * Adds the tokenization form fields to the gateway settings.
506
- *
507
- * Overridden to change the setting name to "Customer Profiles."
508
- *
509
- * @since 2.0.0
510
- *
511
- * @param array $form_fields existing fields
512
- * @return array
513
- */
514
- protected function add_tokenization_form_fields( $form_fields ) {
515
-
516
- $form_fields = parent::add_tokenization_form_fields( $form_fields );
517
-
518
- if ( ! empty( $form_fields['tokenization'] ) ) {
519
- $form_fields['tokenization']['title'] = __( 'Customer Profiles', 'woocommerce-square' );
520
- }
521
-
522
- return $form_fields;
523
- }
524
-
525
-
526
- /**
527
- * Clear the CSC field settings, as CSC is always required by Square.
528
- *
529
- * @since 2.0.0
530
- *
531
- * @param array $form_fields
532
- * @return array
533
- */
534
- protected function add_csc_form_fields( $form_fields ) {
535
-
536
- return $form_fields;
537
- }
538
-
539
-
540
- /**
541
- * Adds the Card Types setting field.
542
- *
543
- * This removes Diners & Discovers from the defaults as they are not supported in the UK or Japan.
544
- *
545
- * @since 2.0.0
546
- *
547
- * @param array $form_fields
548
- * @return array
549
- */
550
- protected function add_card_types_form_fields( $form_fields ) {
551
-
552
- $form_fields = parent::add_card_types_form_fields( $form_fields );
553
-
554
- if ( isset( $form_fields['card_types']['default'] ) ) {
555
-
556
- foreach ( $form_fields['card_types']['default'] as $key => $type ) {
557
-
558
- if ( in_array( $type, [ 'DISC', 'DINERS' ], true ) ) {
559
- unset( $form_fields['card_types']['default'][ $key ] );
560
- }
561
- }
562
- }
563
-
564
- return $form_fields;
565
- }
566
-
567
-
568
- /** Conditional methods *******************************************************************************************/
569
-
570
-
571
- /**
572
- * Determines if the gateway is available.
573
- *
574
- * @since 2.0.0
575
- *
576
- * @return bool
577
- */
578
- public function is_available() {
579
-
580
- return parent::is_available() && $this->get_plugin()->get_settings_handler()->is_connected() && $this->get_plugin()->get_settings_handler()->get_location_id();
581
- }
582
-
583
-
584
- /**
585
- * Determines whether the CSC field is enabled.
586
- *
587
- * This is always required by the Square payment form JS.
588
- *
589
- * @since 2.0.0
590
- *
591
- * @return bool
592
- */
593
- public function csc_enabled() {
594
-
595
- return true;
596
- }
597
-
598
-
599
- /**
600
- * Determines whether new payment customers/tokens should be created before processing a payment.
601
- *
602
- * Square requires we create a new customer & customer card before referencing that customer in a transaction.
603
- *
604
- * @since 2.0.0
605
- *
606
- * @return bool
607
- */
608
- public function tokenize_before_sale() {
609
-
610
- return true;
611
- }
612
-
613
-
614
- /** Getter methods ************************************************************************************************/
615
-
616
-
617
- /**
618
- * Gets order meta.
619
- *
620
- * Overridden to handle any missing transaction ID meta from v1.
621
- *
622
- * @since 2.0.0
623
- *
624
- * @param \WC_Order|int $order order object or ID
625
- * @param string $key meta key
626
- * @return mixed
627
- */
628
- public function get_order_meta( $order, $key ) {
629
-
630
- if ( is_numeric( $order ) ) {
631
- $order = wc_get_order( $order );
632
- }
633
-
634
- // migrate any missing transaction IDs
635
- if ( $order && 'trans_id' === $key && ! parent::get_order_meta( $order, $key ) && $order->get_transaction_id() ) {
636
- $this->update_order_meta( $order, 'trans_id', $order->get_transaction_id() );
637
- }
638
-
639
- return parent::get_order_meta( $order, $key );
640
- }
641
-
642
-
643
- /**
644
- * Gets the authorization -> capture time window.
645
- *
646
- * Square limits captures to 6 days.
647
- *
648
- * @since 2.0.0
649
- *
650
- * @return int
651
- */
652
- public function get_authorization_time_window() {
653
-
654
- return 144;
655
- }
656
-
657
-
658
- /**
659
- * Gets the payment form handler instance.
660
- *
661
- * @since 2.0.0
662
- *
663
- * @return Payment_Form
664
- */
665
- public function get_payment_form_instance() {
666
-
667
- return new Payment_Form( $this );
668
- }
669
-
670
-
671
- /**
672
- * Gets the API instance.
673
- *
674
- * @since 2.0.0
675
- *
676
- * @return Gateway\API
677
- */
678
- public function get_api() {
679
-
680
- if ( ! $this->api ) {
681
- $settings = $this->get_plugin()->get_settings_handler();
682
- $this->api = new Gateway\API( $settings->get_access_token(), $settings->get_location_id(), $settings->is_sandbox() );
683
- }
684
-
685
- return $this->api;
686
- }
687
-
688
-
689
- /**
690
- * Gets the gateway settings fields.
691
- *
692
- * @since 2.0.0
693
- *
694
- * @return array
695
- */
696
- protected function get_method_form_fields() {
697
-
698
- return [];
699
- }
700
-
701
-
702
- /**
703
- * Gets a user's stored customer ID.
704
- *
705
- * Overridden to avoid auto-creating customer IDs, as Square generates them.
706
- *
707
- * @since 2.0.0
708
- *
709
- * @param int $user_id user ID
710
- * @param array $args arguments
711
- * @return string
712
- */
713
- public function get_customer_id( $user_id, $args = [] ) {
714
-
715
- // Square generates customer IDs
716
- $args['autocreate'] = false;
717
-
718
- return parent::get_customer_id( $user_id, $args );
719
- }
720
-
721
-
722
- /**
723
- * Gets a guest's customer ID.
724
- *
725
- * @since 2.0.0
726
- *
727
- * @param \WC_Order $order order object
728
- * @return string|bool
729
- */
730
- public function get_guest_customer_id( \WC_Order $order ) {
731
-
732
- // is there a customer id already tied to this order?
733
- $customer_id = $this->get_order_meta( $order, 'customer_id' );
734
-
735
- if ( $customer_id ) {
736
- return $customer_id;
737
- }
738
-
739
- return false;
740
- }
741
-
742
-
743
- /**
744
- * Gets the configured environment ID.
745
- *
746
- * Square doesn't really support a sandbox, so we don't show a setting for this.
747
- *
748
- * @since 2.0.0
749
- *
750
- * @return string
751
- */
752
- public function get_environment() {
753
-
754
- return self::ENVIRONMENT_PRODUCTION;
755
- }
756
-
757
- /**
758
- * Gets the configured application ID.
759
- *
760
- * @since 2.0.0
761
- *
762
- * @return string
763
- */
764
- public function get_application_id() {
765
-
766
- $square_application_id = 'sq0idp-wGVapF8sNt9PLrdj5znuKA';
767
-
768
- if ( $this->get_plugin()->get_settings_handler()->is_sandbox() ) {
769
- $square_application_id = $this->get_plugin()->get_settings_handler()->get_option( 'sandbox_application_id' );
770
- }
771
-
772
- /**
773
- * Filters the configured application ID.
774
- *
775
- * @since 2.0.0
776
- *
777
- * @param string $application_id application ID
778
- */
779
- return apply_filters( 'wc_square_application_id', $square_application_id );
780
- }
781
-
782
-
783
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API.php DELETED
@@ -1,498 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Model\Order;
30
-
31
- /**
32
- * The base Square gateway API class.
33
- *
34
- * @since 2.0.0
35
- */
36
- class API extends \WooCommerce\Square\API {
37
-
38
-
39
- /** @var string location ID to use for requests */
40
- protected $location_id;
41
-
42
- /** @var \WC_Order order object associated with a request, if any */
43
- protected $order;
44
-
45
-
46
- /**
47
- * Constructs the class.
48
- *
49
- * @since 2.0.0
50
- *
51
- * @param string $access_token the API access token
52
- * @param string $location_id location ID to use for requests
53
- */
54
- public function __construct( $access_token, $location_id, $is_sandbox = null ) {
55
-
56
- parent::__construct( $access_token, $is_sandbox );
57
-
58
- $this->location_id = $location_id;
59
- }
60
-
61
-
62
- /** Transaction methods *******************************************************************************************/
63
-
64
-
65
- /**
66
- * Performs a credit card authorization for the given order.
67
- *
68
- * @since 2.0.0
69
- *
70
- * @param \WC_Order $order order object
71
- * @return \WooCommerce\Square\API\Response
72
- * @throws Framework\SV_WC_API_Exception
73
- */
74
- public function credit_card_authorization( \WC_Order $order ) {
75
-
76
- $request = new API\Requests\Transactions( $this->get_location_id(), $this->client );
77
-
78
- $request->set_authorization_data( $order );
79
-
80
- $this->set_response_handler( API\Responses\Charge::class );
81
-
82
- return $this->perform_request( $request );
83
- }
84
-
85
-
86
- /**
87
- * Performs a credit card charge for the given order.
88
- *
89
- * @since 2.0.0
90
- *
91
- * @param \WC_Order $order order object
92
- * @return \WooCommerce\Square\API\Response
93
- * @throws Framework\SV_WC_API_Exception
94
- */
95
- public function credit_card_charge( \WC_Order $order ) {
96
-
97
- $request = new API\Requests\Transactions( $this->get_location_id(), $this->client );
98
-
99
- $request->set_charge_data( $order );
100
-
101
- $this->set_response_handler( API\Responses\Charge::class );
102
-
103
- return $this->perform_request( $request );
104
- }
105
-
106
-
107
- /**
108
- * Performs a credit card capture for a given authorized order.
109
- *
110
- * @since 2.0.0
111
- *
112
- * @param \WC_Order $order order object
113
- * @return \WooCommerce\Square\API\Response
114
- * @throws Framework\SV_WC_API_Exception
115
- */
116
- public function credit_card_capture( \WC_Order $order ) {
117
-
118
- $location_id = ! empty( $order->capture->location_id ) ? $order->capture->location_id : $this->get_location_id();
119
-
120
- $request = new API\Requests\Transactions( $location_id, $this->client );
121
-
122
- $request->set_capture_data( $order );
123
-
124
- $this->set_response_handler( API\Response::class );
125
-
126
- return $this->perform_request( $request );
127
- }
128
-
129
-
130
- /**
131
- * Performs a refund for the given order.
132
- *
133
- * @since 2.0.0
134
- *
135
- * @param \WC_Order $order order object
136
- * @return \WooCommerce\Square\API\Response
137
- * @throws Framework\SV_WC_API_Exception
138
- */
139
- public function refund( \WC_Order $order ) {
140
-
141
- $location_id = ! empty( $order->refund->location_id ) ? $order->refund->location_id : $this->get_location_id();
142
-
143
- $request = new API\Requests\Transactions( $location_id, $this->client );
144
-
145
- $request->set_refund_data( $order );
146
-
147
- $this->set_response_handler( API\Responses\Refund::class );
148
-
149
- return $this->perform_request( $request );
150
- }
151
-
152
-
153
- /**
154
- * Performs a void for the given order.
155
- *
156
- * @since 2.0.0
157
- *
158
- * @param \WC_Order $order order object
159
- * @return \WooCommerce\Square\API\Response
160
- * @throws Framework\SV_WC_API_Exception
161
- */
162
- public function void( \WC_Order $order ) {
163
-
164
- $location_id = ! empty( $order->refund->location_id ) ? $order->refund->location_id : $this->get_location_id();
165
-
166
- $request = new API\Requests\Transactions( $location_id, $this->client );
167
-
168
- $request->set_void_data( $order );
169
-
170
- $this->set_response_handler( API\Response::class );
171
-
172
- return $this->perform_request( $request );
173
- }
174
-
175
-
176
- /**
177
- * Creates a payment token for the given order.
178
- *
179
- * @since 2.0.0
180
- *
181
- * @param \WC_Order $order the order object
182
- * @return API\Responses\Create_Customer_Card|API\Responses\Create_Customer
183
- * @throws Framework\SV_WC_API_Exception
184
- */
185
- public function tokenize_payment_method( \WC_Order $order ) {
186
-
187
- // a customer ID should've already been created, but just in case...
188
- if ( empty( $order->customer_id ) ) {
189
-
190
- $response = $this->create_customer( $order );
191
-
192
- if ( ! $response->transaction_approved() ) {
193
- return $response;
194
- }
195
-
196
- $order->customer_id = $response->get_customer_id();
197
- }
198
-
199
- return $this->create_customer_card( $order );
200
- }
201
-
202
-
203
- /**
204
- * Creates a payment token for the given order.
205
- *
206
- * @since 2.0.0
207
- *
208
- * @param \WC_Order $order the order object
209
- * @return API\Responses\Create_Customer_Card
210
- * @throws Framework\SV_WC_API_Exception
211
- */
212
- public function create_customer_card( \WC_Order $order ) {
213
-
214
- $request = new API\Requests\Customers( $this->client );
215
-
216
- $request->set_create_card_data( $order );
217
-
218
- $this->set_response_handler( API\Responses\Create_Customer_Card::class );
219
-
220
- return $this->perform_request( $request );
221
- }
222
-
223
-
224
- /**
225
- * Creates a new customer based on the given order.
226
- *
227
- * @since 2.0.0
228
- *
229
- * @param \WC_Order $order order object
230
- * @return API\Responses\Create_Customer
231
- * @throws Framework\SV_WC_API_Exception
232
- */
233
- public function create_customer( \WC_Order $order ) {
234
-
235
- $request = new API\Requests\Customers( $this->client );
236
-
237
- $request->set_create_customer_data( $order );
238
-
239
- $this->set_response_handler( API\Responses\Create_Customer::class );
240
-
241
- return $this->perform_request( $request );
242
- }
243
-
244
-
245
- /**
246
- * Gets all tokenized payment methods for the customer.
247
- *
248
- * @since 2.0.0
249
- *
250
- * @param string $customer_id unique customer id
251
- * @return API\Responses\Get_Customer
252
- * @throws Framework\SV_WC_API_Exception
253
- */
254
- public function get_tokenized_payment_methods( $customer_id ) {
255
-
256
- $request = new API\Requests\Customers( $this->client );
257
-
258
- $request->set_get_customer_data( $customer_id );
259
-
260
- $this->set_response_handler( API\Responses\Get_Customer::class );
261
-
262
- return $this->perform_request( $request );
263
- }
264
-
265
-
266
- /**
267
- * Removes the tokenized payment method.
268
- *
269
- * @since 2.0.0
270
- *
271
- * @param string $token the payment method token
272
- * @param string $customer_id unique customer id
273
- * @return API\Response
274
- * @throws Framework\SV_WC_API_Exception
275
- */
276
- public function remove_tokenized_payment_method( $token, $customer_id ) {
277
-
278
- $request = new API\Requests\Customers( $this->client );
279
-
280
- $request->set_delete_card_data( $customer_id, $token );
281
-
282
- $this->set_response_handler( API\Response::class );
283
-
284
- return $this->perform_request( $request );
285
- }
286
-
287
-
288
- /**
289
- * Creates a new Square order from a WooCommerce order.
290
- *
291
- * @since 2.0.0
292
- *
293
- * @param string $location_id location ID
294
- * @param \WC_Order $order
295
- * @return Order
296
- * @throws Framework\SV_WC_API_Exception
297
- */
298
- public function create_order( $location_id, \WC_Order $order ) {
299
-
300
- $request = new API\Requests\Orders( $this->client );
301
-
302
- $request->set_create_order_data( $location_id, $order );
303
-
304
- $this->set_response_handler( \WooCommerce\Square\API\Response::class );
305
-
306
- $response = $this->perform_request( $request );
307
-
308
- return $response->get_data()->getOrder();
309
- }
310
-
311
-
312
- /**
313
- * Adjusts an existing Square order by amount.
314
- *
315
- * @since 2.0.4
316
- *
317
- * @param string $location_id location ID
318
- * @param \WC_Order $order
319
- * @param int $version Current 'version' value of Square order
320
- * @param int $amount Amount of adjustment in smallest unit
321
- * @return Order
322
- * @throws Framework\SV_WC_API_Exception
323
- */
324
- public function adjust_order( $location_id, \WC_Order $order, $version, $amount ) {
325
-
326
- $request = new API\Requests\Orders( $this->client );
327
-
328
- if ( $amount > 0 ) {
329
- $request->add_line_item_order_data( $location_id, $order, $version, $amount );
330
- } else {
331
- $request->add_discount_order_data( $location_id, $order, $version, -1 * $amount );
332
- }
333
- $this->set_response_handler( \WooCommerce\Square\API\Response::class );
334
-
335
- $response = $this->perform_request( $request );
336
-
337
- return $response->get_data()->getOrder();
338
- }
339
-
340
-
341
- /**
342
- * Gets an existing transaction.
343
- *
344
- * @since 2.0.0
345
- *
346
- * @param string $transaction_id transaction ID
347
- * @param string $location_id location ID
348
- * @return API\Responses\Charge
349
- * @throws Framework\SV_WC_API_Exception
350
- */
351
- public function get_transaction( $transaction_id, $location_id = '' ) {
352
-
353
- if ( ! $location_id ) {
354
- $location_id = $this->get_location_id();
355
- }
356
-
357
- $request = new API\Requests\Transactions( $location_id, $this->client );
358
-
359
- $request->set_get_transaction_data( $transaction_id );
360
-
361
- $this->set_response_handler( API\Responses\Charge::class );
362
-
363
- return $this->perform_request( $request );
364
- }
365
-
366
-
367
- /**
368
- * Validates the parsed response.
369
- *
370
- * @since 2.0.0
371
- *
372
- * @return bool
373
- * @throws Framework\SV_WC_API_Exception
374
- */
375
- protected function do_post_parse_response_validation() {
376
-
377
- // gateway responses need to get through to check API\Response::transaction_approved()
378
- if ( $this->get_response() instanceof API\Response ) {
379
- return true;
380
- }
381
-
382
- return parent::do_post_parse_response_validation();
383
- }
384
-
385
-
386
- /** Conditional methods *******************************************************************************************/
387
-
388
-
389
- /**
390
- * Determines if this API supports getting a customer's tokenized payment methods.
391
- *
392
- * @since 2.0.0
393
- *
394
- * @return bool
395
- */
396
- public function supports_get_tokenized_payment_methods() {
397
-
398
- return true;
399
- }
400
-
401
-
402
- /**
403
- * Determines if this API supports updating tokenized payment methods.
404
- *
405
- * @see SV_WC_Payment_Gateway_API::update_tokenized_payment_method()
406
- *
407
- * @since 2.0.0
408
- *
409
- * @return bool
410
- */
411
- public function supports_update_tokenized_payment_method() {
412
-
413
- return false;
414
- }
415
-
416
-
417
- /**
418
- * Determines if this API supports removing a tokenized payment method.
419
- *
420
- * @since 2.0.0
421
- *
422
- * @return bool
423
- */
424
- public function supports_remove_tokenized_payment_method() {
425
-
426
- return true;
427
- }
428
-
429
-
430
- /** Getter methods ************************************************************************************************/
431
-
432
-
433
- /**
434
- * Gets the location ID to be used for requests.
435
- *
436
- * @since 2.0.0
437
- *
438
- * @return string
439
- */
440
- protected function get_location_id() {
441
-
442
- return $this->location_id;
443
- }
444
-
445
-
446
- /**
447
- * Gets the object associated with the request, if any.
448
- *
449
- * @since 2.0.0
450
- *
451
- * @return \WC_Order
452
- */
453
- public function get_order() {
454
-
455
- return $this->order;
456
- }
457
-
458
-
459
- /**
460
- * Gets the API ID.
461
- *
462
- * @since 2.0.0
463
- *
464
- * @return string
465
- */
466
- protected function get_api_id() {
467
-
468
- return $this->get_plugin()->get_gateway()->get_id();
469
- }
470
-
471
-
472
- /** No-op methods *************************************************************************************************/
473
-
474
-
475
- /**
476
- * The gateway API does not support check debits.
477
- *
478
- * @since 2.0.0
479
- *
480
- * @param \WC_Order $order order object
481
- */
482
- public function check_debit( \WC_Order $order ) {}
483
-
484
-
485
- /**
486
- * Updates a tokenized payment method.
487
- *
488
- * Square API does not allow updating a stored card's address, and instead recommends deleting and re-adding a new
489
- * card. This isn't an option for us since subscriptions would break any time an address is updated.
490
- *
491
- * @since 2.0.0
492
- *
493
- * @param \WC_Order $order order object
494
- */
495
- public function update_tokenized_payment_method( \WC_Order $order ) {}
496
-
497
-
498
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Requests/Customers.php DELETED
@@ -1,162 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Requests;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Model as SquareModel;
30
- use WooCommerce\Square\API;
31
-
32
- /**
33
- * The customers API request class.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Customers extends API\Requests\Customers {
38
-
39
-
40
- /**
41
- * Sets the data for creating a new customer.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @param \WC_Order $order order object
46
- */
47
- public function set_create_customer_data( \WC_Order $order ) {
48
-
49
- $this->square_api_method = 'createCustomer';
50
-
51
- // set the customer email as the WP user email, if available
52
- try {
53
-
54
- if ( ! $order->get_user_id() ) {
55
- throw new Framework\SV_WC_Plugin_Exception( 'No user account' );
56
- }
57
-
58
- $customer = new \WC_Customer( $order->get_user_id() );
59
-
60
- $email = $customer->get_email();
61
-
62
- // otherwise, use the order billing email
63
- } catch ( \Exception $exception ) {
64
-
65
- $email = $order->get_billing_email();
66
- }
67
-
68
- $customer_request = new SquareModel\CreateCustomerRequest();
69
- $customer_request->setGivenName( $order->get_billing_first_name() );
70
- $customer_request->setFamilyName( $order->get_billing_last_name() );
71
- $customer_request->setCompanyName( $order->get_billing_company() );
72
- $customer_request->setEmailAddress( $email );
73
- $customer_request->setPhoneNumber( $order->get_billing_phone() );
74
-
75
- if ( $order->get_user_id() ) {
76
- $customer_request->setReferenceId( (string) $order->get_user_id() );
77
- }
78
-
79
- $customer_request->setAddress( $this->get_address_from_order( $order ) );
80
-
81
- $this->square_request = $customer_request;
82
-
83
- $this->square_api_args = [
84
- $this->square_request,
85
- ];
86
- }
87
-
88
-
89
- /**
90
- * Sets the data for creating a new customer card.
91
- *
92
- * @since 2.0.0
93
- *
94
- * @param \WC_Order $order order object
95
- */
96
- public function set_create_card_data( \WC_Order $order ) {
97
-
98
- $this->square_api_method = 'createCustomerCard';
99
-
100
- $request = new SquareModel\CreateCustomerCardRequest();
101
-
102
- $request->setCardNonce( $order->payment->nonce );
103
- $request->setBillingAddress( $this->get_address_from_order( $order ) );
104
- $request->setCardholderName( $order->get_formatted_billing_full_name() );
105
-
106
- $this->square_request = $request;
107
-
108
- $this->square_api_args = [
109
- $order->customer_id,
110
- $this->square_request,
111
- ];
112
- }
113
-
114
-
115
- /**
116
- * Sets the data for deleting an existing card.
117
- *
118
- * @since 2.0.0
119
- *
120
- * @param string $customer_id Square customer ID
121
- * @param string $card_id Square card ID
122
- */
123
- public function set_delete_card_data( $customer_id, $card_id ) {
124
-
125
- $this->square_api_method = 'deleteCustomerCard';
126
-
127
- $this->square_api_args = [
128
- $customer_id,
129
- $card_id,
130
- ];
131
- }
132
-
133
-
134
- /**
135
- * Gets a billing address model from a WC order.
136
- *
137
- * @since 2.0.0
138
- *
139
- * @param \WC_Order $order order object
140
- * @return SquareModel\Address
141
- */
142
- protected function get_address_from_order( \WC_Order $order ) {
143
-
144
- $address = new SquareModel\Address();
145
- $address->setFirstName( $order->get_billing_first_name() );
146
- $address->setLastName( $order->get_billing_last_name() );
147
- $address->setOrganization( $order->get_billing_company() );
148
- $address->setAddressLine1( $order->get_billing_address_1() );
149
- $address->setAddressLine2( $order->get_billing_address_2() );
150
- $address->setLocality( $order->get_billing_city() );
151
- $address->setAdministrativeDistrictLevel1( $order->get_billing_state() );
152
- $address->setPostalCode( $order->get_billing_postcode() );
153
-
154
- if ( $order->get_billing_country() ) {
155
- $address->setCountry( $order->get_billing_country() );
156
- }
157
-
158
- return $address;
159
- }
160
-
161
-
162
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Requests/Orders.php DELETED
@@ -1,338 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Requests;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Api\OrdersApi;
30
- use SquareConnect\Model as SquareModel;
31
- use WooCommerce\Square\API;
32
- use WooCommerce\Square\Handlers\Product;
33
- use WooCommerce\Square\Utilities\Money_Utility;
34
-
35
- /**
36
- * The Orders API request class.
37
- *
38
- * @since 2.0.0
39
- */
40
- class Orders extends API\Request {
41
-
42
-
43
- /**
44
- * Initializes a new Catalog request.
45
- *
46
- * @since 2.0.0
47
- *
48
- * @param \SquareConnect\ApiClient $api_client the API client
49
- */
50
- public function __construct( $api_client ) {
51
-
52
- $this->square_api = new OrdersApi( $api_client );
53
- }
54
-
55
-
56
- /**
57
- * Sets the data for creating an order.
58
- *
59
- * @since 2.0.0
60
- *
61
- * @param string $location_id location ID
62
- * @param \WC_Order $order order object
63
- */
64
- public function set_create_order_data( $location_id, \WC_Order $order ) {
65
-
66
- $this->square_api_method = 'createOrder';
67
- $this->square_request = new SquareModel\CreateOrderRequest();
68
-
69
- $order_model = new SquareModel\Order();
70
- $order_model->setReferenceId( $order->get_order_number() );
71
-
72
- $line_items = array_merge( $this->get_product_line_items( $order ), $this->get_fee_line_items( $order ), $this->get_shipping_line_items( $order ) );
73
- $taxes = $this->get_order_taxes( $order );
74
-
75
- $this->apply_taxes( $taxes, $line_items );
76
- $order_model->setLineItems( $line_items );
77
- $order_model->setTaxes( $taxes );
78
-
79
- if ( $order->get_discount_total() ) {
80
-
81
- $order_model->setDiscounts( [ new SquareModel\OrderLineItemDiscount( [
82
- 'name' => __( 'Discount', 'woocommerce-square' ),
83
- 'type' => 'FIXED_AMOUNT',
84
- 'amount_money' => Money_Utility::amount_to_money( $order->get_discount_total(), $order->get_currency() ),
85
- 'scope' => 'ORDER',
86
- ] ) ] );
87
- }
88
-
89
- $this->square_request->setIdempotencyKey( wc_square()->get_idempotency_key( $order->unique_transaction_ref ) );
90
- $this->square_request->setOrder( $order_model );
91
-
92
- $this->square_api_args = [
93
- $location_id,
94
- $this->square_request,
95
- ];
96
- }
97
-
98
-
99
- /**
100
- * Gets Square line item objects for an order's product items.
101
- *
102
- * @since 2.0.0
103
- *
104
- * @param \WC_Order $order order object
105
- * @return SquareModel\OrderLineItem[]
106
- */
107
- protected function get_product_line_items( \WC_Order $order ) {
108
-
109
- $line_items = [];
110
-
111
- foreach ( $order->get_items() as $item ) {
112
-
113
- if ( ! $item instanceof \WC_Order_Item_Product ) {
114
- continue;
115
- }
116
-
117
- $line_item = new SquareModel\OrderLineItem();
118
-
119
- $line_item->setQuantity( (string) $item->get_quantity() );
120
- $line_item->setBasePriceMoney( Money_Utility::amount_to_money( $order->get_item_subtotal( $item ), $order->get_currency() ) );
121
-
122
- $square_id = $item->get_meta( Product::SQUARE_VARIATION_ID_META_KEY );
123
-
124
- if ( $square_id ) {
125
- $line_item->setCatalogObjectId( $square_id );
126
- } else {
127
- $line_item->setName( $item->get_name() );
128
- }
129
-
130
- $line_items[] = $line_item;
131
- }
132
-
133
- return $line_items;
134
- }
135
-
136
-
137
- /**
138
- * Gets Square line item objects for an order's fee items.
139
- *
140
- * @since 2.0.0
141
- *
142
- * @param \WC_Order $order order object
143
- * @return SquareModel\OrderLineItem[]
144
- */
145
- protected function get_fee_line_items( \WC_Order $order ) {
146
-
147
- $line_items = [];
148
-
149
- foreach ( $order->get_fees() as $item ) {
150
-
151
- if ( ! $item instanceof \WC_Order_Item_Fee ) {
152
- continue;
153
- }
154
-
155
- $line_item = new SquareModel\OrderLineItem();
156
-
157
- $line_item->setQuantity( (string) 1 );
158
-
159
- $line_item->setName( $item->get_name() );
160
- $line_item->setBasePriceMoney( Money_Utility::amount_to_money( $item->get_total(), $order->get_currency() ) );
161
-
162
- $line_items[] = $line_item;
163
- }
164
-
165
- return $line_items;
166
- }
167
-
168
-
169
- /**
170
- * Gets Square line item objects for an order's shipping items.
171
- *
172
- * @since 2.0.0
173
- *
174
- * @param \WC_Order $order order object
175
- * @return SquareModel\OrderLineItem[]
176
- */
177
- protected function get_shipping_line_items( \WC_Order $order ) {
178
-
179
- $line_items = [];
180
-
181
- foreach ( $order->get_shipping_methods() as $item ) {
182
-
183
- if ( ! $item instanceof \WC_Order_Item_Shipping ) {
184
- continue;
185
- }
186
-
187
- $line_item = new SquareModel\OrderLineItem();
188
-
189
- $line_item->setQuantity( (string) 1 );
190
-
191
- $line_item->setName( $item->get_name() );
192
- $line_item->setBasePriceMoney( Money_Utility::amount_to_money( $item->get_total(), $order->get_currency() ) );
193
-
194
- $line_items[] = $line_item;
195
- }
196
-
197
- return $line_items;
198
- }
199
-
200
-
201
- /**
202
- * Gets the tax line items for an order.
203
- *
204
- * @since 2.0.0
205
- *
206
- * @param \WC_Order $order
207
- * @return SquareModel\OrderLineItemTax[]
208
- */
209
- protected function get_order_taxes( \WC_Order $order ) {
210
-
211
- $taxes = [];
212
-
213
- foreach ( $order->get_taxes() as $tax ) {
214
-
215
- $tax_item = new SquareModel\OrderLineItemTax( [
216
- 'uid' => uniqid(),
217
- 'name' => $tax->get_name(),
218
- 'type' => 'ADDITIVE',
219
- 'scope' => 'LINE_ITEM',
220
- ] );
221
-
222
- $pre_tax_total = (float) $order->get_total() - (float) $order->get_total_tax();
223
- $total_tax = (float) $tax->get_tax_total() + (float) $tax->get_shipping_tax_total();
224
-
225
- $percentage = ( $total_tax / $pre_tax_total ) * 100;
226
-
227
- $tax_item->setPercentage( Framework\SV_WC_Helper::number_format( $percentage ) );
228
-
229
- $taxes[] = $tax_item;
230
- }
231
-
232
- return $taxes;
233
- }
234
-
235
-
236
- /**
237
- * Applies taxes on each Square line item.
238
- *
239
- * @since 2.0.4
240
- *
241
- * @param SquareModel\OrderLineItemTax[] $taxes
242
- * @param SquareModel\OrderLineItem[] $line_items
243
- */
244
- protected function apply_taxes( $taxes, $line_items ) {
245
-
246
- foreach ( $line_items as $line_item ) {
247
-
248
- $applied_taxes = [];
249
-
250
- foreach ( $taxes as $tax ) {
251
-
252
- $applied_taxes[] = new SquareModel\OrderLineItemAppliedTax( [
253
- 'tax_uid' => $tax->getUid(),
254
- ] );
255
- }
256
-
257
- $line_item->setAppliedTaxes( $applied_taxes );
258
- }
259
- }
260
-
261
-
262
- /**
263
- * Sets the data for updating an order with a line item adjustment.
264
- *
265
- * @since 2.0.4
266
- *
267
- * @param string $location_id location ID
268
- * @param \WC_Order $order order object
269
- * @param int $version Current 'version' value of Square order
270
- * @param int $amount Amount of line item in smallest unit
271
- */
272
- public function add_line_item_order_data( $location_id, \WC_Order $order, $version, $amount ) {
273
-
274
- $this->square_api_method = 'updateOrder';
275
- $this->square_request = new SquareModel\UpdateOrderRequest();
276
-
277
- $order_model = new SquareModel\Order();
278
- $order_model->setVersion( $version );
279
-
280
- $order_model->setLineItems( [ new SquareModel\OrderLineItem( [
281
- 'name' => __( 'Adjustment', 'woocommerce-square' ),
282
- 'quantity' => (string) 1,
283
- 'base_price_money' => new SquareModel\Money( [
284
- 'amount' => $amount,
285
- 'currency' => $order->get_currency(),
286
- ] ),
287
- ] ) ] );
288
-
289
- $this->square_request->setIdempotencyKey( wc_square()->get_idempotency_key( $order->unique_transaction_ref ) . $version );
290
- $this->square_request->setOrder( $order_model );
291
-
292
- $this->square_api_args = [
293
- $location_id,
294
- $order->square_order_id,
295
- $this->square_request,
296
- ];
297
- }
298
-
299
-
300
- /**
301
- * Sets the data for updating an order with a discount adjustment.
302
- *
303
- * @since 2.0.4
304
- *
305
- * @param string $location_id location ID
306
- * @param \WC_Order $order order object
307
- * @param int $version Current 'version' value of Square order
308
- * @param int $amount Amount of discount in smallest unit
309
- */
310
- public function add_discount_order_data( $location_id, \WC_Order $order, $version, $amount ) {
311
-
312
- $this->square_api_method = 'updateOrder';
313
- $this->square_request = new SquareModel\UpdateOrderRequest();
314
-
315
- $order_model = new SquareModel\Order();
316
- $order_model->setVersion( $version );
317
-
318
- $order_model->setDiscounts( [ new SquareModel\OrderLineItemDiscount( [
319
- 'name' => __( 'Adjustment', 'woocommerce-square' ),
320
- 'type' => 'FIXED_AMOUNT',
321
- 'amount_money' => new SquareModel\Money( [
322
- 'amount' => $amount,
323
- 'currency' => $order->get_currency(),
324
- ] ),
325
- 'scope' => 'ORDER',
326
- ] ) ] );
327
-
328
- $this->square_request->setIdempotencyKey( wc_square()->get_idempotency_key( $order->unique_transaction_ref ) . $version );
329
- $this->square_request->setOrder( $order_model );
330
-
331
- $this->square_api_args = [
332
- $location_id,
333
- $order->square_order_id,
334
- $this->square_request,
335
- ];
336
- }
337
-
338
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Requests/Transactions.php DELETED
@@ -1,254 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Requests;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Api\TransactionsApi;
30
- use SquareConnect\Model\Address;
31
- use SquareConnect\Model\ChargeRequest;
32
- use SquareConnect\Model\CreateRefundRequest;
33
- use WooCommerce\Square\Utilities\Money_Utility;
34
-
35
- class Transactions extends \WooCommerce\Square\API\Request {
36
-
37
-
38
- /** @var string location ID */
39
- protected $location_id;
40
-
41
-
42
- /**
43
- * Initializes a new transactions request.
44
- *
45
- * @since 2.0.0
46
- *
47
- * @param string $location_id location ID
48
- * @param \SquareConnect\ApiClient $api_client the API client
49
- */
50
- public function __construct( $location_id, $api_client ) {
51
-
52
- $this->location_id = $location_id;
53
- $this->square_api = new TransactionsApi( $api_client );
54
- }
55
-
56
-
57
- /**
58
- * Sets the data for an authorization/delayed capture.
59
- *
60
- * @since 2.0.0
61
- *
62
- * @param \WC_Order $order order object
63
- */
64
- public function set_authorization_data( \WC_Order $order ) {
65
-
66
- $this->set_charge_data( $order, false );
67
- }
68
-
69
-
70
- /**
71
- * Sets the data for a charge.
72
- *
73
- * @since 2.0.0
74
- *
75
- * @param \WC_Order $order
76
- * @param bool $capture whether to immediately capture the charge
77
- */
78
- public function set_charge_data( \WC_Order $order, $capture = true ) {
79
-
80
- $this->square_api_method = 'charge';
81
- $this->square_request = new ChargeRequest();
82
-
83
- $this->square_request->setIdempotencyKey( wc_square()->get_idempotency_key( $order->unique_transaction_ref ) );
84
- $this->square_request->setAmountMoney( Money_Utility::amount_to_money( $order->payment_total, $order->get_currency() ) );
85
- $this->square_request->setReferenceId( $order->get_order_number() );
86
-
87
- /**
88
- * Filters the Square payment order note (legacy filter).
89
- *
90
- * @since 1.0.0
91
- *
92
- * @param string $description the order note (description)
93
- * @param \WC_Order $order the order object
94
- */
95
- $description = (string) apply_filters( 'wc_square_payment_order_note', $order->description, $order );
96
-
97
- $this->square_request->setNote( Framework\SV_WC_Helper::str_truncate( $description, 60 ) );
98
-
99
- $this->square_request->setDelayCapture( ! $capture );
100
-
101
- if ( ! empty( $order->square_customer_id ) ) {
102
- $this->square_request->setCustomerId( $order->square_customer_id );
103
- }
104
-
105
- // payment token (card ID) or card nonce (from JS)
106
- if ( ! empty( $order->payment->token ) ) {
107
- $this->square_request->setCustomerCardId( $order->payment->token );
108
- } else {
109
- $this->square_request->setCardNonce( $order->payment->nonce );
110
- }
111
-
112
- $billing_address = new Address();
113
- $billing_address->setFirstName( $order->get_billing_first_name() );
114
- $billing_address->setLastName( $order->get_billing_last_name() );
115
- $billing_address->setOrganization( $order->get_billing_company() );
116
- $billing_address->setAddressLine1( $order->get_billing_address_1() );
117
- $billing_address->setAddressLine2( $order->get_billing_address_2() );
118
- $billing_address->setLocality( $order->get_billing_city() );
119
- $billing_address->setAdministrativeDistrictLevel1( $order->get_billing_state() );
120
- $billing_address->setPostalCode( $order->get_billing_postcode() );
121
- $billing_address->setCountry( $order->get_billing_country() );
122
-
123
- $this->square_request->setBillingAddress( $billing_address );
124
-
125
- if ( Framework\SV_WC_Order_Compatibility::has_shipping_address( $order ) ) {
126
-
127
- $shipping_address = new Address();
128
- $shipping_address->setFirstName( $order->get_shipping_first_name() );
129
- $shipping_address->setLastName( $order->get_shipping_last_name() );
130
- $shipping_address->setAddressLine1( $order->get_shipping_address_1() );
131
- $shipping_address->setAddressLine2( $order->get_shipping_address_2() );
132
- $shipping_address->setLocality( $order->get_shipping_city() );
133
- $shipping_address->setAdministrativeDistrictLevel1( $order->get_shipping_state() );
134
- $shipping_address->setPostalCode( $order->get_shipping_postcode() );
135
- $shipping_address->setCountry( $order->get_shipping_country() );
136
-
137
- $this->square_request->setShippingAddress( $shipping_address );
138
- }
139
-
140
- $this->square_request->setBuyerEmailAddress( $order->get_billing_email() );
141
-
142
- if ( ! empty( $order->square_order_id ) ) {
143
- $this->square_request->setOrderId( $order->square_order_id );
144
- }
145
-
146
- $this->square_api_args = [
147
- $this->get_location_id(),
148
- $this->square_request,
149
- ];
150
- }
151
-
152
-
153
- /**
154
- * Sets the data for capturing a transaction.
155
- *
156
- * @since 2.0.0
157
- *
158
- * @param \WC_Order $order order object
159
- */
160
- public function set_capture_data( \WC_Order $order ) {
161
-
162
- $this->square_api_method = 'captureTransaction';
163
-
164
- $this->square_api_args = [
165
- $this->get_location_id(),
166
- $order->capture->trans_id,
167
- ];
168
- }
169
-
170
-
171
- /**
172
- * Sets the data for refund a transaction.
173
- *
174
- * @since 2.0.0
175
- *
176
- * @param \WC_Order $order order object
177
- */
178
- public function set_refund_data( \WC_Order $order ) {
179
-
180
- $this->square_api_method = 'createRefund';
181
-
182
- // The refund objects are sorted by date DESC, so the last one created will be at the start of the array
183
- $refunds = $order->get_refunds();
184
- $refund_obj = $refunds[0];
185
-
186
- $this->square_request = new CreateRefundRequest();
187
- $this->square_request->setIdempotencyKey( wc_square()->get_idempotency_key( $order->get_id() . ':' . $refund_obj->get_id() ) );
188
- $this->square_request->setTenderId( $order->refund->tender_id );
189
- $this->square_request->setReason( $order->refund->reason );
190
-
191
- $this->square_request->setAmountMoney( Money_Utility::amount_to_money( $order->refund->amount, $order->get_currency() ) );
192
-
193
- $this->square_api_args = [
194
- $this->get_location_id(),
195
- $order->refund->trans_id,
196
- $this->square_request,
197
- ];
198
- }
199
-
200
-
201
- /**
202
- * Sets the data for voiding a transaction.
203
- *
204
- * @since 2.0.0
205
- *
206
- * @param \WC_Order $order order object
207
- */
208
- public function set_void_data( \WC_Order $order ) {
209
-
210
- $this->square_api_method = 'voidTransaction';
211
-
212
- $this->square_api_args = [
213
- $this->get_location_id(),
214
- $order->refund->trans_id,
215
- ];
216
- }
217
-
218
-
219
- /**
220
- * Sets the data for getting a transaction.
221
- *
222
- * @since 2.0.0
223
- *
224
- * @param string $transaction_id transaction ID
225
- */
226
- public function set_get_transaction_data( $transaction_id ) {
227
-
228
- $this->square_api_method = 'retrieveTransaction';
229
-
230
- $this->square_api_args = [
231
- $this->get_location_id(),
232
- $transaction_id,
233
- ];
234
- }
235
-
236
-
237
- /** Getter methods ************************************************************************************************/
238
-
239
-
240
- /** Gets the location ID for this request.
241
- *
242
- * All requests in this type must have a location ID.
243
- *
244
- * @since 2.0.0
245
- *
246
- * @return string
247
- */
248
- protected function get_location_id() {
249
-
250
- return $this->location_id;
251
- }
252
-
253
-
254
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Response.php DELETED
@@ -1,144 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Gateway;
30
-
31
- class Response extends \WooCommerce\Square\API\Response implements Framework\SV_WC_Payment_Gateway_API_Response {
32
-
33
-
34
- /**
35
- * Determines if the transaction was approved.
36
- *
37
- * @since 2.0.0
38
- *
39
- * @return bool
40
- */
41
- public function transaction_approved() {
42
-
43
- return ! $this->has_errors();
44
- }
45
-
46
-
47
- /**
48
- * Determines if the transaction was held.
49
- *
50
- * @since 2.0.0
51
- *
52
- * @return bool
53
- */
54
- public function transaction_held() {
55
-
56
- return false; // TODO: make sure there are no held responses
57
- }
58
-
59
-
60
- /** Getter methods ************************************************************************************************/
61
-
62
-
63
- /**
64
- * Gets the transaction ID.
65
- *
66
- * @since 2.0.0
67
- *
68
- * @return string
69
- */
70
- public function get_transaction_id() {
71
-
72
- return '';
73
- }
74
-
75
-
76
- /**
77
- * Gets the response status message.
78
- *
79
- * @since 2.0.0
80
- *
81
- * @return string
82
- */
83
- public function get_status_message() {
84
-
85
- $message = '';
86
-
87
- foreach ( $this->get_errors() as $error ) {
88
-
89
- $message = $error->detail;
90
- break;
91
- }
92
-
93
- return $message;
94
- }
95
-
96
-
97
- /**
98
- * Gets the response status code.
99
- *
100
- * @since 2.0.0
101
- *
102
- * @return string
103
- */
104
- public function get_status_code() {
105
-
106
- $code = '';
107
-
108
- foreach ( $this->get_errors() as $error ) {
109
-
110
- $code = $error->code;
111
- break;
112
- }
113
-
114
- return $code;
115
- }
116
-
117
-
118
- /**
119
- * Gets the message to display to the user.
120
- *
121
- * @since 2.0.0
122
- *
123
- * @return string
124
- */
125
- public function get_user_message() {
126
-
127
- return '';
128
- }
129
-
130
-
131
- /**
132
- * Gets the payment type.
133
- *
134
- * @since 2.0.0
135
- *
136
- * @return string
137
- */
138
- public function get_payment_type() {
139
-
140
- return Gateway::PAYMENT_TYPE_CREDIT_CARD;
141
- }
142
-
143
-
144
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Responses/Charge.php DELETED
@@ -1,187 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * The Charge API response object.
32
- *
33
- * @since 2.0.0
34
- *
35
- * @method \SquareConnect\Model\ChargeResponse get_data()
36
- */
37
- class Charge extends \WooCommerce\Square\Gateway\API\Response implements Framework\SV_WC_Payment_Gateway_API_Authorization_Response {
38
-
39
-
40
- /**
41
- * Determines if the charge was held.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return bool
46
- */
47
- public function transaction_held() {
48
-
49
- $held = parent::transaction_held();
50
-
51
- // ensure the tender is CAPTURED
52
- if ( $this->get_tender() ) {
53
- $held = 'AUTHORIZED' === $this->get_tender()->getCardDetails()->getStatus();
54
- }
55
-
56
- return $held;
57
- }
58
-
59
-
60
- /** Getter methods ************************************************************************************************/
61
-
62
-
63
- /**
64
- * Gets the authorization code.
65
- *
66
- * @since 2.0.0
67
- *
68
- * @return string
69
- */
70
- public function get_authorization_code() {
71
-
72
- return $this->get_tender() ? $this->get_tender()->getId() : '';
73
- }
74
-
75
-
76
- /**
77
- * Gets the transaction ID.
78
- *
79
- * @since 2.0.0
80
- *
81
- * @return string
82
- */
83
- public function get_transaction_id() {
84
-
85
- return $this->get_transaction() ? $this->get_transaction()->getId() : '';
86
- }
87
-
88
-
89
- /**
90
- * Gets the location ID.
91
- *
92
- * @since 2.0.0
93
- *
94
- * @return string
95
- */
96
- public function get_location_id() {
97
-
98
- return $this->get_transaction() ? $this->get_transaction()->getLocationId() : '';
99
- }
100
-
101
-
102
- /**
103
- * Gets the Square order ID, if any.
104
- *
105
- * @since 2.0.0
106
- *
107
- * @return string
108
- */
109
- public function get_square_order_id() {
110
-
111
- return $this->get_transaction() ? $this->get_transaction()->getOrderId() : '';
112
- }
113
-
114
-
115
- /**
116
- * Gets the Square tender (auth) object.
117
- *
118
- * @since 2.0.0
119
- *
120
- * @return \SquareConnect\Model\Tender|null
121
- */
122
- public function get_tender() {
123
-
124
- return $this->get_transaction() ? current( $this->get_transaction()->getTenders() ) : null;
125
- }
126
-
127
-
128
- /**
129
- * Gets the Square transaction object.
130
- *
131
- * @since 2.0.0
132
- *
133
- * @return \SquareConnect\Model\Transaction|null
134
- */
135
- public function get_transaction() {
136
-
137
- return ! $this->has_errors() && $this->get_data()->getTransaction() ? $this->get_data()->getTransaction() : null;
138
- }
139
-
140
-
141
- /**
142
- * Gets the message to display to the user.
143
- *
144
- * @since 2.0.0
145
- *
146
- * @return string
147
- */
148
- public function get_user_message() {
149
-
150
- $message_id = '';
151
-
152
- switch ( $this->get_status_code() ) {
153
-
154
- case 'CARD_DECLINED':
155
- $message_id = 'card_declined';
156
- break;
157
-
158
- case 'INVALID_EXPIRATION':
159
- $message_id = 'card_expiry_invalid';
160
- break;
161
-
162
- case 'VERIFY_AVS_FAILURE':
163
- $message_id = 'avs_mismatch';
164
- break;
165
-
166
- case 'VERIFY_CVV_FAILURE':
167
- $message_id = 'csc_mismatch';
168
- break;
169
- }
170
-
171
- $helper = new Framework\SV_WC_Payment_Gateway_API_Response_Message_Helper();
172
-
173
- return $helper->get_user_message( $message_id );
174
- }
175
-
176
-
177
- /** No-op methods *************************************************************************************************/
178
-
179
-
180
- public function get_avs_result() { }
181
-
182
- public function get_csc_result() { }
183
-
184
- public function csc_match() { }
185
-
186
-
187
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Responses/Create_Customer.php DELETED
@@ -1,53 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * Customer create response.
32
- *
33
- * @since 2.0.0
34
- *
35
- * @method \SquareConnect\Model\CreateCustomerResponse get_data()
36
- */
37
- class Create_Customer extends \WooCommerce\Square\Gateway\API\Response implements Framework\SV_WC_Payment_Gateway_API_Customer_Response {
38
-
39
-
40
- /**
41
- * Gets the new customer ID.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return string
46
- */
47
- public function get_customer_id() {
48
-
49
- return $this->get_data() instanceof \SquareConnect\Model\CreateCustomerResponse ? $this->get_data()->getCustomer()->getId() : '';
50
- }
51
-
52
-
53
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Responses/Create_Customer_Card.php DELETED
@@ -1,72 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * Create customer response class.
32
- *
33
- * @since 2.0.0
34
- *
35
- * @method \SquareConnect\Model\CreateCustomerCardResponse get_data()
36
- */
37
- class Create_Customer_Card extends \WooCommerce\Square\Gateway\API\Response implements Framework\SV_WC_Payment_Gateway_API_Create_Payment_Token_Response {
38
-
39
-
40
- /**
41
- * Gets the created payment token.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return Framework\SV_WC_Payment_Gateway_Payment_Token|null
46
- */
47
- public function get_payment_token() {
48
-
49
- $card = $this->get_data() instanceof \SquareConnect\Model\CreateCustomerCardResponse ? $this->get_data()->getCard() : null;
50
- $token = null;
51
-
52
- if ( $card ) {
53
-
54
- $card_type = 'AMERICAN_EXPRESS' === $card->getCardBrand() ? Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_AMEX : $card->getCardBrand();
55
-
56
- $token = new Framework\SV_WC_Payment_Gateway_Payment_Token(
57
- $card->getId(),
58
- [
59
- 'type' => 'credit_card',
60
- 'card_type' => $card_type,
61
- 'last_four' => $card->getLast4(),
62
- 'exp_month' => $card->getExpMonth(),
63
- 'exp_year' => $card->getExpYear(),
64
- ]
65
- );
66
- }
67
-
68
- return $token;
69
- }
70
-
71
-
72
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Responses/Get_Customer.php DELETED
@@ -1,76 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * Get customer response.
32
- *
33
- * @since 2.0.0
34
- *
35
- * @method \SquareConnect\Model\RetrieveCustomerResponse|array get_data()
36
- */
37
- class Get_Customer extends \WooCommerce\Square\Gateway\API\Response implements Framework\SV_WC_Payment_Gateway_API_Get_Tokenized_Payment_Methods_Response {
38
-
39
-
40
- /**
41
- * Returns any payment tokens.
42
- *
43
- * @since 1.0.0
44
- *
45
- * @return Framework\SV_WC_Payment_Gateway_Payment_Token[]
46
- */
47
- public function get_payment_tokens() {
48
-
49
- $cards = $this->get_data() instanceof \SquareConnect\Model\RetrieveCustomerResponse ? $this->get_data()->getCustomer()->getCards() : [];
50
- $tokens = [];
51
-
52
- if ( is_array( $cards ) ) {
53
-
54
- foreach ( $cards as $card ) {
55
-
56
- $token_id = $card->getId();
57
- $card_type = 'AMERICAN_EXPRESS' === $card->getCardBrand() ? Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_AMEX : $card->getCardBrand();
58
-
59
- $tokens[ $token_id ] = new Framework\SV_WC_Payment_Gateway_Payment_Token(
60
- $token_id,
61
- [
62
- 'type' => 'credit_card',
63
- 'card_type' => $card_type,
64
- 'last_four' => $card->getLast4(),
65
- 'exp_month' => $card->getExpMonth(),
66
- 'exp_year' => $card->getExpYear(),
67
- ]
68
- );
69
- }
70
- }
71
-
72
- return $tokens;
73
- }
74
-
75
-
76
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/API/Responses/Refund.php DELETED
@@ -1,86 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway\API\Responses;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- /**
29
- * The refund API response object.
30
- *
31
- * @since 2.0.0
32
- *
33
- * @method \SquareConnect\Model\CreateRefundResponse get_data()
34
- */
35
- class Refund extends \WooCommerce\Square\Gateway\API\Response {
36
-
37
-
38
- /**
39
- * Determines if the transaction was approved.
40
- *
41
- * @since 2.0.0
42
- *
43
- * @return bool
44
- */
45
- public function transaction_approved() {
46
-
47
- return parent::transaction_approved() && ( 'APPROVED' === $this->get_status_code() || 'PENDING' === $this->get_status_code() );
48
- }
49
-
50
-
51
- /** Getter methods ************************************************************************************************/
52
-
53
-
54
- /**
55
- * Gets the transaction ID.
56
- *
57
- * @since 2.0.0
58
- *
59
- * @return string
60
- */
61
- public function get_transaction_id() {
62
-
63
- return $this->get_data() && $this->get_data()->getRefund() ? $this->get_data()->getRefund()->getId() : '';
64
- }
65
-
66
-
67
- /**
68
- * Gets the response status code.
69
- *
70
- * @since 2.0.0
71
- *
72
- * @return string
73
- */
74
- public function get_status_code() {
75
-
76
- if ( ! $this->has_errors() && $this->get_data() ) {
77
- $code = $this->get_data()->getRefund()->getStatus();
78
- } else {
79
- $code = parent::get_status_code();
80
- }
81
-
82
- return $code;
83
- }
84
-
85
-
86
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/Card_Handler.php DELETED
@@ -1,50 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- class Card_Handler extends Framework\SV_WC_Payment_Gateway_Payment_Tokens_Handler {
31
-
32
-
33
- /**
34
- * Determines if a token should be deleted locally after a failed API attempt.
35
- *
36
- * Checks the response code, and if Square indicates the card ID was not found then it's probably safe to delete.
37
- *
38
- * @since 2.0.0
39
- *
40
- * @param Framework\SV_WC_Payment_Gateway_Payment_Token $token
41
- * @param Framework\SV_WC_Payment_Gateway_API_Response $response
42
- * @return bool
43
- */
44
- public function should_delete_token( Framework\SV_WC_Payment_Gateway_Payment_Token $token, Framework\SV_WC_Payment_Gateway_API_Response $response ) {
45
-
46
- return 'NOT_FOUND' === $response->get_status_code();
47
- }
48
-
49
-
50
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/Customer_Helper.php DELETED
@@ -1,192 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- class Customer_Helper {
31
-
32
-
33
- /**
34
- * Adds customers to the local index.
35
- *
36
- * @since 2.0.0
37
- *
38
- * @param \SquareConnect\Model\Customer[] $customers Square API customers
39
- */
40
- public static function add_customers( array $customers ) {
41
- global $wpdb;
42
-
43
- $placeholders = [];
44
- $values = [];
45
-
46
- $query = "INSERT INTO {$wpdb->prefix}woocommerce_square_customers (square_id, email_address) VALUES ";
47
-
48
- foreach ( $customers as $customer ) {
49
-
50
- // skip any bad data
51
- if ( ! $customer instanceof \SquareConnect\Model\Customer ) {
52
- continue;
53
- }
54
-
55
- $placeholders[] = '(%s, %s)';
56
-
57
- $values[] = wc_clean( $customer->getId() );
58
- $values[] = wc_clean( $customer->getEmailAddress() );
59
- }
60
-
61
- $query .= implode( ', ', $placeholders );
62
-
63
- // update the Square ID value when duplicate email addresses are present
64
- $query .= " ON DUPLICATE KEY UPDATE email_address = VALUES(email_address)";
65
-
66
- $wpdb->query( $wpdb->prepare( $query, $values ) );
67
- }
68
-
69
-
70
- /**
71
- * Adds a customer to the index.
72
- *
73
- * @since 2.0.0
74
- *
75
- * @param string $square_id Square customer ID
76
- * @param string $email_address customer email address
77
- * @param int $user_id WordPress user ID
78
- */
79
- public static function add_customer( $square_id, $email_address, $user_id = 0 ) {
80
- global $wpdb;
81
-
82
- if ( is_email( $email_address ) ) {
83
-
84
- $params = [
85
- 'square_id' => wc_clean( $square_id ),
86
- 'email_address' => wc_clean( $email_address ),
87
- ];
88
-
89
- if ( $user_id && is_numeric( $user_id ) ) {
90
- $params['user_id'] = (int) $user_id;
91
- }
92
-
93
- $wpdb->insert(
94
- "{$wpdb->prefix}woocommerce_square_customers",
95
- $params
96
- );
97
- }
98
- }
99
-
100
-
101
- /**
102
- * Gets a Square customer ID from an email address.
103
- *
104
- * @param string $email_address customer email address
105
- * @return string|null
106
- */
107
- public static function get_square_id( $email_address ) {
108
- global $wpdb;
109
-
110
- $square_id = null;
111
-
112
- if ( is_email( $email_address ) ) {
113
-
114
- $square_id = $wpdb->get_var( $wpdb->prepare(
115
- "SELECT square_id FROM {$wpdb->prefix}woocommerce_square_customers WHERE email_address = %s",
116
- $email_address
117
- ) );
118
- }
119
-
120
- return $square_id;
121
- }
122
-
123
-
124
- public static function get_customers_by_email( $email_address ) {
125
- global $wpdb;
126
-
127
- $square_ids = [];
128
-
129
- if ( is_email( $email_address ) ) {
130
-
131
- $square_ids = $wpdb->get_col( $wpdb->prepare(
132
- "SELECT square_id FROM {$wpdb->prefix}woocommerce_square_customers WHERE email_address = %s",
133
- $email_address
134
- ) );
135
- }
136
-
137
- return $square_ids;
138
- }
139
-
140
-
141
- /**
142
- * Determines if a customer exists in the index.
143
- *
144
- * @since 2.0.0
145
- *
146
- * @param string $square_id Square customer ID
147
- * @return bool
148
- */
149
- public static function is_customer_indexed( $square_id ) {
150
- global $wpdb;
151
-
152
- $result = $wpdb->get_var( $wpdb->prepare(
153
- "SELECT * FROM {$wpdb->prefix}woocommerce_square_customers WHERE square_id = %s",
154
- $square_id
155
- ) );
156
-
157
- return (bool) $result;
158
- }
159
-
160
-
161
- /**
162
- * Creates the db table for the customer index.
163
- *
164
- * @since 2.0.0
165
- */
166
- public static function create_table() {
167
- global $wpdb;
168
-
169
- $wpdb->hide_errors();
170
-
171
- $collate = '';
172
-
173
- if ( $wpdb->has_cap( 'collation' ) ) {
174
- $collate = $wpdb->get_charset_collate();
175
- }
176
-
177
- $schema = "
178
- CREATE TABLE IF NOT EXISTS {$wpdb->prefix}woocommerce_square_customers (
179
- square_id varchar(200) NOT NULL,
180
- email_address varchar(200) NOT NULL,
181
- user_id BIGINT UNSIGNED NOT NULL,
182
- PRIMARY KEY (square_id)
183
- ) $collate;
184
- ";
185
-
186
- require_once( ABSPATH . 'wp-admin/includes/upgrade.php' );
187
-
188
- dbDelta( $schema );
189
- }
190
-
191
-
192
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Gateway/Payment_Form.php DELETED
@@ -1,222 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Gateway;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * The payment form handler.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Payment_Form extends Framework\SV_WC_Payment_Gateway_Payment_Form {
36
-
37
-
38
- /**
39
- * Renders the payment fields.
40
- *
41
- * @since 2.0.0
42
- */
43
- public function render_payment_fields() {
44
-
45
- parent::render_payment_fields();
46
-
47
- $fields = [
48
- 'card-type',
49
- 'last-four',
50
- 'exp-month',
51
- 'exp-year',
52
- 'payment-nonce',
53
- 'payment-postcode',
54
- ];
55
-
56
- foreach ( $fields as $field_id ) {
57
- echo '<input type="hidden" name="wc-' . esc_attr( $this->get_gateway()->get_id_dasherized() ) . '-' . esc_attr( $field_id ) . '" />';
58
- }
59
-
60
- $postcode = '';
61
-
62
- if ( is_checkout_pay_page() ) {
63
-
64
- if ( $order = wc_get_order( $this->get_gateway()->get_checkout_pay_page_order_id() ) ) {
65
- $postcode = $order->get_billing_postcode();
66
- }
67
-
68
- } elseif ( WC()->customer && ! is_checkout() ) {
69
-
70
- $postcode = WC()->customer->get_billing_postcode();
71
- }
72
-
73
- if ( $postcode ) {
74
- echo '<input type="hidden" id="billing_postcode" value="' . esc_attr( $postcode ) . '" />';
75
- }
76
- }
77
-
78
-
79
- /**
80
- * Gets the credit card fields.
81
- *
82
- * Overridden to add special iframe classes.
83
- *
84
- * @since 2.0.0
85
- *
86
- * @return array
87
- */
88
- protected function get_credit_card_fields() {
89
-
90
- $fields = parent::get_credit_card_fields();
91
-
92
- // Square JS requires a postal code field for the form, but this is pre-filled and hidden
93
- $fields['card-postal-code'] = [
94
- 'id' => 'wc-' . $this->get_gateway()->get_id_dasherized() . '-postal-code',
95
- 'label' => __( 'Postal code', 'woocommerce-square' ),
96
- 'class' => [ 'form-row-wide' ],
97
- 'required' => true,
98
- 'input_class' => [ 'js-sv-wc-payment-gateway-credit-card-form-input', 'js-sv-wc-payment-gateway-credit-card-form-postal-code' ],
99
- ];
100
-
101
- foreach ( [ 'card-number', 'card-expiry', 'card-csc', 'card-postal-code' ] as $field_key ) {
102
-
103
- if ( isset( $fields[ $field_key ] ) ) {
104
-
105
- // parent div classes - contains both the label and hosted field container div
106
- $fields[ $field_key ]['class'] = array_merge( $fields[ $field_key ]['class'], [ "wc-{$this->get_gateway()->get_id_dasherized()}-{$field_key}-parent", "wc-{$this->get_gateway()->get_id_dasherized()}-hosted-field-parent" ] );
107
-
108
- // hosted field container classes - contains the iframe element
109
- $fields[ $field_key ]['input_class'] = array_merge( $fields[ $field_key ]['input_class'], [ "wc-{$this->get_gateway()->get_id_dasherized()}-hosted-field-{$field_key}", "wc-{$this->get_gateway()->get_id_dasherized()}-hosted-field" ] );
110
- }
111
- }
112
-
113
- return $fields;
114
- }
115
-
116
-
117
- /**
118
- * Renders a payment form field.
119
- *
120
- * @since 2.0.0
121
- *
122
- * @param array $field field to render
123
- */
124
- public function render_payment_field( $field ) {
125
-
126
- ?>
127
- <div class="form-row <?php echo implode( ' ', array_map( 'sanitize_html_class', $field['class'] ) ); ?>">
128
- <label for="<?php echo esc_attr( $field['id'] ) . '-hosted'; ?>"><?php echo esc_html( $field['label'] ); if ( $field['required'] ) : ?><abbr class="required" title="required">&nbsp;*</abbr><?php endif; ?></label>
129
- <div id="<?php echo esc_attr( $field['id'] ) . '-hosted'; ?>" class="<?php echo implode( ' ', array_map( 'sanitize_html_class', $field['input_class'] ) ); ?>" data-placeholder="<?php echo isset( $field['placeholder'] ) ? esc_attr( $field['placeholder'] ) : ''; ?>"></div>
130
- </div>
131
- <?php
132
- }
133
-
134
-
135
- /**
136
- * Renders the payment form JS.
137
- *
138
- * @since 2.0.0
139
- */
140
- public function render_js() {
141
-
142
- $args = [
143
- 'id' => $this->get_gateway()->get_id(),
144
- 'id_dasherized' => $this->get_gateway()->get_id_dasherized(),
145
- 'csc_required' => $this->get_gateway()->csc_enabled(),
146
- 'logging_enabled' => $this->get_gateway()->debug_log(),
147
- 'general_error' => __( 'An error occurred, please try again or try an alternate form of payment.', 'woocommerce-square' ),
148
- 'ajax_url' => admin_url( 'admin-ajax.php' ),
149
- 'ajax_log_nonce' => wp_create_nonce( 'wc_' . $this->get_gateway()->get_id() . '_log_js_data' ),
150
- 'application_id' => $this->get_gateway()->get_application_id(),
151
- ];
152
-
153
- // map the unique square card type string to our framework standards
154
- $square_card_types = [
155
- Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_MASTERCARD => 'masterCard',
156
- Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_AMEX => 'americanExpress',
157
- Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_DINERSCLUB => 'discoverDiners',
158
- Framework\SV_WC_Payment_Gateway_Helper::CARD_TYPE_JCB => 'JCB',
159
- ];
160
-
161
- $card_types = is_array( $this->get_gateway()->get_card_types() ) ? $this->get_gateway()->get_card_types() : [];
162
-
163
- $framework_card_types = array_map( [ Framework\SV_WC_Payment_Gateway_Helper::class, 'normalize_card_type' ], $card_types );
164
- $square_card_types = array_merge( array_combine( $framework_card_types, $framework_card_types ), $square_card_types );
165
-
166
- $args['enabled_card_types'] = $framework_card_types;
167
- $args['square_card_types'] = array_flip( $square_card_types );
168
-
169
- $input_styles = [
170
- [
171
- 'backgroundColor' => 'transparent',
172
- 'fontSize' => '1.3em',
173
- ]
174
- ];
175
-
176
- /**
177
- * Filters the the Square payment form input styles.
178
- *
179
- * @since 2.0.0
180
- *
181
- * @param array $styles array of input styles
182
- */
183
- $args['input_styles'] = (array) apply_filters( 'wc_' . $this->get_gateway()->get_id() . '_payment_form_input_styles', $input_styles, $this );
184
-
185
- // TODO remove the deprecated hook in a future version
186
- if ( has_filter( 'woocommerce_square_payment_input_styles' ) ) {
187
-
188
- _deprecated_hook( 'woocommerce_square_payment_input_styles', '2.0.0', null, 'Use "wc_' . $this->get_gateway()->get_id() . '_payment_form_input_styles" as a replacement.' );
189
-
190
- /**
191
- * Filters the input styles (legacy filter).
192
- *
193
- * @since 1.0.0
194
- *
195
- * @param string $input_styles styles as JSON encoded array
196
- */
197
- $args['input_styles'] = json_decode( (string) apply_filters( 'woocommerce_square_payment_input_styles', wp_json_encode( $args['input_styles'] ) ), true );
198
- }
199
-
200
- /**
201
- * Payment Gateway Payment Form JS Arguments Filter.
202
- *
203
- * Filter the arguments passed to the Payment Form handler JS class
204
- *
205
- * @since 3.0.0
206
- *
207
- * @param array $result {
208
- * @type string $plugin_id plugin ID
209
- * @type string $id gateway ID
210
- * @type string $id_dasherized gateway ID dasherized
211
- * @type string $type gateway payment type (e.g. 'credit-card')
212
- * @type bool $csc_required true if CSC field display is required
213
- * }
214
- * @param Payment_Form $this payment form instance
215
- */
216
- $args = apply_filters( 'wc_' . $this->get_gateway()->get_id() . '_payment_form_js_args', $args, $this );
217
-
218
- wc_enqueue_js( sprintf( 'window.wc_%s_payment_form_handler = new WC_Square_Payment_Form_Handler( %s );', esc_js( $this->get_gateway()->get_id() ), json_encode( $args ) ) );
219
- }
220
-
221
-
222
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Background_Job.php DELETED
@@ -1,367 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\Sync\Interval_Polling;
28
- use WooCommerce\Square\Sync\Job;
29
- use WooCommerce\Square\Sync\Manual_Synchronization;
30
- use WooCommerce\Square\Sync\Product_Import;
31
- use WooCommerce\Square\Sync\Records;
32
-
33
- defined( 'ABSPATH' ) or exit;
34
-
35
- /**
36
- * Product and Inventory Synchronization handler class.
37
- *
38
- * This class handles manual and interval synchronization jobs.
39
- * It is a wrapper for the framework background handler and as such it only handles loopback business to keep the queue processing.
40
- * See the individual job implementations:
41
- *
42
- * @see Manual_Synchronization manual jobs re-process ALL synced products
43
- * @see Interval_Polling interval (polling) jobs perform API requests for ONLY the latest changes and update the associated products
44
- *
45
- * @since 2.0.0
46
- */
47
- class Background_Job extends Framework\SV_WP_Background_Job_Handler {
48
-
49
-
50
- /**
51
- * Initializes the background sync handler.
52
- *
53
- * @since 2.0.0
54
- */
55
- public function __construct() {
56
-
57
- $this->prefix = 'wc_square';
58
- $this->action = 'background_sync';
59
- $this->data_key = 'product_ids';
60
-
61
- parent::__construct();
62
-
63
- $this->maybe_increase_time_limit();
64
-
65
- add_action( "{$this->identifier}_job_complete", [ $this, 'job_complete' ] );
66
- add_action( "{$this->identifier}_job_failed", [ $this, 'job_failed' ] );
67
- add_filter( "{$this->identifier}_default_time_limit", [ $this, 'set_default_time_limit' ] );
68
-
69
- // ensures the queue lock time never expires before our timeout does
70
- add_filter( "{$this->identifier}_queue_lock_time", function( $lock_time ) {
71
-
72
- return $this->set_default_time_limit( $lock_time ) + 10;
73
-
74
- } );
75
- }
76
-
77
-
78
- /**
79
- * Creates a new job.
80
- *
81
- * @since 2.0.0
82
- *
83
- * @param array $attrs array of job attributes
84
- * @return \stdClass|null
85
- */
86
- public function create_job( $attrs ) {
87
-
88
- $sor = wc_square()->get_settings_handler()->get_system_of_record();
89
-
90
- return parent::create_job( wp_parse_args( $attrs, [
91
- 'action' => '', // job action
92
- 'catalog_processed' => false, // whether the Square catalog has been processed
93
- 'cursor' => '', // job advancement position
94
- 'manual' => false, // whether it's a sync job triggered manually
95
- 'percentage' => 0, // percentage completed
96
- 'product_ids' => [], // products to process
97
- 'processed_product_ids' => [], // products processed
98
- 'skipped_products' => [], // remote product IDs that were skipped
99
- 'system_of_record' => $sor, // system of record used
100
- ] ) );
101
- }
102
-
103
-
104
- /**
105
- * Handles job execution.
106
- *
107
- * Overridden to support our multi-step job structure. There are steps that can take a long time to process, so this
108
- * ensures only one step is performed for each background request.
109
- *
110
- * @since 2.0.0
111
- */
112
- protected function handle() {
113
-
114
- $this->lock_process();
115
-
116
- // Get next job in the queue
117
- $job = $this->get_job();
118
-
119
- // handle PHP errors from here on out
120
- register_shutdown_function( array( $this, 'handle_shutdown' ), $job );
121
-
122
- // Start processing
123
- $this->process_job( $job );
124
-
125
- $this->unlock_process();
126
-
127
- // Start next job or complete process
128
- if ( ! $this->is_queue_empty() ) {
129
- $this->dispatch();
130
- } else {
131
- $this->complete();
132
- }
133
-
134
- wp_die();
135
- }
136
-
137
-
138
- /**
139
- * Processes a background job.
140
- *
141
- * @since 2.0.0
142
- *
143
- * @param object|\stdClass $job
144
- * @param null $items_per_batch
145
- * @return false|object|\stdClass
146
- */
147
- public function process_job( $job, $items_per_batch = null ) {
148
-
149
- // indicate that the job has started processing
150
- if ( 'processing' !== $job->status ) {
151
-
152
- $job->status = 'processing';
153
- $job->started_processing_at = current_time( 'mysql' );
154
- $job = $this->update_job( $job );
155
- }
156
-
157
- if ( 'poll' === $job->action ) {
158
-
159
- $job = new Interval_Polling( $job );
160
-
161
- } elseif ( 'product_import' === $job->action ) {
162
-
163
- $job = new Product_Import( $job );
164
-
165
- } elseif ( ! empty( $job->manual ) ) {
166
-
167
- $job = new Manual_Synchronization( $job );
168
- }
169
-
170
- if ( $job instanceof Job ) {
171
- $current_user_id = get_current_user_id();
172
- $job = $job->run();
173
- wp_set_current_user( $current_user_id );
174
- }
175
-
176
- return $job;
177
- }
178
-
179
-
180
- /**
181
- * Handles actions after a sync job is complete.
182
- *
183
- * @since 2.0.0
184
- *
185
- * @param $job
186
- */
187
- public function job_complete( $job ) {
188
-
189
- wc_square()->get_sync_handler()->set_last_synced_at();
190
-
191
- wc_square()->get_sync_handler()->record_sync( $job->processed_product_ids, $job );
192
-
193
- if ( ! empty( $job->manual ) ) {
194
- wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
195
- }
196
- }
197
-
198
-
199
- /**
200
- * Handles actions after a sync job has failed.
201
- *
202
- * @since 2.0.0
203
- *
204
- * @param $job
205
- */
206
- public function job_failed( $job ) {
207
-
208
- Records::set_record( [
209
- 'type' => 'alert',
210
- 'message' => 'Sync failed. Please try again',
211
- ] );
212
-
213
- if ( ! empty( $job->manual ) ) {
214
- wc_square()->get_email_handler()->get_sync_completed_email()->trigger( $job );
215
- }
216
- }
217
-
218
-
219
- /**
220
- * No-op: implements framework parent abstract method.
221
- *
222
- * @since 2.0.0
223
- *
224
- * @param null $item
225
- * @param \stdClass $job
226
- */
227
- protected function process_item( $item, $job ) {}
228
-
229
-
230
- /**
231
- * Clear all background jobs of any status.
232
- *
233
- * @since 2.0.0
234
- */
235
- public function clear_all_jobs() {
236
-
237
- $jobs = $this->get_jobs();
238
-
239
- if ( is_array( $jobs ) ) {
240
- $this->delete_jobs( $jobs );
241
- }
242
-
243
- delete_transient( 'wc_square_background_sync_process_lock' );
244
- }
245
-
246
-
247
- /**
248
- * Deletes a set of background jobs.
249
- *
250
- * @since 2.0.0
251
- *
252
- * @param object[] $jobs jobs to delete
253
- */
254
- public function delete_jobs( $jobs ) {
255
-
256
- foreach ( $jobs as $job ) {
257
- $this->delete_job( $job );
258
- }
259
- }
260
-
261
-
262
- /**
263
- * Attempts to increase the script execution time limit to a filtered value -- defaults to 5 minutes.
264
- *
265
- * @since 2.0.0
266
- */
267
- protected function maybe_increase_time_limit() {
268
-
269
- /**
270
- * Filters the desired time limit for Square requests. Defaults to 5 minutes.
271
- *
272
- * @since 2.0.0
273
- *
274
- * @param int time limit
275
- */
276
- $desired_time_limit = (int) apply_filters( 'wc_square_time_limit', 300 );
277
- $server_time_limit = (int) ini_get( 'max_execution_time' );
278
-
279
- if ( $desired_time_limit > $server_time_limit ) {
280
-
281
- \ActionScheduler_Compatibility::raise_time_limit( $desired_time_limit );
282
- }
283
- }
284
-
285
-
286
- /**
287
- * Sets the default time limit to the server time limit minus a buffer,
288
- * to allow us to clean up a request that has exceeded the time limit.
289
- *
290
- * @internal
291
- *
292
- * @since 2.0.0
293
- *
294
- * @param int $default_time_limit time limit (in seconds)
295
- * @return int
296
- */
297
- public function set_default_time_limit( $default_time_limit ) {
298
-
299
- $server_time_limit = (int) ini_get( 'max_execution_time' );
300
- $time_limit_buffer = 10;
301
-
302
- if ( isset( $server_time_limit ) && $time_limit_buffer < $server_time_limit ) {
303
-
304
- $default_time_limit = $server_time_limit - $time_limit_buffer;
305
- }
306
-
307
- return $default_time_limit;
308
- }
309
-
310
-
311
- /**
312
- * Returns whether a sensible time has been exceeded for this request.
313
- *
314
- * Makes the internal time_exceeded() function publicly accessible.
315
- *
316
- * @since 2.0.0
317
- *
318
- * @return bool
319
- */
320
- public function is_time_exceeded() {
321
-
322
- return $this->time_exceeded();
323
- }
324
-
325
-
326
- /**
327
- * Adds some helpful debug tools.
328
- *
329
- * @since 2.0.0
330
- *
331
- * @param array $tools existing debug tools
332
- * @return array
333
- */
334
- public function add_debug_tool( $tools ) {
335
-
336
- $tools = parent::add_debug_tool( $tools );
337
-
338
- // this key is not unique to the plugin to avoid duplicate tools
339
- $tools['wc_square_clear_background_jobs'] = array(
340
- 'name' => __( 'Clear Square Sync', 'woocommerce-square' ),
341
- 'button' => __( 'Clear', 'woocommerce-square' ),
342
- 'desc' => __( 'This tool will clear any ongoing Square product syncs.', 'woocommerce-square' ),
343
- 'callback' => [ $this, 'run_clear_background_jobs' ],
344
- );
345
-
346
- return $tools;
347
- }
348
-
349
-
350
- /**
351
- * Runs the "Clear Square Sync" tool.
352
- *
353
- * Provides a way for merchants to clear any ongoing or stuck product syncs.
354
- *
355
- * @since 2.0.0
356
- */
357
- public function run_clear_background_jobs() {
358
-
359
- $this->clear_all_jobs();
360
-
361
- $this->debug_message = esc_html__( 'Success! You can now sync your products.', 'woocommerce-square' );
362
-
363
- return true;
364
- }
365
-
366
-
367
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Category.php DELETED
@@ -1,235 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
- defined( 'ABSPATH' ) or exit;
29
-
30
- /**
31
- * Category handler class.
32
- *
33
- * @since 2.0.0
34
- */
35
- class Category {
36
-
37
-
38
- const CATEGORY_MAP_META_KEY = 'wc_square_category_map';
39
-
40
- const SQUARE_ID_META_KEY = 'square_cat_id';
41
-
42
- const SQUARE_VERSION_META_KEY = 'square_cat_version';
43
-
44
-
45
- /**
46
- * Gets the full category map.
47
- *
48
- * @since 2.0.0
49
- *
50
- * @return array
51
- */
52
- public static function get_map() {
53
-
54
- return get_option( self::CATEGORY_MAP_META_KEY, [] );
55
- }
56
-
57
-
58
- /**
59
- * Updates the full category map.
60
- *
61
- * @since 2.0.0
62
- *
63
- * @param array $map
64
- */
65
- public static function update_map( $map ) {
66
-
67
- update_option( self::CATEGORY_MAP_META_KEY, $map );
68
- }
69
-
70
-
71
- /**
72
- * Gets the mapping for a single category ID.
73
- *
74
- * @since 2.0.0
75
- *
76
- * @param int $category_id the category ID
77
- * @return array
78
- */
79
- public static function get_mapping( $category_id ) {
80
-
81
- $category_id = (int) $category_id;
82
- $map = self::get_map();
83
-
84
- if ( isset( $map[ $category_id ] ) ) {
85
-
86
- return $map[ $category_id ];
87
- }
88
-
89
- return [];
90
- }
91
-
92
-
93
- /**
94
- * Returns a Square ID if known, or a temporary ID to be used in API calls.
95
- *
96
- * @since 2.0.0
97
- *
98
- * @param int $category_id
99
- * @return string
100
- */
101
- public static function get_square_id( $category_id ) {
102
-
103
- $mapping = self::get_mapping( $category_id );
104
-
105
- return isset( $mapping['square_id'] ) ? $mapping['square_id'] : '#category_' . $category_id;
106
- }
107
-
108
-
109
- /**
110
- * Gets the Square version for the given category (if known).
111
- *
112
- * @since 2.0.0
113
- *
114
- * @param int $category_id
115
- * @return int
116
- */
117
- public static function get_square_version( $category_id ) {
118
-
119
- $mapping = self::get_mapping( $category_id );
120
-
121
- return isset( $mapping['square_version'] ) ? (int) $mapping['square_version'] : 0;
122
- }
123
-
124
-
125
- /**
126
- * Adds a mapping for a category.
127
- *
128
- * @since 2.0.0
129
- *
130
- * @param int $category_id the category ID
131
- * @param string $square_id the Square Catalog Item ID
132
- * @param string $square_version the Square Item version
133
- *
134
- * @return array the updated full map
135
- */
136
- public static function update_mapping( $category_id, $square_id, $square_version ) {
137
-
138
- $map = self::get_map();
139
-
140
- $map[ $category_id ] = [
141
- 'square_id' => $square_id,
142
- 'square_version' => $square_version,
143
- ];
144
-
145
- self::update_map( $map );
146
-
147
- return $map;
148
- }
149
-
150
-
151
- /**
152
- * Imports or updates local category data for a remote CatalogObject.
153
- *
154
- * @since 2.0.0
155
- *
156
- * @param \SquareConnect\Model\CatalogObject $catalog_object the catalog object
157
- * @return int|null the category ID, if found
158
- */
159
- public static function import_or_update( $catalog_object ) {
160
-
161
- $id = $catalog_object->getId();
162
- $version = $catalog_object->getVersion();
163
- $name = $catalog_object->getCategoryData()->getName();
164
-
165
- // look for category ID by the square ID
166
- $category_id = self::get_category_id_by_square_id( $id );
167
-
168
- // if not found, search for the category by name
169
- if ( ! $category_id ) {
170
-
171
- if ( $category = get_term_by( 'name', $name, 'product_cat', ARRAY_A ) ) {
172
-
173
- $category_id = isset( $category['term_id'] ) ? absint( $category['term_id'] ) : null;
174
- }
175
- }
176
-
177
- // if still not found, create a new category
178
- if ( ! $category_id ) {
179
-
180
- $inserted_term = wp_insert_term( $name, 'product_cat' );
181
-
182
- $category_id = isset( $inserted_term['term_id'] ) ? $inserted_term['term_id'] : null;
183
- }
184
-
185
-
186
- if ( $category_id ) {
187
- wp_update_term( $category_id, 'product_cat', [ 'name' => $name ] );
188
- self::update_square_meta( $category_id, $id, $version );
189
- }
190
-
191
- return $category_id;
192
- }
193
-
194
-
195
- /**
196
- * Updates a category's Square metadata.
197
- *
198
- * @since 2.0.0
199
- *
200
- * @param int $category_id the category ID
201
- * @param string $square_id the square ID
202
- * @param string $square_version the square version
203
- */
204
- public static function update_square_meta( $category_id, $square_id, $square_version ) {
205
-
206
- update_term_meta( $category_id, self::SQUARE_ID_META_KEY, $square_id );
207
- update_term_meta( $category_id, self::SQUARE_VERSION_META_KEY, $square_version );
208
- }
209
-
210
-
211
- /**
212
- * Gets a category ID from a known square ID.
213
- *
214
- * @since 2.0.0
215
- *
216
- * @param string $square_id the square ID
217
- * @return int|null
218
- */
219
- public static function get_category_id_by_square_id( $square_id ) {
220
- global $wpdb;
221
-
222
- $query = $wpdb->prepare( "
223
- SELECT t.term_id FROM {$wpdb->prefix}terms AS t
224
- LEFT JOIN {$wpdb->prefix}term_taxonomy AS tt ON t.term_id = tt.term_id
225
- LEFT JOIN {$wpdb->prefix}termmeta AS tm ON t.term_id = tm.term_id
226
- WHERE tt.taxonomy = 'product_cat'
227
- AND tm.meta_key = '%s'
228
- AND tm.meta_value = '%s'
229
- ", self::SQUARE_ID_META_KEY, $square_id );
230
-
231
- return $wpdb->get_var( $query );
232
- }
233
-
234
-
235
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Connection.php DELETED
@@ -1,516 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use SquareConnect\Model\ListCustomersResponse;
30
- use WooCommerce\Square;
31
-
32
- /**
33
- * The admin connection handler.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Connection {
38
-
39
-
40
- /** @var string production connect URL */
41
- const CONNECT_URL_PRODUCTION = 'https://connect.woocommerce.com/login/square';
42
-
43
- /** @var string sandbox connect URL */
44
- const CONNECT_URL_SANDBOX = 'https://connect.woocommerce.com/login/squaresandbox';
45
-
46
- /** @var string production refresh URL */
47
- const REFRESH_URL_PRODUCTION = 'https://connect.woocommerce.com/renew/square';
48
-
49
- /** @var string sandbox refresh URL */
50
- const REFRESH_URL_SANDBOX = 'https://connect.woocommerce.com/renew/squaresandbox';
51
-
52
- /** @var Square\Plugin plugin instance */
53
- protected $plugin;
54
-
55
-
56
- /**
57
- * Constructs the class.
58
- *
59
- * @since 2.0.0
60
- *
61
- * @param Square\Plugin $plugin plugin instance
62
- */
63
- public function __construct( Square\Plugin $plugin ) {
64
-
65
- $this->plugin = $plugin;
66
-
67
- $this->add_hooks();
68
- }
69
-
70
-
71
- /**
72
- * Adds the action and filter hooks.
73
- *
74
- * @since 2.0.0
75
- */
76
- protected function add_hooks() {
77
-
78
- add_action( 'admin_action_wc_' . $this->get_plugin()->get_id() . '_connected', [ $this, 'handle_connected' ] );
79
-
80
- add_action( 'admin_action_wc_' . $this->get_plugin()->get_id() . '_disconnect', [ $this, 'handle_disconnect' ] );
81
-
82
- // refresh the connection, triggered by Action Scheduler
83
- add_action( 'wc_' . $this->get_plugin()->get_id() . '_refresh_connection', [ $this, 'refresh_connection' ] );
84
-
85
- // index customers, triggered by Action Scheduler
86
- add_action( 'wc_' . $this->get_plugin()->get_id() . '_index_customers', [ $this, 'index_customers' ] );
87
- }
88
-
89
-
90
- /**
91
- * Handles a successful connection.
92
- *
93
- * @internal
94
- *
95
- * @since 2.0.0
96
- */
97
- public function handle_connected() {
98
-
99
- $nonce = isset( $_GET['_wpnonce'] ) ? wc_clean( $_GET['_wpnonce'] ) : '';
100
-
101
- // check the user role & nonce
102
- if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( $nonce, 'wc_' . $this->get_plugin()->get_id() . '_connected' ) ) {
103
- wp_die( __( 'Sorry, you do not have permission to manage the Square connection.', 'woocommerce-square' ) );
104
- }
105
-
106
- $access_token = ! empty( $_GET['square_access_token'] ) ? sanitize_text_field( urldecode( $_GET['square_access_token'] ) ) : '';
107
-
108
- if ( empty( $access_token ) ) {
109
- $this->get_plugin()->log( 'Error: No access token was received.' );
110
- add_action( 'admin_notices', function () {
111
- ?>
112
- <div class="notice notice-error is-dismissible">
113
- <p><?php _e( 'Square Error: We could not connect to Square. No access token was given.!', 'woocommerce-square' ); ?></p>
114
- </div>
115
- <?php
116
- });
117
- return;
118
- }
119
-
120
- $this->get_plugin()->get_settings_handler()->update_access_token( $access_token );
121
- $this->get_plugin()->log( 'Access token successfully received.' );
122
-
123
- $refresh_token = ! empty( $_GET['square_refresh_token'] ) ? sanitize_text_field( urldecode( $_GET['square_refresh_token'] ) ) : '';
124
- if ( empty( $refresh_token ) ) {
125
- $this->get_plugin()->log( 'Failed to receive refresh token from connect server.' );
126
- } else {
127
- $this->get_plugin()->get_settings_handler()->update_refresh_token( $refresh_token );
128
- $this->get_plugin()->log( 'Refresh token successfully received.' );
129
- }
130
-
131
- $this->schedule_refresh();
132
- $this->schedule_customer_index();
133
-
134
- // on connect after upgrading to v2.0 from v1.0, initiate a catalog sync to refresh the Square item IDs
135
- if ( get_option( 'wc_square_updated_to_2_0_0' ) ) {
136
-
137
- // delete any old access token from v1, as it will be invalidated
138
- delete_option( 'woocommerce_square_merchant_access_token' );
139
-
140
- if ( $this->get_plugin()->get_settings_handler()->is_system_of_record_square() ) {
141
- $this->get_plugin()->get_sync_handler()->start_manual_sync();
142
- }
143
- }
144
-
145
- delete_option( 'wc_square_updated_to_2_0_0' );
146
-
147
- wp_safe_redirect( $this->get_plugin()->get_settings_url() );
148
- exit;
149
- }
150
-
151
-
152
- /**
153
- * Handles disconnection.
154
- *
155
- * @internal
156
- *
157
- * @since 2.0.0
158
- */
159
- public function handle_disconnect() {
160
-
161
- // remove the refresh fail flag if previously set
162
- delete_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed' );
163
-
164
- $nonce = isset( $_GET['_wpnonce'] ) ? wc_clean( $_GET['_wpnonce'] ) : '';
165
-
166
- // check the user role & nonce
167
- if ( ! current_user_can( 'manage_woocommerce' ) || ! wp_verify_nonce( $nonce, 'wc_' . $this->get_plugin()->get_id() . '_disconnect' ) ) {
168
- wp_die( __( 'Sorry, you do not have permission to manage the Square connection.', 'woocommerce-square' ) );
169
- }
170
-
171
- // disconnect by clearing tokens, unscheduling syncs, etc...
172
- $this->disconnect();
173
-
174
- $this->get_plugin()->log( 'Manually disconnected' );
175
-
176
- $this->get_plugin()->get_message_handler()->add_message( __( 'Disconnected successfully', 'woocommerce-square' ) );
177
-
178
- wp_safe_redirect( $this->get_plugin()->get_settings_url() );
179
- exit;
180
- }
181
-
182
-
183
- /**
184
- * Disconnects the plugin.
185
- *
186
- * @since 2.0.0
187
- */
188
- public function disconnect() {
189
-
190
- // don't try to refresh anymore
191
- $this->unschedule_refresh();
192
-
193
- // unschedule the interval sync
194
- $this->get_plugin()->get_sync_handler()->unschedule_sync();
195
-
196
- // fully clear the access token
197
- $this->get_plugin()->get_settings_handler()->clear_access_tokens();
198
- $this->get_plugin()->get_settings_handler()->clear_refresh_tokens();
199
-
200
- // clear all background jobs so further API requests aren't attempted
201
- $this->get_plugin()->get_background_job_handler()->clear_all_jobs();
202
- }
203
-
204
-
205
- /** Refresh methods ***********************************************************************************************/
206
-
207
-
208
- /**
209
- * Schedules the connection refresh.
210
- *
211
- * @since 2.0.0
212
- */
213
- public function schedule_refresh() {
214
-
215
- if ( ! $this->get_plugin()->get_settings_handler()->is_connected() ) {
216
- return;
217
- }
218
-
219
- /**
220
- * Filters the frequency with which the OAuth connection should be refreshed.
221
- *
222
- * @since 2.0.0
223
- *
224
- * @param int $interval refresh interval
225
- */
226
- $interval = apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_connection_refresh_interval', WEEK_IN_SECONDS );
227
-
228
- // Make sure that all refresh actions are cancelled before scheduling it.
229
- $this->unschedule_refresh();
230
-
231
- as_schedule_single_action( time() + $interval, 'wc_' . $this->get_plugin()->get_id() . '_refresh_connection', [], $this->get_plugin()->get_id() );
232
- }
233
-
234
-
235
- /**
236
- * Refreshes the access token via the Woo proxy.
237
- *
238
- * @since 2.0.0
239
- */
240
- public function refresh_connection() {
241
- if ( $this->get_plugin()->get_settings_handler()->is_sandbox() ) {
242
- return;
243
- }
244
-
245
- try {
246
-
247
- if ( $this->get_plugin()->get_settings_handler()->is_debug_enabled() ) {
248
- $this->get_plugin()->log( 'Refreshing connection...' );
249
- }
250
-
251
- $refresh_token = $this->get_plugin()->get_settings_handler()->get_refresh_token();
252
-
253
- if ( ! $refresh_token ) {
254
- $this->get_plugin()->log( 'No refresh token stored, cannot refresh connection.' );
255
- update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
256
- return;
257
- }
258
-
259
- $request = [
260
- 'body' => [
261
- 'token' => $this->get_plugin()->get_settings_handler()->get_refresh_token(),
262
- ],
263
- 'timeout' => 45,
264
- ];
265
-
266
- // make the request
267
- $response = wp_remote_post( $this->get_refresh_url(), $request );
268
-
269
- // handle HTTP errors
270
- if ( is_wp_error( $response ) ) {
271
- throw new Framework\SV_WC_Plugin_Exception( $response->get_error_message() );
272
- }
273
-
274
- $response = new Square\API\Responses\Connection_Refresh_Response( wp_remote_retrieve_body( $response ) );
275
-
276
- // check for errors in the response
277
- if ( $response->has_error() ) {
278
- throw new Framework\SV_WC_Plugin_Exception( $response->get_error_message() );
279
- }
280
-
281
- // ensure an access token, just in case
282
- if ( ! $response->get_token() ) {
283
- throw new Framework\SV_WC_Plugin_Exception( 'Access token missing from the response' );
284
- }
285
-
286
- // store the new token
287
- $this->get_plugin()->get_settings_handler()->update_access_token( $response->get_token() );
288
-
289
- // In case square updates the refresh token.
290
- if( $response->get_refresh_token() ) {
291
- $this->get_plugin()->get_settings_handler()->update_refresh_token( $response->get_refresh_token() );
292
- $this->get_plugin()->log( 'Connection successfully refreshed.' );
293
- }
294
-
295
- // in case this option was set
296
- delete_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed' );
297
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
298
-
299
- $this->get_plugin()->log( 'Unable to refresh connection: ' . $exception->getMessage() );
300
-
301
- update_option( 'wc_' . $this->get_plugin()->get_id() . '_refresh_failed', 'yes' );
302
- }
303
-
304
- $this->schedule_refresh();
305
- }
306
-
307
-
308
- /**
309
- * Unschedules the connection refresh.
310
- *
311
- * @since 2.0.0
312
- */
313
- protected function unschedule_refresh() {
314
- as_unschedule_all_actions( 'wc_' . $this->get_plugin()->get_id() . '_refresh_connection', [], $this->get_plugin()->get_id() );
315
- }
316
-
317
-
318
- /** Customer index methods ****************************************************************************************/
319
-
320
-
321
- /**
322
- * Index existing Square customers.
323
- *
324
- * @since 2.0.0
325
- *
326
- * @param string $cursor pagination cursor
327
- */
328
- public function index_customers( $cursor = '' ) {
329
-
330
- try {
331
-
332
- $response = $this->get_plugin()->get_api()->get_customers( $cursor );
333
-
334
- if ( $response->get_data() instanceof ListCustomersResponse && is_array( $response->get_data()->getCustomers() ) ) {
335
-
336
- Square\Gateway\Customer_Helper::add_customers( $response->get_data()->getCustomers() );
337
-
338
- // if there are more customers to query, schedule a followup action to index the next batch of customers
339
- if ( $response->get_data()->getCursor() ) {
340
- $this->schedule_customer_index( $response->get_data()->getCursor() );
341
- }
342
- }
343
-
344
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
345
-
346
-
347
- }
348
- }
349
-
350
-
351
- /**
352
- * Schedules the customer index action.
353
- *
354
- * @since 2.0.0
355
- *
356
- * @param string $cursor pagination cursor
357
- */
358
- protected function schedule_customer_index( $cursor = '' ) {
359
-
360
- if ( false === as_next_scheduled_action( 'wc_' . $this->get_plugin()->get_id() . '_index_customers', [ $cursor ], $this->get_plugin()->get_id() ) ) {
361
- as_schedule_single_action( time(), 'wc_' . $this->get_plugin()->get_id() . '_index_customers', [ $cursor ], $this->get_plugin()->get_id() );
362
- }
363
- }
364
-
365
-
366
- /** Getter methods ************************************************************************************************/
367
-
368
-
369
- /**
370
- * Gets the Connect button HTML.
371
- *
372
- * @since 2.0.0
373
- *
374
- * @param bool $is_sandbox whether to point the button to production or sandbox
375
- * @return string
376
- */
377
- public function get_connect_button_html( $is_sandbox = false ) {
378
-
379
- ob_start();
380
- ?>
381
- <a href="<?php echo esc_url( $this->get_connect_url( $is_sandbox ) ); ?>" class="button-primary">
382
- <?php esc_html_e( 'Connect with Square', 'woocommerce-square' ); ?>
383
- </a>
384
- <?php
385
-
386
- return ob_get_clean();
387
- }
388
-
389
-
390
- /**
391
- * Gets the disconnect button HTML.
392
- *
393
- * @since 2.0.0
394
- *
395
- * @return string
396
- */
397
- public function get_disconnect_button_html() {
398
-
399
- ob_start();
400
- ?>
401
- <a href="<?php echo esc_url( $this->get_disconnect_url() ); ?>" class='button-primary'>
402
- <?php echo esc_html__( 'Disconnect from Square', 'woocommerce-square' ); ?>
403
- </a>
404
- <?php
405
-
406
- return ob_get_clean();
407
- }
408
-
409
-
410
- /**
411
- * Gets the connection URL.
412
- *
413
- * @since 2.0.0
414
- *
415
- * @param bool $is_sandbox whether to point to production or sandbox
416
- * @return string
417
- */
418
- public function get_connect_url( $is_sandbox = false ) {
419
-
420
- if ( $is_sandbox ) {
421
- $raw_url = self::CONNECT_URL_SANDBOX;
422
- } else {
423
- $raw_url = self::CONNECT_URL_PRODUCTION;
424
- }
425
-
426
- /**
427
- * Filters the connection URL.
428
- *
429
- * @since 2.0.0
430
- *
431
- * @param string $raw_url API URL
432
- */
433
- $url = (string) apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_api_url', $raw_url );
434
-
435
- $action = 'wc_' . $this->get_plugin()->get_id() . '_connected';
436
- $redirect_url = wp_nonce_url( add_query_arg( 'action', $action, admin_url() ), $action );
437
-
438
- $args = [
439
- 'redirect' => urlencode( urlencode( $redirect_url ) ),
440
- 'scopes' => implode( ',', $this->get_scopes() ),
441
- ];
442
-
443
- return add_query_arg( $args, $url );
444
- }
445
-
446
-
447
- /**
448
- * Gets the disconnect URL.
449
- *
450
- * @since 2.0.0
451
- *
452
- * @return string
453
- */
454
- protected function get_disconnect_url() {
455
-
456
- $action = 'wc_' . $this->get_plugin()->get_id() . '_disconnect';
457
- $url = add_query_arg( 'action', $action, admin_url() );
458
-
459
- return wp_nonce_url( $url, $action );
460
- }
461
-
462
-
463
- /**
464
- * Gets the token refresh URL.
465
- *
466
- * @since 2.0.0
467
- *
468
- * @return string
469
- */
470
- protected function get_refresh_url() {
471
-
472
- return $this->get_plugin()->get_settings_handler()->is_sandbox() ? self::REFRESH_URL_SANDBOX : self::REFRESH_URL_PRODUCTION;
473
- }
474
-
475
- /**
476
- * Gets the connection scopes.
477
- *
478
- * @since 2.0.0
479
- *
480
- * @return string[]
481
- */
482
- protected function get_scopes() {
483
-
484
- $scopes = [
485
- 'MERCHANT_PROFILE_READ',
486
- 'PAYMENTS_READ',
487
- 'PAYMENTS_WRITE',
488
- 'ORDERS_READ',
489
- 'ORDERS_WRITE',
490
- 'CUSTOMERS_READ',
491
- 'CUSTOMERS_WRITE',
492
- 'SETTLEMENTS_READ',
493
- 'ITEMS_READ',
494
- 'ITEMS_WRITE',
495
- 'INVENTORY_READ',
496
- 'INVENTORY_WRITE',
497
- ];
498
-
499
- return (array) apply_filters( 'wc_' . $this->get_plugin()->get_id() . '_connection_scopes', $scopes );
500
- }
501
-
502
-
503
- /**
504
- * Gets the plugin instance.
505
- *
506
- * @since 2.0.0
507
- *
508
- * @return Square\Plugin
509
- */
510
- public function get_plugin() {
511
-
512
- return $this->plugin;
513
- }
514
-
515
-
516
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Email.php DELETED
@@ -1,129 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\Emails;
28
-
29
- defined( 'ABSPATH' ) or exit;
30
-
31
- /**
32
- * Emails handler class.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Email {
37
-
38
-
39
- /** @var Emails\Sync_Completed instance */
40
- private $square_sync_completed;
41
-
42
-
43
- /**
44
- * Sets up Square emails.
45
- *
46
- * @since 1.0.0
47
- */
48
- public function __construct() {
49
-
50
- // add email handlers to WooCommerce core
51
- add_action( 'woocommerce_loaded', [ $this, 'init_emails' ] );
52
- add_filter( 'woocommerce_email_classes', [ $this, 'get_email_classes' ] );
53
- }
54
-
55
-
56
- /**
57
- * Ensures the WooCommerce email handlers are loaded.
58
- *
59
- * @since 2.0.0
60
- */
61
- private function init_mailer() {
62
-
63
- // loads the base WooCommerce Email base class
64
- if ( ! class_exists( 'WC_Email' ) ) {
65
- WC()->mailer();
66
- }
67
- }
68
-
69
-
70
- /**
71
- * Initializes Square email classes.
72
- *
73
- * @internal
74
- *
75
- * @since 2.0.0
76
- */
77
- public function init_emails() {
78
-
79
- $this->init_mailer();
80
-
81
- if ( null === $this->square_sync_completed ) {
82
- $this->square_sync_completed = new Emails\Sync_Completed();
83
- }
84
- }
85
-
86
-
87
- /**
88
- * Adds WooCommerce Square email handlers.
89
- *
90
- * @internal
91
- *
92
- * @since 2.0.0
93
- *
94
- * @param \WC_Email[] $emails associative array of email IDs and objects
95
- * @return \WC_Email[]
96
- */
97
- public function get_email_classes( $emails = [] ) {
98
-
99
- // init emails if uninitialized
100
- $this->init_emails();
101
-
102
- if ( ! array_key_exists( 'wc_square_sync_completed', $emails ) || ! $emails['wc_square_sync_completed'] instanceof Emails\Sync_Completed ) {
103
- $emails['wc_square_sync_completed'] = $this->square_sync_completed;
104
- }
105
-
106
- return $emails;
107
- }
108
-
109
-
110
- /**
111
- * Gets the Square sync completed email instance.
112
- *
113
- * @since 2.0.0
114
- *
115
- * @return Emails\Sync_Completed
116
- */
117
- public function get_sync_completed_email() {
118
-
119
- $this->init_mailer();
120
-
121
- if ( null === $this->square_sync_completed ) {
122
- $this->square_sync_completed = new Emails\Sync_Completed();
123
- }
124
-
125
- return $this->square_sync_completed;
126
- }
127
-
128
-
129
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Order.php DELETED
@@ -1,260 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\Plugin;
28
- use WooCommerce\Square\Handlers\Product;
29
-
30
- defined( 'ABSPATH' ) or exit;
31
-
32
- /**
33
- * Order handler class.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Order {
38
-
39
- /**
40
- * Array of previous stock values.
41
- *
42
- * @var []
43
- */
44
- private $previous_stock = [];
45
-
46
- /**
47
- * Array of product IDs that have been scheduled for sync in this request.
48
- *
49
- * @var []
50
- */
51
- private $products_to_sync = [];
52
-
53
-
54
- /**
55
- * Sets up Square order handler.
56
- *
57
- * @since 2.0.0
58
- */
59
- public function __construct() {
60
-
61
- // remove Square variation IDs from order item meta
62
- add_action( 'woocommerce_hidden_order_itemmeta', [ $this, 'hide_square_order_item_meta' ] );
63
-
64
- // ADD hooks for stock syncs based on changes from orders not from this gateway
65
- add_action( 'woocommerce_checkout_order_processed', [ $this, 'maybe_sync_stock_for_order_via_other_gateway' ], 10, 3 );
66
-
67
- // ADD hooks to listen to refunds on orders from other gateways.
68
- add_action( 'woocommerce_order_refunded', [ $this, 'maybe_sync_stock_for_refund_from_other_gateway' ], 10, 2 );
69
- }
70
-
71
-
72
- /**
73
- * Ensures the Square order item meta is hidden.
74
- *
75
- * @since 2.0.0
76
- *
77
- * @param string[] $hidden the hidden order item meta
78
- * @return string[] updated meta
79
- */
80
- public function hide_square_order_item_meta( $hidden ) {
81
-
82
- $hidden[] = '_square_item_variation_id';
83
-
84
- return $hidden;
85
- }
86
-
87
-
88
- /**
89
- * Checks if we should sync stock for this order.
90
- * We only sync for other gateways that Square will not be aware of.
91
- *
92
- * This functions sets a process in motion that gathers products that will be processed on shutdown.
93
- *
94
- * @since 2.0.8
95
- *
96
- * @param int $order_id Order ID number.
97
- * @param array $posted_data Submitted order data.
98
- * @param WC_Order $order Order object.
99
- */
100
- public function maybe_sync_stock_for_order_via_other_gateway( $order_id, $posted_data, $order ) {
101
-
102
- if ( ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
103
- return;
104
- }
105
-
106
- // Confirm we are not processing the order through the Square gateway.
107
- if ( ! $order instanceof \WC_Order || Plugin::GATEWAY_ID === $order->get_payment_method() ) {
108
- return;
109
- }
110
-
111
- $this->cache_previous_stock( $order );
112
-
113
- add_action( 'woocommerce_product_set_stock', [ $this, 'maybe_stage_inventory_updates_for_product' ] );
114
- add_action( 'woocommerce_variation_set_stock', [ $this, 'maybe_stage_inventory_updates_for_product' ] );
115
-
116
- add_action( 'shutdown', [ $this, 'maybe_sync_staged_inventory_updates' ] );
117
- }
118
-
119
- /**
120
- * Loop through order and cached previous stock values before they are reduced.
121
- *
122
- * @since 2.0.8
123
- *
124
- * @param WC_Order $order Order object.
125
- */
126
- private function cache_previous_stock( $order ) {
127
-
128
- // Loop over all items.
129
- foreach ( $order->get_items() as $item ) {
130
- if ( ! $item->is_type( 'line_item' ) ) {
131
- continue;
132
- }
133
-
134
- // Check to make sure it hasn't already been reduced.
135
- $product = $item->get_product();
136
- $item_stock_reduced = $item->get_meta( '_reduced_stock', true );
137
-
138
- if ( $item_stock_reduced || ! $product || ! $product->managing_stock() ) {
139
- continue;
140
- }
141
-
142
- $this->previous_stock[ $product->get_id() ] = $product->get_stock_quantity();
143
- }
144
- }
145
-
146
- /**
147
- * Stages a product inventory update for sync with Square when a product stock is updated.
148
- *
149
- * @internal The staged values will be stored in product_to_sync
150
- *
151
- * @since 2.0.8
152
- *
153
- * @param WC_Product $product the updated product with inventory updates.
154
- */
155
- public function maybe_stage_inventory_updates_for_product( $product ) {
156
-
157
- // Do not add inventory changes if we are already doing a sync, or we are not syncing this product.
158
- if ( defined( 'DOING_SQUARE_SYNC' ) || ! $product || ! Product::is_synced_with_square( $product ) ) {
159
- return;
160
- }
161
-
162
- // Compare stock to get difference.
163
- $product_id = $product->get_id();
164
- $previous = isset( $this->previous_stock[ $product_id ] ) ? $this->previous_stock[ $product_id ] : false;
165
- $current = $product->get_stock_quantity();
166
- $adjustment = (int) $current - $previous;
167
-
168
- if ( false === $previous || 0 === $adjustment ) {
169
- return;
170
- }
171
-
172
- // Record what type of inventory action occurred.
173
- $this->products_to_sync[ $product_id ] = $adjustment;
174
- }
175
-
176
-
177
- /**
178
- * Initializes a synchronization event for any staged inventory updates in this request.
179
- *
180
- * @internal
181
- *
182
- * @since 2.0.8
183
- */
184
- public function maybe_sync_staged_inventory_updates() {
185
-
186
- $inventory_adjustments = [];
187
-
188
- foreach ( $this->products_to_sync as $product_id => $adjustment ) {
189
-
190
- $product = wc_get_product( $product_id );
191
- if ( ! $product instanceof \WC_Product ) {
192
- continue;
193
- }
194
-
195
- $inventory_adjustment = Product::get_inventory_change_adjustment_type( $product, $adjustment );
196
-
197
- if ( empty( $inventory_adjustment ) ) {
198
- continue;
199
- }
200
-
201
- $inventory_adjustments[] = $inventory_adjustment;
202
- }
203
-
204
- if ( empty( $inventory_adjustments ) ) {
205
- return;
206
- }
207
-
208
- wc_square()->log( 'New order from other gateway inventory syncing..' );
209
- $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $inventory_adjustments ) ) . '_change_inventory' );
210
- wc_square()->get_api()->batch_change_inventory( $idempotency_key, $inventory_adjustments );
211
- }
212
-
213
- /**
214
- * Handle order refunds inventory/stock changes sync.
215
- *
216
- * @since 2.0.8
217
- *
218
- * @param in $order_id
219
- * @param int $refund_id
220
- */
221
- public function maybe_sync_stock_for_refund_from_other_gateway( $order_id, $refund_id ) {
222
-
223
- // Confirm we are not processing the order through the Square gateway.
224
- $order = wc_get_order( $order_id );
225
- if ( ! $order instanceof \WC_Order || Plugin::GATEWAY_ID === $order->get_payment_method() ) {
226
- return;
227
- }
228
-
229
- $refund = new \WC_Order_Refund( $refund_id );
230
- $inventory_adjustments = [];
231
- foreach ( $refund->get_items() as $item ) {
232
-
233
- if ( 'line_item' !== $item->get_type() ) {
234
- continue;
235
- }
236
-
237
- $product = $item->get_product();
238
- if ( ! $product instanceof \WC_Product ) {
239
- continue;
240
- }
241
-
242
- $adjustment = -1 * ( $item->get_quantity() ); // we want a positive value to increase the stock and a negative number to decrease it.
243
- $inventory_adjustment = Product::get_inventory_change_adjustment_type( $product, $adjustment );
244
-
245
- if ( empty( $inventory_adjustment ) ) {
246
- continue;
247
- }
248
-
249
- $inventory_adjustments[] = $inventory_adjustment;
250
- }
251
-
252
- if ( empty( $inventory_adjustments ) ) {
253
- return;
254
- }
255
-
256
- wc_square()->log( 'Order from other gateway Refund inventory updates syncing..' );
257
- $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $inventory_adjustments ) ) . '_change_inventory' );
258
- wc_square()->get_api()->batch_change_inventory( $idempotency_key, $inventory_adjustments );
259
- }
260
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Product.php DELETED
@@ -1,1389 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\CatalogObject;
28
- use WooCommerce\Square\Utilities\Money_Utility;
29
- use WooCommerce\Square\Sync\Records;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * Product handler class.
35
- *
36
- * @since 2.0.0
37
- */
38
- class Product {
39
-
40
-
41
- /** @var string the taxonomy name that flags whether a product is marked as 'synced' with Square */
42
- const SYNCED_WITH_SQUARE_TAXONOMY = 'wc_square_synced';
43
-
44
- const SQUARE_ID_META_KEY = '_square_item_id';
45
-
46
- const SQUARE_VERSION_META_KEY = '_square_item_version';
47
-
48
- const SQUARE_VARIATION_ID_META_KEY = '_square_item_variation_id';
49
-
50
- const SQUARE_VARIATION_VERSION_META_KEY = '_square_item_variation_version';
51
-
52
- const SQUARE_IMAGE_ID_META_KEY = '_square_item_image_id';
53
-
54
-
55
- /**
56
- * @param \WC_Product $product
57
- * @param \SquareConnect\Model\CatalogObject $catalog_object
58
- */
59
- public static function update_product( \WC_Product $product, \SquareConnect\Model\CatalogObject $catalog_object ) {
60
-
61
- if ( 'ITEM' !== $catalog_object->getType() || ! $catalog_object->getItemData() ) {
62
- throw new \InvalidArgumentException( 'Type of $catalog_object must be an ITEM' );
63
- }
64
-
65
- $product->update_meta_data( self::SQUARE_ID_META_KEY, $catalog_object->getId() );
66
- $product->update_meta_data( self::SQUARE_VERSION_META_KEY, $catalog_object->getVersion() );
67
- $product->update_meta_data( self::SQUARE_IMAGE_ID_META_KEY, $catalog_object->getImageId() );
68
-
69
- $product->save();
70
- }
71
-
72
-
73
- /**
74
- * @param \WC_Product $product
75
- * @param \SquareConnect\Model\CatalogObject $catalog_object
76
- */
77
- public static function update_variation( \WC_Product $product, \SquareConnect\Model\CatalogObject $catalog_object ) {
78
-
79
- if ( 'ITEM_VARIATION' !== $catalog_object->getType() || ! $catalog_object->getItemVariationData() ) {
80
- throw new \InvalidArgumentException( 'Type of $catalog_object must be an ITEM_VARIATION' );
81
- }
82
-
83
- $product->update_meta_data( self::SQUARE_VARIATION_ID_META_KEY, $catalog_object->getId() );
84
- $product->update_meta_data( self::SQUARE_VARIATION_VERSION_META_KEY, $catalog_object->getVersion() );
85
-
86
- $product->save();
87
- }
88
-
89
-
90
- /**
91
- * Updates a WooCommerce product from Square data.
92
- *
93
- * @since 2.0.0
94
- *
95
- * @param \WC_Product $product product object
96
- * @param \SquareConnect\Model\CatalogItem $catalog_item Square API catalog item data
97
- * @param bool $with_inventory whether to pull the latest product inventory from Square
98
- * @throws Framework\SV_WC_Plugin_Exception
99
- */
100
- public static function update_from_square( \WC_Product $product, \SquareConnect\Model\CatalogItem $catalog_item, $with_inventory = true ) {
101
-
102
- $catalog_id = null;
103
- $catalog_variations = $catalog_item->getVariations();
104
-
105
- if ( $product instanceof \WC_Product_Variable ) {
106
-
107
- foreach ( $catalog_variations as $catalog_variation ) {
108
-
109
- // sanity check to ensure the correct data structure
110
- if ( ! $catalog_variation->getItemVariationData() instanceof \SquareConnect\Model\CatalogItemVariation ) {
111
- continue;
112
- }
113
-
114
- $catalog_id = $catalog_variation->getItemVariationData()->getItemId();
115
-
116
- if ( $variation = wc_get_product( wc_get_product_id_by_sku( $catalog_variation->getItemVariationData()->getSku() ) ) ) {
117
-
118
- if ( ! $variation instanceof \WC_Product_Variation || $variation->get_parent_id() !== $product->get_id() ) {
119
- continue;
120
- }
121
-
122
- $variation->update_meta_data( self::SQUARE_VARIATION_ID_META_KEY, $catalog_variation->getId() );
123
-
124
- $variation->set_name( $catalog_variation->getItemVariationData()->getName() );
125
-
126
- if ( $catalog_variation->getItemVariationData()->getPriceMoney() ) {
127
- $variation->set_regular_price( Money_Utility::cents_to_float( $catalog_variation->getItemVariationData()->getPriceMoney()->getAmount() ) );
128
- }
129
-
130
- if ( $with_inventory && wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
131
- self::update_stock_from_square( $variation, false );
132
- }
133
-
134
- $variation->save();
135
-
136
- /**
137
- * Fires after updating a WooCommerce variation product from Square data.
138
- *
139
- * @since 2.0.0
140
- *
141
- * @param \WC_Product_Variation $variation variation object
142
- * @param \SquareConnect\Model\CatalogItemVariation $catalog_variation Square API catalog variation item object
143
- */
144
- do_action( 'wc_square_updated_product_variation_from_square', $variation, $catalog_variation );
145
- }
146
- }
147
-
148
- } else {
149
-
150
- $catalog_variation = current( $catalog_variations );
151
-
152
- if ( $product->get_sku() !== $catalog_variation->getItemVariationData()->getSku() ) {
153
- throw new Framework\SV_WC_Plugin_Exception( 'The WooCommerce SKU and Square SKU do not match' );
154
- }
155
-
156
- $catalog_id = $catalog_variation->getItemVariationData()->getItemId();
157
-
158
- $product->update_meta_data( self::SQUARE_VARIATION_ID_META_KEY, $catalog_variation->getId() );
159
-
160
- if ( $catalog_variation->getItemVariationData()->getPriceMoney() ) {
161
- $product->set_regular_price( Money_Utility::cents_to_float( $catalog_variation->getItemVariationData()->getPriceMoney()->getAmount() ) );
162
- }
163
-
164
- if ( $with_inventory && wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
165
- self::update_stock_from_square( $product, false );
166
- }
167
- }
168
-
169
- $product->set_name( wc_clean( $catalog_item->getName() ) );
170
- $product->set_description( $catalog_item->getDescription() );
171
-
172
- $category_id = Category::get_category_id_by_square_id( $catalog_item->getCategoryId() );
173
-
174
- if ( $category_id ) {
175
- wp_set_object_terms( $product->get_id(), intval( $category_id ), 'product_cat' );
176
- } else {
177
- $message = sprintf(
178
- /* translators: Placeholder: %s category ID */
179
- __( 'Square category with id (%s) was not imported to your Store. Please run Import Products from Square settings.', 'woocommerce-square' ),
180
- $catalog_item->getCategoryId()
181
- );
182
-
183
- $records = Records::get_records();
184
- foreach ($records as $record) {
185
- if ( $record->get_message() === $message ) {
186
- $is_recorded = true;
187
- }
188
- }
189
-
190
- if ( ! isset( $is_recorded ) ) {
191
- Records::set_record( [
192
- 'type' => 'alert',
193
- 'message' => $message,
194
- ] );
195
- }
196
- }
197
-
198
- if ( $catalog_id ) {
199
- $product->update_meta_data( self::SQUARE_ID_META_KEY, $catalog_id );
200
- }
201
-
202
- $product->save();
203
-
204
- /**
205
- * Fires after updating a WooCommerce product from Square data.
206
- *
207
- * @since 2.0.0
208
- *
209
- * @param \WC_Product $product product object
210
- * @param \SquareConnect\Model\CatalogItem $catalog_item Square API catalog item object
211
- */
212
- do_action( 'wc_square_updated_product_from_square', $product, $catalog_item );
213
- }
214
-
215
-
216
- /**
217
- * Updates a product image from a URL provided by Square (helper method).
218
- *
219
- * Note: does not save the product for persistence. If opening to public, consider changing this behavior.
220
- *
221
- * @since 2.0.0
222
- *
223
- * @param \WC_Product|int $product product object or product ID
224
- * @param string $image_id
225
- * @return \WC_Product updated product
226
- */
227
- public static function update_image_from_square( $product, $image_id ) {
228
-
229
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
230
-
231
- try {
232
-
233
- if ( ! $product instanceof \WC_Product ) {
234
- throw new Framework\SV_WC_Plugin_Exception( 'Invalid product' );
235
- }
236
-
237
- $image_response = wc_square()->get_api()->retrieve_catalog_object( $image_id );
238
-
239
- if ( ! $image_response->get_data() || ! $image_response->get_data()->getObject() || ! $image_response->get_data()->getObject()->getImageData() ) {
240
- throw new Framework\SV_WC_Plugin_Exception( 'No image data present' );
241
- }
242
-
243
- $image_url = $image_response->get_data()->getObject()->getImageData()->getUrl();
244
-
245
- // grab remote image to upload into WordPress before attaching to product
246
- $url_parts = parse_url( $image_url );
247
- $url_parts = explode( '/', $url_parts['path'] );
248
- $file_name = end( $url_parts );
249
- $upload_dir = wp_upload_dir();
250
- $remote_file_data = file_get_contents( $image_url );
251
-
252
- $iterator = 0;
253
-
254
- do {
255
-
256
- $file_prefix = 0 === $iterator ? '' : $iterator . '_';
257
- $local_file_path = untrailingslashit( $upload_dir['path'] ) . '/' . $file_prefix . $file_name;
258
- $iterator++;
259
-
260
- } while ( file_exists( $local_file_path ) );
261
-
262
- if ( empty( $remote_file_data ) ) {
263
- throw new Framework\SV_WC_Plugin_Exception( 'Could not fetch remote image data' );
264
- }
265
-
266
- $local_file = fopen( $local_file_path, 'wb' );
267
-
268
- if ( ! $local_file ) {
269
- throw new Framework\SV_WC_Plugin_Exception( 'Could not create new file' );
270
- }
271
-
272
- $write = fwrite( $local_file, $remote_file_data );
273
- $close = fclose( $local_file );
274
-
275
- if ( ! $write || ! $close ) {
276
- throw new Framework\SV_WC_Plugin_Exception( 'Could not write to file' );
277
- }
278
-
279
- $wp_file = wp_check_filetype( basename( $local_file_path ) );
280
-
281
- if ( ! $wp_file || ! isset( $wp_file['type'] ) ) {
282
- throw new Framework\SV_WC_Plugin_Exception( 'WordPress could not open the imported file' );
283
- }
284
-
285
- // some attachment media functions may not be available from WordPress core at this time
286
- if ( ! function_exists( 'wp_generate_attachment_metadata' ) || ! function_exists( 'wp_update_attachment_metadata' ) ) {
287
- include_once( ABSPATH . 'wp-admin/includes/image.php' );
288
- }
289
-
290
- $attachment = [
291
- 'post_mime_type' => $wp_file['type'],
292
- 'post_title' => $product->get_title(),
293
- 'post_content' => '',
294
- 'post_status' => 'inherit'
295
- ];
296
-
297
- // create WordPress attachment in database
298
- $attachment_id = wp_insert_attachment( $attachment, $local_file_path );
299
- $attachment_post = ! $attachment_id instanceof \WP_Error ? get_post( $attachment_id ) : null;
300
-
301
- if ( ! $attachment_post ) {
302
- throw new Framework\SV_WC_Plugin_Exception( 'WordPress cold not generate an attachment' );
303
- }
304
-
305
- $full_size_path = get_attached_file( $attachment_post->ID );
306
-
307
- if ( ! $full_size_path ) {
308
- throw new Framework\SV_WC_Plugin_Exception( 'WordPress could not fetch the attached file' );
309
- }
310
-
311
- $attachment_data = wp_generate_attachment_metadata( $attachment_id, $full_size_path );
312
-
313
- wp_update_attachment_metadata( $attachment_id, $attachment_data );
314
-
315
- // attach the newly updated image to product
316
- $product->set_image_id( $attachment_id );
317
-
318
- } catch ( Framework\SV_WC_Plugin_Exception $e ) {
319
-
320
- wc_square()->log( sprintf( 'Could not import image from Square at %1$s for attaching to product #%2$s. %3$s.', $image_url, $product->get_id(), $e->getMessage() ) );
321
- }
322
-
323
- $product->save();
324
-
325
- return $product;
326
- }
327
-
328
-
329
- /**
330
- * Updates a product's stock by getting the latest values from Square.
331
- *
332
- * @since 2.0.0
333
- *
334
- * @param \WC_Product $product product object
335
- * @param bool $save whether to save the product object
336
- * @return \WC_Product
337
- * @throws Framework\SV_WC_Plugin_Exception
338
- */
339
- public static function update_stock_from_square( \WC_Product $product, $save = true ) {
340
-
341
- $square_id = $product->get_meta( self::SQUARE_VARIATION_ID_META_KEY );
342
-
343
- if ( ! $square_id ) {
344
- throw new Framework\SV_WC_Plugin_Exception( __( 'Product not synced with Square', 'woocommerce-square' ) );
345
- }
346
-
347
- // if saving the product, flag as syncing so updating the stock won't trigger another sync
348
- if ( $save && ( ! defined( 'DOING_SQUARE_SYNC' ) || false === DOING_SQUARE_SYNC ) ) {
349
- define( 'DOING_SQUARE_SYNC', true );
350
- }
351
-
352
- $response = wc_square()->get_api()->retrieve_inventory_count( $square_id );
353
-
354
- $stock = 0;
355
-
356
- if ( $response->get_data() && $response->get_data()->getCounts() ) {
357
-
358
- /* @type \SquareConnect\Model\InventoryCount $count */
359
- foreach ( $response->get_data()->getCounts() as $count ) {
360
-
361
- if ( 'IN_STOCK' === $count->getState() ) {
362
- $stock += (float) $count->getQuantity();
363
- }
364
- }
365
- }
366
-
367
- $product->set_manage_stock( true );
368
- $product->set_stock_quantity( $stock );
369
-
370
- if ( $save ) {
371
- $product->save();
372
- }
373
-
374
- return $product;
375
- }
376
-
377
-
378
- /**
379
- * Initializes custom product taxonomies.
380
- *
381
- * @since 2.0.0
382
- */
383
- public static function init_taxonomies() {
384
-
385
- register_taxonomy( self::SYNCED_WITH_SQUARE_TAXONOMY, [ 'product' ],
386
- [
387
- 'hierarchical' => false,
388
- 'update_count_callback' => '_update_generic_term_count',
389
- 'show_ui' => false,
390
- 'show_in_nav_menus' => false,
391
- 'query_var' => is_admin(),
392
- 'rewrite' => false,
393
- ]
394
- );
395
- }
396
-
397
-
398
- /**
399
- * Sets a product's synced with Square status.
400
- *
401
- * @since 2.0.0
402
- *
403
- * @param \WC_Product|int $product a valid product object or product ID
404
- * @param string $synced either 'yes' (default) or 'no'
405
- * @return bool
406
- */
407
- public static function set_synced_with_square( $product, $synced = 'yes' ) {
408
-
409
- $success = false;
410
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
411
-
412
- if ( $product instanceof \WC_Product && in_array( $synced, [ 'yes', 'no' ], true ) ) {
413
-
414
- // ensure only one term is associated with the product at any time
415
- wp_delete_object_term_relationships( $product->get_id(), [ self::SYNCED_WITH_SQUARE_TAXONOMY ] );
416
-
417
- if ( 'yes' === $synced ) {
418
-
419
- $set_term = wp_set_post_terms( $product->get_id(), [ $synced ], self::SYNCED_WITH_SQUARE_TAXONOMY );
420
- $success = is_array( $set_term );
421
-
422
- if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
423
- $product->set_manage_stock( ! $product->is_type( 'variable' ) );
424
- }
425
-
426
- $product->save();
427
-
428
- } else {
429
-
430
- $success = true;
431
- }
432
- }
433
-
434
- return $success;
435
- }
436
-
437
-
438
- /**
439
- * Removes a product flag from being synced with Square.
440
- *
441
- * @since 2.0.0
442
- *
443
- * @param \WC_Product $product a valid product object
444
- * @return bool
445
- */
446
- public static function unset_synced_with_square( $product ) {
447
-
448
- return self::set_synced_with_square( $product, 'no' );
449
- }
450
-
451
-
452
- /**
453
- * Determines whether a product is set to be synced with Square.
454
- *
455
- * @since 2.0.0
456
- *
457
- * @param false|\WC_Product $product a valid product object
458
- * @return bool
459
- */
460
- public static function is_synced_with_square( $product ) {
461
-
462
- if ( $product instanceof \WC_Product ) {
463
-
464
- // if this is a variation, check its parent
465
- if ( $parent_product = wc_get_product( $product->get_parent_id() ) ) {
466
-
467
- if ( $parent_product instanceof \WC_Product ) {
468
- $product = $parent_product;
469
- }
470
- }
471
-
472
- $terms = wp_get_post_terms( $product->get_id(), self::SYNCED_WITH_SQUARE_TAXONOMY, [ 'fields' => 'names' ] );
473
- }
474
-
475
- return ! empty( $terms ) && 'yes' === $terms[0];
476
- }
477
-
478
-
479
- /**
480
- * Determines if a product can be synced with Square.
481
- *
482
- * SKUs and single-dimension attributes are required, so this helps us validate that in case a product has been
483
- * marked as "Sync with Square" manually.
484
- *
485
- * @since 2.0.2
486
- *
487
- * @param \WC_Product $product product object
488
- * @return bool
489
- */
490
- public static function can_sync_with_square( \WC_Product $product ) {
491
-
492
- $can_sync = self::has_sku( $product );
493
-
494
- if ( $can_sync && $product->is_type( 'variable' ) ) {
495
- $can_sync = ! self::has_multiple_variation_attributes( $product );
496
- }
497
-
498
- return (bool) apply_filters( 'wc_square_product_can_sync_with_square', $can_sync, $product );
499
- }
500
-
501
- /**
502
- * Return a link to the product's edit page
503
- *
504
- * @since 2.0.8
505
- *
506
- * @param \WC_Product $product product object
507
- * @return string
508
- */
509
- public static function get_product_edit_link( \WC_Product $product ) {
510
- return '<a href="' . esc_url( get_edit_post_link( $product->get_id() ) ) . '">' . esc_html( $product->get_formatted_name() ) . '</a>';
511
- }
512
-
513
- /**
514
- * Determines if a product has a SKU set.
515
- *
516
- * For variable products, this checks if all of its variations have a SKU.
517
- *
518
- * @since 2.0.2
519
- *
520
- * @param \WC_Product $product product object
521
- * @return bool
522
- */
523
- public static function has_sku( \WC_Product $product ) {
524
- if ( $product->is_type( 'variable' ) && $product->has_child() ) {
525
- foreach ( $product->get_children() as $variation_id ) {
526
- $variation = wc_get_product( $variation_id );
527
-
528
- if ( $variation instanceof \WC_Product && empty( $variation->get_sku() ) ) {
529
- return false;
530
- }
531
- }
532
- return true;
533
- }
534
-
535
- return ! empty( $product->get_sku() );
536
- }
537
-
538
-
539
- /**
540
- * Determines if a product has multiple variation attributes.
541
- *
542
- * @since 2.0.2
543
- *
544
- * @param \WC_Product $product product object
545
- * @return bool
546
- */
547
- public static function has_multiple_variation_attributes( \WC_Product $product ) {
548
-
549
- $has_attributes = false;
550
-
551
- if ( $product->is_type( 'variable' ) ) {
552
-
553
- $variation_attributes = [];
554
-
555
- foreach ( $product->get_attributes() as $attribute ) {
556
-
557
- if ( $attribute instanceof \WC_Product_Attribute && $attribute->get_variation() ) {
558
- $variation_attributes[] = $attribute;
559
- }
560
- }
561
-
562
- if ( count( $variation_attributes ) > 1 ) {
563
- $has_attributes = true;
564
- }
565
- }
566
-
567
- return $has_attributes;
568
- }
569
-
570
-
571
- /**
572
- * Gets an ID list of products that have a synced with Square status set.
573
- *
574
- * @since 2.0.0
575
- *
576
- * @param string $status either 'yes' or 'no'
577
- * @return int[] array of product IDs
578
- */
579
- private static function get_products_synced_status( $status ) {
580
-
581
- $sync_status_term = get_term_by( 'name', 'yes', self::SYNCED_WITH_SQUARE_TAXONOMY );
582
- $product_ids = [];
583
-
584
- if ( $sync_status_term instanceof \WP_Term && in_array( $status, [ 'yes', 'no' ], true ) ) {
585
-
586
- $tax_query_args = [
587
- 'taxonomy' => self::SYNCED_WITH_SQUARE_TAXONOMY,
588
- 'field' => 'id',
589
- 'terms' => $sync_status_term->term_id,
590
- 'include_children' => false,
591
- ];
592
-
593
- if ( 'no' === $status ) {
594
- $tax_query_args['operator'] = 'NOT IN';
595
- }
596
-
597
- $product_ids = get_posts( [
598
- 'post_type' => [ 'product', 'product_variation' ],
599
- 'post_status' => 'any',
600
- 'fields' => 'ids',
601
- 'nopaging' => true,
602
- 'tax_query' => [ $tax_query_args ],
603
- ] );
604
- }
605
-
606
- return $product_ids;
607
- }
608
-
609
-
610
- /**
611
- * Gets a list of products explicitly not set to be synced with Square.
612
- *
613
- * @since 2.0.0
614
- *
615
- * @return int[]
616
- */
617
- public static function get_products_not_synced_with_square() {
618
-
619
- return self::get_products_synced_status( 'no' );
620
- }
621
-
622
-
623
- /**
624
- * Gets a list of products that are set to be synced with Square.
625
- *
626
- * @since 2.0.0
627
- *
628
- * @return int[] array of product IDs
629
- */
630
- public static function get_products_synced_with_square() {
631
-
632
- return self::get_products_synced_status( 'yes' );
633
- }
634
-
635
-
636
- /**
637
- * Gets a product ID from a Square API variation ID.
638
- *
639
- * @since 2.0.0
640
- *
641
- * @param string $variation_id Square API variation item ID
642
- * @return int|null
643
- */
644
- public static function get_product_id_by_square_variation_id( $variation_id ) {
645
- global $wpdb;
646
-
647
- return $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = %s AND meta_value = %s", self::SQUARE_VARIATION_ID_META_KEY, $variation_id ) );
648
- }
649
-
650
-
651
- /**
652
- * Gets a product from a Square API variation ID.
653
- *
654
- * @since 2.0.0
655
- *
656
- * @param string $variation_id Square API variation item ID
657
- * @return \WC_Product|null
658
- */
659
- public static function get_product_by_square_variation_id( $variation_id ) {
660
-
661
- $product = wc_get_product( self::get_product_id_by_square_variation_id( $variation_id ) );
662
-
663
- if ( ! $product ) {
664
- $product = null;
665
- }
666
-
667
- return $product;
668
- }
669
-
670
-
671
- /**
672
- * Gets a product ID from a Square API ID.
673
- *
674
- * @since 2.0.0
675
- *
676
- * @param string $square_id Square API item ID
677
- * @return int|null
678
- */
679
- public static function get_product_id_by_square_id( $square_id ) {
680
- global $wpdb;
681
-
682
- return $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = %s AND meta_value = %s", self::SQUARE_ID_META_KEY, $square_id ) );
683
- }
684
-
685
-
686
- /**
687
- * Gets a product from a Square API ID.
688
- *
689
- * @since 2.0.0
690
- *
691
- * @param string $square_id Square API item ID
692
- * @return \WC_Product|null
693
- */
694
- public static function get_product_by_square_id( $square_id ) {
695
-
696
- $product = wc_get_product( self::get_product_id_by_square_id( $square_id ) );
697
-
698
- // ensure we have a parent product
699
- if ( ! $product || $product instanceof \WC_Product_Variation ) {
700
- $product = null;
701
- }
702
-
703
- return $product;
704
- }
705
-
706
-
707
- /**
708
- * Converts a WC_Product to a Square CatalogObject.
709
- *
710
- * @since 2.0.0
711
- *
712
- * @param \WC_Product $product
713
- * @return null|\SquareConnect\Model\CatalogObject
714
- */
715
- public static function convert_to_catalog_object( \WC_Product $product ) {
716
-
717
- if ( ! $product ) {
718
- return null;
719
- }
720
-
721
- $parent_id = $product->get_parent_id();
722
-
723
- if ( 0 !== $parent_id ) {
724
- return self::convert_to_catalog_object( wc_get_product( $parent_id ) );
725
- }
726
-
727
- $variations = [];
728
-
729
- if ( $product->has_child() ) {
730
-
731
- foreach ( $product->get_children() as $child_product_id ) {
732
-
733
- $child_product = wc_get_product( $child_product_id );
734
-
735
- if ( $child_product && $variation = self::extract_catalog_item_variation_data( $child_product ) ) {
736
-
737
- $variations[] = $variation;
738
- }
739
- }
740
-
741
- } else {
742
-
743
- $variation = self::extract_catalog_item_variation_data( $product );
744
- $variations = $variation ? [ $variation ] : [];
745
- }
746
-
747
- if ( empty( $variations ) ) {
748
- return null;
749
- }
750
-
751
- $data = [
752
- 'type' => 'ITEM',
753
- 'id' => self::get_square_item_id( $product ),
754
- 'version' => self::get_square_version( $product ),
755
- 'present_at_location_ids' => [ wc_square()->get_settings_handler()->get_location_id() ],
756
- 'item_data' => [
757
- 'name' => $product->get_name(),
758
- 'variations' => $variations,
759
- ],
760
- ];
761
-
762
- // TODO: Handle categories
763
-
764
- return new \SquareConnect\Model\CatalogObject( $data );
765
- }
766
-
767
-
768
- /**
769
- * Extracts the data for a catalog item from a \WC_Product.
770
- *
771
- * @since 2.0.0
772
- *
773
- * @param \WC_Product $product the product object
774
- * @param \SquareConnect\Model\CatalogItemVariation[] $variations (optional) array of variations to include
775
- * @param bool $is_soft_delete whether or not this item data is for a soft-delete
776
- * @return array
777
- */
778
- public static function extract_catalog_item_data( \WC_Product $product, array $variations = [], $is_soft_delete = false ) {
779
-
780
- if ( ! $product ) {
781
- return null;
782
- }
783
-
784
- $data = [
785
- 'type' => 'ITEM',
786
- 'id' => self::get_square_item_id( $product ),
787
- 'version' => self::get_square_version( $product ),
788
- 'present_at_location_ids' => [ wc_square()->get_settings_handler()->get_location_id() ],
789
- 'item_data' => [
790
- 'name' => $product->get_name(),
791
- 'variations' => $variations,
792
- ],
793
- ];
794
-
795
- $square_category_id = 0;
796
-
797
- foreach ( $product->get_category_ids() as $category_id ) {
798
-
799
- $map = Category::get_mapping( $category_id );
800
-
801
- if ( ! empty( $map['square_id'] ) ) {
802
- $square_category_id = $map['square_id'];
803
- break;
804
- }
805
- }
806
-
807
- // if a category with a Square ID was found
808
- if ( $square_category_id ) {
809
- $data['item_data']['category_id'] = $square_category_id;
810
- }
811
-
812
- if ( $is_soft_delete ) {
813
-
814
- $data['present_at_all_locations'] = false;
815
- $data['present_at_location_ids'] = [];
816
- }
817
-
818
- return $data;
819
- }
820
-
821
-
822
- /**
823
- * Extracts the data for a catalog item variation from a \WC_Product.
824
- *
825
- * @since 2.0.0
826
- *
827
- * @param \WC_Product $product the product to get the variation data for
828
- * @param \WC_Product $parent_product (optional) the parent product - prevents additional calls to wc_get_product()
829
- * * @param bool $is_soft_delete whether or not this item data is for a soft-delete
830
- * @return array
831
- */
832
- public static function extract_catalog_item_variation_data( \WC_Product $product, \WC_Product $parent_product = null, $is_soft_delete = false ) {
833
-
834
- if ( ! $product ) {
835
- return null;
836
- }
837
-
838
- $parent_product_id = $product->get_parent_id();
839
-
840
- if ( 0 === $parent_product_id ) {
841
-
842
- $parent_product = $product;
843
-
844
- } elseif ( null === $parent_product || $parent_product_id !== $parent_product->get_id() ) {
845
-
846
- $parent_product = wc_get_product( $parent_product_id );
847
- }
848
-
849
- if ( $parent_product instanceof \WC_Product ) {
850
-
851
- $item_id = self::get_square_item_id( $parent_product );
852
-
853
- $data = [
854
- 'type' => 'ITEM_VARIATION',
855
- 'id' => self::get_square_item_variation_id( $product ),
856
- 'version' => self::get_square_variation_version( $product ),
857
- 'item_variation_data' => [
858
- 'item_id' => $item_id,
859
- 'name' => $product->get_name(),
860
- 'sku' => $product->get_sku(),
861
- 'pricing_type' => 'FIXED_PRICING',
862
- 'price_money' => self::price_to_money( $product->get_regular_price() ),
863
- 'track_inventory' => true,
864
- ]
865
- ];
866
-
867
- if ( $is_soft_delete ) {
868
-
869
- $data['present_at_all_locations'] = false;
870
- $data['present_at_location_ids'] = [];
871
- }
872
- }
873
-
874
- return $data;
875
- }
876
-
877
-
878
- /**
879
- * Converts a product price to a Money object.
880
- *
881
- * @since 2.0.0
882
- *
883
- * @param int|float $price
884
- * @return \SquareConnect\Model\Money
885
- */
886
- public static function price_to_money( $price ) {
887
-
888
- return Money_Utility::amount_to_money( $price, get_woocommerce_currency() );
889
- }
890
-
891
-
892
- /**
893
- * Returns the square item ID (if known) or generates one based on local data.
894
- *
895
- * @since 2.0.0
896
- *
897
- * @param int|\WC_Product $product_id the product ID or product object
898
- * @param bool $generate_if_not_found whether a temporary ID should be returned if an ID is not found
899
- * @return string
900
- */
901
- public static function get_square_item_id( $product_id, $generate_if_not_found = true ) {
902
-
903
- if ( $product_id instanceof \WC_Product ) {
904
- $product_id = $product_id->get_id();
905
- }
906
-
907
- $square_item_id = get_post_meta( $product_id, self::SQUARE_ID_META_KEY, true ) ?: null;
908
-
909
- if ( ! $square_item_id && true === $generate_if_not_found ) {
910
-
911
- $square_item_id = '#item_' . $product_id;
912
- }
913
-
914
- return $square_item_id;
915
- }
916
-
917
-
918
- /**
919
- * Sets the Square item ID for a given product.
920
- *
921
- * @since 2.0.0
922
- *
923
- * @param int|false|\WC_Product $product the product object or ID
924
- * @param string $item_id the Square item ID
925
- */
926
- public static function set_square_item_id( $product, $item_id ) {
927
-
928
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
929
-
930
- if ( $product instanceof \WC_Product ) {
931
-
932
- $product->update_meta_data( self::SQUARE_ID_META_KEY, $item_id );
933
- $product->save();
934
- }
935
- }
936
-
937
-
938
- /**
939
- * Returns the square item variation ID (if known) or generates one based on local data.
940
- *
941
- * @since 2.0.0
942
- *
943
- * @param int|\WC_Product $product_id the product ID or product object
944
- * @param bool $generate_if_not_found whether a temporary ID should be returned if an ID is not found
945
- * @return string|null
946
- */
947
- public static function get_square_item_variation_id( $product_id, $generate_if_not_found = true ) {
948
-
949
- if ( $product_id instanceof \WC_Product ) {
950
- $product_id = $product_id->get_id();
951
- }
952
-
953
- $square_item_variation_id = get_post_meta( $product_id, self::SQUARE_VARIATION_ID_META_KEY, true ) ?: null;
954
-
955
- if ( ! $square_item_variation_id && true === $generate_if_not_found ) {
956
-
957
- $square_item_variation_id = '#item_variation_' . $product_id;
958
- }
959
-
960
- return $square_item_variation_id;
961
- }
962
-
963
-
964
- /**
965
- * Sets the Square item variation ID for a given product.
966
- *
967
- * @since 2.0.0
968
- *
969
- * @param int|false|\WC_Product $product the product object or ID
970
- * @param string $item_variation_id the Square item variation ID
971
- */
972
- public static function set_square_item_variation_id( $product, $item_variation_id ) {
973
-
974
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
975
-
976
- if ( $product instanceof \WC_Product ) {
977
-
978
- $product->update_meta_data( self::SQUARE_VARIATION_ID_META_KEY, $item_variation_id );
979
- $product->save();
980
- }
981
- }
982
-
983
-
984
- /**
985
- * Returns the Square item version (if known) for the given product.
986
- *
987
- * @since 2.0.0
988
- *
989
- * @param int|\WC_Product $product_id the product ID or product object
990
- * @return int
991
- */
992
- public static function get_square_version( $product_id ) {
993
-
994
- if ( $product_id instanceof \WC_Product ) {
995
- $product_id = $product_id->get_id();
996
- }
997
-
998
- $square_version = get_post_meta( $product_id, self::SQUARE_VERSION_META_KEY, true );
999
-
1000
- return $square_version ? (int) $square_version : 0;
1001
- }
1002
-
1003
-
1004
- /**
1005
- * Sets the Square item version for a given product.
1006
- *
1007
- * @since 2.0.0
1008
- *
1009
- * @param int|false|\WC_Product $product the product object or ID
1010
- * @param int $version the Square item version
1011
- */
1012
- public static function set_square_version( $product, $version ) {
1013
-
1014
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
1015
-
1016
- if ( $product instanceof \WC_Product ) {
1017
-
1018
- $product->update_meta_data( self::SQUARE_VERSION_META_KEY, $version );
1019
- $product->save();
1020
- }
1021
- }
1022
-
1023
-
1024
- /**
1025
- * Returns the Square item variation version (if known) for the given product.
1026
- *
1027
- * @since 2.0.0
1028
- *
1029
- * @param int|\WC_Product $product_id the product ID or product object
1030
- * @return int
1031
- */
1032
- public static function get_square_variation_version( $product_id ) {
1033
-
1034
- if ( $product_id instanceof \WC_Product ) {
1035
- $product_id = $product_id->get_id();
1036
- }
1037
-
1038
- $square_variation_version = get_post_meta( $product_id, self::SQUARE_VARIATION_VERSION_META_KEY, true );
1039
-
1040
- return $square_variation_version ? (int) $square_variation_version : 0;
1041
- }
1042
-
1043
-
1044
- /**
1045
- * Sets the Square item ID for a given product.
1046
- *
1047
- * @since 2.0.0
1048
- *
1049
- * @param int|false|\WC_Product $product the product object or ID
1050
- * @param int $variation_version the Square item variation version
1051
- */
1052
- public static function set_square_variation_version( $product, $variation_version ) {
1053
-
1054
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
1055
-
1056
- if ( $product instanceof \WC_Product ) {
1057
-
1058
- $product->update_meta_data( self::SQUARE_VARIATION_VERSION_META_KEY, $variation_version );
1059
- $product->save();
1060
- }
1061
- }
1062
-
1063
-
1064
- /**
1065
- * Gets a product's Square image ID.
1066
- *
1067
- * @since 2.0.0
1068
- *
1069
- * @param \WC_Product|int $product product object or ID
1070
- * @return string
1071
- */
1072
- public static function get_square_image_id( $product ) {
1073
-
1074
- $image_id = '';
1075
-
1076
- if ( is_numeric( $product ) ) {
1077
- $product = wc_get_product( $product );
1078
- }
1079
-
1080
- if ( $product instanceof \WC_Product ) {
1081
- $image_id = $product->get_meta( self::SQUARE_IMAGE_ID_META_KEY );
1082
- }
1083
-
1084
- return $image_id;
1085
- }
1086
-
1087
-
1088
- /**
1089
- * Sets a product's Square image ID.
1090
- *
1091
- * @since 2.0.0
1092
- *
1093
- * @param \WC_Product|int $product product object or ID
1094
- * @param string $image_id Square image ID
1095
- */
1096
- public static function set_square_image_id( $product, $image_id ) {
1097
-
1098
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
1099
-
1100
- if ( $product instanceof \WC_Product ) {
1101
-
1102
- $product->update_meta_data( self::SQUARE_IMAGE_ID_META_KEY, $image_id );
1103
- $product->save_meta_data();
1104
- }
1105
- }
1106
-
1107
-
1108
- /**
1109
- * Gets all the Square meta data for the given product IDs.
1110
- *
1111
- * @see Product::get_square_meta_single()
1112
- *
1113
- * @since 2.0.0
1114
- *
1115
- * @param int[] $product_ids the product IDs to look up
1116
- * @param string $array_key the variable to use as the array key in the resulting array
1117
- * @return array associative array of arrays of data, indexed by $array_key found values (e.g. product ID or square ID, etc.)
1118
- */
1119
- public static function get_square_meta( $product_ids, $array_key = 'product_id' ) {
1120
- global $wpdb;
1121
-
1122
- $results = $square_meta = [];
1123
-
1124
- if ( ! empty( $product_ids ) ) {
1125
-
1126
- $meta_keys = [
1127
- 'square_item_id' => self::SQUARE_ID_META_KEY,
1128
- 'square_item_variation_id' => self::SQUARE_VARIATION_ID_META_KEY,
1129
- 'square_version' => self::SQUARE_VERSION_META_KEY,
1130
- 'square_variation_version' => self::SQUARE_VARIATION_VERSION_META_KEY,
1131
- ];
1132
-
1133
- $array_key = array_key_exists( $array_key, $meta_keys ) ? $array_key : 'product_id';
1134
- $post_ids_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $product_ids ) ) ) . ')';
1135
- $meta_key_in = "('" . self::SQUARE_ID_META_KEY . "','" . self::SQUARE_VARIATION_ID_META_KEY . "','" . self::SQUARE_VERSION_META_KEY . "','" . self::SQUARE_VARIATION_VERSION_META_KEY . "')";
1136
- $products_meta = $wpdb->get_results( "
1137
- SELECT post_id AS product_id, meta_key, meta_value
1138
- FROM $wpdb->postmeta
1139
- WHERE post_id IN $post_ids_in
1140
- AND meta_key IN $meta_key_in
1141
- ", ARRAY_A );
1142
-
1143
- foreach ( $products_meta as $post_meta ) {
1144
-
1145
- if ( ! array_key_exists( (string) $post_meta['product_id'], $square_meta ) ) {
1146
- $square_meta[ (string) $post_meta['product_id'] ] = [
1147
- 'product_id' => (int) $post_meta['product_id'],
1148
- 'square_item_id' => false,
1149
- 'square_item_variation_id' => false,
1150
- 'square_version' => false,
1151
- 'square_variation_version' => false,
1152
- ];
1153
- }
1154
-
1155
- foreach ( $meta_keys as $square_meta_key => $post_meta_key ) {
1156
- if ( isset( $post_meta[ 'meta_key' ] ) && $post_meta_key === $post_meta['meta_key'] ) {
1157
- $square_meta[ $post_meta['product_id'] ][ $square_meta_key ] = $post_meta['meta_value'];
1158
- break;
1159
- }
1160
- }
1161
- }
1162
-
1163
- foreach ( $product_ids as $product_id ) {
1164
-
1165
- // sanity checks: cannot build index without a valid key
1166
- if ( ! array_key_exists( $product_id, $square_meta )
1167
- || ! isset( $square_meta[ $product_id ][ $array_key ] )
1168
- || ! $square_meta[ (string) $product_id ][ $array_key ] ) {
1169
-
1170
- continue;
1171
- }
1172
-
1173
- $results[ (string) $square_meta[ (string) $product_id ][ $array_key ] ] = $square_meta[ (string) $product_id ];
1174
- }
1175
- }
1176
-
1177
- return $results;
1178
- }
1179
-
1180
-
1181
- /**
1182
- * Gets all the Square meta data for the given single product ID.
1183
- *
1184
- * @see Product::get_square_meta() for getting meta data for all products
1185
- *
1186
- * @since 2.0.0
1187
- *
1188
- * @param int|\WC_Product $product_id the product ID or object
1189
- * @return array associative array
1190
- */
1191
- public static function get_square_meta_single( $product_id ) {
1192
-
1193
- if ( $product_id instanceof \WC_Product ) {
1194
- $product_id = $product_id->get_id();
1195
- }
1196
-
1197
- return [
1198
- 'product_id' => $product_id,
1199
- 'square_item_id' => self::get_square_item_id( $product_id ),
1200
- 'square_item_variation_id' => self::get_square_item_variation_id( $product_id ),
1201
- 'square_version' => self::get_square_version( $product_id ),
1202
- ];
1203
- }
1204
-
1205
-
1206
- /**
1207
- * Checks if a product is mapped to a Square Item.
1208
- *
1209
- * @since 2.0.0
1210
- *
1211
- * @param int|\WC_Product $product_id the product ID or product object
1212
- * @return bool
1213
- */
1214
- public static function is_mapped( $product_id ) {
1215
-
1216
- $item_id = self::get_square_item_id( $product_id );
1217
-
1218
- return ! empty( $item_id ) && false === strpos( $item_id, '#' );
1219
- }
1220
-
1221
-
1222
- /**
1223
- * Updates square meta for a given product ID.
1224
- *
1225
- * @since 2.0.0
1226
- *
1227
- * @param int|\WC_Product $product_id the product ID or the product object
1228
- * @param array $meta_data the meta data to update
1229
- * @type string $item_id the Square Item ID
1230
- * @type int $item_version the Square Item version
1231
- * @type string $item_variation_id the Square Item Variation ID
1232
- * @type int $item_variation_version the Square Item Variation Version
1233
- */
1234
- public static function update_square_meta( $product_id, $meta_data ) {
1235
-
1236
- foreach ( $meta_data as $meta_key => $meta_value ) {
1237
-
1238
- switch ( $meta_key ) {
1239
-
1240
- case 'item_id':
1241
- self::set_square_item_id( $product_id, $meta_value );
1242
- break;
1243
-
1244
- case 'item_version':
1245
- self::set_square_version( $product_id, $meta_value );
1246
- break;
1247
-
1248
- case 'item_variation_id':
1249
- self::set_square_item_variation_id( $product_id, $meta_value );
1250
- break;
1251
-
1252
- case 'item_variation_version':
1253
- self::set_square_variation_version( $product_id, $meta_value );
1254
- break;
1255
-
1256
- case 'item_image_id':
1257
- self::set_square_image_id( $product_id, $meta_value );
1258
- break;
1259
- }
1260
- }
1261
- }
1262
-
1263
-
1264
- /**
1265
- * Clears the Square meta for a given product.
1266
- *
1267
- * @since 2.0.0
1268
- *
1269
- * @param int[] $product_ids array of product IDs
1270
- */
1271
- public static function clear_square_meta( $product_ids ) {
1272
- global $wpdb;
1273
-
1274
- $product_ids = is_array( $product_ids ) ? $product_ids : [ $product_ids ];
1275
-
1276
- $meta_keys = [
1277
- self::SQUARE_ID_META_KEY,
1278
- self::SQUARE_VERSION_META_KEY,
1279
- self::SQUARE_VARIATION_ID_META_KEY,
1280
- self::SQUARE_VARIATION_VERSION_META_KEY,
1281
- self::SQUARE_IMAGE_ID_META_KEY,
1282
- ];
1283
-
1284
- $meta_key_in = '("' . implode( '","', $meta_keys ) . '")';
1285
- $post_ids_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $product_ids ) ) ) . ')';
1286
-
1287
- $wpdb->query( "
1288
- UPDATE $wpdb->postmeta
1289
- SET meta_value = ''
1290
- WHERE meta_key IN $meta_key_in
1291
- AND post_id IN $post_ids_in;
1292
- " );
1293
- }
1294
-
1295
-
1296
- /**
1297
- * Imports meta data from a remote product to the given local product ID.
1298
- *
1299
- * @since 2.0.0
1300
- *
1301
- * @param int|false|\WC_Product $product the product object or ID
1302
- * @param \SquareConnect\Model\CatalogObject $remote_product the remote catalog object
1303
- */
1304
- public static function import_remote_meta( $product, $remote_product ) {
1305
-
1306
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
1307
-
1308
- if ( $product ) {
1309
-
1310
- self::update_square_meta( $product->get_id(), [
1311
- 'item_id' => $remote_product->getId(),
1312
- 'item_version' => $remote_product->getVersion(),
1313
- 'item_image_id' => $remote_product->getImageId(),
1314
- ] );
1315
- }
1316
- }
1317
-
1318
-
1319
- /**
1320
- * Gets an InventoryChange object filled with a \SquareConnect\Model\InventoryPhysicalCount object for a given product.
1321
- *
1322
- * @since 2.0.0
1323
- *
1324
- * @param \WC_Product $product the product object
1325
- * @return \SquareConnect\Model\InventoryChange|null
1326
- */
1327
- public static function get_inventory_change_physical_count_type( \WC_Product $product ) {
1328
-
1329
- $inventory_change = null;
1330
-
1331
- if ( $square_variation_id = self::get_square_item_variation_id( $product->get_id(), false ) ) {
1332
-
1333
- $inventory_change = new \SquareConnect\Model\InventoryChange( [
1334
- 'type' => 'PHYSICAL_COUNT',
1335
- 'physical_count' => new \SquareConnect\Model\InventoryPhysicalCount( [
1336
- 'catalog_object_id' => $square_variation_id,
1337
- 'quantity' => '' . max( 0, $product->get_stock_quantity() ),
1338
- 'location_id' => wc_square()->get_settings_handler()->get_location_id(),
1339
- 'state' => 'IN_STOCK',
1340
- 'occurred_at' => date( 'Y-m-d\TH:i:sP' ),
1341
- ] ),
1342
- ] );
1343
- }
1344
-
1345
- return $inventory_change;
1346
- }
1347
-
1348
-
1349
- /**
1350
- * Gets an InventoryChange object filled with a \SquareConnect\Model\InventoryAdjustment object for a given product.
1351
- *
1352
- * @since 2.0.8
1353
- *
1354
- * @param \WC_Product $product the product object
1355
- * @param int $adjustment Value can negative or positive.
1356
- *
1357
- * @return \SquareConnect\Model\InventoryChange|null
1358
- */
1359
- public static function get_inventory_change_adjustment_type( \WC_Product $product, $adjustment ) {
1360
-
1361
- $square_variation_id = self::get_square_item_variation_id( $product->get_id(), false );
1362
-
1363
- if ( empty( $square_variation_id ) || 0 === $adjustment) {
1364
- return null;
1365
- }
1366
-
1367
- if ( 0 > $adjustment ) {
1368
- $from = 'IN_STOCK';
1369
- $to = 'SOLD';
1370
- } else {
1371
- $from = 'NONE';
1372
- $to = 'IN_STOCK';
1373
- }
1374
-
1375
- $inventory_change = new \SquareConnect\Model\InventoryChange([
1376
- 'type' => 'ADJUSTMENT',
1377
- 'adjustment' => new \SquareConnect\Model\InventoryAdjustment([
1378
- 'catalog_object_id' => $square_variation_id,
1379
- 'location_id' => wc_square()->get_settings_handler()->get_location_id(),
1380
- 'quantity' => '' . absint( $adjustment ),
1381
- 'from_state' => $from,
1382
- 'to_state' => $to,
1383
- 'occurred_at' => date( 'Y-m-d\TH:i:sP' ),
1384
- ]),
1385
- ]);
1386
-
1387
- return $inventory_change;
1388
- }
1389
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Product/Woo_SOR.php DELETED
@@ -1,292 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers\Product;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\CatalogObject;
28
-
29
- class Woo_SOR extends \WooCommerce\Square\Handlers\Product {
30
-
31
-
32
- /**
33
- * Updates a Square catalog item with a WooCommerce product's data.
34
- *
35
- * @since 2.0.0
36
- *
37
- * @param CatalogObject $catalog_object Square SDK catalog object
38
- * @param \WC_Product $product WooCommerce product
39
- * @return CatalogObject
40
- * @throws Framework\SV_WC_Plugin_Exception
41
- */
42
- public static function update_catalog_item( CatalogObject $catalog_object, \WC_Product $product ) {
43
-
44
- if ( 'ITEM' !== $catalog_object->getType() || ! $catalog_object->getItemData() ) {
45
- throw new Framework\SV_WC_Plugin_Exception( 'Type of $catalog_object must be an ITEM' );
46
- }
47
-
48
- // ensure the product meta is persisted
49
- self::update_product( $product, $catalog_object );
50
-
51
- if ( ! $catalog_object->getId() ) {
52
- $catalog_object->setId( self::get_square_item_id( $product ) );
53
- }
54
-
55
- $is_delete = 'trash' === $product->get_status();
56
-
57
- $catalog_object = self::set_catalog_object_location_ids( $catalog_object, $is_delete );
58
-
59
- $item_data = $catalog_object->getItemData();
60
-
61
- $item_data->setName( $product->get_name() );
62
-
63
- $square_category_id = 0;
64
-
65
- foreach ( $product->get_category_ids() as $category_id ) {
66
-
67
- $map = \WooCommerce\Square\Handlers\Category::get_mapping( $category_id );
68
-
69
- if ( ! empty( $map['square_id'] ) ) {
70
-
71
- $square_category_id = $map['square_id'];
72
- break;
73
- }
74
- }
75
-
76
- // if a category with a Square ID was found
77
- if ( $square_category_id ) {
78
- $item_data->setCategoryId( $square_category_id );
79
- }
80
-
81
- $catalog_variations = $item_data->getVariations() ?: [];
82
-
83
- // if dealing with a variable product, try and match the variations
84
- if ( $product->is_type( 'variable' ) ) {
85
-
86
- $product_variation_ids = $product->get_children();
87
-
88
- if ( is_array( $catalog_variations ) ) {
89
-
90
- foreach ( $catalog_variations as $object_key => $variation_object ) {
91
-
92
- $product_variation_id = self::get_product_id_by_square_variation_id( $variation_object->getId() );
93
-
94
- // ID might not be set, so try the SKU
95
- if ( ! $product_variation_id ) {
96
- $product_variation_id = wc_get_product_id_by_sku( $variation_object->getItemVariationData()->getSku() );
97
- }
98
-
99
- // if a product was found and belongs to the parent, use it
100
- if ( false !== ( $key = array_search( $product_variation_id, $product_variation_ids, false ) ) ) {
101
-
102
- $product_variation = wc_get_product( $product_variation_id );
103
-
104
- if ( $product_variation instanceof \WC_Product ) {
105
-
106
- $catalog_variations[ $object_key ] = self::update_catalog_variation( $variation_object, $product_variation );
107
-
108
- // consider this variation taken care of
109
- unset( $product_variation_ids[ $key ] );
110
- }
111
-
112
- } else {
113
-
114
- unset( $catalog_variations[ $object_key ] );
115
- }
116
- }
117
- }
118
-
119
- // all that's left are variations that didn't have a match, so create new variations
120
- foreach ( $product_variation_ids as $product_variation_id ) {
121
-
122
- $product_variation = wc_get_product( $product_variation_id );
123
-
124
- if ( ! $product_variation instanceof \WC_Product ) {
125
- continue;
126
- }
127
-
128
- $variation_object = new CatalogObject( [
129
- 'type' => 'ITEM_VARIATION',
130
- 'item_variation_data' => new \SquareConnect\Model\CatalogItemVariation( [
131
- 'item_id' => $catalog_object->getId(),
132
- ] ),
133
- ] );
134
-
135
- $catalog_variations[] = self::update_catalog_variation( $variation_object, $product_variation );
136
- }
137
-
138
- // otherwise, we have a simple product
139
- } else {
140
-
141
- if ( ! empty( $catalog_variations ) ) {
142
-
143
- $variation_object = $catalog_variations[0];
144
-
145
- } else {
146
-
147
- $variation_object = new CatalogObject( [
148
- 'type' => 'ITEM_VARIATION',
149
- 'item_variation_data' => new \SquareConnect\Model\CatalogItemVariation( [
150
- 'item_id' => $catalog_object->getId(),
151
- ] ),
152
- ] );
153
- }
154
-
155
- $catalog_variations = [ self::update_catalog_variation( $variation_object, $product ) ];
156
- }
157
-
158
- $item_data->setVariations( array_values( $catalog_variations ) );
159
-
160
- $catalog_object->setItemData( $item_data );
161
-
162
- /**
163
- * Fires when updating a Square catalog item with WooCommerce product data.
164
- *
165
- * @since 2.0.0
166
- *
167
- * @param CatalogObject $catalog_object Square SDK catalog object
168
- * @param \WC_Product $product WooCommerce product
169
- */
170
- $catalog_object = apply_filters( 'wc_square_update_catalog_item', $catalog_object, $product );
171
-
172
- return $catalog_object;
173
- }
174
-
175
-
176
- /**
177
- * Updates a Square catalog item variation with a WooCommerce product's data.
178
- *
179
- * @since 2.0.0
180
- *
181
- * @param CatalogObject $catalog_object Square SDK catalog object
182
- * @param \WC_Product $product WooCommerce product
183
- * @return CatalogObject
184
- * @throws Framework\SV_WC_Plugin_Exception
185
- */
186
- public static function update_catalog_variation( CatalogObject $catalog_object, \WC_Product $product ) {
187
-
188
- if ( 'ITEM_VARIATION' !== $catalog_object->getType() || ! $catalog_object->getItemVariationData() ) {
189
- throw new Framework\SV_WC_Plugin_Exception( 'Type of $catalog_object must be an ITEM_VARIATION' );
190
- }
191
-
192
- // ensure the variation meta is persisted
193
- self::update_variation( $product, $catalog_object );
194
-
195
- if ( ! $catalog_object->getId() ) {
196
- $catalog_object->setId( self::get_square_item_variation_id( $product ) );
197
- }
198
-
199
- if ( ! $catalog_object->getVersion() ) {
200
- $catalog_object->setVersion( self::get_square_variation_version( $product ) );
201
- }
202
-
203
- $catalog_object = self::set_catalog_object_location_ids( $catalog_object, 'trash' === $product->get_status() );
204
-
205
- $variation_data = $catalog_object->getItemVariationData();
206
-
207
- if ( $product->get_regular_price() || $product->get_sale_price() ) {
208
- $variation_data->setPriceMoney( self::price_to_money( $product->get_sale_price() ?: $product->get_regular_price() ) );
209
- } else {
210
- $variation_data->setPriceMoney( self::price_to_money( 0 ) );
211
- }
212
-
213
- $variation_data->setPricingType( 'FIXED_PRICING' );
214
-
215
- $variation_data->setName( $product->get_name() );
216
-
217
- if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
218
- $variation_data->setTrackInventory( true );
219
- }
220
-
221
- $variation_data->setSku( $product->get_sku() );
222
-
223
- if ( ! $variation_data->getItemId() ) {
224
-
225
- $parent_product = $product->get_parent_id() ? wc_get_product( $product->get_parent_id() ) : $product;
226
-
227
- if ( ! $parent_product instanceof \WC_Product ) {
228
- $variation_data->setItemId( self::get_square_item_id( $parent_product ) );
229
- }
230
- }
231
-
232
- $catalog_object->setItemVariationData( $variation_data );
233
-
234
- /**
235
- * Fires when updating a Square catalog item variation with WooCommerce product data.
236
- *
237
- * @since 2.0.0
238
- *
239
- * @param CatalogObject $catalog_object Square SDK catalog object
240
- * @param \WC_Product $product WooCommerce product
241
- */
242
- $catalog_object = apply_filters( 'wc_square_update_catalog_item_variation', $catalog_object, $product );
243
-
244
- return $catalog_object;
245
- }
246
-
247
-
248
- /**
249
- * Sets the present/absent location IDs to a catalog object.
250
- *
251
- * @since 2.0.0
252
- *
253
- * @param CatalogObject $catalog_object Square SDK catalog object
254
- * @param bool $is_delete whether the product is being deleted
255
- * @return CatalogObject
256
- */
257
- public static function set_catalog_object_location_ids( CatalogObject $catalog_object, $is_delete = false ) {
258
-
259
- $location_id = wc_square()->get_settings_handler()->get_location_id();
260
-
261
- $present_location_ids = $catalog_object->getPresentAtLocationIds() ?: [];
262
- $absent_location_ids = $catalog_object->getAbsentAtLocationIds() ?: [];
263
-
264
- // if trashed, set as absent at our location
265
- if ( $is_delete ) {
266
-
267
- $absent_location_ids[] = $location_id;
268
-
269
- if ( false !== ( $key = array_search( $location_id, $present_location_ids, true ) ) ) {
270
- unset( $present_location_ids[ $key ] );
271
- }
272
-
273
- // otherwise, it's present
274
- } else {
275
-
276
- $present_location_ids[] = $location_id;
277
-
278
- if ( false !== ( $key = array_search( $location_id, $absent_location_ids, true ) ) ) {
279
- unset( $absent_location_ids[ $key ] );
280
- }
281
- }
282
-
283
- $catalog_object->setAbsentAtLocationIds( array_unique( array_values( $absent_location_ids ) ) );
284
- $catalog_object->setPresentAtLocationIds( array_unique( array_values( $present_location_ids ) ) );
285
-
286
- $catalog_object->setPresentAtAllLocations( false );
287
-
288
- return $catalog_object;
289
- }
290
-
291
-
292
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Products.php DELETED
@@ -1,719 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Product;
30
- use WooCommerce\Square\Sync\Records;
31
- use WooCommerce\Square;
32
-
33
- /**
34
- * Products admin handler.
35
- *
36
- * @since 2.0.0
37
- */
38
- class Products {
39
-
40
-
41
- /** @var array associative array of product error codes and messages */
42
- private $product_errors;
43
-
44
- /** @var array associative array of memoized errors being output for a product at one time */
45
- private $output_errors = [];
46
-
47
- /** @var int[] array of product IDs that have been scheduled for sync in this request */
48
- private $products_to_sync = [];
49
-
50
- /** @var int[] array of product IDs that have been scheduled for deletion in this request */
51
- private $products_to_delete = [];
52
-
53
- /** @var Square\Plugin plugin instance */
54
- private $plugin;
55
-
56
- /**
57
- * Sets up the products admin handler.
58
- *
59
- * @since 2.0.0
60
- */
61
- public function __construct( Square\Plugin $plugin ) {
62
-
63
- $this->plugin = $plugin;
64
-
65
- // add common errors
66
- $this->product_errors = [
67
- /* translators: Placeholder: %s - product name */
68
- 'missing_sku' => __( "Please add an SKU to sync %s with Square. The SKU must match the item's SKU in your Square account.", 'woocommerce-square' ),
69
- /* translators: Placeholder: %s - product name */
70
- 'missing_variation_sku' => __( "Please add an SKU to every variation of %s for syncing with Square. Each SKU must match the corresponding item's SKU in your Square account.", 'woocommerce-square' ),
71
- /* translators: Placeholder: %s - product name */
72
- 'multiple_attributes' => __( '%s has multiple variation attributes and cannot be synced with Square.', 'woocommerce-square' ),
73
- ];
74
-
75
- // add hooks
76
- $this->add_products_edit_screen_hooks();
77
- $this->add_product_edit_screen_hooks();
78
- $this->add_product_sync_hooks();
79
- }
80
-
81
-
82
- /**
83
- * Adds hooks to the admin products edit screen.
84
- *
85
- * Products filtering, bulk actions, etc.
86
- *
87
- * @since 2.0.0
88
- */
89
- private function add_products_edit_screen_hooks() {
90
-
91
- // adds an option to the "Filter by product type" dropdown
92
- add_action( 'restrict_manage_posts', [ $this, 'add_filter_products_synced_with_square_option' ] );
93
- // allow filtering products by sync status by altering results
94
- add_filter( 'request', [ $this, 'filter_products_synced_with_square' ] );
95
-
96
- // prevent copying Square data when duplicating a product automatically
97
- add_action( 'woocommerce_product_duplicate', [ $this, 'handle_product_duplication' ], 20, 2 );
98
-
99
- // handle quick/bulk edit actions in the products edit screen for setting sync status
100
- add_action( 'woocommerce_product_quick_edit_end', [ $this, 'add_quick_edit_inputs' ] );
101
- add_action( 'woocommerce_product_bulk_edit_end', [ $this, 'add_bulk_edit_inputs' ] );
102
- add_action( 'woocommerce_product_quick_edit_save', [ $this, 'set_synced_with_square' ] );
103
- add_action( 'woocommerce_product_bulk_edit_save', [ $this, 'set_synced_with_square' ] );
104
- }
105
-
106
-
107
- /**
108
- * Adds hooks to individual products edit screens.
109
- *
110
- * Product data input fields, variations, etc.
111
- *
112
- * @since 2.0.0
113
- */
114
- private function add_product_edit_screen_hooks() {
115
-
116
- add_action( 'woocommerce_variation_options', [ $this, 'add_variation_manage_stock' ] );
117
-
118
- // handle individual products input fields for setting sync status
119
- add_action( 'woocommerce_product_options_general_product_data', [ $this, 'add_product_data_fields' ] );
120
- add_action( 'woocommerce_admin_process_product_object', [ $this, 'process_product_data' ], 20 );
121
- add_action( 'woocommerce_before_product_object_save', [ $this, 'maybe_adjust_square_stock'] );
122
-
123
- add_action( 'admin_notices', [ $this, 'add_notice_product_hidden_from_catalog' ] );
124
- }
125
-
126
-
127
- /**
128
- * Adds our own hidden "manage stock" input to the variation fields.
129
- *
130
- * We disable the core checkbox, but this causes stock management to be disabled for the variations because the
131
- * disabled field doesn't get POSTed. This overrides the checkbox value so that we can still disable it in the UI.
132
- *
133
- * @since 2.0.2
134
- *
135
- * @param int $loop currently looped variation
136
- */
137
- public function add_variation_manage_stock( $loop ) {
138
-
139
- if ( ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
140
- return;
141
- }
142
-
143
- ?> <input type="hidden" id="wc_square_variation_manage_stock" name="variable_manage_stock[<?php echo esc_attr( $loop ); ?>]" value="1" /> <?php
144
- }
145
-
146
-
147
- /**
148
- * Adds hooks to sync products that have been updated.
149
- *
150
- * @since 2.0.0
151
- */
152
- private function add_product_sync_hooks() {
153
-
154
- add_action( 'woocommerce_update_product', [ $this, 'validate_product_update_and_sync' ] );
155
- add_action( 'trashed_post', [ $this, 'maybe_stage_products_for_deletion' ] );
156
- add_action( 'shutdown', [ $this, 'maybe_sync_staged_products' ] );
157
- add_action( 'shutdown', [ $this, 'maybe_delete_staged_products' ] );
158
- }
159
-
160
-
161
- /**
162
- * Adds an option to filter products by sync status.
163
- *
164
- * @internal
165
- *
166
- * @since 2.0.0
167
- *
168
- * @param string $post_type the post type context
169
- */
170
- public function add_filter_products_synced_with_square_option( $post_type ) {
171
-
172
- if ( 'product' !== $post_type ) {
173
- return;
174
- }
175
-
176
- $label = esc_html__( 'Synced with Square', 'woocommerce-square' );
177
- $selected = isset( $_GET['product_type'] ) && 'synced-with-square' === $_GET['product_type'] ? 'selected=\"selected\"' : '';
178
-
179
- wc_enqueue_js( "
180
- jQuery( document ).ready( function( $ ) {
181
- $( 'select#dropdown_product_type' ).append( '<option value=\"synced-with-square\" ' + '" . $selected . "' + '>' + '" . $label ."' + '</option>' );
182
- } );
183
- " );
184
- }
185
-
186
-
187
- /**
188
- * Filters products in admin edit screen by sync status with Square.
189
- *
190
- * @internal
191
- *
192
- * @since 2.0.0
193
- *
194
- * @param array $query_vars query variables
195
- * @return array
196
- */
197
- public function filter_products_synced_with_square( $query_vars ){
198
- global $typenow;
199
-
200
- if ( 'product' === $typenow && isset( $_GET['product_type'] ) && 'synced-with-square' === $_GET['product_type'] ) {
201
-
202
- // not really a product type, otherwise WooCommerce will handle it as such
203
- unset( $query_vars['product_type'] );
204
-
205
- if ( ! isset( $query_vars['tax_query'] ) ) {
206
- $query_vars['tax_query'] = [];
207
- } else {
208
- $query_vars['tax_query']['relation'] = 'AND';
209
- }
210
-
211
- $query_vars['tax_query'][] = [
212
- 'taxonomy' => Product::SYNCED_WITH_SQUARE_TAXONOMY,
213
- 'field' => 'slug',
214
- 'terms' => [ 'yes' ],
215
- ];
216
- }
217
-
218
- return $query_vars;
219
- }
220
-
221
-
222
- /**
223
- * Adds general product data options to a product metabox.
224
- *
225
- * @internal
226
- *
227
- * @since 2.0.0
228
- */
229
- public function add_product_data_fields() {
230
- global $product_object;
231
-
232
- if ( ! $product_object instanceof \WC_Product ) {
233
- return;
234
- }
235
-
236
- // don't show fields if product sync is disabled
237
- if ( ! wc_square()->get_settings_handler()->is_product_sync_enabled() ) {
238
- return;
239
- }
240
-
241
- ?>
242
- <div class="wc-square-sync-with-square options_group show_if_simple show_if_variable">
243
- <?php
244
-
245
- $selector = '_' . Product::SYNCED_WITH_SQUARE_TAXONOMY;
246
- $value = Product::is_synced_with_square( $product_object ) ? 'yes' : 'no';
247
- $errors = $this->check_product_sync_errors( $product_object );
248
-
249
- $setting_label = wc_square()->get_settings_handler()->is_system_of_record_square() ? __( 'Update product data with Square data', 'woocommerce-square' ) : __( 'Send product data to Square', 'woocommerce-square' );
250
-
251
- woocommerce_wp_checkbox( [
252
- 'id' => $selector,
253
- 'label' => __( 'Sync with Square', 'woocommerce-square' ),
254
- 'value' => $value,
255
- 'cbvalue' => 'yes',
256
- 'default' => 'no',
257
- 'description' => $setting_label,
258
- 'custom_attributes' => ! empty( $errors ) ? [ 'disabled' => 'disabled' ] : [],
259
- ] );
260
-
261
- ?>
262
- <p class="form-field wc-square-sync-with-square-errors">
263
- <?php foreach ( $this->product_errors as $error_code => $error_message ) : ?>
264
- <?php $styles = ! in_array( $error_code, array_keys( $errors ), true ) ? 'display:none; color:#A00;' : 'display:block; color:#A00;'; ?>
265
- <span class="wc-square-sync-with-square-error <?php echo sanitize_html_class( $error_code ); ?>" style="<?php echo $styles; ?>"><?php echo $this->format_product_error( $error_code, $product_object ); ?></span>
266
- <?php endforeach; ?>
267
- </p>
268
-
269
- <input type="hidden" id="<?php echo esc_attr( Product::SQUARE_VARIATION_ID_META_KEY ); ?>" value="<?php echo esc_attr( $product_object->get_meta( Product::SQUARE_VARIATION_ID_META_KEY ) ); ?>" />
270
-
271
- </div>
272
- <?php
273
- }
274
-
275
-
276
- /**
277
- * Outputs HTML with a dropdown field to mark a product to be synced with Square.
278
- *
279
- * @since 2.0.0
280
- *
281
- * @param bool $bulk whether the field is meant for bulk edit
282
- */
283
- private function output_synced_with_square_edit_field( $bulk = false ) {
284
-
285
- ?>
286
- <div class="inline-edit-group wc-square-sync-with-square">
287
- <label>
288
- <span class="title"><?php esc_html_e( 'Sync with Square?', 'woocommerce-square' ); ?></span>
289
- <span class="input-text-wrap">
290
- <select class="square-synced" name="<?php echo esc_attr( Product::SYNCED_WITH_SQUARE_TAXONOMY ); ?>">
291
- <?php if ( true === $bulk ) : // in bulk actions there's the option to leave the value unchanged (or unset) ?>
292
- <option value="">&mdash; <?php esc_html_e( 'No change', 'woocommerce-square' ); ?> &mdash;</option>
293
- <?php endif; ?>
294
- <option value="no"><?php esc_html_e( 'No', 'woocommerce-square' ); ?></option>
295
- <option value="yes"><?php esc_html_e( 'Yes', 'woocommerce-square' ); ?></option>
296
- </select>
297
- </span>
298
- </label>
299
- <p class="form-field wc-square-sync-with-square-errors">
300
- <?php foreach ( $this->product_errors as $error_code => $error_message ) : ?>
301
- <?php $product_name_placeholder = __( 'This product', 'woocommerce-square' ); ?>
302
- <?php $product_name = ( 'multiple_attributes' !== $error_code ) ? strtolower( $product_name_placeholder ) : $product_name_placeholder; ?>
303
- <span class="wc-square-sync-with-square-error <?php echo $error_code; ?>" style="display:none; color:#A00;"><?php echo esc_html( sprintf( $error_message, $product_name ) ); ?></span>
304
- <?php endforeach; ?>
305
- </p>
306
- </div>
307
- <?php
308
- }
309
-
310
-
311
- /**
312
- * Adds quick edit fields to the products screen.
313
- *
314
- * @internal
315
- *
316
- * @since 2.0.0
317
- */
318
- public function add_quick_edit_inputs() {
319
-
320
- $this->output_synced_with_square_edit_field();
321
- }
322
-
323
-
324
- /**
325
- * Adds bulk edit fields to the products screen.
326
- *
327
- * @internal
328
- *
329
- * @since 2.0.0
330
- */
331
- public function add_bulk_edit_inputs() {
332
-
333
- $this->output_synced_with_square_edit_field( true );
334
- }
335
-
336
-
337
- /**
338
- * In case Woo is the SOR, validates whether a product can be synced with Square and disable sync if not
339
- *
340
- * @since 2.0.8
341
- *
342
- * @param int $product_id the product ID
343
- */
344
- public function validate_product_update_and_sync( $product_id ) {
345
- if ( ! wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
346
- return;
347
- }
348
-
349
- $product = wc_get_product( $product_id );
350
-
351
- if ( ! Product::is_synced_with_square( $product ) ) {
352
- return;
353
- }
354
-
355
- $errors = $this->check_product_sync_errors( $product );
356
-
357
- if ( ! empty( $errors ) ) {
358
- // if there are errors, remove the link and display them
359
- Product::unset_synced_with_square( $product );
360
-
361
- foreach ( $errors as $error ) {
362
- wc_square()->get_message_handler()->add_error( $error );
363
- Records::set_record( [ 'type' => 'alert', 'product_id' => $product_id, 'message' => $error ] );
364
- }
365
- } else {
366
- $this->maybe_stage_product_for_sync( $product );
367
- }
368
- }
369
-
370
- /**
371
- * Stages a product for sync with Square on product save if Woo is the SOR and the product is set to 'synced with square'.
372
- *
373
- * @internal
374
- *
375
- * @since 2.0.0
376
- *
377
- * @param WC_Product $product the product object
378
- */
379
- public function maybe_stage_product_for_sync( $product ) {
380
- if ( ! defined( 'DOING_SQUARE_SYNC' ) && ! in_array( $product->get_id(), $this->products_to_sync ) ) {
381
-
382
- if ( $product && Product::is_synced_with_square( $product ) ) {
383
-
384
- // the triggering action for this method can be called multiple times in a single request - keep track
385
- // of product IDs that have been scheduled for sync here to avoid multiple syncs on the same request
386
- $this->products_to_sync[] = $product->get_id();
387
- }
388
- }
389
- }
390
-
391
-
392
- /**
393
- * Initializes a synchronization event for any staged products in this request.
394
- *
395
- * @internal
396
- *
397
- * @since 2.0.0
398
- */
399
- public function maybe_sync_staged_products() {
400
-
401
- if ( ! defined( 'DOING_SQUARE_SYNC' ) && ! empty( $this->products_to_sync ) && wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
402
-
403
- wc_square()->get_sync_handler()->start_manual_sync( true, $this->products_to_sync );
404
- }
405
- }
406
-
407
-
408
- /**
409
- * Removes a product from Square if it is deleted locally and Woo is the SOR.
410
- *
411
- * @since 2.0.0
412
- *
413
- * @param int $product_id the product ID
414
- */
415
- public function maybe_stage_products_for_deletion( $product_id ) {
416
-
417
- if ( wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
418
-
419
- $product = wc_get_product( $product_id );
420
-
421
- if ( $product && Product::is_synced_with_square( $product ) ) {
422
-
423
- // the triggering action for this method can be called multiple times in a single request - keep track
424
- // of product IDs that have been scheduled for sync here to avoid multiple syncs on the same request
425
- $this->products_to_delete[] = $product_id;
426
- }
427
- }
428
- }
429
-
430
-
431
- /**
432
- * Deletes any products staged for remote deletion.
433
- *
434
- * @since 2.0.0
435
- */
436
- public function maybe_delete_staged_products() {
437
-
438
- if ( ! empty( $this->products_to_delete ) && wc_square()->get_settings_handler()->is_system_of_record_woocommerce() ) {
439
-
440
- wc_square()->get_sync_handler()->start_manual_deletion( $this->products_to_delete );
441
- }
442
- }
443
-
444
-
445
- /**
446
- * Sets a product's synced with Square status for quick/bulk edit action.
447
- *
448
- * @internal
449
- *
450
- * @since 2.0.0
451
- *
452
- * @param \WC_Product $product a product object
453
- */
454
- public function set_synced_with_square( $product ) {
455
-
456
- $posted_data_key = Product::SYNCED_WITH_SQUARE_TAXONOMY;
457
-
458
- if ( 'woocommerce_product_bulk_edit_save' === current_action() ) {
459
- $default_value = null; // in bulk actions this will preserve the existing setting if nothing is specified
460
- } else {
461
- $default_value = 'no'; // in individual products context, the value should be always an explicit yes or no
462
- }
463
-
464
- $square_synced = isset( $_REQUEST[ $posted_data_key ] ) && in_array( $_REQUEST[ $posted_data_key ], [ 'yes', 'no' ], true ) ? $_REQUEST[ $posted_data_key ] : $default_value;
465
-
466
- if ( is_string( $square_synced ) ) {
467
- $errors = $this->check_product_sync_errors( $product );
468
- if ( 'no' === $square_synced || empty( $errors ) ) {
469
- Product::set_synced_with_square( $product, $square_synced );
470
- } else if ( ! empty( $errors ) ) {
471
- foreach ( $errors as $error ) {
472
- wc_square()->get_message_handler()->add_error( $error );
473
- }
474
- }
475
- }
476
- }
477
-
478
-
479
- /**
480
- * Updates Square sync status for a product upon saving.
481
- *
482
- * @internal
483
- *
484
- * @since 2.0.0
485
- *
486
- * @param \WC_Product $product product object
487
- */
488
- public function process_product_data( $product ) {
489
-
490
- // don't process fields if product sync is disabled
491
- if ( ! wc_square()->get_settings_handler()->is_product_sync_enabled() ) {
492
- return;
493
- }
494
-
495
- // bail if no valid product found, if it's a variation, errors have already been output
496
- if ( ! $product || ( $product instanceof \WC_Product_Variation || $product->is_type( 'product_variation' ) ) || ! empty( $this->output_errors[ $product->get_id() ] ) ) {
497
- return;
498
- }
499
-
500
- $errors = [];
501
- $posted_key = '_' . Product::SYNCED_WITH_SQUARE_TAXONOMY;
502
- $set_synced = isset( $_POST[ $posted_key ] ) && 'yes' === $_POST[ $posted_key ];
503
- $was_synced = Product::is_synced_with_square( $product );
504
-
505
- // condition has unchanged
506
- if ( ! $set_synced && ! $was_synced ) {
507
- return;
508
- }
509
-
510
- if ( $set_synced || $was_synced ) {
511
- if ( $set_synced && $product->is_type( 'variable' ) && wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
512
- // if syncing inventory with Square, parent variable products don't manage stock
513
- $product->set_manage_stock( false );
514
-
515
- // if there are no errors, and the product is variable, force enable stock management for all its variations
516
- foreach ( $product->get_children() as $variation_id ) {
517
- if ( $variation = wc_get_product( $variation_id ) ) {
518
- $variation->set_manage_stock( true );
519
- $variation->save();
520
- }
521
- }
522
- }
523
-
524
- // finally, set the product sync with Square flag
525
- Product::set_synced_with_square( $product, $set_synced ? 'yes' : 'no' );
526
- }
527
- }
528
-
529
-
530
- /**
531
- * Adjusts a product's Square stock.
532
- *
533
- * @since 2.0.0
534
- *
535
- * @param \WC_Product $product product object
536
- */
537
- public function maybe_adjust_square_stock( $product ) {
538
-
539
- // this is hooked in to general product object save, so scope to specifically saving products via the admin
540
- if ( ! doing_action( 'wp_ajax_woocommerce_save_variations' ) && ! doing_action( 'woocommerce_admin_process_product_object' ) ) {
541
- return;
542
- }
543
-
544
- // only send stock updates for Woo SOR
545
- if ( ! wc_square()->get_settings_handler()->is_system_of_record_woocommerce() || ! wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
546
- return;
547
- }
548
-
549
- if ( ! $product instanceof \WC_Product || ! Product::is_synced_with_square( $product ) ) {
550
- return;
551
- }
552
-
553
- $square_id = $product->get_meta( Product::SQUARE_VARIATION_ID_META_KEY );
554
-
555
- // only send when the product has an associated Square ID
556
- if ( ! $square_id ) {
557
- return;
558
- }
559
-
560
- // set to manage stock if not a variable product
561
- $product->set_manage_stock( ! $product->is_type( 'variable' ) );
562
-
563
- $data = $product->get_data();
564
- $changes = $product->get_changes();
565
- $change = 0;
566
-
567
- if ( isset( $data['stock_quantity'], $changes['stock_quantity'] ) ) {
568
- $change = (int) $changes['stock_quantity'] - $data['stock_quantity'];
569
- }
570
-
571
- if ( $change !== 0 ) {
572
-
573
- try {
574
-
575
- if ( $change > 0 ) {
576
- wc_square()->get_api()->add_inventory( $square_id, $change );
577
- } else {
578
- wc_square()->get_api()->remove_inventory( $square_id, $change );
579
- }
580
-
581
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
582
-
583
- wc_square()->log( 'Could not adjust Square inventory for ' . $product->get_formatted_name() . '. ' . $exception->getMessage() );
584
-
585
- $quantity = (float) $data['stock_quantity'];
586
-
587
- // if the API request fails, set the product quantity back from whence it came
588
- $product->set_stock_quantity( $quantity );
589
- }
590
- }
591
- }
592
-
593
-
594
- /**
595
- * Prevents copying Square data when duplicating a product in admin.
596
- *
597
- * @internal
598
- *
599
- * @since 2.0.0
600
- *
601
- * @param \WC_Product $duplicated_product product duplicate
602
- * @param \WC_Product $original_product product duplicated
603
- */
604
- public function handle_product_duplication( $duplicated_product, $original_product ) {
605
-
606
- if ( Product::is_synced_with_square( $original_product ) ) {
607
- Product::unset_synced_with_square( $duplicated_product );
608
- }
609
-
610
- $duplicated_product->delete_meta_data( Product::SQUARE_ID_META_KEY );
611
- $duplicated_product->delete_meta_data( Product::SQUARE_VARIATION_ID_META_KEY );
612
-
613
- if ( $duplicated_product->is_type( 'variable' ) ) {
614
-
615
- foreach ( $duplicated_product->get_children() as $duplicated_variation_id ) {
616
-
617
- if ( $duplicated_product_variation = wc_get_product( $duplicated_variation_id ) ) {
618
-
619
- $duplicated_product_variation->delete_meta_data( Product::SQUARE_VARIATION_ID_META_KEY );
620
- $duplicated_product_variation->save_meta_data();
621
- }
622
- }
623
- }
624
-
625
- $duplicated_product->save_meta_data();
626
- }
627
-
628
-
629
- /**
630
- * Outputs an admin notice when a product was hidden from catalog upon a sync error.
631
- *
632
- * @internal
633
- *
634
- * @since 2.0.0
635
- */
636
- public function add_notice_product_hidden_from_catalog() {
637
- global $current_screen, $post;
638
-
639
- if ( $post && $current_screen && 'product' === $current_screen->id ) {
640
-
641
- $product = wc_get_product( $post );
642
-
643
- if ( $product && 'hidden' === $product->get_catalog_visibility() ) {
644
-
645
- $product_id = $product->get_id();
646
- $records = Records::get_records( [ 'product' => $product_id ] );
647
-
648
- foreach ( $records as $record ) {
649
-
650
- if ( $record->was_product_hidden() && $product_id === $record->get_product_id() ) {
651
-
652
- wc_square()->get_message_handler()->add_warning(
653
- sprintf(
654
- /* translators: Placeholder: %1$s - date (localized), %2$s - time (localized), %3$s - opening <a> HTML link tag, %4$s closing </a> HTML link tag */
655
- esc_html__( 'The product catalog visibility has been set to "hidden", as a matching product could not be found in Square on %1$s at %2$s. %3$sCheck sync records%4$s.', 'woocommerce-square' ),
656
- date_i18n( wc_date_format(), $record->get_timestamp() ),
657
- date_i18n( wc_time_format(), $record->get_timestamp() ),
658
- '<a href="' . esc_url( add_query_arg( [ 'section' => 'update' ], wc_square()->get_settings_url() ) ) . '">', '</a>'
659
- )
660
- );
661
-
662
- break;
663
- }
664
- }
665
- }
666
- }
667
- }
668
-
669
-
670
- /**
671
- * Check whether this product can be synced with Square
672
- *
673
- * @param \WC_Product $product product object
674
- * @return array errors
675
- */
676
- private function check_product_sync_errors( \WC_Product $product ) {
677
- $errors = [];
678
- if ( $product->is_type( 'variable' ) && $product->has_child() ) {
679
- if ( Product::has_multiple_variation_attributes( $product ) ) {
680
- $errors['multiple_attributes'] = $this->format_product_error( 'multiple_attributes', $product );
681
- } else if ( ! Product::has_sku( $product ) ) {
682
- $errors['missing_variation_sku'] = $this->format_product_error( 'missing_variation_sku', $product );
683
- }
684
- } else {
685
- if ( ! Product::has_sku( $product ) ) {
686
- $errors['missing_sku'] = $this->format_product_error( 'missing_sku', $product );
687
- }
688
- }
689
- return $errors;
690
- }
691
-
692
-
693
- /**
694
- * Formats product error message with product information
695
- *
696
- * @param string $error error identifier (e.g. 'multiple_attributes', 'missing_variation_sku' or 'missing_sku')
697
- * @param \WC_Product $product product object
698
- * @return string formatted error message
699
- */
700
- private function format_product_error( string $error, \WC_Product $product ) {
701
- return sprintf(
702
- $this->product_errors[$error],
703
- Product::get_product_edit_link( $product )
704
- );
705
- }
706
-
707
-
708
- /**
709
- * Gets the plugin instance.
710
- *
711
- * @since 2.0.8
712
- *
713
- * @return Plugin
714
- */
715
- protected function get_plugin() {
716
- return $this->plugin;
717
- }
718
-
719
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Handlers/Sync.php DELETED
@@ -1,501 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Handlers;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\Plugin;
28
- use WooCommerce\Square\Sync\Interval_Polling;
29
- use WooCommerce\Square\Sync\Records;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * Synchronization handler class
35
- *
36
- * @since 2.0.0
37
- */
38
- class Sync {
39
-
40
-
41
- /** @var string key of the option that stores a timestamp when the last sync job completed */
42
- private $last_synced_at_option_key = 'wc_square_last_synced_at';
43
-
44
- /** @var string name of the Action Scheduler event name for syncing with Square */
45
- private $sync_scheduled_event_name;
46
-
47
- /** @var Plugin plugin instance */
48
- private $plugin;
49
-
50
-
51
- /**
52
- * Constructs the class.
53
- *
54
- * @since 2.0.0
55
- *
56
- * @param Plugin $plugin
57
- */
58
- public function __construct( Plugin $plugin ) {
59
-
60
- $this->plugin = $plugin;
61
-
62
- $this->sync_scheduled_event_name = 'wc_' . $this->get_plugin()->get_id() . '_sync';
63
-
64
- $this->add_hooks();
65
- }
66
-
67
-
68
- /**
69
- * Adds the action & filter hooks.
70
- *
71
- * @since 2.0.0
72
- */
73
- private function add_hooks() {
74
-
75
- // schedule the interval sync
76
- add_action( 'init', [ $this, 'schedule_sync' ] );
77
-
78
- // run the interval sync when fired by Action Scheduler
79
- add_action( $this->sync_scheduled_event_name, [ $this, 'start_interval_sync' ] );
80
- }
81
-
82
-
83
- /**
84
- * Gets the sync schedule interval in seconds.
85
- *
86
- * @since 2.0.0
87
- *
88
- * @return int
89
- */
90
- private function get_sync_schedule_interval() {
91
-
92
- /**
93
- * Filters the frequency with which products should be synced.
94
- *
95
- * @since 2.0.0
96
- *
97
- * @param int $interval sync interval in seconds (defaults to one hour)
98
- */
99
- return (int) max( MINUTE_IN_SECONDS, (int) apply_filters( 'wc_square_sync_interval', HOUR_IN_SECONDS ) );
100
- }
101
-
102
-
103
- /**
104
- * Schedules the interval sync.
105
- *
106
- * @since 2.0.0
107
- */
108
- public function schedule_sync() {
109
-
110
- // bail if product sync is not enabled or there hasn't been a previous sync
111
- if ( $this->is_sync_in_progress() || ! $this->get_last_synced_at() || ! $this->get_plugin()->get_settings_handler()->is_connected() || ! $this->get_plugin()->get_settings_handler()->is_product_sync_enabled() ) {
112
- return;
113
- }
114
-
115
- $plugin_id = $this->get_plugin()->get_id();
116
- $interval = $this->get_sync_schedule_interval();
117
-
118
- if ( false === as_next_scheduled_action( $this->sync_scheduled_event_name, [], $plugin_id ) ) {
119
- as_schedule_recurring_action( time() + $interval, $interval, $this->sync_scheduled_event_name, [], $plugin_id );
120
- }
121
- }
122
-
123
-
124
- /**
125
- * Unschedules the interval sync.
126
- *
127
- * @since 2.0.0
128
- */
129
- public function unschedule_sync() {
130
-
131
- as_unschedule_action( $this->sync_scheduled_event_name, [], $this->get_plugin()->get_id() );
132
- }
133
-
134
-
135
- /**
136
- * Performs a product import from Square.
137
- *
138
- * @since 2.0.0
139
- *
140
- * @param bool $dispatch whether the job should be immediately dispatched
141
- * @return \stdClass|null
142
- */
143
- public function start_product_import( $dispatch = true ) {
144
-
145
- $job = $this->get_plugin()->get_background_job_handler()->create_job( [
146
- 'action' => 'product_import',
147
- ] );
148
-
149
- if ( $job ) {
150
-
151
- if ( $dispatch ) {
152
- $this->get_plugin()->get_background_job_handler()->dispatch();
153
- }
154
- }
155
-
156
- return $job;
157
- }
158
-
159
-
160
- /**
161
- * Performs a manual sync.
162
- *
163
- * @since 2.0.0
164
- *
165
- * @param bool $dispatch whether the job should be immediately dispatched
166
- * @param int[] $product_ids (optional) array of product IDs to sync
167
- * @return \stdClass|null
168
- */
169
- public function start_manual_sync( $dispatch = true, array $product_ids = [] ) {
170
-
171
- $product_ids = empty( $product_ids ) ? Product::get_products_synced_with_square() : $product_ids;
172
-
173
- $job = $this->get_plugin()->get_background_job_handler()->create_job( [
174
- 'action' => 'sync',
175
- 'manual' => true,
176
- 'product_ids' => $product_ids,
177
- ] );
178
-
179
- if ( $job ) {
180
-
181
- if ( $dispatch ) {
182
- $this->get_plugin()->get_background_job_handler()->dispatch();
183
- }
184
- }
185
-
186
- return $job;
187
- }
188
-
189
-
190
- /**
191
- * Performs a manual product deletion.
192
- *
193
- * @since 2.0.0
194
- *
195
- * @param int[] $product_ids array of product IDs to delete
196
- * @param bool $dispatch whether the job should be immediately dispatched
197
- * @return \stdClass|null
198
- */
199
- public function start_manual_deletion( array $product_ids, $dispatch = true ) {
200
-
201
- $job = $this->get_plugin()->get_background_job_handler()->create_job( [
202
- 'action' => 'delete',
203
- 'manual' => true,
204
- 'product_ids' => $product_ids,
205
- ] );
206
-
207
- if ( $job ) {
208
-
209
- if ( $dispatch ) {
210
- $this->get_plugin()->get_background_job_handler()->dispatch();
211
- }
212
- }
213
-
214
- return $job;
215
- }
216
-
217
-
218
- /**
219
- * Performs an interval sync with Square.
220
- *
221
- * @since 2.0.0
222
- */
223
- public function start_interval_sync() {
224
-
225
- // bail if there is already a sync in progress
226
- if ( ! $this->is_sync_enabled() || $this->is_sync_in_progress() ) {
227
- return;
228
- }
229
-
230
- // use this opportunity to clear old background jobs
231
- $this->get_plugin()->get_background_job_handler()->clear_all_jobs();
232
-
233
- $job = $this->get_plugin()->get_background_job_handler()->create_job( [
234
- 'action' => 'poll',
235
- 'manual' => false,
236
- 'catalog_last_synced_at' => $this->get_last_synced_at(),
237
- 'inventory_last_synced_at' => $this->get_inventory_last_synced_at(),
238
- ] );
239
-
240
- if ( $job ) {
241
- $this->get_plugin()->get_background_job_handler()->dispatch();
242
- }
243
- }
244
-
245
-
246
- /** Conditional methods *******************************************************************************************/
247
-
248
-
249
- /**
250
- * Determines whether a sync process should happen in background.
251
- *
252
- * @since 2.0.0
253
- *
254
- * @return bool
255
- */
256
- public function should_sync_in_background() {
257
-
258
- /**
259
- * Filters whether a sync process should happen in background.
260
- *
261
- * @since 2.0.0
262
- *
263
- * @param bool $sync_in_background defaults to whether loopback connections are supported
264
- */
265
- return (bool) apply_filters( 'wc_square_sync_in_background', $this->get_plugin()->get_background_job_handler()->test_connection() );
266
- }
267
-
268
-
269
- /**
270
- * Determines whether a sync, scheduled or manual, is in progress.
271
- *
272
- * @since 2.0.0
273
- *
274
- * @return bool
275
- */
276
- public function is_sync_in_progress() {
277
-
278
- return ( defined( 'DOING_SQUARE_SYNC' ) && true === DOING_SQUARE_SYNC )
279
- || null !== $this->get_job_in_progress();
280
- }
281
-
282
-
283
- /**
284
- * Determines if sync is enabled.
285
- *
286
- * @since 2.0.0
287
- *
288
- * @return bool
289
- */
290
- public function is_sync_enabled() {
291
-
292
- return $this->get_plugin()->get_settings_handler()->is_product_sync_enabled();
293
- }
294
-
295
-
296
- /** Setter methods ************************************************************************************************/
297
-
298
-
299
- /**
300
- * Records a successful sync.
301
- *
302
- * @since 2.0.0
303
- *
304
- * @param int[] $product_ids IDs of products synced
305
- * @param null|\stdClass $job optional sync job, may be used to set the job ID to prevent duplicates
306
- */
307
- public function record_sync( array $product_ids, $job = null ) {
308
-
309
- $products = count( $product_ids );
310
-
311
- // only add a record of some products were synced
312
- if ( $products ) {
313
-
314
- Records::set_record( [
315
- 'id' => $job && isset( $job->id ) ? $job->id : null,
316
- 'message' => sprintf(
317
- /* translators: Placeholder: %d number of products processed */
318
- _n( 'Updated data for %d product.', 'Updated data for %d products.', $products, 'woocommerce-square' ),
319
- $products
320
- ),
321
- ] );
322
- }
323
-
324
- /**
325
- * Fires after a set of products are synced with square.
326
- *
327
- * @since 2.0.0
328
- *
329
- * @param int[] $product_ids IDs for products that were synced
330
- */
331
- do_action( 'wc_square_products_synced', $product_ids );
332
- }
333
-
334
-
335
- /**
336
- * Updates the time when the last sync job occurred.
337
- *
338
- * @since 2.0.0
339
- *
340
- * @param int|string|null $timestamp a valid timestamp in UTC (optional, will default to now)
341
- * @return bool success
342
- */
343
- public function set_last_synced_at( $timestamp = null ) {
344
-
345
- if ( null === $timestamp ) {
346
- $timestamp = current_time( 'timestamp', true );
347
- }
348
-
349
- return is_numeric( $timestamp ) && update_option( $this->last_synced_at_option_key, (int) $timestamp );
350
- }
351
-
352
-
353
- /** Getter methods ************************************************************************************************/
354
-
355
-
356
- /**
357
- * Gets a job that is currently in progress.
358
- *
359
- * @since 2.0.0
360
- *
361
- * @return null|\stdClass background job object or null if not found
362
- */
363
- public function get_job_in_progress() {
364
-
365
- $handler = $this->get_plugin()->get_background_job_handler();
366
-
367
- try {
368
- $job = $handler->get_job();
369
- } catch ( \Exception $e ) {
370
- $job = null;
371
- }
372
-
373
- return $job && isset( $job->status ) && in_array( $job->status, [ 'created', 'queued', 'processing' ], true ) ? $job : null;
374
- }
375
-
376
-
377
- /**
378
- * Gets a date or time of a sync job (helper method).
379
- *
380
- * @see Sync::get_last_synced_at()
381
- * @see Sync::get_next_sync_at()
382
- *
383
- * @since 2.0.0
384
- *
385
- * @param null|int $timestamp a valid timestamp (raw data)
386
- * @param string $format the output type, either 'timestamp' or a valid PHP date format for a date string
387
- * @param string|null|\DateTimeZone $timezone the timezone output (defaults to the site timezone)
388
- * @return int|string|null a timestamp or date, or null on error or invalid timestamp
389
- */
390
- private function get_sync_date_time( $timestamp, $format, $timezone ) {
391
-
392
- $output = null;
393
-
394
- if ( is_numeric( $timestamp ) ) {
395
-
396
- try {
397
-
398
- if ( null === $timezone ) {
399
- $timezone = new \DateTimeZone( wc_timezone_string() );
400
- } elseif ( is_string( $timezone ) ) {
401
- $timezone = new \DateTimeZone( $timezone );
402
- }
403
-
404
- $date = new \DateTime( date( 'Y-m-d H:i:s', (int) $timestamp ), new \DateTimeZone( 'UTC' ) );
405
- $offset = $timezone->getOffset( $date );
406
- $timestamp = $date->getTimestamp() + $offset;
407
-
408
- } catch ( \Exception $e ) {
409
-
410
- $timestamp = null;
411
- }
412
- }
413
-
414
- if ( is_numeric( $timestamp ) ) {
415
- if ( 'timestamp' !== $format ) {
416
- $output = date( $format, (int) $timestamp );
417
- } else {
418
- $output = (int) $timestamp;
419
- }
420
- }
421
-
422
- return $output;
423
- }
424
-
425
-
426
- /**
427
- * Gets the timestamp when the next sync job should start.
428
- *
429
- * @since 2.0.0
430
- *
431
- * @return int
432
- */
433
- public function get_next_sync_at() {
434
-
435
- $timestamp = null;
436
-
437
- if ( $scheduled = as_next_scheduled_action( $this->sync_scheduled_event_name ) ) {
438
- $timestamp = $scheduled;
439
- }
440
-
441
- return (int) $timestamp > 1 ? $timestamp : null;
442
- }
443
-
444
-
445
- /**
446
- * Gets the timestamp for when the last sync job completed.
447
- *
448
- * @since 2.0.0
449
- *
450
- * @return int
451
- */
452
- public function get_last_synced_at() {
453
-
454
- $timestamp = get_option( $this->last_synced_at_option_key, null );
455
-
456
- return (int) $timestamp > 1 ? $timestamp : null;
457
- }
458
-
459
-
460
- /**
461
- * Sets the timestamp for when the last inventory sync job completed.
462
- *
463
- * @since 2.0.0
464
- *
465
- * @return int
466
- */
467
- public function set_inventory_last_synced_at() {
468
-
469
- return update_option( $this->last_synced_at_option_key . '_inventory', current_time( 'timestamp', true ) );
470
- }
471
-
472
-
473
- /**
474
- * Gets the timestamp for when the last inventory sync job completed.
475
- *
476
- * @since 2.0.0
477
- *
478
- * @return int
479
- */
480
- public function get_inventory_last_synced_at() {
481
-
482
- $timestamp = get_option( $this->last_synced_at_option_key . '_inventory', null );
483
-
484
- return (int) $timestamp > 1 ? $timestamp : null;
485
- }
486
-
487
-
488
- /**
489
- * Gets the plugin instance.
490
- *
491
- * @since 2.0.0
492
- *
493
- * @return Plugin
494
- */
495
- private function get_plugin() {
496
-
497
- return $this->plugin;
498
- }
499
-
500
-
501
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Lifecycle.php DELETED
@@ -1,426 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Product;
30
-
31
- /**
32
- * The plugin lifecycle handler.
33
- *
34
- * @since 2.0.0
35
- *
36
- * @method Plugin get_plugin()
37
- */
38
- class Lifecycle extends Framework\Plugin\Lifecycle {
39
-
40
-
41
- /**
42
- * Lifecycle constructor.
43
- *
44
- * @since 2.0.0
45
- *
46
- * @param Plugin $plugin main instance
47
- */
48
- public function __construct( Plugin $plugin ) {
49
-
50
- parent::__construct( $plugin );
51
-
52
- // plugin upgrade path: maps automatically each semver to upgrade_to_x_y_z() protected method
53
- $this->upgrade_versions = [
54
- '2.0.0',
55
- '2.0.4',
56
- ];
57
- }
58
-
59
-
60
- /**
61
- * Performs plugin installation.
62
- *
63
- * @since 2.0.0
64
- */
65
- protected function install() {
66
-
67
- // create the db table for the customer index
68
- Gateway\Customer_Helper::create_table();
69
-
70
- /**
71
- * Fires upon plugin installed.
72
- *
73
- * @since 2.0.0
74
- *
75
- * @param string $version plugin version (available from v2.0.0)
76
- */
77
- do_action( 'wc_square_installed', Plugin::VERSION );
78
- }
79
-
80
-
81
- /**
82
- * Performs upgrade tasks.
83
- *
84
- * @since 2.0.0
85
- *
86
- * @param string $installed_version semver
87
- */
88
- protected function upgrade( $installed_version ) {
89
-
90
- parent::upgrade( $installed_version );
91
-
92
- /**
93
- * Fires upon plugin upgraded (legacy hook).
94
- *
95
- * @since 1.0.0
96
- *
97
- * @param string $version version updating to (available from v2.0.0)
98
- * @param string $version version updating from (available from v2.0.0)
99
- */
100
- do_action( 'wc_square_updated', Plugin::VERSION, $installed_version );
101
- }
102
-
103
-
104
- /**
105
- * Upgrades to version 2.0.0
106
- *
107
- * @since 2.0.0
108
- */
109
- protected function upgrade_to_2_0_0() {
110
-
111
- // create the db table for the customer index
112
- Gateway\Customer_Helper::create_table();
113
-
114
- /** @see \wc_set_time_limit() */
115
- if ( function_exists( 'set_time_limit' )
116
- && ! ini_get( 'safe_mode' )
117
- && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) ) {
118
-
119
- @set_time_limit( 300 );
120
- }
121
-
122
- // migrate all the things!
123
- $syncing_products = $this->migrate_plugin_settings();
124
-
125
- $this->migrate_gateway_settings();
126
- $this->migrate_orders();
127
-
128
- // only set the products "sync" status if v2 is now configured to sync products
129
- if ( $syncing_products ) {
130
-
131
- $this->migrate_products();
132
-
133
- // assume a last sync occurred before upgrading
134
- $this->get_plugin()->get_sync_handler()->set_last_synced_at();
135
- $this->get_plugin()->get_sync_handler()->set_inventory_last_synced_at();
136
- }
137
-
138
- $this->migrate_customers();
139
-
140
- // mark upgrade complete
141
- update_option( 'wc_square_updated_to_2_0_0', true );
142
- }
143
-
144
-
145
- /**
146
- * Upgrades to version 2.0.4.
147
- *
148
- * @since 2.0.4
149
- */
150
- protected function upgrade_to_2_0_4() {
151
-
152
- $v1_settings = get_option( 'woocommerce_squareconnect_settings', [] );
153
- $v2_settings = get_option( 'wc_square_settings', [] );
154
-
155
- $v2_settings = $this->get_migrated_system_of_record( $v1_settings, $v2_settings );
156
-
157
- update_option( 'wc_square_settings', $v2_settings );
158
- }
159
-
160
-
161
- /**
162
- * Migrates plugin settings from v1 to v2.
163
- *
164
- * @see Lifecycle::upgrade_to_2_0_0()
165
- *
166
- * @since 2.0.0
167
- *
168
- * @return bool whether a system of record was enabled from migration
169
- */
170
- private function migrate_plugin_settings() {
171
-
172
- $this->get_plugin()->log( 'Migrating plugin settings...' );
173
-
174
- // get legacy and new default settings
175
- $new_settings = get_option( 'wc_square_settings', [] );
176
- $legacy_settings = get_option( 'woocommerce_squareconnect_settings', [] );
177
- $email_settings = get_option( 'woocommerce_wc_square_sync_completed_settings', [] );
178
-
179
- // bail if they already have v2 settings present
180
- if ( ! empty( $new_settings ) ) {
181
- return;
182
- }
183
-
184
- // handle access token first
185
- if ( $legacy_access_token = get_option( 'woocommerce_square_merchant_access_token' ) ) {
186
-
187
- // the access token was previously stored unencrypted
188
- if ( ! empty( $legacy_access_token ) && Utilities\Encryption_Utility::is_encryption_supported() ) {
189
-
190
- $encryption = new Utilities\Encryption_Utility();
191
-
192
- try {
193
- $legacy_access_token = $encryption->encrypt_data( $legacy_access_token );
194
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
195
- // log the event, but don't halt the process
196
- $this->get_plugin()->log( 'Could not encrypt access token during upgrade. ' . $exception->getMessage() );
197
- }
198
- }
199
-
200
- // previously only 'production' environment was assumed
201
- $access_tokens = get_option( 'wc_square_access_tokens', [] );
202
- $access_tokens['production'] = is_string( $legacy_access_token ) ? $legacy_access_token : '';
203
-
204
- update_option( 'wc_square_access_tokens', $access_tokens );
205
- }
206
-
207
- // migrate store location
208
- if ( ! empty( $legacy_settings['location'] ) ) {
209
- $new_settings['location_id'] = $legacy_settings['location'];
210
- }
211
-
212
- // toggle debug logging
213
- $new_settings['debug_logging_enabled'] = isset( $legacy_settings['logging'] ) && in_array( $legacy_settings['logging'], [ 'yes', 'no' ], true ) ? $legacy_settings['logging'] : 'no';
214
-
215
- // set the SOR and inventory sync values
216
- $new_settings = $this->get_migrated_system_of_record( $legacy_settings, $new_settings );
217
-
218
- // migrate email notification settings: if there's a recipient, we enable email and pass recipient(s) to email setting
219
- if ( isset( $legacy_settings['sync_email'] ) && is_string( $legacy_settings['sync_email'] ) && '' !== trim( $legacy_settings['sync_email'] ) ) {
220
- $email_settings['enabled'] = 'yes';
221
- $email_settings['recipient'] = $legacy_settings['sync_email'] ;
222
- } else {
223
- $email_settings['enabled'] = 'no';
224
- $email_settings['recipient'] = '';
225
- }
226
-
227
- // save email settings
228
- update_option( 'woocommerce_wc_square_sync_completed_settings', $email_settings );
229
- // save plugin settings
230
- update_option( 'wc_square_settings', $new_settings );
231
-
232
- $this->get_plugin()->log( 'Plugin settings migration complete.' );
233
-
234
- return isset( $new_settings['system_of_record'] ) && $new_settings['system_of_record'] !== Settings::SYSTEM_OF_RECORD_DISABLED;
235
- }
236
-
237
-
238
- /**
239
- * Migrates gateway settings from v1 to v2.
240
- *
241
- * @see Lifecycle::upgrade_to_2_0_0()
242
- *
243
- * @since 2.0.0
244
- */
245
- private function migrate_gateway_settings() {
246
-
247
- $this->get_plugin()->log( 'Migrating gateway settings...' );
248
-
249
- $legacy_settings = get_option( 'woocommerce_square_settings', [] );
250
- $new_settings = get_option( 'woocommerce_square_credit_card_settings', [] );
251
-
252
- // bail if they already have v2 settings present
253
- if ( ! empty( $new_settings ) ) {
254
- return;
255
- }
256
-
257
- if ( isset( $legacy_settings['enabled'] ) ) {
258
- $new_settings['enabled'] = 'yes' === $legacy_settings['enabled'] ? 'yes' : 'no';
259
- }
260
-
261
- if ( isset( $legacy_settings['title'] ) && is_string( $legacy_settings['title'] ) ) {
262
- $new_settings['title'] = $legacy_settings['title'];
263
- }
264
-
265
- if ( isset( $legacy_settings['description'] ) && is_string( $legacy_settings['description'] ) ) {
266
- $new_settings['description'] = $legacy_settings['description'];
267
- }
268
-
269
- // note: the following is not an error, the setting on v1 intends "delayed" capture, hence authorization only, if set
270
- if ( isset( $legacy_settings['capture'] ) ) {
271
- $new_settings['transaction_type'] = 'yes' === $legacy_settings['capture'] ? Gateway::TRANSACTION_TYPE_AUTHORIZATION : Gateway::TRANSACTION_TYPE_CHARGE;
272
- }
273
-
274
- // not quite the same, since tokenization is a new thing, but we could presume the intention to let customers save their payment details
275
- if ( isset( $legacy_settings['create_customer'] ) ) {
276
- $new_settings['tokenization'] = 'yes' === $legacy_settings['create_customer'] ? 'yes' : 'no';
277
- }
278
-
279
- if ( isset( $legacy_settings['logging'] ) ) {
280
- $new_settings['debug_mode'] = 'yes' === $legacy_settings['logging'] ? 'log' : 'off';
281
- }
282
-
283
- // there was no card types setting in v1
284
- $new_settings['card_types'] = [
285
- 'VISA',
286
- 'MC',
287
- 'AMEX',
288
- 'JCB',
289
- // purposefully omit dinersclub & discover
290
- ];
291
-
292
- // save migrated settings
293
- update_option( 'woocommerce_square_credit_card_settings', $new_settings );
294
-
295
- $this->get_plugin()->log( 'Gateway settings migration complete.' );
296
- }
297
-
298
-
299
- /**
300
- * Migrates order data from v1 to v2.
301
- *
302
- * @see Lifecycle::upgrade_to_2_0_0()
303
- *
304
- * @since 2.0.0
305
- */
306
- private function migrate_orders() {
307
- global $wpdb;
308
-
309
- $this->get_plugin()->log( 'Migrating orders data...' );
310
-
311
- // move charge captured flag in orders to SkyVerge framework meta key
312
- $wpdb->update( $wpdb->postmeta, [ 'meta_key' => '_wc_square_credit_card_charge_captured' ], [ 'meta_key' => '_square_charge_captured' ] );
313
-
314
- // move payment ID to new gateway ID meta key value
315
- $wpdb->update( $wpdb->postmeta, [ 'meta_value' => 'square_credit_card' ], [ 'meta_key' => '_payment_method', 'meta_value' => 'square' ] );
316
-
317
- $this->get_plugin()->log( 'Orders migration complete.' );
318
- }
319
-
320
-
321
- /**
322
- * Migrates product data from v1 to v2.
323
- *
324
- * @see Lifecycle::upgrade_to_2_0_0()
325
- *
326
- * @since 2.0.0
327
- */
328
- private function migrate_products() {
329
- global $wpdb;
330
-
331
- $this->get_plugin()->log( 'Migrating products data...' );
332
-
333
- // the handling in v1 was reversed, so we want products where sync wasn't disabled
334
- $legacy_product_ids = get_posts( [
335
- 'nopaging' => true,
336
- 'post_type' => 'product',
337
- 'post_status' => 'all',
338
- 'fields' => 'ids',
339
- 'meta_query' => [
340
- 'relation' => 'OR',
341
- [
342
- 'key' => '_wcsquare_disable_sync',
343
- 'value' => 'no',
344
- ],
345
- [
346
- 'key' => '_wcsquare_disable_sync',
347
- 'compare' => 'NOT EXISTS',
348
- ]
349
- ],
350
- ] );
351
-
352
- // in v2 we turn those products as flagged to be sync-enabled instead
353
- if ( ! empty( $legacy_product_ids ) ) {
354
-
355
- $failed_products = [];
356
-
357
- // ensure taxonomy is registered at this stage
358
- if ( ! taxonomy_exists( Product::SYNCED_WITH_SQUARE_TAXONOMY ) ) {
359
- Product::init_taxonomies();
360
- }
361
-
362
- // will not create the term if already exists
363
- wp_create_term( 'yes', Product::SYNCED_WITH_SQUARE_TAXONOMY );
364
-
365
- // set Square sync status via taxonomy term
366
- foreach ( $legacy_product_ids as $i => $product_id ) {
367
-
368
- $set_term = wp_set_object_terms( $product_id, [ 'yes' ], Product::SYNCED_WITH_SQUARE_TAXONOMY );
369
-
370
- if ( ! is_array( $set_term ) ) {
371
-
372
- unset( $legacy_product_ids[ $i ] );
373
-
374
- $failed_products[] = $product_id;
375
- }
376
- }
377
-
378
- // log any errors
379
- if ( ! empty( $failed_products ) ) {
380
- $this->get_plugin()->log( 'Could not update sync with Square status for products with ID: ' . implode( ', ', array_unique( $failed_products ) ) . '.' );
381
- }
382
- }
383
-
384
- $this->get_plugin()->log( 'Products migration complete.' );
385
- }
386
-
387
-
388
- /**
389
- * Migrates customer data.
390
- *
391
- * @since 2.0.0
392
- */
393
- private function migrate_customers() {
394
- global $wpdb;
395
-
396
- $this->get_plugin()->log( 'Migrating customer data.' );
397
-
398
- $rows = (int) $wpdb->update( $wpdb->usermeta, [ 'meta_key' => 'wc_square_customer_id' ], [ 'meta_key' => '_square_customer_id' ] );
399
-
400
- $this->get_plugin()->log( sprintf( '%d customers migrated', $rows ) );
401
- }
402
-
403
-
404
- /**
405
- * Adds the system of record setting to the v2 plugin settings depending on v1 setting values.
406
- *
407
- * @since 2.0.2
408
- *
409
- * @param array $v1_settings v1 plugin settings
410
- * @param array $v2_settings v2 plugin settings
411
- * @return array
412
- */
413
- private function get_migrated_system_of_record( $v1_settings, $v2_settings ) {
414
-
415
- $sync_products = isset( $v1_settings['sync_products'] ) && 'yes' === $v1_settings['sync_products'];
416
- $sync_inventory = $sync_products && isset( $v1_settings['sync_inventory'] ) && 'yes' === $v1_settings['sync_inventory'];
417
- $inventory_polling = isset( $v1_settings['inventory_polling'] ) && 'yes' === $v1_settings['inventory_polling'];
418
-
419
- $v2_settings['system_of_record'] = $sync_products && $inventory_polling ? Settings::SYSTEM_OF_RECORD_SQUARE : Settings::SYSTEM_OF_RECORD_DISABLED;
420
- $v2_settings['enable_inventory_sync'] = $inventory_polling || $sync_inventory ? 'yes' : 'no';
421
-
422
- return $v2_settings;
423
- }
424
-
425
-
426
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Plugin.php DELETED
@@ -1,898 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Handlers\Background_Job;
30
- use WooCommerce\Square\Handlers\Email;
31
- use WooCommerce\Square\Handlers\Order;
32
- use WooCommerce\Square\Handlers\Product;
33
- use WooCommerce\Square\Handlers\Sync;
34
- use WooCommerce\Square\Handlers\Products;
35
-
36
- /**
37
- * The main plugin class.
38
- *
39
- * @since 2.0.0
40
- */
41
- class Plugin extends Framework\SV_WC_Payment_Gateway_Plugin {
42
-
43
-
44
- /** plugin version number */
45
- const VERSION = '2.0.8';
46
-
47
- /** plugin ID */
48
- const PLUGIN_ID = 'square';
49
-
50
- /** string gateway ID */
51
- const GATEWAY_ID = 'square_credit_card';
52
-
53
-
54
- /** @var Plugin plugin instance */
55
- protected static $instance;
56
-
57
- /** @var Settings settings handler instance */
58
- private $settings_handler;
59
-
60
- /** @var Handlers\Connection connection handler instance */
61
- private $connection_handler;
62
-
63
- /** @var Admin admin handler instance */
64
- private $admin_handler;
65
-
66
- /** @var Sync sync handler instance */
67
- private $sync_handler;
68
-
69
- /** @var Background_Job background handler instance */
70
- private $background_job_handler;
71
-
72
- /** @var AJAX handler instance */
73
- private $ajax_handler;
74
-
75
- /** @var Email emails handler */
76
- private $email_handler;
77
-
78
- /** @var Order orders handler */
79
- private $order_handler;
80
-
81
- /** @var Products products handler */
82
- private $products_handler;
83
-
84
- /**
85
- * Constructs the plugin.
86
- *
87
- * @since 2.0.0
88
- */
89
- public function __construct() {
90
-
91
- parent::__construct(
92
- self::PLUGIN_ID,
93
- self::VERSION,
94
- [
95
- 'text_domain' => 'woocommerce-square',
96
- 'gateways' => [ self::GATEWAY_ID => Gateway::class ],
97
- 'require_ssl' => true,
98
- 'supports' => [
99
- self::FEATURE_CAPTURE_CHARGE,
100
- self::FEATURE_CUSTOMER_ID,
101
- self::FEATURE_MY_PAYMENT_METHODS,
102
- ],
103
- 'dependencies' => [
104
- 'php_extensions' => [ 'curl', 'json', 'mbstring' ],
105
- ],
106
- ]
107
- );
108
-
109
- $this->includes();
110
-
111
- /**
112
- * Fires upon plugin loaded (legacy hook).
113
- *
114
- * @since 1.0.0
115
- */
116
- do_action( 'wc_square_loaded' );
117
-
118
- add_action( 'woocommerce_register_taxonomy', [ $this, 'init_taxonomies' ] );
119
-
120
- add_filter( 'woocommerce_locate_template', [ $this, 'locate_template' ], 20, 3 );
121
- add_filter( 'woocommerce_locate_core_template', [ $this, 'locate_template' ], 20, 3 );
122
- }
123
-
124
-
125
- /**
126
- * Includes required classes.
127
- *
128
- * @since 2.0.0
129
- */
130
- private function includes() {
131
-
132
- $this->connection_handler = new Handlers\Connection( $this );
133
-
134
- $this->sync_handler = new Sync( $this );
135
-
136
- // background export must be loaded all the time, because otherwise background jobs simply won't work
137
- require_once $this->get_framework_path() . '/utilities/class-sv-wp-async-request.php';
138
- require_once $this->get_framework_path() . '/utilities/class-sv-wp-background-job-handler.php';
139
- require_once $this->get_framework_path() . '/utilities/class-sv-wp-job-batch-handler.php';
140
-
141
- $this->background_job_handler = new Background_Job();
142
-
143
- $this->ajax_handler = new AJAX();
144
-
145
- $this->email_handler = new Email();
146
-
147
- $this->order_handler = new Order();
148
- }
149
-
150
-
151
- /**
152
- * Adds API request logging.
153
- *
154
- * @internal
155
- *
156
- * @since 2.0.0
157
- */
158
- public function add_api_request_logging() {
159
-
160
- if ( ! has_action( 'wc_' . $this->get_id() . '_api_request_performed' ) ) {
161
- add_action( 'wc_' . $this->get_id() . '_api_request_performed', [ $this, 'log_api_request' ], 10, 2 );
162
- }
163
- }
164
-
165
-
166
- /**
167
- * Logs an API request & response.
168
- *
169
- * @since 2.0.0
170
- *
171
- * @param array $request request data
172
- * @param array $response response data
173
- * @param string|null $log_id log ID
174
- */
175
- public function log_api_request( $request, $response, $log_id = null ) {
176
-
177
- if ( $this->get_settings_handler() && $this->get_settings_handler()->is_debug_enabled() ) {
178
- parent::log_api_request( $request, $response, $log_id );
179
- }
180
- }
181
-
182
-
183
- /**
184
- * Initializes the lifecycle handler.
185
- *
186
- * @since 2.0.0
187
- */
188
- public function init_lifecycle_handler() {
189
-
190
- $this->lifecycle_handler = new Lifecycle( $this );
191
- }
192
-
193
-
194
- /**
195
- * Registers custom taxonomies.
196
- *
197
- * @internal
198
- *
199
- * @since 2.0.0
200
- */
201
- public function init_taxonomies() {
202
-
203
- Product::init_taxonomies();
204
- }
205
-
206
-
207
- /**
208
- * Initializes the general plugin functionality.
209
- *
210
- * @since 2.0.0
211
- */
212
- public function init_plugin() {
213
-
214
- $this->settings_handler = new Settings( $this );
215
- $this->products_handler = new Products( $this );
216
-
217
- if ( ! $this->admin_handler && is_admin() ) {
218
- $this->admin_handler = new Admin( $this );
219
- }
220
- }
221
-
222
-
223
- /**
224
- * Locates the WooCommerce template files from our templates directory.
225
- *
226
- * @internal
227
- *
228
- * @since 2.0.0
229
- *
230
- * @param string $template already found template
231
- * @param string $template_name searchable template name
232
- * @param string $template_path template path
233
- * @return string search result for the template
234
- */
235
- public function locate_template( $template, $template_name, $template_path ) {
236
-
237
- // only keep looking if no custom theme template was found
238
- // or if a default WooCommerce template was found
239
- if ( ! $template || Framework\SV_WC_Helper::str_starts_with( $template, WC()->plugin_path() ) ) {
240
-
241
- // set the path to our templates directory
242
- $plugin_path = $this->get_plugin_path() . '/templates/';
243
-
244
- // if a template is found, make it so
245
- if ( is_readable( $plugin_path . $template_name ) ) {
246
- $template = $plugin_path . $template_name;
247
- }
248
- }
249
-
250
- return $template;
251
- }
252
-
253
-
254
- /** Admin methods *************************************************************************************************/
255
-
256
-
257
- /**
258
- * Adds admin notices.
259
- *
260
- * @since 2.0.0
261
- */
262
- public function add_admin_notices() {
263
-
264
- parent::add_admin_notices();
265
-
266
- // show any one-off messages
267
- $this->get_message_handler()->show_messages();
268
-
269
- // display a notice if the auto-refresh failed
270
- if ( get_option( 'wc_' . $this->get_id() . '_refresh_failed', false ) ) {
271
-
272
- $message = sprintf(
273
- __( 'Heads up! There may be a problem with your connection to Square. In order to continue accepting payments, please %1$sdisconnect and re-connect your site%2$s.', 'woocommerce-square' ),
274
- '<a href="' . esc_url( $this->get_settings_url() ) . '">', '</a>'
275
- );
276
-
277
- $this->get_admin_notice_handler()->add_admin_notice( $message, 'refresh-failed', [
278
- 'dismissible' => false,
279
- 'notice_class' => 'notice-warning',
280
- ] );
281
- }
282
-
283
- if ( $this->get_settings_handler()->is_connected() ) {
284
-
285
- $message = '<strong>' . __( 'You are connected to Square!', 'woocommerce-square' ) . '</strong>';
286
-
287
- // prompt to set a location if not set
288
- if ( ! $this->get_settings_handler()->get_location_id() ) {
289
-
290
- if ( $this->is_plugin_settings() ) {
291
-
292
- $instruction = __( 'To get started, set your business location.', 'woocommerce-square' );
293
-
294
- } else {
295
-
296
- $instruction = sprintf(
297
- /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
298
- __( 'Visit the %1$splugin settings%2$s to set your business location.', 'woocommerce-square' ),
299
- '<a href="' . esc_url( $this->get_settings_url() ) . '">', '</a>'
300
- );
301
- }
302
-
303
- $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'set-location' );
304
-
305
- } elseif ( ! $this->get_sync_handler()->get_last_synced_at() && $this->get_settings_handler()->is_product_sync_enabled() ) {
306
-
307
- $message = __( 'You are ready to sync products!', 'woocommerce-square' );
308
-
309
- if ( ! empty( Product::get_products_synced_with_square() ) ) {
310
-
311
- $instruction = sprintf(
312
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - product count, %3$s - </strong> tag, %4$s - <a> tag, %5$s - </a> tag */
313
- __( '%1$s%2$d products%3$s are marked "sync with Square". %4$sStart a new sync now &raquo;%5$s', 'woocommerce-square' ),
314
- '<strong>', count( Product::get_products_synced_with_square() ), '</strong>',
315
- '<a href="' . esc_url( add_query_arg( 'section', 'update', $this->get_settings_url() ) ) . '">', '</a>'
316
- );
317
-
318
- } else {
319
-
320
- $instruction = sprintf(
321
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
322
- __( '%1$sNo products%2$s are marked "sync with Square". %3$sUpdate your products to sync data &raquo;%4$s', 'woocommerce-square' ),
323
- '<strong>', '</strong>',
324
- '<a href="' . esc_url( admin_url( 'edit.php?post_type=product' ) ) . '">', '</a>'
325
- );
326
- }
327
-
328
- $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'set-location' );
329
- }
330
-
331
- // a notice for when WC stock handling is globally disabled
332
- if ( 'yes' !== get_option( 'woocommerce_manage_stock' ) && $this->get_settings_handler()->is_inventory_sync_enabled() ) {
333
-
334
- $message = sprintf(
335
- __( 'Heads up! Square is configured to sync product inventory, but WooCommerce stock management is disabled. Please %1$senable stock management%2$s to ensure product inventory counts are kept in sync.', 'woocommerce-square' ),
336
- '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings&tab=products&section=inventory' ) ) . '">', '</a>'
337
- );
338
-
339
- $this->get_admin_notice_handler()->add_admin_notice( $message, 'enable-wc-sync', [
340
- 'notice_class' => 'notice-warning',
341
- ] );
342
- }
343
-
344
- } else {
345
-
346
- if ( $this->is_plugin_settings() ) {
347
-
348
- $instruction = __( 'To get started, connect with Square.', 'woocommerce-square' );
349
-
350
- } else {
351
-
352
- $instruction = sprintf(
353
- /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
354
- __( 'To get started, %1$sconnect with Square &raquo;%2$s', 'woocommerce-square' ),
355
- '<a href="' . esc_url( $this->get_settings_url() ) . '">', '</a>'
356
- );
357
- }
358
-
359
- $message = sprintf(
360
- /* translators: Placeholders: %1$s - plugin name */
361
- __( 'Thanks for installing %1$s!', 'woocommerce-square' ),
362
- esc_html( $this->get_plugin_name() )
363
- );
364
-
365
- $this->get_admin_notice_handler()->add_admin_notice( $message . ' ' . $instruction, 'connect' );
366
- }
367
-
368
- // add a notice for out-of-bounds base locations
369
- $this->add_base_location_admin_notice();
370
-
371
- // add a notice when background processing is not supported
372
- $this->add_background_processing_notice();
373
-
374
- // add a notice when no refresh token is available
375
- $this->add_missing_refresh_token_notice();
376
-
377
- // add a tax-inclusive warning to product pages
378
- $this->add_tax_inclusive_pricing_notice();
379
-
380
- if ( get_option( 'wc_square_updated_to_2_0_0' ) ) {
381
-
382
- $this->get_admin_notice_handler()->add_admin_notice(
383
- sprintf(
384
- /* translators: Placeholders: %1$s - plugin name, %2$ - plugin version number, %3$s - opening <a> HTML link tag, %4$s - closing </a> HTML link tag, %5$s - opening <a> HTML link tag, %6$s - closing </a> HTML link tag*/
385
- esc_html__( '%1$s has been updated to version %2$s. In order to continue syncing product inventory, please make sure to disconnect and reconnect with Square from the %3$splugin settings%4$s and re-sync your products. Read more in the %5$supdated documentation%6$s.', 'woocommerce-square' ),
386
- '<strong>' . esc_html( $this->get_plugin_name() ) . '</strong>',
387
- $this->get_version(),
388
- '<a href="' . esc_url( $this->get_settings_url() ) . '">', '</a>',
389
- '<a href="' . esc_url( $this->get_documentation_url() ) . '">', '</a>'
390
- ),
391
- 'updated-to-v2',
392
- [ 'notice_class' => 'notice-warning' ]
393
- );
394
- }
395
- }
396
-
397
-
398
- /**
399
- * Adds a notice for out-of-bounds base locations.
400
- *
401
- * @since 2.0.0
402
- */
403
- protected function add_base_location_admin_notice() {
404
-
405
- $accepted_countries = [
406
- 'US',
407
- 'CA',
408
- 'GB',
409
- 'AU',
410
- 'JP',
411
- ];
412
-
413
- $base_location = wc_get_base_location();
414
-
415
- if ( isset( $base_location['country'] ) && ! in_array( $base_location['country'], $accepted_countries, true ) ) {
416
-
417
- $this->get_admin_notice_handler()->add_admin_notice( sprintf(
418
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - 2-character country code, %4$s - comma separated list of 2-character country codes */
419
- __( '%1$sWooCommerce Square:%2$s Your base country is %3$s, but Square can’t accept transactions from merchants outside of %4$s.', 'woocommerce-square' ),
420
- '<strong>', '</strong>',
421
- esc_html( $base_location['country'] ),
422
- esc_html( Framework\SV_WC_Helper::list_array_items( $accepted_countries ) )
423
- ), 'wc-square-base-location', [
424
- 'notice_class' => 'notice-error',
425
- ] );
426
- }
427
- }
428
-
429
-
430
- /**
431
- * Adds a notice when background processing is not supported.
432
- *
433
- * @since 2.0.0
434
- */
435
- protected function add_background_processing_notice() {
436
-
437
- if ( $this->get_settings_handler()->is_product_sync_enabled() && ! $this->get_background_job_handler()->test_connection() ) {
438
-
439
- $this->get_admin_notice_handler()->add_admin_notice( sprintf(
440
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
441
- __( '%1$sWooCommerce Square:%2$s It looks like your site does not support background processing, which means large numbers of products may not sync successfully with Square. %3$sRead more here%4$s on how to resolve this.', 'woocommerce-square' ),
442
- '<strong>', '</strong>',
443
- '<a href="https://docs.woocommerce.com/document/woocommerce-square/#sync-issues" target="_blank">', '</a>'
444
- ), 'wc-square-background-processing', [
445
- 'notice_class' => 'notice-warning',
446
- ] );
447
- }
448
- }
449
-
450
- /**
451
- * Adds a notice if no refresh token has been cached.
452
- *
453
- * @since 2.0.5
454
- */
455
- protected function add_missing_refresh_token_notice() {
456
- if ( $this->get_settings_handler()->is_sandbox() ) {
457
- return;
458
- }
459
-
460
- $refresh_token = '';
461
- $settings_handler = $this->get_settings_handler();
462
-
463
- if ( method_exists( $settings_handler, 'get_access_token' ) ) {
464
- $access_token = $settings_handler->get_access_token();
465
- if ( empty( $access_token ) ) {
466
- // We are already in a disconnected state, don't show the warning.
467
- return;
468
- }
469
- }
470
-
471
- if ( method_exists( $settings_handler, 'get_refresh_token' ) ) {
472
- $refresh_token = $settings_handler->get_refresh_token();
473
- }
474
-
475
- if ( empty( $refresh_token ) ) {
476
- $this->get_admin_notice_handler()->add_admin_notice(
477
- sprintf(
478
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
479
- __( '%1$sWooCommerce Square:%2$s Automatic refreshing of the connection to Square is inactive. Please disconnect and reconnect to resolve.', 'woocommerce-square' ),
480
- '<strong>',
481
- '</strong>'
482
- ),
483
- 'wc-square-missing-refresh-token',
484
- [
485
- 'dismissible' => false,
486
- 'notice_class' => 'notice-error',
487
- ]
488
- );
489
- }
490
- }
491
-
492
-
493
- /**
494
- * Adds a tax-inclusive admin warning to product pages.
495
- *
496
- * @since 2.0.0
497
- */
498
- protected function add_tax_inclusive_pricing_notice() {
499
- global $typenow;
500
-
501
- // only show on product edit pages when configured that prices include tax
502
- if ( 'product' === $typenow && isset( $_GET['action'], $_GET['post'] ) && 'edit' === $_GET['action'] && wc_prices_include_tax() && $this->get_settings_handler()->is_product_sync_enabled() ) {
503
-
504
- $product = wc_get_product( (int) $_GET['post'] );
505
-
506
- // only show for products configured as taxable and sync with Square
507
- if ( $product instanceof \WC_Product && $product->is_taxable() && Product::is_synced_with_square( $product ) ) {
508
-
509
- $this->get_admin_notice_handler()->add_admin_notice( sprintf(
510
- __( '%1$sWooCommerce Square:%2$s Product prices are entered inclusive of tax, but Square does not support syncing tax-inclusive prices. Please make sure your Square tax rates match your WooCommerce tax rates.', 'woocommerce-square' ),
511
- '<strong>', '</strong>'
512
- ), 'wc-square-tax-inclusive', [
513
- 'notice_class' => 'notice-warning',
514
- ] );
515
- }
516
- }
517
- }
518
-
519
-
520
- /**
521
- * Adds admin notices for currency issues.
522
- *
523
- * @since 2.0.0
524
- */
525
- protected function add_currency_admin_notices() {
526
-
527
- parent::add_currency_admin_notices();
528
-
529
- if ( isset( $_GET['page'] ) && 'wc-settings' === $_GET['page'] && $this->get_settings_handler()->is_connected() ) {
530
-
531
- foreach ( $this->get_settings_handler()->get_locations() as $location ) {
532
-
533
- if ( $this->get_settings_handler()->get_location_id() === $location->getId() && get_woocommerce_currency() !== $location->getCurrency() ) {
534
-
535
- $this->get_admin_notice_handler()->add_admin_notice( sprintf(
536
- __( 'Heads up! Your store currency is %1$s but your configured Square business location currency is %2$s, so payments cannot be processed. Please %3$schoose a different business location%4$s or change your %5$sshop currency%6$s.', 'woocommerce-square' ),
537
- '<strong>' . esc_html( get_woocommerce_currency() ) . '</strong>',
538
- '<strong>' . esc_html( $location->getCurrency() ) . '</strong>',
539
- '<a href="' . esc_url( $this->get_settings_url() ) . '">', '</a>',
540
- '<a href="' . esc_url( admin_url( 'admin.php?page=wc-settings' ) ) . '">', '</a>'
541
- ), 'wc-square-currency-mismatch', [
542
- 'notice_class' => 'notice-error',
543
- ] );
544
- }
545
- }
546
- }
547
- }
548
-
549
-
550
- /** Helper methods ************************************************************************************************/
551
-
552
-
553
- /**
554
- * Returns an idempotency key to be used in Square API requests.
555
- *
556
- * @since 2.0.0
557
- *
558
- * @param string $key_input
559
- * @return string
560
- */
561
- public function get_idempotency_key( $key_input = '' ) {
562
-
563
- if ( '' === $key_input ) {
564
- $key_input = uniqid( '', false );
565
- }
566
-
567
- /**
568
- * Filters an idempotency key.
569
- *
570
- * @since 2.0.0
571
- *
572
- * @param string $key_input
573
- */
574
- return apply_filters( 'wc_square_idempotency_key', md5( get_option( 'siteurl' ) ) . ':' . $key_input );
575
- }
576
-
577
-
578
- /** Conditional methods *******************************************************************************************/
579
-
580
-
581
- /**
582
- * Determines if viewing the plugin settings.
583
- *
584
- * @since 2.0.0
585
- *
586
- * @return bool
587
- */
588
- public function is_plugin_settings() {
589
-
590
- return parent::is_plugin_settings() || ( isset( $_GET['page'], $_GET['tab'] ) && 'wc-settings' === $_GET['page'] && self::PLUGIN_ID === $_GET['tab'] );
591
- }
592
-
593
-
594
- /** Getter methods ************************************************************************************************/
595
-
596
-
597
- /**
598
- * Gets the main Square API handler.
599
- *
600
- * @since 2.0.0
601
- *
602
- * @param string|null $access_token API access token
603
- * @return API
604
- */
605
- public function get_api( $access_token = null, $is_sandbox = null ) {
606
-
607
- if ( ! $access_token ) {
608
- $access_token = $this->get_settings_handler()->get_access_token();
609
- }
610
-
611
- if ( is_null( $is_sandbox ) ) {
612
- $is_sandbox = $this->get_settings_handler()->is_sandbox();
613
- }
614
-
615
- return new API( $access_token, $is_sandbox );
616
- }
617
-
618
-
619
- /**
620
- * Gets the connection handler.
621
- *
622
- * @since 2.0.0
623
- *
624
- * @return Handlers\Connection
625
- */
626
- public function get_connection_handler() {
627
-
628
- return $this->connection_handler;
629
- }
630
-
631
-
632
- /**
633
- * Gets the sync handler instance.
634
- *
635
- * @since 2.0.0
636
- *
637
- * @return Sync
638
- */
639
- public function get_sync_handler() {
640
-
641
- return $this->sync_handler;
642
- }
643
-
644
-
645
- /**
646
- * Gets the background sync handler instance.
647
- *
648
- * @since 2.0.0
649
- *
650
- * @return Background_Job
651
- */
652
- public function get_background_job_handler() {
653
-
654
- return $this->background_job_handler;
655
- }
656
-
657
-
658
- /**
659
- * Gets the settings handler instance.
660
- *
661
- * @since 2.0.0
662
- *
663
- * @return Settings
664
- */
665
- public function get_settings_handler() {
666
-
667
- return $this->settings_handler;
668
- }
669
-
670
-
671
- /**
672
- * Gets the admin handler instance.
673
- *
674
- * @since 2.0.0
675
- *
676
- * @return Admin|null
677
- */
678
- public function get_admin_handler() {
679
-
680
- // throw a notice if calling before admin_init
681
- Framework\SV_WC_Helper::maybe_doing_it_early( 'admin_init', __METHOD__, '2.0.0' );
682
-
683
- return $this->admin_handler;
684
- }
685
-
686
-
687
- /**
688
- * Gets the email handler instance.
689
- *
690
- * @since 2.0.0
691
- *
692
- * @return Email
693
- */
694
- public function get_email_handler() {
695
-
696
- return $this->email_handler;
697
- }
698
-
699
-
700
- /**
701
- * Gets the order handler instance.
702
- *
703
- * @since 2.0.0
704
- *
705
- * @return Order
706
- */
707
- public function get_order_handler() {
708
-
709
- return $this->order_handler;
710
- }
711
-
712
- /**
713
- * Get the products handler instance/
714
- *
715
- * @since 2.0.8
716
- *
717
- * @return Products
718
- */
719
- public function get_products_handler() {
720
- return $this->products_handler;
721
- }
722
-
723
-
724
- /**
725
- * Gets the deprecated hook details.
726
- *
727
- * @see Framework\SV_WC_Hook_Deprecator
728
- *
729
- * @since 2.0.0
730
- *
731
- * @return array
732
- */
733
- protected function get_deprecated_hooks() {
734
-
735
- // the following are filters, except when an action is explicitly mentioned
736
- $v2_0_0_removed_hooks = [
737
-
738
- // to filter the locale, the default WordPress filter should be used:
739
- 'woocommerce_square_plugin_locale' => [ 'replacement' => 'plugin_locale', 'map' => true ],
740
-
741
- // sync square product variation properties
742
- 'woocommerce_square_currency' => [], // used when passing a WooCommerce product price into a Square ItemVariation
743
- 'wc_square_sync_to_square_price' => [], // used when passing a WooCommerce product price into a Square ItemVariation
744
- 'woocommerce_square_format_price' => [], // formats the price coming from Square
745
- 'woocommerce_square_sync_from_square_description' => [], // flag whether to add a description to created item
746
-
747
- // we no longer filter inventory type in v2.0.0 and timeout is handled by background job differently
748
- 'woocommerce_square_inventory_type' => [],
749
- 'woocommerce_square_inventory_sync_timeout_limit' => [],
750
- 'woocommerce_square_inventory_poll_frequency' => [],
751
-
752
- // Square payment
753
- 'woocommerce_square_payment_form_trigger_element' => [],
754
- 'woocommerce_square_payment_order_note' => [ 'replacement' => 'wc_square_payment_order_note', 'map' => true ],
755
- 'woocommerce_square_description' => [], // front end payment fields description
756
-
757
- // most gateway properties and settings can be mapped to new filters:
758
- 'woocommerce_square_api_url' => [ 'replacement' => 'wc_square_api_url', 'map' => true ], // filter is reinstated with name change for consistency
759
- 'woocommerce_square_payment_gateway_is_available' => [ 'replacement' => 'wc_gateway_square_credit_card_is_available', 'map' => true ], // filter handled by SkyVerge Framework
760
- 'woocommerce_square_integration_settings_args' => [ 'replacement' => 'woocommerce_settings_api_form_fields_square', 'map' => true ], // filters gateway settings
761
- 'woocommerce_square_integration_custom_settings' => [ 'replacement' => 'woocommerce_settings_tabs_square', 'map' => true ], // settings action hook
762
-
763
- // API requests filters, these are handled differently and can't be mapped:
764
- 'woocommerce_square_request_args' => [],
765
- 'woocommerce_square_request_retries' => [],
766
-
767
- // transients are no longer used to handle these cache types:
768
- 'woocommerce_square_business_location_cache' => [],
769
- 'woocommerce_square_item_sku_cache' => [],
770
- 'woocommerce_square_inventory_cache' => [],
771
- 'woocommerce_square_sync_processing_ids_cache' => [],
772
- 'woocommerce_square_manual_sync_processing_cache' => [],
773
- 'woocommerce_square_syncing_square_ids_cache' => [],
774
- 'woocommerce_square_syncing_wc_product_ids_cache' => [],
775
-
776
- // when a bulk sync action is triggered (action hook):
777
- 'woocommerce_square_bulk_syncing_square_to_wc' => [],
778
-
779
- // get_posts args filter, the new implementation has different scope:
780
- 'woocommerce_square_get_all_product_ids_args' => [],
781
-
782
- // idempotency key
783
- 'woocommerce_square_idempotency_key' => [ 'replacement' => 'wc_square_idempotency_key', 'map' => true ],
784
-
785
- ];
786
-
787
- // add common array data for all removed hooks in version 2.0.0
788
- foreach ( array_keys( $v2_0_0_removed_hooks ) as $hook_name ) {
789
- $v2_0_0_removed_hooks[ $hook_name ]['version'] = '2.0.0';
790
- $v2_0_0_removed_hooks[ $hook_name ]['removed'] = true;
791
- }
792
-
793
- return $v2_0_0_removed_hooks;
794
- }
795
-
796
-
797
- /**
798
- * Gets the plugin name.
799
- *
800
- * @since 2.0.0
801
- *
802
- * @return string
803
- */
804
- public function get_plugin_name() {
805
-
806
- return __( 'WooCommerce Square', 'woocommerce-square' );
807
- }
808
-
809
-
810
- /**
811
- * Gets the settings URL.
812
- *
813
- * @since 2.0.0
814
- *
815
- * @param null|string $gateway_id gateway ID
816
- * @return string
817
- */
818
- public function get_settings_url( $gateway_id = null ) {
819
-
820
- $params = [
821
- 'page' => 'wc-settings',
822
- 'tab' => self::PLUGIN_ID,
823
- ];
824
-
825
- return add_query_arg( $params, admin_url( 'admin.php' ) );
826
- }
827
-
828
-
829
- /**
830
- * Gets the sale page URL.
831
- *
832
- * @since 2.0.0
833
- *
834
- * @return string
835
- */
836
- public function get_sales_page_url() {
837
-
838
- return 'https://woocommerce.com/products/woocommerce-square/';
839
- }
840
-
841
-
842
- /**
843
- * Gets the documentation URL.
844
- *
845
- * @since 2.0.0
846
- *
847
- * @return string
848
- */
849
- public function get_documentation_url() {
850
-
851
- return 'https://docs.woocommerce.com/document/woocommerce-square/';
852
- }
853
-
854
-
855
- /**
856
- * Gets the support URL.
857
- *
858
- * @since 2.0.0
859
- *
860
- * @return string
861
- */
862
- public function get_support_url() {
863
-
864
- return 'https://wordpress.org/support/plugin/woocommerce-square/'; // TODO: confirm this
865
- }
866
-
867
-
868
- /**
869
- * Gets __DIR__.
870
- *
871
- * @since 2.0.0
872
- *
873
- * @return string
874
- */
875
- protected function get_file() {
876
-
877
- return __DIR__;
878
- }
879
-
880
-
881
- /**
882
- * Gets the singleton instance of the plugin.
883
- *
884
- * @since 2.0.0
885
- *
886
- * @return Plugin
887
- */
888
- public static function instance() {
889
-
890
- if ( null === self::$instance ) {
891
- self::$instance = new self();
892
- }
893
-
894
- return self::$instance;
895
- }
896
-
897
-
898
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Settings.php DELETED
@@ -1,825 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * The settings API class.
32
- *
33
- * This handles registering, getting, and storing the general plugin options.
34
- *
35
- * Note that this is separate from the gateway settings.
36
- *
37
- * @since 2.0.0
38
- */
39
- class Settings extends \WC_Settings_API {
40
-
41
-
42
- /** @var string square system of record indicator */
43
- const SYSTEM_OF_RECORD_SQUARE = 'square';
44
-
45
- /** @var string square system of record indicator */
46
- const SYSTEM_OF_RECORD_WOOCOMMERCE = 'woocommerce';
47
-
48
- /** @var string system of record indicator for disabled sync */
49
- const SYSTEM_OF_RECORD_DISABLED = 'disabled';
50
-
51
-
52
- /** @var string un-encrypted refresh token */
53
- protected $refresh_token;
54
-
55
- /** @var string un-encrypted access token */
56
- protected $access_token;
57
-
58
- /** @var array business locations returned by the API */
59
- protected $locations;
60
-
61
- /** @var Plugin plugin instance */
62
- protected $plugin;
63
-
64
-
65
- /**
66
- * Constructs the class.
67
- *
68
- * @since 2.0.0
69
- *
70
- * @param Plugin $plugin plugin instance
71
- */
72
- public function __construct( Plugin $plugin ) {
73
-
74
- $this->plugin = $plugin;
75
- $this->plugin_id = 'wc_';
76
- $this->id = $plugin->get_id();
77
-
78
- $this->init_form_fields();
79
-
80
- $this->init_settings();
81
-
82
- // remove some of our custom fields that shouldn't be saved
83
- add_action( 'woocommerce_settings_api_sanitized_fields_' . $this->id, function( $fields ) {
84
-
85
- unset( $fields['general'], $fields['connect'], $fields['import_products'] );
86
-
87
- return $fields;
88
- } );
89
-
90
- // Save sandbox token.
91
- if ( $this->is_sandbox() ) {
92
- add_action(
93
- 'woocommerce_settings_api_sanitized_fields_' . $this->id,
94
- function( $fields ) {
95
- $this->update_access_token( $fields['sandbox_token'] );
96
- $this->access_token = false; // Remove encrypted token.
97
- $this->refresh_token = false; // Remove encrypted token.
98
- $this->init_form_fields(); // Reload form fields after saving token.
99
- return $fields;
100
- }
101
- );
102
- }
103
- }
104
-
105
-
106
- /**
107
- * Initializes the form fields.
108
- *
109
- * @since 2.0.0
110
- */
111
- public function init_form_fields() {
112
-
113
- if ( $this->is_connected() ) {
114
-
115
- $general_description = sprintf(
116
- /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
117
- __( 'Sync your products and inventory and also accept credit and debit card payments at checkout. %1$sClick here%2$s to configure payments.', 'woocommerce-square' ),
118
- '<a href="' . esc_url( $this->get_plugin()->get_payment_gateway_configuration_url( $this->get_plugin()->get_gateway()->get_id() ) ) . '">', '</a>'
119
- );
120
-
121
- } else {
122
-
123
- $general_description = __( 'Connect with Square to start syncing your products and inventory and also accept credit and debit card payments at checkout.', 'woocommerce-square' );
124
- }
125
-
126
- $fields = [
127
- 'general' => [
128
- 'type' => 'title',
129
- 'description' => $general_description,
130
- ],
131
- ];
132
-
133
- if ( $this->is_sandbox() ) {
134
- $fields['sandbox_settings'] = [
135
- 'type' => 'title',
136
- 'title' => __( 'Sandbox settings', 'woocommerce-square' ),
137
- 'description' => sprintf(
138
- // translators: Placeholders: %1$s - URL
139
- __( 'Sandbox details can be created at: %s', 'woocommerce-square' ),
140
- sprintf( '<a href="%1$s">%1$s</a>', 'https://developer.squareup.com/apps' )
141
- ),
142
- ];
143
- $fields['sandbox_application_id'] = [
144
- 'type' => 'input',
145
- 'title' => __( 'Sandbox Application ID', 'woocommerce-square' ),
146
- 'description' => __( 'Application ID for the Sandbox Application, see the details in the My Applications section.', 'woocommerce-square' ),
147
- ];
148
- $fields['sandbox_token'] = [
149
- 'type' => 'input',
150
- 'title' => __( 'Sandbox Access Token', 'woocommerce-square' ),
151
- 'description' => __( 'Access Token for the Sandbox Test Account, see the details in the Sandbox Test Account section. Make sure you use the correct Sandbox Access Token for your application. For a given Sandbox Test Account, each Authorized Application is assigned a different Access Token.', 'woocommerce-square' ),
152
- ];
153
- }
154
-
155
- // display these fields only if connected
156
- if ( $this->is_connected() ) {
157
-
158
- $fields['location_id'] = [
159
- 'title' => __( 'Business location', 'woocommerce-square' ),
160
- 'type' => 'select',
161
- 'class' => 'wc-enhanced-select',
162
- 'description' => sprintf(
163
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
164
- __( 'Select a location to link to this site. Only %1$sactive%2$s %3$slocations%4$s that support credit card processing in Square can be linked.', 'woocommerce-square' ),
165
- '<strong>', '</strong>',
166
- '<a href="https://squareup.com/help/us/en/article/5580-manage-multiple-locations-with-square" target="_blank">', '</a>'
167
- ),
168
- 'options' => [], // this is populated on display
169
- ];
170
-
171
- $fields['system_of_record'] = [
172
- 'title' => __( 'Product system of record', 'woocommerce-square' ),
173
- 'type' => 'select',
174
- 'class' => 'wc-enhanced-select',
175
- 'description' => sprintf(
176
- /* translators: Placeholders: %1$s - <strong> tag, %2$s - </strong> tag, %3$s - <a> tag, %4$s - </a> tag */
177
- __( 'Choose where you will update data for synced products. Inventory in Square is %1$salways%2$s checked for adjustments when sync is enabled. %3$sClick here%4$s to read more about choosing a system of record.', 'woocommerce-square' ),
178
- '<strong>', '</strong>',
179
- '<a href="' . esc_url( wc_square()->get_documentation_url() ) . '#sync">', '</a>'
180
- ),
181
- 'options' => [
182
- self::SYSTEM_OF_RECORD_DISABLED => __( 'Do not sync product data', 'woocommerce-square' ),
183
- self::SYSTEM_OF_RECORD_SQUARE => __( 'Square', 'woocommerce-square' ),
184
- self::SYSTEM_OF_RECORD_WOOCOMMERCE => __( 'WooCommerce', 'woocommerce-square' ),
185
- ],
186
- 'default' => 'disabled',
187
- ];
188
-
189
- $fields['enable_inventory_sync'] = [
190
- 'title' => __( 'Sync inventory', 'woocommerce-square' ),
191
- 'label' => '<span>' . __( 'Enable to sync product inventory with Square', 'woocommerce-square' ) . '</span>',
192
- 'type' => 'checkbox',
193
- 'description' => __( 'Inventory is fetched from Square periodically and updated in WooCommerce', 'woocommerce-square' ),
194
- ];
195
-
196
- $fields['hide_missing_products'] = [
197
- 'title' => __( 'Handle missing products', 'woocommerce-square' ),
198
- 'label' => __( 'Hide synced products when not found in Square', 'woocommerce-square' ),
199
- 'type' => 'checkbox',
200
- 'description' => __( 'Products not found in Square will be hidden in the WooCommerce product catalog.', 'woocommerce-square' ),
201
- ];
202
-
203
- $fields['import_products'] = [
204
- 'title' => __( 'Import Products', 'woocommerce-square' ),
205
- 'type' => 'import_products',
206
- 'desc_tip' => __( 'Run an import to create new products in this WooCommerce store for each new product created in Square that has a unique SKU not existing in here. Needs to be run each time new items are created in Square.', 'woocommerce-square' ),
207
- ];
208
- }
209
-
210
- // In sandbox mode we don't want to intially display the connect button, only disconnect.
211
- if ( ! ( $this->is_sandbox() && ! $this->is_connected() ) ) {
212
- $fields = array_merge(
213
- $fields,
214
- [
215
- 'connect' => [
216
- 'title' => __( 'Connection', 'woocommerce-square' ),
217
- 'type' => 'connect',
218
- 'desc_tip' => '',
219
- ],
220
- ]
221
- );
222
- }
223
-
224
- // Always display these fields.
225
- $fields = array_merge(
226
- $fields,
227
- [
228
- 'debug_logging_enabled' => [
229
- 'title' => __( 'Enable Logging', 'woocommerce-square' ),
230
- 'type' => 'checkbox',
231
- 'label' => sprintf(
232
- /* translators: Placeholders: %1$s - <a> tag, %2$s - </a> tag */
233
- __( 'Log debug messages to the %1$sWooCommerce status log%2$s', 'woocommerce-square' ),
234
- '<a href="' . esc_url( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) . '">', '</a>'
235
- ),
236
- ],
237
- ]
238
- );
239
-
240
- $this->form_fields = $fields;
241
- }
242
-
243
-
244
- /**
245
- * Gets the form fields.
246
- *
247
- * Overridden to populate the Location settings options on display.
248
- *
249
- * @since 2.0.0
250
- *
251
- * @return array
252
- */
253
- public function get_form_fields() {
254
-
255
- $fields = parent::get_form_fields();
256
-
257
- if ( ! empty( $fields['location_id'] ) ) {
258
-
259
- $locations = [
260
- '' => __( 'Please choose a location', 'woocommerce-square' ),
261
- ];
262
-
263
- if ( ! empty( $this->get_locations() ) ) {
264
-
265
- foreach ( $this->get_locations() as $location ) {
266
-
267
- if ( 'ACTIVE' === $location->getStatus() && in_array( 'CREDIT_CARD_PROCESSING', (array) $location->getCapabilities(), true ) ) {
268
- $locations[ $location->getId() ] = $location->getName();
269
- }
270
- }
271
- }
272
-
273
- $fields['location_id']['options'] = $locations;
274
- }
275
-
276
- return $fields;
277
- }
278
-
279
-
280
- public function generate_import_products_html( $id, $field ) {
281
-
282
- ob_start();
283
- ?>
284
- <tr valign="top">
285
- <th scope="row" class="titledesc">
286
- <label for="<?php echo esc_attr( $id ); ?>"><?php echo wp_kses_post( $field['title'] ); ?> <?php echo $this->get_tooltip_html( $field ); ?></label>
287
- </th>
288
- <td class="forminp">
289
- <a href='#' class='button js-import-square-products'>
290
- <?php echo esc_html__( 'Import all products from Square', 'woocommerce-square' ); ?>
291
- </a>
292
- </td>
293
- </tr>
294
- <?php
295
-
296
- return ob_get_clean();
297
- }
298
-
299
-
300
- /**
301
- * Generates the Connection field HTML.
302
- *
303
- * @since 2.0.0
304
- *
305
- * @param string $id field ID
306
- * @param array $field field data
307
- * @return string
308
- */
309
- public function generate_connect_html( $id, $field ) {
310
-
311
- ob_start();
312
- ?>
313
- <tr valign="top">
314
- <th scope="row" class="titledesc">
315
- <label for="<?php echo esc_attr( $id ); ?>"><?php echo wp_kses_post( $field['title'] ); ?> <?php echo $this->get_tooltip_html( $field ); ?></label>
316
- </th>
317
- <td class="forminp">
318
- <?php if ( $this->get_access_token() ) {
319
- echo $this->get_plugin()->get_connection_handler()->get_disconnect_button_html();
320
- } else {
321
- echo $this->get_plugin()->get_connection_handler()->get_connect_button_html( $this->is_sandbox() );
322
- } ?>
323
- </td>
324
- </tr>
325
- <?php
326
-
327
- return ob_get_clean();
328
- }
329
-
330
-
331
- /**
332
- * Updates the stored refresh token.
333
- *
334
- * @since 2.0.0
335
- *
336
- * @param string $token refresh token
337
- */
338
- public function update_refresh_token( $token ) {
339
-
340
- $refresh_tokens = $this->get_refresh_tokens();
341
- $environment = $this->get_environment();
342
-
343
- if ( ! empty( $token ) ) {
344
-
345
- $this->refresh_token = $token;
346
-
347
- if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
348
-
349
- $encryption = new Utilities\Encryption_Utility();
350
-
351
- try {
352
-
353
- $token = $encryption->encrypt_data( $token );
354
-
355
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
356
-
357
- // log the event, but don't halt the process
358
- $this->get_plugin()->log( 'Could not encrypt refresh token. ' . $exception->getMessage() );
359
- }
360
- }
361
-
362
- $refresh_tokens[ $environment ] = $token;
363
- }
364
-
365
- update_option( 'wc_square_refresh_tokens', $refresh_tokens );
366
- }
367
-
368
-
369
- /**
370
- * Updates the stored access token.
371
- *
372
- * @since 2.0.0
373
- *
374
- * @param string $token access token
375
- */
376
- public function update_access_token( $token ) {
377
-
378
- $access_tokens = $this->get_access_tokens();
379
- $environment = $this->get_environment();
380
-
381
- if ( ! empty( $token ) ) {
382
-
383
- $this->access_token = $token;
384
-
385
- if ( Utilities\Encryption_Utility::is_encryption_supported() ) {
386
-
387
- $encryption = new Utilities\Encryption_Utility();
388
-
389
- try {
390
-
391
- $token = $encryption->encrypt_data( $token );
392
-
393
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
394
-
395
- // log the event, but don't halt the process
396
- $this->get_plugin()->log( 'Could not encrypt access token. ' . $exception->getMessage() );
397
- }
398
- }
399
-
400
- $access_tokens[ $environment ] = $token;
401
- }
402
-
403
- update_option( 'wc_square_access_tokens', $access_tokens );
404
- }
405
-
406
-
407
- /**
408
- * Clears any stored refresh tokens.
409
- *
410
- * @since 2.0.0
411
- */
412
- public function clear_refresh_tokens() {
413
- delete_option( 'wc_square_refresh_tokens' );
414
- }
415
-
416
-
417
- /**
418
- * Clears any stored access tokens.
419
- *
420
- * @since 2.0.0
421
- */
422
- public function clear_access_tokens() {
423
-
424
- delete_option( 'wc_square_access_tokens' );
425
- }
426
-
427
-
428
- /**
429
- * Clears the location ID from the settings.
430
- *
431
- * This is helpful on disconnect / revoke so that previously set location IDs don't stick around and cause confusion.
432
- *
433
- * @since 2.0.0
434
- */
435
- public function clear_location_id() {
436
-
437
- $settings = get_option( $this->get_option_key(), [] );
438
-
439
- $settings['location_id'] = '';
440
-
441
- update_option( $this->get_option_key(), $settings );
442
- }
443
-
444
-
445
- /** Conditional methods *******************************************************************************************/
446
-
447
-
448
- /**
449
- * Determines if WooCommerce is configured to be the system of record.
450
- *
451
- * @since 2.0.0
452
- *
453
- * @return bool
454
- */
455
- public function is_system_of_record_woocommerce() {
456
-
457
- return self::SYSTEM_OF_RECORD_WOOCOMMERCE === $this->get_system_of_record();
458
- }
459
-
460
-
461
- /**
462
- * Determines if Square is configured to be the system of record.
463
- *
464
- * @since 2.0.0
465
- *
466
- * @return bool
467
- */
468
- public function is_system_of_record_square() {
469
-
470
- return self::SYSTEM_OF_RECORD_SQUARE === $this->get_system_of_record();
471
- }
472
-
473
-
474
- /**
475
- * Determines if there is no system of record.
476
- *
477
- * @since 2.0.0
478
- *
479
- * @return bool
480
- */
481
- public function is_system_of_record_disabled() {
482
-
483
- $sor = $this->get_system_of_record();
484
-
485
- return empty( $sor ) || self::SYSTEM_OF_RECORD_DISABLED === $sor;
486
- }
487
-
488
-
489
- /**
490
- * Determines if inventory sync is enabled.
491
- *
492
- * @since 2.0.0
493
- *
494
- * @return bool
495
- */
496
- public function is_inventory_sync_enabled() {
497
-
498
- return (bool) apply_filters( 'wc_square_inventory_sync_enabled', 'yes' === get_option( 'woocommerce_manage_stock' ) && $this->is_product_sync_enabled() && 'yes' === $this->get_option( 'enable_inventory_sync' ) );
499
- }
500
-
501
-
502
- /**
503
- * Determines if product sync is enabled.
504
- *
505
- * @since 2.0.0
506
- *
507
- * @return bool
508
- */
509
- public function is_product_sync_enabled() {
510
-
511
- return ! $this->is_system_of_record_disabled();
512
- }
513
-
514
-
515
- /**
516
- * Determines whether to hide products that don't exist in square from the catalog.
517
- *
518
- * @since 2.0.0
519
- *
520
- * @return bool
521
- */
522
- public function hide_missing_square_products() {
523
-
524
- return 'yes' === $this->get_option( 'hide_missing_products' );
525
- }
526
-
527
-
528
- /**
529
- * Determines if the plugin settings are fully configured.
530
- *
531
- * @since 2.0.0
532
- *
533
- * @return bool
534
- */
535
- public function is_configured() {
536
-
537
- return $this->get_location_id() && $this->get_system_of_record();
538
- }
539
-
540
-
541
- /**
542
- * Determines if the plugin is connected to Square.
543
- *
544
- * @since 2.0.0
545
- *
546
- * @return bool
547
- */
548
- public function is_connected() {
549
-
550
- return (bool) $this->get_access_token();
551
- }
552
-
553
-
554
- /**
555
- * Determines if configured in the sandbox environment.
556
- *
557
- * @since 2.0.0
558
- *
559
- * @return bool
560
- */
561
- public function is_sandbox() {
562
-
563
- return 'sandbox' === $this->get_environment();
564
- }
565
-
566
-
567
- /**
568
- * Determines if debug logging is enabled.
569
- *
570
- * @since 2.0.0
571
- *
572
- * @return bool
573
- */
574
- public function is_debug_enabled() {
575
-
576
- return 'yes' === $this->get_option( 'debug_logging_enabled' );
577
- }
578
-
579
-
580
- /** Getter methods ************************************************************************************************/
581
-
582
-
583
- /**
584
- * Gets the configured location.
585
- *
586
- * @since 2.0.0
587
- *
588
- * @return string
589
- */
590
- public function get_location_id() {
591
-
592
- return $this->get_option( 'location_id' );
593
- }
594
-
595
-
596
- /**
597
- * Gets the available locations.
598
- *
599
- * @since 2.0.0
600
- *
601
- * @return \SquareConnect\Model\Location[]
602
- */
603
- public function get_locations() {
604
-
605
- if ( ! is_array( $this->locations ) ) {
606
-
607
- $this->locations = [];
608
-
609
- try {
610
-
611
- // cache the locations returned so they can be used elsewhere
612
- $this->locations = $this->get_plugin()->get_api( $this->get_access_token(), $this->is_sandbox() )->get_locations();
613
-
614
- // check the returned IDs against what's currently configured
615
- $stored_location_id = $this->get_location_id();
616
- $found = ! $stored_location_id;
617
-
618
- foreach ( $this->locations as $location ) {
619
-
620
- if ( $stored_location_id && $location->getId() === $stored_location_id ) {
621
- $found = true;
622
- break;
623
- }
624
- }
625
-
626
- // if the currently set location ID is not present in the connected account's available locations, clear it locally
627
- if ( ! $found ) {
628
- $this->clear_location_id();
629
- }
630
-
631
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
632
-
633
- $this->get_plugin()->log( 'Could not retrieve business locations.' );
634
- }
635
- }
636
-
637
- return $this->locations;
638
- }
639
-
640
-
641
- /**
642
- * Gets the configured system of record.
643
- *
644
- * @since 2.0.0
645
- *
646
- * @return string
647
- */
648
- public function get_system_of_record() {
649
-
650
- return $this->get_option( 'system_of_record' );
651
- }
652
-
653
-
654
- /**
655
- * Gets the configured system of record name.
656
- *
657
- * @since 2.0.0
658
- *
659
- * @return string or empty string if no system of record is configured
660
- */
661
- public function get_system_of_record_name() {
662
-
663
- switch ( $this->get_system_of_record() ) {
664
-
665
- case 'square' :
666
- $sor = __( 'Square', 'woocommerce-square' );
667
- break;
668
- case 'woocommerce' :
669
- $sor = __( 'WooCommerce', 'woocommerce-square' );
670
- break;
671
- default :
672
- $sor = '';
673
- break;
674
- }
675
-
676
- return $sor;
677
- }
678
-
679
- /**
680
- * Gets the refresh token.
681
- *
682
- * @since 2.0.0
683
- *
684
- * @return string|null
685
- */
686
- public function get_refresh_token() {
687
-
688
- if ( empty( $this->refresh_token ) ) {
689
-
690
- $tokens = $this->get_refresh_tokens();
691
- $token = null;
692
-
693
- if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
694
- $token = $tokens[ $this->get_environment() ];
695
- }
696
-
697
- if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
698
-
699
- $encryption = new Utilities\Encryption_Utility();
700
-
701
- try {
702
-
703
- $token = $encryption->decrypt_data( $token );
704
-
705
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
706
-
707
- // log the event, but don't halt the process
708
- $this->get_plugin()->log( 'Could not decrypt refresh token. ' . $exception->getMessage() );
709
- }
710
- }
711
-
712
- $this->refresh_token = $token;
713
- }
714
-
715
- /**
716
- * Filters the configured refresh token.
717
- *
718
- * @since 2.0.0
719
- *
720
- * @param string $refresh_token
721
- */
722
- return apply_filters( 'wc_square_refresh_token', $this->refresh_token );
723
- }
724
-
725
- /**
726
- * Gets the access token.
727
- *
728
- * @since 2.0.0
729
- *
730
- * @return string|null
731
- */
732
- public function get_access_token() {
733
-
734
- if ( empty( $this->access_token ) ) {
735
-
736
- $tokens = $this->get_access_tokens();
737
- $token = null;
738
-
739
- if ( ! empty( $tokens[ $this->get_environment() ] ) ) {
740
- $token = $tokens[ $this->get_environment() ];
741
- }
742
-
743
- if ( $token && Utilities\Encryption_Utility::is_encryption_supported() ) {
744
-
745
- $encryption = new Utilities\Encryption_Utility();
746
-
747
- try {
748
-
749
- $token = $encryption->decrypt_data( $token );
750
-
751
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
752
-
753
- // log the event, but don't halt the process
754
- $this->get_plugin()->log( 'Could not decrypt access token. ' . $exception->getMessage() );
755
- }
756
- }
757
-
758
- $this->access_token = $token;
759
- }
760
-
761
- /**
762
- * Filters the configured access token.
763
- *
764
- * @since 2.0.0
765
- *
766
- * @param string $access_token access token
767
- */
768
- return apply_filters( 'wc_square_access_token', $this->access_token );
769
- }
770
-
771
-
772
- /**
773
- * Gets the stored access tokens.
774
- *
775
- * Each environment may have its own token.
776
- *
777
- * @since 2.0.0
778
- *
779
- * @return array
780
- */
781
- public function get_access_tokens() {
782
- return (array) get_option( 'wc_square_access_tokens', [] );
783
- }
784
-
785
-
786
- /**
787
- * Gets the stored refresh tokens.
788
- *
789
- * Each environment may have its own token.
790
- *
791
- * @since 2.0.0
792
- *
793
- * @return array
794
- */
795
- public function get_refresh_tokens() {
796
- return (array) get_option( 'wc_square_refresh_tokens', [] );
797
- }
798
-
799
-
800
- /**
801
- * Gets the configured environment.
802
- *
803
- * @since 2.0.0
804
- *
805
- * @return string
806
- */
807
- public function get_environment() {
808
- return defined( 'WC_SQUARE_SANDBOX' ) && WC_SQUARE_SANDBOX ? 'sandbox' : 'production';
809
- }
810
-
811
-
812
- /**
813
- * Gets the plugin instance.
814
- *
815
- * @since 2.0.0
816
- *
817
- * @return Plugin
818
- */
819
- public function get_plugin() {
820
-
821
- return $this->plugin;
822
- }
823
-
824
-
825
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Catalog_Item.php DELETED
@@ -1,149 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use WooCommerce\Square\Handlers\Product;
28
-
29
- defined( 'ABSPATH' ) or exit;
30
-
31
- /**
32
- * Class to represent a single catalog item.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Catalog_Item {
37
-
38
-
39
- /** @var \WC_Product the product object */
40
- protected $product;
41
-
42
- /** @var \SquareConnect\Model\CatalogObjectBatch the batch object */
43
- protected $batch;
44
-
45
- /** @var int the total number of catalog objects in this batch */
46
- protected $batch_object_count = 0;
47
-
48
- /** @var bool whether or not this catalog item should be soft-deleted */
49
- protected $soft_delete = false;
50
-
51
- /**
52
- * Constructs the catalog item.
53
- *
54
- * @since 2.0.0
55
- *
56
- * @param int|false|\WC_Product $product the product ID or product object
57
- * @param bool $is_soft_delete whether this catalog object should be soft-deleted
58
- * @throws Framework\SV_WC_Plugin_Exception
59
- */
60
- public function __construct( $product, $is_soft_delete = false ) {
61
-
62
- $product = is_numeric( $product ) ? wc_get_product( $product ) : $product;
63
-
64
- if ( ! $product instanceof \WC_Product ) {
65
-
66
- throw new Framework\SV_WC_Plugin_Exception( 'Invalid product' );
67
- }
68
-
69
- $this->product = $product;
70
- $this->soft_delete = $is_soft_delete;
71
- }
72
-
73
-
74
- /**
75
- * Gets the object batch.
76
- *
77
- * @since 2.0.0
78
- *
79
- * @param \SquareConnect\Model\CatalogObject|null $catalog_object existing catalog object or null to create a new one
80
- * @return \SquareConnect\Model\CatalogObjectBatch
81
- * @throws Framework\SV_WC_Plugin_Exception
82
- */
83
- public function get_batch( \SquareConnect\Model\CatalogObject $catalog_object = null ) {
84
-
85
- if ( ! $this->batch ) {
86
- $this->create_batch( $catalog_object );
87
- }
88
-
89
- return $this->batch;
90
- }
91
-
92
-
93
- /**
94
- * Gets the total number of objects in the batch.
95
- *
96
- * @since 2.0.0
97
- *
98
- * @return int
99
- */
100
- public function get_batch_object_count() {
101
-
102
- return $this->batch_object_count;
103
- }
104
-
105
-
106
- /**
107
- * Returns whether this catalog object should be soft-deleted.
108
- *
109
- * @since 2.0.0
110
- *
111
- * @return bool
112
- */
113
- protected function is_soft_delete() {
114
-
115
- return true === $this->soft_delete;
116
- }
117
-
118
-
119
- /**
120
- * Creates a batch containing this item and any variations.
121
- *
122
- * @since 2.0.0
123
- *
124
- * @param \SquareConnect\Model\CatalogObject|null $catalog_object existing catalog object or null to create a new one
125
- * @throws Framework\SV_WC_Plugin_Exception
126
- */
127
- protected function create_batch( \SquareConnect\Model\CatalogObject $catalog_object = null ) {
128
-
129
- if ( ! $catalog_object ) {
130
-
131
- $catalog_object = new \SquareConnect\Model\CatalogObject( [
132
- 'type' => 'ITEM',
133
- ] );
134
- }
135
-
136
- // update the object data from the Woo product
137
- $catalog_object = Product\Woo_SOR::update_catalog_item( $catalog_object, $this->product );
138
-
139
- $batch_data = [ 'objects' => [ $catalog_object ] ];
140
-
141
- $this->batch = new \SquareConnect\Model\CatalogObjectBatch( $batch_data );
142
-
143
- $variations = $catalog_object->getItemData()->getVariations() ?: [];
144
-
145
- $this->batch_object_count = 1 + count( $variations );
146
- }
147
-
148
-
149
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Interval_Polling.php DELETED
@@ -1,272 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\SearchCatalogObjectsResponse;
28
- use WooCommerce\Square\Handlers\Product;
29
- use WooCommerce\Square\Handlers\Category;
30
-
31
- defined( 'ABSPATH' ) or exit;
32
-
33
- /**
34
- * Class to represent a synchronization job to poll latest product updates at intervals.
35
- *
36
- * @since 2.0.0
37
- */
38
- class Interval_Polling extends Stepped_Job {
39
-
40
-
41
- /**
42
- * Assigns the next steps needed for this sync job.
43
- *
44
- * Adds the next steps to the 'next_steps' attribute.
45
- *
46
- * @since 2.0.0
47
- */
48
- protected function assign_next_steps() {
49
-
50
- $next_steps = [];
51
-
52
- if ( $this->is_system_of_record_square() ) {
53
-
54
- $next_steps = [
55
- 'update_category_data',
56
- 'update_product_data',
57
- ];
58
- }
59
-
60
- // only pull latest inventory if enabled
61
- if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
62
- $next_steps[] = 'update_inventory_counts';
63
- }
64
-
65
- $this->set_attr( 'next_steps', $next_steps );
66
- }
67
-
68
- /**
69
- * Updates categories from Square.
70
- *
71
- * @since 2.0.8
72
- *
73
- * @throws Framework\SV_WC_Plugin_Exception
74
- */
75
- protected function update_category_data() {
76
- $date = new \DateTime();
77
- $date->setTimestamp( $this->get_attr( 'catalog_last_synced_at', (int) wc_square()->get_sync_handler()->get_last_synced_at() ) );
78
- $date->setTimezone( new \DateTimeZone( 'UTC' ) );
79
-
80
- $response = wc_square()->get_api()->search_catalog_objects( [
81
- 'object_types' => [ 'CATEGORY' ],
82
- 'begin_time' => $date->format( DATE_ATOM ),
83
- ] );
84
-
85
- $categories = $response->get_data()->getObjects();
86
-
87
- if ( $categories && is_array( $categories ) ) {
88
- foreach ( $categories as $category ) {
89
- Category::import_or_update( $category );
90
- }
91
-
92
- Records::set_record( [
93
- 'type' => 'info',
94
- 'message' => sprintf(
95
- /* translator: Placeholder %d number of categories */
96
- _n( 'Updated data for %d category.', 'Updated data for %d categories.', count( $categories ), 'woocommerce-square' ),
97
- count( $categories )
98
- )
99
- ] );
100
- }
101
-
102
- $this->complete_step( 'update_category_data' );
103
- }
104
-
105
- /**
106
- * Updates products from Square.
107
- *
108
- * @since 2.0.0
109
- *
110
- * @throws Framework\SV_WC_Plugin_Exception
111
- */
112
- protected function update_product_data() {
113
-
114
- $date = new \DateTime();
115
- $date->setTimestamp( $this->get_attr( 'catalog_last_synced_at', (int) wc_square()->get_sync_handler()->get_last_synced_at() ) );
116
- $date->setTimezone( new \DateTimeZone( 'UTC' ) );
117
-
118
- $products_updated = $this->get_attr( 'processed_product_ids', [] );
119
- $cursor = $this->get_attr( 'update_product_data_cursor' );
120
-
121
- $response = wc_square()->get_api()->search_catalog_objects( [
122
- 'object_types' => [ 'ITEM' ],
123
- 'include_deleted_objects' => true,
124
- 'begin_time' => $date->format( DATE_ATOM ),
125
- 'cursor' => $cursor,
126
- ] );
127
-
128
- // store the timestamp after this API request was completed
129
- // we don't want to set it at the end, as counts may have changed in the time it takes to process the data
130
- if ( ! $cursor ) {
131
- wc_square()->get_sync_handler()->set_last_synced_at();
132
- }
133
-
134
- if ( $response->get_data() instanceof SearchCatalogObjectsResponse && is_array( $response->get_data()->getObjects() ) ) {
135
-
136
- foreach ( $response->get_data()->getObjects() as $object ) {
137
-
138
- // filter out objects that aren't at our configured location
139
- if ( ! $object->getPresentAtAllLocations() && ( ! is_array( $object->getPresentAtLocationIds() ) || ! in_array( wc_square()->get_settings_handler()->get_location_id(), $object->getPresentAtLocationIds(), true ) ) ) {
140
- continue;
141
- }
142
-
143
- $product = Product::get_product_by_square_id( $object->getId() );
144
-
145
- if ( $product instanceof \WC_Product ) {
146
-
147
- // deleted items won't have any data to set, so don't try and update the product
148
- if ( $object->getIsDeleted() ) {
149
-
150
- $record = [
151
- 'type' => 'alert',
152
- 'product_id' => $product->get_id(),
153
- ];
154
-
155
- // if enabled, hide the product from the catalog
156
- if ( wc_square()->get_settings_handler()->hide_missing_square_products() ) {
157
-
158
- try {
159
-
160
- $product->set_catalog_visibility( 'hidden' );
161
- $product->save();
162
-
163
- $record['product_hidden'] = true;
164
-
165
- } catch ( \Exception $e ) {}
166
- }
167
-
168
- Records::set_record( $record );
169
-
170
- } else {
171
-
172
- try {
173
-
174
- Product::update_from_square( $product, $object->getItemData(), false );
175
-
176
- if ( ! $product->get_image_id() && $object->getImageId() ) {
177
- Product::update_image_from_square( $product, $object->getImageId() );
178
- }
179
-
180
- $products_updated[] = $product->get_id();
181
-
182
- } catch ( \Exception $exception ) {
183
-
184
- Records::set_record( [
185
- 'type' => 'alert',
186
- 'product_id' => $product->get_id(),
187
- ] );
188
- }
189
- }
190
- }
191
- }
192
- }
193
-
194
- $cursor = $response->get_data()->getCursor();
195
-
196
- $this->set_attr( 'update_product_data_cursor', $cursor );
197
- $this->set_attr( 'processed_product_ids', array_unique( $products_updated ) );
198
-
199
- if ( ! $cursor ) {
200
- $this->complete_step( 'update_product_data' );
201
- }
202
- }
203
-
204
-
205
- /**
206
- * Updates the inventory counts from the latest in Square.
207
- *
208
- * Helper method, do not open to public.
209
- *
210
- * @since 2.0.0
211
- *
212
- * @throws Framework\SV_WC_API_Exception
213
- */
214
- protected function update_inventory_counts() {
215
-
216
- $products_updated = $this->get_attr( 'processed_product_ids' );
217
- $cursor = $this->get_attr( 'update_inventory_counts_cursor' );
218
-
219
- $args = [
220
- 'location_ids' => [ wc_square()->get_settings_handler()->get_location_id() ],
221
- 'cursor' => $cursor,
222
- ];
223
-
224
- $last_synced_at = $this->get_attr( 'inventory_last_synced_at' );
225
-
226
- if ( $last_synced_at ) {
227
-
228
- $date = new \DateTime();
229
- $date->setTimestamp( $last_synced_at );
230
- $date->setTimezone( new \DateTimeZone( 'UTC' ) );
231
-
232
- $args['updated_after'] = $date->format( DATE_ATOM );
233
- }
234
-
235
- $response = wc_square()->get_api()->batch_retrieve_inventory_counts( $args );
236
-
237
- // store the timestamp after the first API request was completed
238
- // we don't want to set it at the end, as counts may have changed in the time it takes to process the data
239
- // we also check that this is the first or only request to be made (no cursor) so we don't set it again if there's more data to query
240
- if ( ! $cursor ) {
241
- wc_square()->get_sync_handler()->set_inventory_last_synced_at();
242
- }
243
-
244
- foreach ( $response->get_counts() as $count ) {
245
-
246
- // Square can return multiple "types" of counts, WooCommerce only distinguishes whether a product is in stock or not
247
- if ( 'IN_STOCK' === $count->getState() ) {
248
-
249
- $product = Product::get_product_by_square_variation_id( $count->getCatalogObjectId() );
250
-
251
- if ( $product instanceof \WC_Product ) {
252
-
253
- $product->set_stock_quantity( $count->getQuantity() );
254
- $product->save();
255
-
256
- $products_updated[] = $product->get_id();
257
- }
258
- }
259
- }
260
-
261
- $cursor = $response->get_data()->getCursor();
262
-
263
- $this->set_attr( 'update_inventory_counts_cursor', $cursor );
264
- $this->set_attr( 'processed_product_ids', array_unique( $products_updated ) );
265
-
266
- if ( ! $cursor ) {
267
- $this->complete_step( 'update_inventory_counts' );
268
- }
269
- }
270
-
271
-
272
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Job.php DELETED
@@ -1,223 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
- defined( 'ABSPATH' ) or exit;
29
-
30
- /**
31
- * Synchronization Job abstract.
32
- *
33
- * Synchronization jobs should extend this parent method with their own synchronization logic.
34
- * @see \WooCommerce\Square\Handlers\Background_Job main handler should be responsible to set and create all Square background jobs
35
- *
36
- * @since 2.0.0
37
- */
38
- class Job {
39
-
40
-
41
- /** @var \stdClass background job object */
42
- protected $job;
43
-
44
-
45
- /**
46
- * Synchronization job constructor.
47
- *
48
- * @since 2.0.0
49
- *
50
- * @param null|\stdClass $job background synchronization job object
51
- */
52
- public function __construct( $job = null ) {
53
-
54
- if ( null === $job ) {
55
- $job = new \stdClass();
56
- }
57
-
58
- $this->job = $job;
59
- }
60
-
61
-
62
- /**
63
- * Gets an attribute from the underlying job object.
64
- *
65
- * @since 2.0.0
66
- *
67
- * @param string $attr_name the attribute name
68
- * @param mixed $default_value value if attribute is not found
69
- * @return mixed
70
- */
71
- protected function get_attr( $attr_name, $default_value = null ) {
72
-
73
- return isset( $this->job->$attr_name ) ? $this->job->$attr_name : $default_value;
74
- }
75
-
76
-
77
- /**
78
- * Sets an attribute on the underlying job object.
79
- *
80
- * @since 2.0.0
81
- *
82
- * @param string $attr_name the attribute name
83
- * @param mixed $attr_value the attribute value
84
- * @param bool $update whether to update the job object (defaults to true)
85
- */
86
- protected function set_attr( $attr_name, $attr_value, $update = true ) {
87
-
88
- $this->job->$attr_name = $attr_value;
89
-
90
- if ( true === $update ) {
91
- wc_square()->get_background_job_handler()->update_job( $this->job );
92
- }
93
- }
94
-
95
-
96
- /**
97
- * Checks if the job is currently locked.
98
- *
99
- * @since 2.0.0
100
- *
101
- * @return bool
102
- */
103
- protected function is_job_locked() {
104
-
105
- return (bool) $this->get_attr( 'locked' );
106
- }
107
-
108
-
109
- /**
110
- * Locks the job.
111
- *
112
- * @since 2.0.0
113
- */
114
- protected function lock_job() {
115
-
116
- $this->set_attr( 'locked', true );
117
- }
118
-
119
-
120
- /**
121
- * Unlocks the job.
122
- *
123
- * @since 2.0.0
124
- */
125
- protected function unlock_job() {
126
-
127
- $this->set_attr( 'locked', false );
128
- }
129
-
130
-
131
- /**
132
- * Executes the job.
133
- *
134
- * Child implementation should override this method with their own job processing logic.
135
- *
136
- * @since 2.0.0
137
- *
138
- * @return \stdClass the job object
139
- */
140
- public function run() {
141
- wp_set_current_user( $this->get_attr( 'created_by' ) );
142
-
143
- if ( ! defined( 'DOING_SQUARE_SYNC' ) || false === DOING_SQUARE_SYNC ) {
144
- define( 'DOING_SQUARE_SYNC', true );
145
- }
146
-
147
- return $this->job;
148
- }
149
-
150
-
151
- /**
152
- * Completes the job.
153
- *
154
- * @since 2.0.0
155
- *
156
- * @return \stdClass the job object
157
- */
158
- protected function complete() {
159
-
160
- return $this->job = wc_square()->get_background_job_handler()->complete_job( $this->job );
161
- }
162
-
163
-
164
- /**
165
- * Fails the job.
166
- *
167
- * @since 2.0.0
168
- *
169
- * @param string $reason failure reason message (optional)
170
- * @return \stdClass the job object
171
- */
172
- protected function fail( $reason = '' ) {
173
-
174
- if ( ! empty( $reason ) ) {
175
- wc_square()->log( $reason );
176
- }
177
-
178
- return $this->job = wc_square()->get_background_job_handler()->fail_job( $this->job, $reason );
179
- }
180
-
181
-
182
- /**
183
- * Checks if this job uses WooCommerce as the SOR.
184
- *
185
- * @since 2.0.0
186
- *
187
- * @return bool
188
- */
189
- public function is_system_of_record_woocommerce() {
190
-
191
- return 'woocommerce' === $this->get_attr( 'system_of_record' );
192
- }
193
-
194
-
195
- /**
196
- * Checks if this is job uses square as the SOR.
197
- *
198
- * @since 2.0.0
199
- *
200
- * @return bool
201
- */
202
- public function is_system_of_record_square() {
203
-
204
- return 'square' === $this->get_attr( 'system_of_record' );
205
- }
206
-
207
-
208
- /**
209
- * Checks if a sensible time has been exceeded for this request.
210
- *
211
- * Convenience method for accessing the background job handler.
212
- *
213
- * @since 2.0.0
214
- *
215
- * @return bool
216
- */
217
- protected function is_time_exceeded() {
218
-
219
- return wc_square()->get_background_job_handler()->is_time_exceeded();
220
- }
221
-
222
-
223
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Manual_Synchronization.php DELETED
@@ -1,1754 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\BatchRetrieveInventoryCountsResponse;
28
- use SquareConnect\Model\BatchUpsertCatalogObjectsResponse;
29
- use SquareConnect\Model\CatalogObject;
30
- use SquareConnect\Model\CatalogObjectBatch;
31
- use SquareConnect\Model\SearchCatalogObjectsResponse;
32
- use SquareConnect\ObjectSerializer;
33
- use WooCommerce\Square\Handlers\Category;
34
- use WooCommerce\Square\Handlers\Product;
35
-
36
- defined( 'ABSPATH' ) or exit;
37
-
38
- /**
39
- * Class to represent a single synchronization job triggered manually.
40
- *
41
- * @since 2.0.0
42
- */
43
- class Manual_Synchronization extends Stepped_Job {
44
-
45
-
46
- /** @var int the limit for how many objects can be upserted in a batch upsert request */
47
- const BATCH_UPSERT_OBJECT_LIMIT = 600;
48
-
49
- /** @var int the limit for how many inventory changes can be made in a single request */
50
- const BATCH_CHANGE_INVENTORY_LIMIT = 100;
51
-
52
-
53
- /**
54
- * Validates the products attached to this job.
55
- *
56
- * @since 2.0.0
57
- */
58
- protected function validate_products() {
59
-
60
- $product_ids = $this->get_attr( 'product_ids' );
61
-
62
- $products_query = [
63
- 'include' => $product_ids,
64
- 'limit' => -1,
65
- 'return' => 'ids'
66
- ];
67
-
68
- $validated_products = wc_get_products( $products_query );
69
-
70
- if ( 'delete' === $this->get_attr( 'action' ) ) {
71
-
72
- $products_query['status'] = 'trash';
73
- $trashed_products = wc_get_products( $products_query );
74
-
75
- $validated_products = array_unique( array_merge( $validated_products, $trashed_products ), SORT_NUMERIC );
76
- }
77
-
78
- $this->set_attr( 'validated_product_ids', $validated_products );
79
-
80
- $this->complete_step( 'validate_products' );
81
- }
82
-
83
-
84
- /**
85
- * Updates the catalog API limits.
86
- *
87
- * @since 2.0.0
88
- */
89
- protected function update_limits() {
90
-
91
- try {
92
-
93
- $catalog_info = wc_square()->get_api()->catalog_info();
94
-
95
- if ( $catalog_info->get_data() && $catalog_info->get_data()->getLimits() ) {
96
-
97
- $limits = $catalog_info->get_data()->getLimits();
98
-
99
- $this->set_attr( 'max_objects_to_retrieve', $limits->getBatchRetrieveMaxObjectIds() );
100
- $this->set_attr( 'max_objects_per_batch', $limits->getBatchUpsertMaxObjectsPerBatch() );
101
- $this->set_attr( 'max_objects_total', $limits->getBatchUpsertMaxTotalObjects() );
102
- }
103
-
104
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {} // no need to handle errors here
105
-
106
- $this->complete_step( 'update_limits' );
107
- }
108
-
109
-
110
- /**
111
- * Extracts the category IDs from the list of product IDs in this job, and saves them.
112
- *
113
- * @since 2.0.0
114
- */
115
- protected function extract_category_ids() {
116
-
117
- $category_ids = $this->get_shared_category_ids( $this->get_attr( 'validated_product_ids' ) );
118
-
119
- $this->set_attr( 'category_ids', $category_ids );
120
-
121
- $this->complete_step( 'extract_category_ids' );
122
- }
123
-
124
-
125
- /**
126
- * Refreshes mappings for categories with known Square IDs.
127
- *
128
- * @since 2.0.0
129
- *
130
- * @throws Framework\SV_WC_API_Exception
131
- */
132
- protected function refresh_category_mappings() {
133
-
134
- $map = Category::get_map();
135
- $category_ids = $this->get_attr( 'refresh_mappings_category_ids', $this->get_attr( 'category_ids' ) );
136
- $mapped_categories = [];
137
- $unmapped_categories = $this->get_attr( 'unmapped_categories', [] );
138
- $unmapped_category_ids = [];
139
-
140
- if ( empty( $category_ids ) ) {
141
- $this->complete_step( 'refresh_category_mappings' );
142
- return;
143
- }
144
-
145
- if ( count( $category_ids ) > $this->get_max_objects_to_retrieve() ) {
146
-
147
- $category_ids_batch = array_slice( $category_ids, 0, $this->get_max_objects_to_retrieve() );
148
-
149
- $this->set_attr( 'refresh_mappings_category_ids', array_diff( $category_ids, $category_ids_batch ) );
150
-
151
- $category_ids = $category_ids_batch;
152
-
153
- } else {
154
-
155
- $this->set_attr( 'refresh_mappings_category_ids', [] );
156
- }
157
-
158
- foreach ( $category_ids as $category_id ) {
159
-
160
- if ( isset( $map[ $category_id ] ) ) {
161
-
162
- $mapped_categories[ $category_id ] = $map[ $category_id ];
163
-
164
- } else {
165
-
166
- $unmapped_category_ids[] = $category_id;
167
- }
168
- }
169
-
170
- if ( ! empty( $mapped_categories ) ) {
171
-
172
- $square_ids = array_values( array_filter( array_map( function ( $mapped_category ) {
173
- return isset( $mapped_category['square_id'] ) ? $mapped_category['square_id'] : null;
174
- }, $mapped_categories ) ) );
175
-
176
- $response = wc_square()->get_api()->batch_retrieve_catalog_objects( $square_ids );
177
-
178
- // swap the square ID into the array key for quick lookup
179
- $mapped_category_audit = [];
180
-
181
- foreach ( $mapped_categories as $mapped_category_id => $mapped_category ) {
182
- $mapped_category_audit[ $mapped_category['square_id'] ] = $mapped_category_id;
183
- }
184
-
185
- // handle response
186
- if ( is_array( $response->get_data()->getObjects() ) ) {
187
-
188
- foreach ( $response->get_data()->getObjects() as $category ) {
189
-
190
- // don't check for the name, it will get overwritten by the Woo value anyway
191
- if ( isset( $mapped_category_audit[ $category->getId() ] ) ) {
192
-
193
- $category_id = $mapped_category_audit[ $category->getId() ];
194
-
195
- $map[ $category_id ]['version'] = $category->getVersion();
196
- unset( $mapped_category_audit[ $category->getId() ] );
197
- }
198
- }
199
- }
200
-
201
- // any remaining categories were not found in Square and should have their local mapping data removed
202
- if ( ! empty( $mapped_category_audit ) ) {
203
-
204
- $outdated_category_ids = array_values( $mapped_category_audit );
205
-
206
- foreach ( $outdated_category_ids as $outdated_category_id ) {
207
-
208
- unset( $map[ $outdated_category_id ], $mapped_categories[ $outdated_category_id ] );
209
-
210
- $unmapped_category_ids[] = $outdated_category_id;
211
- }
212
-
213
- $unmapped_category_ids = array_unique( $unmapped_category_ids );
214
- }
215
-
216
- // update unmapped list
217
- }
218
-
219
- if ( ! empty( $unmapped_category_ids ) ) {
220
-
221
- $unmapped_category_terms = get_terms( [
222
- 'taxonomy' => 'product_cat',
223
- 'include' => $unmapped_category_ids,
224
- ] );
225
-
226
- // make the 'name' attribute the array key, for more efficient searching later.
227
- foreach ( $unmapped_category_terms as $unmapped_category_term ) {
228
- $unmapped_categories[ strtolower( wp_specialchars_decode( $unmapped_category_term->name ) ) ] = $unmapped_category_term;
229
- }
230
- }
231
-
232
- // save category lists
233
- $this->set_attr( 'mapped_categories', $mapped_categories );
234
- $this->set_attr( 'unmapped_categories', $unmapped_categories );
235
-
236
- Category::update_map( $map );
237
- }
238
-
239
-
240
- /**
241
- * Checks the Square API for any unmapped categories we may have.
242
- *
243
- * @since 2.0.0
244
- *
245
- * @throws Framework\SV_WC_API_Exception
246
- */
247
- protected function query_unmapped_categories() {
248
-
249
- $unmapped_categories = $this->get_attr( 'unmapped_categories', [] );
250
- $mapped_categories = $this->get_attr( 'mapped_categories', [] );
251
-
252
- if ( empty( $unmapped_categories ) ) {
253
-
254
- $this->complete_step( 'query_unmapped_categories' );
255
-
256
- } else {
257
-
258
- $response = wc_square()->get_api()->search_catalog_objects( [
259
- 'object_types' => [ 'CATEGORY' ],
260
- 'cursor' => $this->get_attr( 'unmapped_categories_cursor' ),
261
- ] );
262
-
263
- $category_map = Category::get_map();
264
- $categories = $response->get_data()->getObjects();
265
-
266
- if ( is_array( $categories ) ) {
267
-
268
- foreach ( $categories as $category_object ) {
269
-
270
- $unmapped_category_key = strtolower( $category_object->getCategoryData()->getName() );
271
-
272
- if ( isset( $unmapped_categories[ $unmapped_category_key ] ) ) {
273
-
274
- $category_id = $unmapped_categories[ $unmapped_category_key ]['term_id'];
275
-
276
- $category_map[ $category_id ] = [
277
- 'square_id' => $category_object->getId(),
278
- 'square_version' => $category_object->getVersion(),
279
- ];
280
-
281
- $mapped_categories[] = $category_id;
282
- unset( $unmapped_categories[ $unmapped_category_key ] );
283
- }
284
- }
285
- }
286
-
287
- Category::update_map( $category_map );
288
- $this->set_attr( 'mapped_categories', $mapped_categories );
289
- $this->set_attr( 'unmapped_categories', $unmapped_categories );
290
-
291
- $cursor = $response->get_data()->getCursor();
292
- $this->set_attr( 'unmapped_categories_cursor', $cursor );
293
-
294
- if ( empty( $cursor ) ) {
295
-
296
- $this->complete_step( 'query_unmapped_categories' );
297
- }
298
- }
299
- }
300
-
301
-
302
- /**
303
- * Upserts the categories for the selected products to Square.
304
- *
305
- * @since 2.0.0
306
- *
307
- * @throws Framework\SV_WC_API_Exception
308
- */
309
- protected function upsert_categories() {
310
-
311
- $category_ids = $this->get_attr( 'category_ids' );
312
- $categories = get_terms( [
313
- 'taxonomy' => 'product_cat',
314
- 'include' => $category_ids,
315
- ] );
316
-
317
- $batches = [];
318
- $reverse_map = [];
319
-
320
- // For now, keep it to one category per batch. Since we can still send 1000 batches per request, it's efficient,
321
- // and insulates errors per category rather than a single category error breaking the entire batch it is in.
322
- // TODO: Performance - Consider sending larger-sized batches to reduce total requests for shops with thousands of categories.
323
- // This will require the ability to handle a failed batch, pulling out the error-causing category, and retrying the batch.
324
- foreach ( $categories as $category ) {
325
-
326
- $category_id = $category->term_id;
327
- $square_id = Category::get_square_id( $category_id );
328
- $square_version = Category::get_square_version( $category_id );
329
-
330
- $reverse_map[ $square_id ] = $category_id;
331
-
332
- $catalog_object_data = [
333
- 'type' => 'CATEGORY',
334
- 'id' => $square_id,
335
- 'category_data' => [
336
- 'name' => wp_specialchars_decode( $category->name ), // names are stored encoded in the database
337
- ]
338
- ];
339
-
340
- if ( 0 < $square_version ) {
341
- $catalog_object_data['version'] = $square_version;
342
- }
343
-
344
- $batches[] = new \SquareConnect\Model\CatalogObjectBatch( [ 'objects' => [ new \SquareConnect\Model\CatalogObject( $catalog_object_data ) ] ] );
345
- }
346
-
347
- $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $batches ) . $this->get_attr( 'id' ) ) . '_upsert_categories' );
348
-
349
- $result = wc_square()->get_api()->batch_upsert_catalog_objects( $idempotency_key, $batches );
350
-
351
- // new entries to Square will return in the ID Mapping
352
- if ( $id_mappings = $result->get_data()->getIdMappings() ) {
353
-
354
- foreach ( $id_mappings as $id_mapping ) {
355
-
356
- $client_object_id = $id_mapping->getClientObjectId();
357
- $remote_object_id = $id_mapping->getObjectId();
358
-
359
- if ( isset( $reverse_map[ $client_object_id ] ) ) {
360
-
361
- $reverse_map[ $remote_object_id ] = $reverse_map[ $client_object_id ];
362
- unset( $reverse_map[ $client_object_id ] );
363
- }
364
- }
365
- }
366
-
367
- foreach ( $result->get_data()->getObjects() as $upserted_category ) {
368
-
369
- $id = $upserted_category->getId();
370
- $version = $upserted_category->getVersion();
371
-
372
- if ( isset( $reverse_map[ $id ] ) ) {
373
-
374
- Category::update_mapping( $reverse_map[ $id ], $id, $version );
375
- unset( $reverse_map[ $id ] );
376
- }
377
- }
378
-
379
- $this->complete_step( 'upsert_categories' );
380
- }
381
-
382
-
383
- /**
384
- * Prepares a set of products that already have a Square ID set and are found in the catalog.
385
- *
386
- * @since 2.0.0
387
- *
388
- * @throws Framework\SV_WC_Plugin_Exception
389
- */
390
- protected function prepare_matched_products_for_upsert() {
391
-
392
- $product_ids_to_prepare = $this->get_attr( 'product_ids_to_prepare', $this->get_attr( 'validated_product_ids', [] ) );
393
- $in_progress = $this->get_attr( 'in_progress_prepare_matched_products_for_upsert', [] );
394
-
395
- if ( empty( $product_ids_to_prepare ) ) {
396
- $this->complete_step( 'prepare_matched_products_for_upsert' );
397
- return;
398
- }
399
-
400
- if ( isset( $in_progress['product_ids'] ) && ! empty( $in_progress['product_ids'] ) ) {
401
- $product_ids = $in_progress['product_ids'];
402
- } elseif ( count( $product_ids_to_prepare ) > $this->get_max_objects_to_retrieve() ) {
403
- $product_ids = array_slice( $product_ids_to_prepare, 0, $this->get_max_objects_to_retrieve() );
404
- } else {
405
- $product_ids = $product_ids_to_prepare;
406
- }
407
-
408
- $in_progress['product_ids'] = $product_ids;
409
-
410
- $products_map = Product::get_square_meta( $product_ids, 'square_item_id' );
411
- $square_ids = array_keys( $products_map );
412
-
413
- // none of the products have square IDs - move to the next batch
414
- if ( empty( $square_ids ) ) {
415
- $this->set_attr( 'product_ids_to_prepare', array_diff( $product_ids_to_prepare, $product_ids ) );
416
- return;
417
- }
418
-
419
- if ( $this->is_time_exceeded() ) {
420
- wc_square()->log( 'Time exceeded preparing matched products for upsert' );
421
- $this->set_attr( 'in_progress_prepare_matched_products_for_upsert', $in_progress );
422
- return;
423
- }
424
-
425
- $response = null;
426
-
427
- // attempt to restore the response from the in-progress data
428
- if ( isset( $in_progress['api_response'] ) ) {
429
-
430
- try {
431
-
432
- $objects = [];
433
- $api_response = json_decode( $in_progress['api_response'], true );
434
-
435
- if ( isset( $api_response['objects'] ) ) {
436
- foreach ( $api_response['objects'] as $object ) {
437
- $objects[] = new CatalogObject( $object );
438
- }
439
- }
440
-
441
- $response = new \SquareConnect\Model\BatchRetrieveCatalogObjectsResponse( [ 'objects' => $objects ] );
442
-
443
- } catch ( \Exception $e ) {}
444
- }
445
-
446
- if ( null === $response ) {
447
-
448
- $api_response = wc_square()->get_api()->batch_retrieve_catalog_objects( $square_ids );
449
-
450
- if ( ! $api_response->get_data() ) {
451
- throw new Framework\SV_WC_API_Exception( 'Response data is missing' );
452
- }
453
-
454
- $in_progress['api_response'] = json_encode( json_decode( $api_response->get_data() . '', true ) ); // convert the response to a string and un-pretty-print it
455
- $response = $api_response->get_data();
456
- }
457
-
458
- if ( $this->is_time_exceeded() ) {
459
- $this->set_attr( 'in_progress_prepare_matched_products_for_upsert', $in_progress );
460
- return;
461
- }
462
-
463
- $catalog_objects = isset( $in_progress['catalog_objects'] ) ? $in_progress['catalog_objects'] : [];
464
-
465
- if ( $response && $response_objects = $response->getObjects() ) {
466
-
467
- foreach ( $response_objects as $index => $catalog_object ) {
468
-
469
- if ( $this->is_time_exceeded() ) {
470
-
471
- $response->setObjects( $response_objects );
472
- $in_progress['api_response'] = json_encode( json_decode( $response . '', true ) );
473
- $in_progress['catalog_objects'] = $catalog_objects;
474
-
475
- $this->set_attr( 'in_progress_prepare_matched_products_for_upsert', $in_progress );
476
- return;
477
- }
478
-
479
- if ( ! empty( $products_map[ $catalog_object->getId() ]['product_id'] ) ) {
480
-
481
- $product_id = $products_map[ $catalog_object->getId() ]['product_id'];
482
-
483
- $catalog_objects[ $product_id ] = json_encode( json_decode( $catalog_object . '', true ) ); // convert the object to a string
484
- }
485
-
486
- unset( $response_objects[ $index ] );
487
- }
488
- }
489
-
490
- $matched_products_to_upsert = $this->get_attr( 'matched_products_to_upsert', [] );
491
-
492
- $this->set_attr( 'matched_products_to_upsert', $matched_products_to_upsert + $catalog_objects );
493
- $this->set_attr( 'product_ids_to_prepare', array_diff( $product_ids_to_prepare, $product_ids ) );
494
- $this->set_attr( 'in_progress_prepare_matched_products_for_upsert', [] );
495
- }
496
-
497
-
498
- /**
499
- * Upserts matched products that have been updated with Woo data to Square.
500
- *
501
- * @since 2.0.0
502
- *
503
- * @throws Framework\SV_WC_Plugin_Exception
504
- */
505
- protected function upsert_matched_products() {
506
-
507
- $matched_products_to_upsert = $this->get_attr( 'matched_products_to_upsert', [] );
508
-
509
- if ( empty( $matched_products_to_upsert ) ) {
510
-
511
- $this->complete_step( 'upsert_matched_products' );
512
- return;
513
- }
514
-
515
- // this method ends early in case of timeouts
516
- $result = $this->upsert_catalog_objects( $matched_products_to_upsert );
517
-
518
- if ( isset( $result['processed'] ) ) {
519
-
520
- $processed_product_ids = $this->get_attr( 'processed_product_ids', [] );
521
-
522
- $this->set_attr( 'processed_product_ids', array_merge( $processed_product_ids, $result['processed'] ) );
523
-
524
- $matched_products_to_upsert = array_diff_key( $matched_products_to_upsert, array_flip( $result['processed'] ) );
525
- $this->set_attr( 'matched_products_to_upsert', $matched_products_to_upsert );
526
- }
527
- }
528
-
529
-
530
- /**
531
- * Updates a set of products that already have a Square ID set and are found in the catalog.
532
- *
533
- * @since 2.0.0
534
- *
535
- * @throws Framework\SV_WC_Plugin_Exception
536
- */
537
- protected function update_matched_products() {
538
-
539
- $product_ids = $this->get_attr( 'matched_product_ids', $this->get_attr( 'validated_product_ids', [] ) );
540
- $processed_product_ids = $this->get_attr( 'processed_product_ids', [] );
541
-
542
- // remove IDs that have already been processed
543
- $product_ids = array_diff( $product_ids, $processed_product_ids );
544
-
545
- if ( empty( $product_ids ) ) {
546
-
547
- $this->complete_step( 'update_matched_products' );
548
- return;
549
- }
550
-
551
- if ( count( $product_ids ) > $this->get_max_objects_to_retrieve() ) {
552
-
553
- $product_ids_batch = array_slice( $product_ids, 0, $this->get_max_objects_to_retrieve() );
554
-
555
- $this->set_attr( 'matched_product_ids', array_diff( $product_ids, $product_ids_batch ) );
556
-
557
- $product_ids = $product_ids_batch;
558
-
559
- } else {
560
-
561
- $this->set_attr( 'matched_product_ids', [] );
562
- }
563
-
564
- $products_map = Product::get_square_meta( $product_ids, 'square_item_id' );
565
- $square_ids = array_keys( $products_map );
566
-
567
- if ( empty( $square_ids ) ) {
568
- return;
569
- }
570
-
571
- $response = wc_square()->get_api()->batch_retrieve_catalog_objects( $square_ids );
572
-
573
- if ( ! $response->get_data() ) {
574
- throw new Framework\SV_WC_API_Exception( 'Response data is missing' );
575
- }
576
-
577
- $catalog_objects = [];
578
-
579
- if ( $response->get_data()->getObjects() ) {
580
-
581
- foreach ( $response->get_data()->getObjects() as $catalog_object ) {
582
-
583
- if ( ! empty( $products_map[ $catalog_object->getId() ]['product_id'] ) ) {
584
-
585
- $product_id = $products_map[ $catalog_object->getId() ]['product_id'];
586
-
587
- $catalog_objects[ $product_id ] = $catalog_object;
588
- }
589
- }
590
- }
591
-
592
- if ( ! empty( $catalog_objects ) ) {
593
-
594
- $result = $this->upsert_catalog_objects( $catalog_objects );
595
-
596
- $this->set_attr( 'processed_product_ids', array_merge( $result['processed'], $processed_product_ids ) );
597
-
598
- // any products that were staged but not processed, push to the matched array to try next time
599
- $matched_product_ids = $this->get_attr( 'matched_product_ids', [] );
600
- $this->set_attr( 'matched_product_ids', array_merge( $result['unprocessed'], $matched_product_ids ) );
601
- }
602
- }
603
-
604
-
605
- /**
606
- * Searches the full Square catalog to find matches and updates them.
607
- *
608
- * @since 2.0.0
609
- *
610
- * @throws Framework\SV_WC_Plugin_Exception
611
- */
612
- protected function search_matched_products() {
613
-
614
- $product_ids = $this->get_attr( 'search_product_ids', $this->get_attr( 'validated_product_ids', [] ) );
615
- $processed_product_ids = $this->get_attr( 'processed_product_ids', [] );
616
- $in_progress = $this->get_attr( 'in_progress_search_matched_products', [
617
- 'unprocessed_search_response' => null,
618
- 'processed_remote_object_ids' => [],
619
- 'catalog_objects_to_update' => [],
620
- 'upserting' => false,
621
- ] );
622
-
623
- // remove IDs that have already been processed
624
- $product_ids = array_diff( $product_ids, $processed_product_ids );
625
-
626
- if ( empty( $product_ids ) ) {
627
-
628
- $this->complete_step( 'search_matched_products' );
629
- return;
630
- }
631
-
632
- // at this point nothing has been done, so nothing to save
633
- if ( $this->is_time_exceeded() ) {
634
- wc_square()->log( 'Time exceeded (search_matched_products)' );
635
- return;
636
- }
637
-
638
- $products_map = Product::get_square_meta( $product_ids, 'square_item_id' );
639
-
640
- if ( ! empty( $in_progress['unprocessed_search_response'] ) ) {
641
-
642
- $search_response = ObjectSerializer::deserialize( json_decode( $in_progress['unprocessed_search_response'], false ), SearchCatalogObjectsResponse::class );
643
-
644
- } else {
645
-
646
- $response = wc_square()->get_api()->search_catalog_objects( [
647
- 'cursor' => $this->get_attr( 'search_products_cursor' ),
648
- 'object_types' => [ 'ITEM' ],
649
- 'limit' => $this->get_max_objects_to_retrieve(),
650
- ] );
651
-
652
- $search_response = $response->get_data();
653
-
654
- $in_progress['unprocessed_search_response'] = json_encode( json_decode( $search_response . '', true ) );
655
- }
656
-
657
- if ( ! $search_response ) {
658
- throw new Framework\SV_WC_API_Exception( 'Response data is missing' );
659
- }
660
-
661
- $catalog_objects = $search_response->getObjects() ?: [];
662
- $cursor = $search_response->getCursor();
663
- $catalog_objects_to_update = $in_progress['catalog_objects_to_update'];
664
-
665
- if ( true !== $in_progress['upserting'] ) {
666
-
667
- wc_square()->log( 'Searching through ' . count( $catalog_objects ) . ' catalog objects' );
668
-
669
- foreach ( $catalog_objects as $catalog_object ) {
670
-
671
- if ( $this->is_time_exceeded() ) {
672
-
673
- $this->set_attr( 'in_progress_search_matched_products', $in_progress );
674
- wc_square()->log( 'Time exceeded (search_matched_products)' );
675
-
676
- return;
677
- }
678
-
679
- $remote_object_id = $catalog_object->getId();
680
-
681
- if ( in_array( $remote_object_id, $in_progress['processed_remote_object_ids'], true ) ) {
682
- continue;
683
- }
684
-
685
- if ( isset( $products_map[ $remote_object_id ]['product_id'] ) ) {
686
-
687
- $product_id = $products_map[ $remote_object_id ]['product_id'];
688
-
689
- // update the product's meta
690
- if ( $product = wc_get_product( $product_id ) ) {
691
- Product\Woo_SOR::update_product( $product, $catalog_object );
692
- }
693
-
694
- foreach ( $catalog_object->getItemData()->getVariations() as $catalog_variation ) {
695
-
696
- if ( $variation_product_id = Product::get_product_id_by_square_variation_id( $catalog_variation->getId() ) ) {
697
-
698
- $variation = wc_get_product( $variation_product_id );
699
-
700
- if ( $variation ) {
701
- Product\Woo_SOR::update_variation( $variation, $catalog_variation );
702
- }
703
- }
704
- }
705
-
706
- $catalog_objects_to_update[ $product_id ] = json_encode( json_decode( $catalog_object . '', true ) );
707
-
708
- } else {
709
-
710
- // no variations? no sku
711
- if ( ! is_array( $catalog_object->getItemData()->getVariations() ) ) {
712
- continue;
713
- }
714
-
715
- $product_id = 0;
716
- $matched_object = null;
717
-
718
- foreach ( $catalog_object->getItemData()->getVariations() as $catalog_variation ) {
719
-
720
- $product_id = wc_get_product_id_by_sku( $catalog_variation->getItemVariationData()->getSku() );
721
-
722
- $product = wc_get_product( $product_id );
723
-
724
- if ( ! $product ) {
725
- continue;
726
- }
727
-
728
- if ( $product->get_parent_id() && $parent_product = wc_get_product( $product->get_parent_id() ) ) {
729
- $product = $parent_product;
730
- }
731
-
732
- if ( ! in_array( $product->get_id(), $product_ids, false ) ) {
733
- continue;
734
- }
735
-
736
- $product_id = $product->get_id();
737
- $matched_object = $catalog_object;
738
-
739
- break;
740
- }
741
-
742
- if ( $product_id && $matched_object ) {
743
- $catalog_objects_to_update[ $product_id ] = json_encode( json_decode( $matched_object . '', true ) );
744
- }
745
- }
746
-
747
- $in_progress['processed_remote_object_ids'][] = $remote_object_id;
748
- $in_progress['catalog_objects_to_update'] = $catalog_objects_to_update;
749
- }
750
- }
751
-
752
- $in_progress['upserting'] = true;
753
-
754
- $catalog_processed = ! $cursor;
755
-
756
- $remaining_product_ids = array_diff( $product_ids, array_keys( $catalog_objects_to_update ) );
757
-
758
- if ( ! empty( $catalog_objects_to_update ) ) {
759
-
760
- $result = $this->upsert_catalog_objects( $catalog_objects_to_update );
761
-
762
- $processed_product_ids = array_merge( $result['processed'], $processed_product_ids );
763
- $this->set_attr( 'processed_product_ids', $processed_product_ids );
764
-
765
- if ( ! empty( $result['unprocessed'] ) ) {
766
-
767
- $catalog_processed = false;
768
- $remaining_product_ids = array_merge( $result['unprocessed'], $remaining_product_ids );
769
- $in_progress['catalog_objects_to_update'] = array_diff_key( $catalog_objects_to_update, array_flip( $processed_product_ids ) );
770
-
771
- } else {
772
-
773
- $in_progress = null;
774
- }
775
-
776
- $this->set_attr( 'in_progress_search_matched_products', $in_progress );
777
- }
778
-
779
- if ( ! $catalog_processed && ! empty( $remaining_product_ids ) ) {
780
-
781
- $this->set_attr( 'search_products_cursor', $cursor );
782
- $this->set_attr( 'search_product_ids', $remaining_product_ids );
783
-
784
- } else {
785
-
786
- Product::clear_square_meta( $remaining_product_ids );
787
- $this->complete_step( 'search_matched_products' );
788
- }
789
- }
790
-
791
-
792
- /**
793
- * @throws Framework\SV_WC_Plugin_Exception
794
- */
795
- protected function upsert_new_products() {
796
-
797
- $product_ids = $this->get_attr( 'upsert_new_product_ids', $this->get_attr( 'validated_product_ids', [] ) );
798
- $processed_product_ids = $this->get_attr( 'processed_product_ids', [] );
799
-
800
- // remove IDs that have already been processed
801
- $product_ids = array_diff( $product_ids, $processed_product_ids );
802
-
803
- if ( empty( $product_ids ) ) {
804
-
805
- $this->complete_step( 'upsert_new_products' );
806
- return;
807
- }
808
-
809
- $catalog_objects = [];
810
-
811
- foreach ( $product_ids as $product_id ) {
812
-
813
- $catalog_objects[ $product_id ] = new CatalogObject( [
814
- 'type' => 'ITEM',
815
- 'item_data' => new \SquareConnect\Model\CatalogItem(),
816
- ] );
817
- }
818
-
819
- $result = $this->upsert_catalog_objects( $catalog_objects );
820
-
821
- // newly upserted IDs should get their inventory pushed
822
- $this->set_attr( 'inventory_push_product_ids', $result['processed'] );
823
-
824
- $processed_product_ids = array_merge( $result['processed'], $processed_product_ids );
825
-
826
- $this->set_attr( 'processed_product_ids', $processed_product_ids );
827
-
828
- if ( ! empty( $result['unprocessed'] ) ) {
829
-
830
- $this->set_attr( 'upsert_new_product_ids', $result['unprocessed'] );
831
-
832
- } else {
833
-
834
- // at this point, log a failure for any products that weren't processed
835
- foreach ( array_diff( $product_ids, $processed_product_ids ) as $product_id ) {
836
- Records::set_record( $product_id );
837
- }
838
-
839
- $this->complete_step( 'upsert_new_products' );
840
- }
841
- }
842
-
843
-
844
- /**
845
- * Upserts a list of catalog objects and updates their cooresponding products.
846
- *
847
- * @since 2.0.0
848
- *
849
- * @param array $objects list of catalog objects to update, as $product_id => CatalogItem
850
- * @return array
851
- * @throws Framework\SV_WC_Plugin_Exception
852
- */
853
- protected function upsert_catalog_objects( array $objects ) {
854
-
855
- wc_square()->log( 'Upserting ' . count( $objects ) . ' catalog objects' );
856
-
857
- $is_delete_action = 'delete' === $this->get_attr( 'action' );
858
- $product_ids = array_keys( $objects );
859
- $staged_product_ids = [];
860
- $successful_product_ids = [];
861
- $total_object_count = 0;
862
- $batches = [];
863
- $result = [
864
- 'processed' => [],
865
- 'unprocessed' => $product_ids,
866
- ];
867
-
868
- $in_progress = $this->get_attr( 'in_progress_upsert_catalog_objects', [
869
- 'batches' => [],
870
- 'staged_product_ids' => [],
871
- 'total_object_count' => null,
872
- 'unprocessed_upsert_response' => null,
873
- 'mapped_client_item_ids' => [],
874
- 'processed_remote_catalog_item_ids' => []
875
- ] );
876
-
877
- if ( null === $in_progress['unprocessed_upsert_response'] ) {
878
-
879
- // need all three items to restore from in-progress
880
- if ( ! empty( $in_progress['batches'] ) && ! empty( $in_progress['staged_product_ids'] ) && ! empty( $in_progress['total_object_count'] ) ) {
881
-
882
- $staged_product_ids = $in_progress['staged_product_ids'];
883
- $total_object_count = $in_progress['total_object_count'];
884
- $batches = array_map( static function ( $batch_data ) {
885
- return ObjectSerializer::deserialize( json_decode( $batch_data, false ), CatalogObjectBatch::class );
886
- }, $in_progress['batches'] );
887
- }
888
-
889
- foreach ( $objects as $product_id => $object ) {
890
-
891
- if ( $this->is_time_exceeded() ) {
892
-
893
- $in_progress['staged_product_ids'] = $staged_product_ids;
894
- $in_progress['total_object_count'] = $total_object_count;
895
- $in_progress['batches'] = array_map( 'strval', $batches );
896
-
897
- $this->set_attr( 'in_progress_upsert_catalog_objects', $in_progress );
898
- wc_square()->log( 'Time exceeded (upsert_catalog_objects)' );
899
-
900
- return $result;
901
- }
902
-
903
- if ( in_array( $product_id, $staged_product_ids, true ) ) {
904
- continue;
905
- }
906
-
907
- if ( ! $object instanceof CatalogObject ) {
908
- $object = $this->convert_to_catalog_object( $object );
909
- }
910
-
911
- $catalog_item = new Catalog_Item( $product_id, $is_delete_action );
912
- $batch = $catalog_item->get_batch( $object );
913
- $object_count = $catalog_item->get_batch_object_count();
914
-
915
- if ( $this->get_max_objects_total() >= $object_count + $total_object_count ) {
916
- $batches[] = $batch;
917
- $total_object_count += $object_count;
918
- $staged_product_ids[] = $product_id;
919
- } else {
920
- break;
921
- }
922
- }
923
- }
924
-
925
- $upsert_response = null;
926
-
927
- if ( null !== $in_progress['unprocessed_upsert_response'] ) {
928
- $upsert_response = ObjectSerializer::deserialize( json_decode( $in_progress['unprocessed_upsert_response'], false ), BatchUpsertCatalogObjectsResponse::class );
929
- }
930
-
931
- if ( ! $upsert_response instanceof BatchUpsertCatalogObjectsResponse ) {
932
-
933
- $start = microtime( true );
934
-
935
- $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $batches ) ) . '_upsert_products' );
936
- $response = wc_square()->get_api()->batch_upsert_catalog_objects( $idempotency_key, $batches );
937
- $upsert_response = $response->get_data();
938
-
939
- if ( ! $upsert_response instanceof BatchUpsertCatalogObjectsResponse ) {
940
- throw new Framework\SV_WC_API_Exception( 'API response data is missing' );
941
- }
942
-
943
- $duration = number_format( microtime( true ) - $start, 2 );
944
-
945
- wc_square()->log( 'Upserted ' . count( $upsert_response->getObjects() ) . ' objects in ' . $duration . 's' );
946
-
947
- $in_progress['unprocessed_upsert_response'] = $response->get_data() . '';
948
- }
949
-
950
- if ( $this->is_time_exceeded() ) {
951
-
952
- $this->set_attr( 'in_progress_upsert_catalog_objects', $in_progress );
953
- wc_square()->log( 'Time exceeded (upsert_catalog_objects)' );
954
-
955
- return $result;
956
- }
957
-
958
- // update local square meta for newly upserted objects
959
- if ( ! $is_delete_action && $upsert_response instanceof BatchUpsertCatalogObjectsResponse && is_array( $upsert_response->getIdMappings() ) ) {
960
-
961
- wc_square()->log( 'Mapping new Square item IDs to WooCommerce product IDs' );
962
-
963
- $start = microtime( true );
964
-
965
- foreach ( $upsert_response->getIdMappings() as $id_mapping ) {
966
-
967
- if ( $this->is_time_exceeded() ) {
968
-
969
- $this->set_attr( 'in_progress_upsert_catalog_objects', $in_progress );
970
- wc_square()->log( 'Time exceeded (upsert_catalog_objects)' );
971
-
972
- return $result;
973
- }
974
-
975
- $client_item_id = $id_mapping->getClientObjectId();
976
- $remote_item_id = $id_mapping->getObjectId();
977
-
978
- if ( in_array( $client_item_id, $in_progress['mapped_client_item_ids'], true ) ) {
979
- continue;
980
- }
981
-
982
- if ( 0 === strpos( $client_item_id, '#item_variation_' ) ) {
983
-
984
- $product_id = substr( $client_item_id, strlen( '#item_variation_' ) );
985
- Product::set_square_item_variation_id( $product_id, $remote_item_id );
986
-
987
- } elseif ( 0 === strpos( $client_item_id, '#item_' ) ) {
988
-
989
- $product_id = substr( $client_item_id, strlen( '#item_' ) );
990
- Product::set_square_item_id( $product_id, $remote_item_id );
991
- }
992
-
993
- $in_progress['mapped_client_item_ids'][] = $client_item_id;
994
- }
995
-
996
- $duration = number_format( microtime( true ) - $start, 2 );
997
-
998
- wc_square()->log( 'Mapped ' . count( $in_progress['mapped_client_item_ids'] ) . ' Square IDs in ' . $duration . 's' );
999
- }
1000
-
1001
- $pull_inventory_variation_ids = $this->get_attr( 'pull_inventory_variation_ids', [] );
1002
-
1003
- wc_square()->log( 'Storing Square item data to WooCommerce products' );
1004
-
1005
- $start = microtime( true );
1006
-
1007
- // loop through all returned objects and store their IDs to Woo products
1008
- foreach ( $upsert_response->getObjects() as $remote_catalog_item ) {
1009
-
1010
- if ( $this->is_time_exceeded() ) {
1011
-
1012
- $this->set_attr( 'in_progress_upsert_catalog_objects', $in_progress );
1013
- wc_square()->log( 'Time exceeded (upsert_catalog_objects)' );
1014
-
1015
- return $result;
1016
- }
1017
-
1018
- $remote_item_id = $remote_catalog_item->getId();
1019
-
1020
- if ( in_array( $remote_item_id, $in_progress['processed_remote_catalog_item_ids'], true ) ) {
1021
- continue;
1022
- }
1023
-
1024
- $product = Product::get_product_by_square_id( $remote_item_id );
1025
-
1026
- if ( ! $product ) {
1027
- $in_progress['processed_remote_catalog_item_ids'][] = $remote_item_id;
1028
- continue;
1029
- }
1030
-
1031
- Product::update_square_meta( $product, [
1032
- 'item_id' => $remote_item_id,
1033
- 'item_version' => $remote_catalog_item->getVersion(),
1034
- 'item_image_id' => $remote_catalog_item->getImageId(),
1035
- ] );
1036
-
1037
- $successful_product_ids[] = $product->get_id();
1038
-
1039
- if ( is_array( $remote_catalog_item->getItemData()->getVariations() ) ) {
1040
-
1041
- foreach ( $remote_catalog_item->getItemData()->getVariations() as $catalog_item_variation ) {
1042
-
1043
- if ( $product_variation = Product::get_product_by_square_variation_id( $catalog_item_variation->getId() ) ) {
1044
-
1045
- $pull_inventory_variation_ids[] = $catalog_item_variation->getId();
1046
-
1047
- Product::update_square_meta( $product_variation, [
1048
- 'item_variation_id' => $catalog_item_variation->getId(),
1049
- 'item_variation_version' => $catalog_item_variation->getVersion(),
1050
- ] );
1051
- }
1052
- }
1053
- }
1054
-
1055
- if ( $this->is_time_exceeded() ) {
1056
-
1057
- $this->set_attr( 'in_progress_upsert_catalog_objects', $in_progress );
1058
- wc_square()->log( 'Time exceeded (upsert_catalog_objects)' );
1059
-
1060
- return $result;
1061
- }
1062
-
1063
- // there is no batch image endpoint
1064
- $this->push_product_image( $product );
1065
-
1066
- $in_progress['processed_remote_catalog_item_ids'][] = $remote_item_id;
1067
-
1068
- $result['processed'][] = $product->get_id();
1069
- $result['unprocessed'] = array_diff( $product_ids, $result['processed'] );
1070
- }
1071
-
1072
- $this->set_attr( 'pull_inventory_variation_ids', $pull_inventory_variation_ids );
1073
-
1074
- $duration = number_format( microtime( true ) - $start, 2 );
1075
-
1076
- wc_square()->log( 'Stored Square data to ' . count( $result['processed'] ) . ' products in ' . $duration . 's' );
1077
-
1078
- // log any failed products
1079
- foreach ( array_diff( $staged_product_ids, $successful_product_ids ) as $product_id ) {
1080
-
1081
- Records::set_record( [
1082
- 'type' => 'alert',
1083
- 'product_id' => $product_id,
1084
- 'message' => sprintf(
1085
- /* translators: Placeholder: %s - product ID */
1086
- esc_html__( 'Product %s could not be updated in Square.', 'woocommerce-square' ),
1087
- '<a href="' . esc_url( get_edit_post_link( $product_id ) ) . '">' . $product_id . '</a>'
1088
- ),
1089
- ] );
1090
- }
1091
-
1092
- $this->set_attr( 'in_progress_upsert_catalog_objects', null );
1093
-
1094
- $result['processed'] = $staged_product_ids;
1095
- $result['unprocessed'] = array_diff( $product_ids, $staged_product_ids );
1096
-
1097
- return $result;
1098
- }
1099
-
1100
-
1101
- /**
1102
- * Converts object data to an instance of CatalogObject.
1103
- *
1104
- * @since 2.0.0
1105
- *
1106
- * @param array|string $object_data json string or array of object data
1107
- * @return CatalogObject
1108
- */
1109
- protected function convert_to_catalog_object( $object_data ) {
1110
-
1111
- if ( is_string( $object_data ) ) {
1112
- $object_data = json_decode( $object_data, false );
1113
- }
1114
-
1115
- $object = ObjectSerializer::deserialize( $object_data, CatalogObject::class );
1116
-
1117
- return $object instanceof CatalogObject ? $object : null;
1118
- }
1119
-
1120
-
1121
- /**
1122
- * Pushes a product's image to Square.
1123
- *
1124
- * @since 2.0.0
1125
- *
1126
- * @param \WC_Product|int $product product object or ID
1127
- */
1128
- protected function push_product_image( $product ) {
1129
-
1130
- $product = wc_get_product( $product );
1131
-
1132
- if ( ! $product instanceof \WC_Product || ! $product->get_image_id() ) {
1133
- return;
1134
- }
1135
-
1136
- $local_image_id = $product->get_image_id();
1137
-
1138
- // if there is no image, or if the latest uploaded image is the same
1139
- if ( ! $local_image_id || $local_image_id == $product->get_meta( '_square_uploaded_image_id' ) ) {
1140
- return;
1141
- }
1142
-
1143
- if ( $image_path = get_attached_file( $local_image_id ) ) {
1144
-
1145
- try {
1146
-
1147
- $image_id = wc_square()->get_api()->create_image( $image_path, Product::get_square_item_id( $product ), $product->get_name() );
1148
-
1149
- Product::set_square_image_id( $product, $image_id );
1150
-
1151
- // record the WC image ID that was uploaded
1152
- $product->update_meta_data( '_square_uploaded_image_id', $local_image_id );
1153
- $product->save_meta_data();
1154
-
1155
- } catch ( Framework\SV_WC_API_Exception $exception ) {
1156
-
1157
- if ( wc_square()->get_settings_handler()->is_debug_enabled() ) {
1158
- wc_square()->log( 'Could not upload image for product #' . $product->get_id() . ': ' . $exception->getMessage() );
1159
- }
1160
- }
1161
- }
1162
- }
1163
-
1164
-
1165
- /**
1166
- * Pushes WooCommerce inventory to Square for synced items.
1167
- *
1168
- * @since 2.0.0
1169
- *
1170
- * @throws Framework\SV_WC_Plugin_Exception
1171
- */
1172
- protected function push_inventory() {
1173
-
1174
- $product_ids = $this->get_attr( 'inventory_push_product_ids', [] );
1175
- $inventory_changes = [];
1176
- $inventory_change_count = 0;
1177
-
1178
- foreach ( $product_ids as $key => $product_id ) {
1179
-
1180
- $product = wc_get_product( $product_id );
1181
-
1182
- if ( $product instanceof \WC_Product ) {
1183
-
1184
- $product_inventory_changes = [];
1185
-
1186
- if ( $product->is_type( 'variable' ) && $product->has_child() ) {
1187
-
1188
- foreach ( $product->get_children() as $child_id ) {
1189
-
1190
- $child = wc_get_product( $child_id );
1191
-
1192
- if ( $child instanceof \WC_Product && $inventory_change = Product::get_inventory_change_physical_count_type( $child ) ) {
1193
-
1194
- $product_inventory_changes[] = $inventory_change;
1195
- }
1196
- }
1197
-
1198
- } elseif ( $square_variation_id = Product::get_square_item_variation_id( $product_id, false ) ) {
1199
-
1200
- if ( $inventory_change = Product::get_inventory_change_physical_count_type( $product ) ) {
1201
-
1202
- $product_inventory_changes[] = $inventory_change;
1203
- }
1204
- }
1205
-
1206
- if ( self::BATCH_CHANGE_INVENTORY_LIMIT >= $inventory_change_count + count( $product_inventory_changes ) ) {
1207
-
1208
- $inventory_changes[] = $product_inventory_changes;
1209
- $inventory_change_count += count( $product_inventory_changes );
1210
- unset( $product_ids[ $key ] );
1211
-
1212
- } else {
1213
-
1214
- break;
1215
- }
1216
-
1217
- } else {
1218
-
1219
- unset( $product_ids[ $key ] );
1220
- }
1221
- }
1222
-
1223
- if ( ! empty( $inventory_changes ) ) {
1224
-
1225
- $inventory_changes = array_merge( ...$inventory_changes );
1226
- $idempotency_key = wc_square()->get_idempotency_key( md5( serialize( $inventory_changes ) ) . '_change_inventory' );
1227
- $result = wc_square()->get_api()->batch_change_inventory( $idempotency_key, $inventory_changes );
1228
- }
1229
-
1230
- $this->set_attr( 'inventory_push_product_ids', $product_ids );
1231
-
1232
- if ( empty( $product_ids ) ) {
1233
-
1234
- $this->complete_step( 'push_inventory' );
1235
- }
1236
- }
1237
-
1238
-
1239
- /**
1240
- * Performs a sync when Square is the system of record.
1241
- *
1242
- * @since 2.0.0
1243
- */
1244
- protected function square_sor_sync() {
1245
-
1246
- $synced_product_ids = $this->get_attr( 'validated_product_ids', [] );
1247
- $processed_product_ids = $this->get_attr( 'processed_product_ids', [] );
1248
- $unprocessed_product_ids = array_diff( $synced_product_ids, $processed_product_ids );
1249
- $catalog_processed = $this->get_attr( 'catalog_processed', false );
1250
-
1251
- if ( $catalog_processed ) {
1252
-
1253
- wc_square()->log( 'Square catalog fully processed' );
1254
-
1255
- if ( ! empty( $unprocessed_product_ids ) ) {
1256
- $this->mark_failed_products( $unprocessed_product_ids );
1257
- }
1258
-
1259
- $this->complete_step( 'square_sor_sync' );
1260
- return;
1261
- }
1262
-
1263
- try {
1264
-
1265
- $response_data = $this->get_attr( 'catalog_objects_search_response_data', null );
1266
-
1267
- if ( ! $response_data ) {
1268
-
1269
- wc_square()->log( 'Generating a new catalog search request' );
1270
-
1271
- $cursor = $this->get_attr( 'square_sor_cursor' );
1272
-
1273
- $response = wc_square()->get_api()->search_catalog_objects( [
1274
- 'cursor' => $cursor,
1275
- 'object_types' => [ 'ITEM' ],
1276
- 'include_related_objects' => true,
1277
- 'limit' => $this->get_max_objects_to_retrieve(),
1278
- ] );
1279
-
1280
- $response_data = $response->get_data();
1281
-
1282
- $this->set_attr( 'catalog_objects_search_response_data', $response_data . '' );
1283
-
1284
- } else {
1285
-
1286
- $response_data = ObjectSerializer::deserialize( json_decode( $response_data, false ), SearchCatalogObjectsResponse::class );
1287
- }
1288
-
1289
- if ( ! $response_data instanceof SearchCatalogObjectsResponse ) {
1290
- throw new Framework\SV_WC_API_Exception( 'API response data is missing' );
1291
- }
1292
-
1293
- $cursor = $response_data->getCursor();
1294
- $this->set_attr( 'square_sor_cursor', $cursor );
1295
-
1296
- $catalog_processed = ! $cursor;
1297
- $this->set_attr( 'catalog_processed', $catalog_processed );
1298
-
1299
- // bail early and fail for any API and plugin errors
1300
- } catch ( \Exception $exception ) {
1301
-
1302
- $this->fail( 'Product sync failed. ' . $exception->getMessage() );
1303
- return;
1304
- }
1305
-
1306
- $related_objects = $response->get_data()->getRelatedObjects();
1307
-
1308
- if ( $related_objects && is_array( $related_objects ) ) {
1309
- // first import any related categories
1310
- foreach ( $related_objects as $related_object ) {
1311
- if ( 'CATEGORY' === $related_object->getType() ) {
1312
- Category::import_or_update( $related_object );
1313
- }
1314
- }
1315
- }
1316
-
1317
- $pull_inventory_variation_ids = $this->get_attr( 'pull_inventory_variation_ids', [] );
1318
-
1319
- /** @var \SquareConnect\Model\CatalogObject[] */
1320
- $catalog_objects = $products_to_update = [];
1321
-
1322
- wc_square()->log( 'Searching for products in ' . count( $response_data->getObjects() ) . ' Square objects' );
1323
-
1324
- foreach ( $response_data->getObjects() as $object ) {
1325
-
1326
- $found_product = null;
1327
-
1328
- if ( ! $object instanceof CatalogObject ) {
1329
- continue;
1330
- }
1331
-
1332
- // filter out objects that aren't at our configured location
1333
- if ( ! $object->getPresentAtAllLocations() && ( ! is_array( $object->getPresentAtLocationIds() ) || ! in_array( wc_square()->get_settings_handler()->get_location_id(), $object->getPresentAtLocationIds(), true ) ) ) {
1334
- continue;
1335
- }
1336
-
1337
- // even simple items have a single variation
1338
- if ( ! is_array( $object->getItemData()->getVariations() ) ) {
1339
- continue;
1340
- }
1341
-
1342
- foreach ( $object->getItemData()->getVariations() as $variation ) {
1343
-
1344
- $found_product_id = wc_get_product_id_by_sku( $variation->getItemVariationData()->getSku() );
1345
-
1346
- // bail if this product has already been processed
1347
- if ( in_array( $found_product_id, $processed_product_ids, false ) ) {
1348
- break;
1349
- }
1350
-
1351
- $found_product = wc_get_product( $found_product_id );
1352
-
1353
- if ( ! $found_product ) {
1354
- continue;
1355
- }
1356
-
1357
- if ( $found_product instanceof \WC_Product_Variation ) {
1358
-
1359
- $found_variation = $found_product;
1360
- $found_parent_id = $found_product->get_parent_id() ?: 0;
1361
- $found_product = null;
1362
-
1363
- // bail if this parent product has already been processed
1364
- if ( in_array( $found_parent_id, $processed_product_ids, false ) ) {
1365
- break;
1366
- }
1367
-
1368
- $found_parent = wc_get_product( $found_parent_id );
1369
-
1370
- if ( $found_parent ) {
1371
-
1372
- Product::set_square_item_variation_id( $found_variation, $variation->getId() );
1373
-
1374
- $found_product = $found_parent;
1375
- }
1376
-
1377
- break;
1378
-
1379
- } else {
1380
-
1381
- Product::set_square_item_variation_id( $found_product, $variation->getId() );
1382
- }
1383
- }
1384
-
1385
- if ( $found_product && in_array( $found_product->get_id(), $synced_product_ids, false ) ) {
1386
-
1387
- Product::set_square_item_id( $found_product, $object->getId() );
1388
-
1389
- $products_to_update[] = $found_product;
1390
-
1391
- $catalog_objects[ $found_product->get_id() ] = $object;
1392
- }
1393
- }
1394
-
1395
- wc_square()->log( 'Found ' . count( $products_to_update ) . ' products with matching SKUs' );
1396
-
1397
- // Square SOR always gets the latest inventory
1398
- // set this before processing so nothing is missed during processing
1399
- wc_square()->get_sync_handler()->set_inventory_last_synced_at();
1400
-
1401
- foreach ( $products_to_update as $product ) {
1402
-
1403
- try {
1404
-
1405
- $square_object = ! empty( $catalog_objects[ $product->get_id() ] ) ? $catalog_objects[ $product->get_id() ] : null;
1406
-
1407
- // if no Square object was found, log as a failure
1408
- if ( ! $square_object ) {
1409
- throw new Framework\SV_WC_Plugin_Exception( 'Product does not exist in the Square catalog' );
1410
- }
1411
-
1412
- foreach ( $square_object->getItemData()->getVariations() as $variation ) {
1413
- $pull_inventory_variation_ids[] = $variation->getId();
1414
- }
1415
-
1416
- Product::update_from_square( $product, $square_object->getItemData(), false );
1417
-
1418
- if ( ! $product->get_image_id() && $square_object->getImageId() ) {
1419
- Product::update_image_from_square( $product, $square_object->getImageId() );
1420
- }
1421
-
1422
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
1423
-
1424
- $this->mark_failed_products( [ $product ] );
1425
- }
1426
-
1427
- $processed_product_ids[] = $product->get_id();
1428
- }
1429
-
1430
- $this->set_attr( 'catalog_objects_search_response_data', null );
1431
-
1432
- $this->set_attr( 'pull_inventory_variation_ids', $pull_inventory_variation_ids );
1433
-
1434
- $this->set_attr( 'processed_product_ids', $processed_product_ids );
1435
- }
1436
-
1437
-
1438
- /**
1439
- * Pulls the latest inventory counts for the variation IDs in `pull_inventory_variation_ids`.
1440
- *
1441
- * @since 2.0.2
1442
- *
1443
- * @throws Framework\SV_WC_Plugin_Exception
1444
- */
1445
- protected function pull_inventory() {
1446
-
1447
- $processed_ids = $this->get_attr( 'processed_square_variation_ids', [] );
1448
-
1449
- $in_progress = wp_parse_args( $this->get_attr( 'in_progress_pull_inventory', [] ), [
1450
- 'response_data' => null,
1451
- 'processed_variation_ids' => [],
1452
- ] );
1453
-
1454
- $response_data = null;
1455
-
1456
- // if a response was never cleared, we likely had a timeout
1457
- if ( null !== $in_progress['response_data'] ) {
1458
- $response_data = ObjectSerializer::deserialize( json_decode( $in_progress['response_data'], false ), BatchRetrieveInventoryCountsResponse::class );
1459
- }
1460
-
1461
- // if the saved response was somehow corrupted, start over
1462
- if ( ! $response_data instanceof BatchRetrieveInventoryCountsResponse ) {
1463
-
1464
- $square_variation_ids = $this->get_attr( 'pull_inventory_variation_ids', [] );
1465
-
1466
- // remove IDs that have already been processed
1467
- $square_variation_ids = array_diff( $square_variation_ids, $processed_ids );
1468
-
1469
- if ( empty( $square_variation_ids ) ) {
1470
-
1471
- $this->complete_step( 'pull_inventory' );
1472
- return;
1473
- }
1474
-
1475
- if ( count( $square_variation_ids ) > 100 ) {
1476
-
1477
- $variation_ids_batch = array_slice( $square_variation_ids, 0, 100 );
1478
-
1479
- $this->set_attr( 'pull_inventory_variation_ids', array_diff( $square_variation_ids, $variation_ids_batch ) );
1480
-
1481
- $square_variation_ids = $variation_ids_batch;
1482
- }
1483
-
1484
- $response = wc_square()->get_api()->batch_retrieve_inventory_counts( [
1485
- 'catalog_object_ids' => array_values( $square_variation_ids ),
1486
- 'location_ids' => [ wc_square()->get_settings_handler()->get_location_id() ],
1487
- ] );
1488
-
1489
- if ( ! $response->get_data() instanceof BatchRetrieveInventoryCountsResponse ) {
1490
- throw new Framework\SV_WC_Plugin_Exception( 'Response data missing or invalid' );
1491
- }
1492
-
1493
- $response_data = $response->get_data();
1494
-
1495
- // if no counts were returned, there's nothing to process
1496
- if ( ! is_array( $response_data->getCounts() ) ) {
1497
-
1498
- $this->set_attr( 'processed_square_variation_ids', array_merge( $processed_ids, $square_variation_ids ) );
1499
- return;
1500
- }
1501
-
1502
- $in_progress['response_data'] = $response_data . '';
1503
- }
1504
-
1505
- foreach ( $response_data->getCounts() as $count ) {
1506
-
1507
- if ( in_array( $count->getCatalogObjectId(), $in_progress['processed_variation_ids'], false ) ) {
1508
- continue;
1509
- }
1510
-
1511
- if ( $this->is_time_exceeded() ) {
1512
-
1513
- $this->set_attr( 'in_progress_pull_inventory', $in_progress );
1514
-
1515
- wc_square()->log( 'Time exceeded (pull_inventory)' );
1516
- return;
1517
- }
1518
-
1519
- // Square can return multiple "types" of counts, WooCommerce only distinguishes whether a product is in stock or not
1520
- if ( 'IN_STOCK' === $count->getState() ) {
1521
-
1522
- $product = Product::get_product_by_square_variation_id( $count->getCatalogObjectId() );
1523
-
1524
- if ( $product instanceof \WC_Product ) {
1525
- $product->set_manage_stock( true );
1526
- $product->set_stock_quantity( $count->getQuantity() );
1527
- $product->save();
1528
- }
1529
- }
1530
-
1531
- $in_progress['processed_variation_ids'][] = $count->getCatalogObjectId();
1532
-
1533
- $this->set_attr( 'in_progress_pull_inventory', $in_progress );
1534
- }
1535
-
1536
- $this->set_attr( 'processed_square_variation_ids', array_merge( $processed_ids, $in_progress['processed_variation_ids'] ) );
1537
-
1538
- // clear any in-progress data
1539
- $this->set_attr( 'in_progress_pull_inventory', [] );
1540
- }
1541
-
1542
- /**
1543
- * Marks a set of products as failed to sync.
1544
- *
1545
- * @since 2.0.0
1546
- *
1547
- * @param \WC_Product[]|int[] $products products to mark as failed
1548
- */
1549
- protected function mark_failed_products( $products = [] ) {
1550
-
1551
- foreach ( $products as $product ) {
1552
-
1553
- $product = wc_get_product( $product );
1554
-
1555
- if ( ! $product instanceof \WC_Product ) {
1556
- continue;
1557
- }
1558
-
1559
- $record_data = [
1560
- 'type' => 'alert',
1561
- 'product_id' => $product->get_id(),
1562
- ];
1563
-
1564
- // optionally hide unmatched products from catalog
1565
- if ( wc_square()->get_settings_handler()->is_system_of_record_square() && wc_square()->get_settings_handler()->hide_missing_square_products() ) {
1566
-
1567
- try {
1568
-
1569
- $product->set_catalog_visibility( 'hidden' );
1570
- $product->save();
1571
-
1572
- $record_data['product_hidden'] = true;
1573
-
1574
- } catch ( \Exception $e ) {}
1575
- }
1576
-
1577
- Records::set_record( $record_data );
1578
- }
1579
- }
1580
-
1581
-
1582
- /**
1583
- * Gets a list of unique category IDs used by a group of product IDs.
1584
- *
1585
- * @since 2.0.0
1586
- *
1587
- * @param int[] $product_ids array of product IDs
1588
- * @return int[]
1589
- */
1590
- protected function get_shared_category_ids( $product_ids ) {
1591
- global $wpdb;
1592
-
1593
- if ( ! empty( $product_ids ) ) {
1594
-
1595
- $term_ids = $wpdb->get_col( " SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE taxonomy = 'product_cat' " );
1596
- $term_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $term_ids ) ) ) . ')';
1597
- $post_in = '(' . implode( ',', array_map( 'absint', array_merge( [ 0 ], $product_ids ) ) ) . ')';
1598
- $category_ids = $wpdb->get_results( "
1599
- SELECT term_taxonomy_id
1600
- FROM $wpdb->term_relationships
1601
- WHERE object_id IN $post_in
1602
- AND term_taxonomy_id IN $term_in
1603
- ", ARRAY_N );
1604
- }
1605
-
1606
- return ! empty( $category_ids ) ? array_unique( array_map( 'absint', array_merge( ...$category_ids ) ) ) : [];
1607
- }
1608
-
1609
-
1610
- /**
1611
- * Assigns the next steps needed for this sync job.
1612
- *
1613
- * @since 2.0.0
1614
- */
1615
- protected function assign_next_steps() {
1616
-
1617
- $next_steps = [];
1618
-
1619
- if ( $this->is_system_of_record_woocommerce() ) {
1620
-
1621
- if ( 'delete' === $this->get_attr( 'action' ) ) {
1622
-
1623
- $next_steps = [
1624
- 'validate_products',
1625
- 'update_matched_products',
1626
- 'search_matched_products',
1627
- ];
1628
-
1629
- } else {
1630
-
1631
- $next_steps = [
1632
- 'validate_products',
1633
- 'extract_category_ids',
1634
- 'refresh_category_mappings',
1635
- 'query_unmapped_categories',
1636
- 'upsert_categories',
1637
- 'update_matched_products',
1638
- 'search_matched_products',
1639
- 'upsert_new_products',
1640
- ];
1641
-
1642
- // only handle product inventory if enabled
1643
- if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
1644
- $next_steps[] = 'push_inventory';
1645
- $next_steps[] = 'pull_inventory';
1646
- }
1647
- }
1648
-
1649
- } elseif ( $this->is_system_of_record_square() ) {
1650
-
1651
- $next_steps = [
1652
- 'validate_products',
1653
- 'square_sor_sync',
1654
- ];
1655
-
1656
- // only pull product inventory if enabled
1657
- if ( wc_square()->get_settings_handler()->is_inventory_sync_enabled() ) {
1658
- $next_steps[] = 'pull_inventory';
1659
- }
1660
- }
1661
-
1662
- $this->set_attr( 'next_steps', $next_steps );
1663
- }
1664
-
1665
-
1666
- /**
1667
- * Gets the maximum number of objects to retrieve in a single sync job.
1668
- *
1669
- * @since 2.0.0
1670
- *
1671
- * @return int
1672
- */
1673
- protected function get_max_objects_to_retrieve() {
1674
-
1675
- $max = $this->get_attr( 'max_objects_to_retrieve', 300 );
1676
-
1677
- /**
1678
- * Filters the maximum number of objects to retrieve in a single sync job.
1679
- *
1680
- * @since 2.0.0
1681
- *
1682
- * $param int $max
1683
- */
1684
- return max( 1, (int) apply_filters( 'wc_square_sync_max_objects_to_retrieve', $max ) );
1685
- }
1686
-
1687
-
1688
- /**
1689
- * Gets the maximum number of objects per batch in a single sync job.
1690
- *
1691
- * @since 2.0.0
1692
- *
1693
- * @return int
1694
- */
1695
- protected function get_max_objects_per_batch() {
1696
-
1697
- $max = $this->get_attr( 'max_objects_per_batch', 1000 );
1698
-
1699
- /**
1700
- * Filters the maximum number of objects per batch in a single sync job.
1701
- *
1702
- * @since 2.0.0
1703
- *
1704
- * $param int $max
1705
- */
1706
- return max( 10, (int) apply_filters( 'wc_square_sync_max_objects_per_batch', $max ) );
1707
- }
1708
-
1709
-
1710
- /**
1711
- * Gets the maximum number of objects per batch upsert in a single request.
1712
- *
1713
- * @since 2.0.0
1714
- *
1715
- * @return int
1716
- */
1717
- protected function get_max_objects_per_upsert() {
1718
-
1719
- $max = $this->get_attr( 'max_objects_per_upsert', 5000 );
1720
-
1721
- /**
1722
- * Filters the maximum number of objects per upsert in a single request.
1723
- *
1724
- * @since 2.0.0
1725
- *
1726
- * $param int $max
1727
- */
1728
- return max( 1, (int) apply_filters( 'wc_square_sync_max_objects_per_upsert', $max ) );
1729
- }
1730
-
1731
-
1732
- /**
1733
- * Gets the maximum number of objects allowed in a single sync job.
1734
- *
1735
- * @since 2.0.0
1736
- *
1737
- * @return int
1738
- */
1739
- protected function get_max_objects_total() {
1740
-
1741
- $max = $this->get_attr( 'max_objects_total', self::BATCH_UPSERT_OBJECT_LIMIT );
1742
-
1743
- /**
1744
- * Filters the maximum number of objects allowed in a single sync job.
1745
- *
1746
- * @since 2.0.0
1747
- *
1748
- * $param int $max
1749
- */
1750
- return max( 1, (int) apply_filters( 'wc_square_sync_max_objects_total', $max ) );
1751
- }
1752
-
1753
-
1754
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Product_Import.php DELETED
@@ -1,1141 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
- use SquareConnect\Model\SearchCatalogObjectsResponse;
28
- use WooCommerce\Square\Handlers\Category;
29
- use WooCommerce\Square\Handlers\Product;
30
- use WooCommerce\Square\Sync\Records\Record;
31
- use WooCommerce\Square\Utilities\Money_Utility;
32
-
33
- defined( 'ABSPATH' ) or exit;
34
-
35
- /**
36
- * Class to represent a synchronization job to import products from Square.
37
- *
38
- * @since 2.0.0
39
- */
40
- class Product_Import extends Stepped_Job {
41
-
42
-
43
- protected function assign_next_steps() {
44
-
45
- $this->set_attr( 'next_steps', [
46
- 'import_products',
47
- 'import_inventory',
48
- ] );
49
- }
50
-
51
-
52
- /**
53
- * Gets the limit for how many items to import per request.
54
- *
55
- * Square has a hard maximum for this at 1000, but 100 seems to be a sane
56
- * default to allow for creating products without timing out.
57
- *
58
- * @since 2.0.0
59
- *
60
- * @return int
61
- */
62
- protected function get_import_api_limit() {
63
-
64
- /**
65
- * Filters the number of items to import from the Square API per request.
66
- *
67
- * @since 2.0.0
68
- *
69
- * @param int limit
70
- */
71
- $limit = (int) apply_filters( 'wc_square_import_api_limit', 100 );
72
-
73
- return max( 1, min( 1000, $limit ) );
74
- }
75
-
76
-
77
- /**
78
- * Performs a product import.
79
- *
80
- * @since 2.0.0
81
- *
82
- * @throws Framework\SV_WC_Plugin_Exception
83
- */
84
- protected function import_products() {
85
-
86
- $products_imported = $this->get_attr( 'processed_product_ids', [] );
87
- $cursor = $this->get_attr( 'fetch_products_cursor' );
88
- $skipped_products = $this->get_attr( 'skipped_products', [] );
89
-
90
- $response = wc_square()->get_api()->search_catalog_objects( [
91
- 'cursor' => $cursor,
92
- 'object_types' => [ 'ITEM' ],
93
- 'include_related_objects' => true,
94
- 'limit' => $this->get_import_api_limit(),
95
- ] );
96
-
97
- $related_objects = $response->get_data()->getRelatedObjects();
98
-
99
- if ( $related_objects && is_array( $related_objects ) ) {
100
-
101
- // first import any related categories
102
- foreach ( $related_objects as $related_object ) {
103
-
104
- if ( 'CATEGORY' === $related_object->getType() ) {
105
-
106
- Category::import_or_update( $related_object );
107
- }
108
- }
109
- }
110
-
111
- $catalog_objects = $response->get_data()->getObjects();
112
- $time_exceeded = false;
113
-
114
- foreach ( $catalog_objects as $catalog_object_index => $catalog_object ) {
115
-
116
- if ( $this->is_time_exceeded() ) {
117
-
118
- $time_exceeded = true;
119
- break;
120
- }
121
-
122
- $item_id = $catalog_object->getId();
123
-
124
- // ignore items not available at our location
125
- if ( ! $catalog_object->getPresentAtAllLocations() && ( ! is_array( $catalog_object->getPresentAtLocationIds() ) || ! in_array( wc_square()->get_settings_handler()->get_location_id(), $catalog_object->getPresentAtLocationIds(), true ) ) ) {
126
-
127
- $skipped_products[ $item_id ] = null;
128
- continue;
129
- }
130
-
131
- // if we have a match for this item ID, skip it - it will already be synced
132
- if ( $product_id = Product::get_product_id_by_square_id( $item_id ) ) {
133
-
134
- $skipped_products[ $item_id ] = null;
135
- continue;
136
- }
137
-
138
- // look in variation SKUs for a match - if so, skip the parent item, a normal sync should link it automatically
139
- if ( $this->item_variation_has_matching_sku( $catalog_object ) ) {
140
- continue;
141
- }
142
-
143
- $product_id = $this->import_product( $catalog_object );
144
-
145
- if ( $product_id ) {
146
-
147
- Product::set_synced_with_square( $product_id );
148
-
149
- $products_imported[] = $product_id;
150
- }
151
- }
152
-
153
- if ( $time_exceeded ) {
154
-
155
- wc_square()->log( '[Time Exceeded] Imported Products Count: ' . count( $products_imported ) );
156
-
157
- } else {
158
-
159
- wc_square()->log( 'Imported Products Count: ' . count( $products_imported ) );
160
-
161
- $cursor = $response->get_data()->getCursor();
162
- $this->set_attr( 'fetch_products_cursor', $cursor );
163
-
164
- if ( ! $cursor ) {
165
-
166
- $this->complete_step( 'import_products' );
167
- }
168
- }
169
-
170
- $this->set_attr( 'skipped_products', $skipped_products );
171
- $this->set_attr( 'processed_product_ids', $products_imported );
172
- }
173
-
174
-
175
- /**
176
- * Imports inventory counts for all the tracked Square products.
177
- *
178
- * @since 2.0.0
179
- *
180
- * @throws Framework\SV_WC_Plugin_Exception
181
- */
182
- protected function import_inventory() {
183
-
184
- $search_result = wc_square()->get_api()->search_catalog_objects( [
185
- 'object_types' => [ 'ITEM_VARIATION' ],
186
- 'limit' => 100,
187
- 'cursor' => $this->get_attr( 'import_inventory_cursor', null ),
188
- ] );
189
-
190
- $cursor = $search_result->get_data()->getCursor();
191
- $variation_ids = array_map( static function( \SquareConnect\Model\CatalogObject $catalog_object ) {
192
-
193
- return $catalog_object->getId();
194
-
195
- }, $search_result->get_data()->getObjects() );
196
-
197
- $result = wc_square()->get_api()->batch_retrieve_inventory_counts( [
198
- 'catalog_object_ids' => $variation_ids,
199
- 'location_ids' => [ wc_square()->get_settings_handler()->get_location_id() ],
200
- ] );
201
-
202
- foreach ( $result->get_counts() as $inventory_count ) {
203
-
204
- // all inventory should be tied to a variation, but check here just in case
205
- if ( 'ITEM_VARIATION' === $inventory_count->getCatalogObjectType() ) {
206
-
207
- $product = Product::get_product_by_square_variation_id( $inventory_count->getCatalogObjectId() );
208
-
209
- if ( $product && $product instanceof \WC_Product ) {
210
-
211
- $product->set_stock_quantity( $inventory_count->getQuantity() );
212
- $product->save();
213
- }
214
- }
215
- }
216
-
217
- $this->set_attr( 'import_inventory_cursor', $cursor );
218
-
219
- if ( ! $cursor ) {
220
-
221
- $this->complete_step( 'import_inventory' );
222
- }
223
- }
224
-
225
-
226
- /**
227
- * Determines whether a SKU within a catalog item is found in WooCommerce.
228
- *
229
- * @since 2.0.0
230
- *
231
- * @param \SquareConnect\Model\CatalogObject $catalog_object the catalog object
232
- * @return bool
233
- */
234
- private function item_variation_has_matching_sku( $catalog_object ) {
235
-
236
- foreach ( $catalog_object->getItemData()->getVariations() as $variation ) {
237
-
238
- if ( wc_get_product_id_by_sku( $variation->getItemVariationData()->getSku() ) ) {
239
-
240
- return true;
241
- }
242
- }
243
-
244
- return false;
245
- }
246
-
247
-
248
- /**
249
- * Creates a product from a catalog object.
250
- *
251
- * @since 2.0.0
252
- *
253
- * @param \SquareConnect\Model\CatalogObject $catalog_object the catalog object
254
- * @return int|null
255
- */
256
- private function import_product( $catalog_object ) {
257
-
258
- $product_id = 0;
259
-
260
- try {
261
-
262
- // validate permissions
263
- if ( ! current_user_can( 'publish_products' ) ) {
264
- throw new Framework\SV_WC_Plugin_Exception( __( 'You do not have permission to create products', 'woocommerce-square' ) );
265
- }
266
-
267
- // sanity check for valid API data
268
- if ( ! $catalog_object instanceof \SquareConnect\Model\CatalogObject || ! $catalog_object->getItemData() instanceof \SquareConnect\Model\CatalogItem ) {
269
- throw new Framework\SV_WC_Plugin_Exception( __( 'Invalid data', 'woocommerce-square' ) );
270
- }
271
-
272
- $data = $this->extract_product_data( $catalog_object );
273
-
274
- /**
275
- * Filters the data that is used to create a new WooCommerce product during import.
276
- *
277
- * @since 2.0.0
278
- *
279
- * @param array $data product data
280
- * @param \SquareConnect\Model\CatalogObject $catalog_object the catalog object from the Square API
281
- * @param Product_Import $this import class instance
282
- */
283
- $data = apply_filters( 'woocommerce_square_create_product_data', $data, $catalog_object, $this );
284
-
285
- // validate title field
286
- if ( ! isset( $data['title'] ) ) {
287
- throw new Framework\SV_WC_Plugin_Exception( sprintf( __( 'Missing parameter %s', 'woocommerce-square' ), 'title' ) );
288
- }
289
-
290
- // set default type
291
- if ( ! isset( $data['type'] ) ) {
292
- $data['type'] = 'simple';
293
- }
294
-
295
- // set default catalog_visibility
296
- if ( ! isset( $data['catalog_visibility'] ) ) {
297
- $data['catalog_visibility'] = 'visible';
298
- }
299
-
300
- // validate type
301
- if ( ! array_key_exists( wc_clean( $data['type'] ), wc_get_product_types() ) ) {
302
- throw new Framework\SV_WC_Plugin_Exception( sprintf( __( 'Invalid product type - the product type must be any of these: %s', 'woocommerce-square' ), implode( ', ', array_keys( wc_get_product_types() ) ) ) );
303
- }
304
-
305
- // set description
306
- $post_content = isset( $data['description'] ) ? wc_clean( $data['description'] ) : '';
307
- if ( $post_content && isset( $data['enable_html_description'] ) && true === $data['enable_html_description'] ) {
308
-
309
- $post_content = $data['description'];
310
- }
311
-
312
- $new_product = [
313
- 'post_title' => wc_clean( $data['title'] ),
314
- 'post_status' => isset( $data['status'] ) ? wc_clean( $data['status'] ) : 'publish',
315
- 'post_type' => 'product',
316
- 'post_content' => isset( $data['description'] ) ? $post_content : '',
317
- 'post_author' => get_current_user_id(),
318
- 'menu_order' => isset( $data['menu_order'] ) ? (int) $data['menu_order'] : 0,
319
- ];
320
-
321
- if ( ! empty( $data['name'] ) ) {
322
- $new_product = array_merge( $new_product, [ 'post_name' => sanitize_title( $data['name'] ) ] );
323
- }
324
-
325
- // attempt to create the new product
326
- $product_id = wp_insert_post( $new_product, true );
327
-
328
- if ( is_wp_error( $product_id ) ) {
329
- throw new Framework\SV_WC_Plugin_Exception( $product_id->get_error_message() );
330
- }
331
-
332
- // save product meta fields
333
- $this->save_product_meta( $product_id, $data );
334
-
335
- // save the image, if included
336
- if ( ! empty( $data['image_id'] ) ) {
337
- Product::update_image_from_square( $product_id, $data['image_id'] );
338
- }
339
-
340
- // save variations
341
- if ( 'variable' === $data['type'] && is_array( $data['variations'] ) && isset( $data['type'], $data['variations'] ) ) {
342
-
343
- $this->save_variations( $product_id, $data );
344
- }
345
-
346
- /**
347
- * Fired when a product is created from a square product import.
348
- *
349
- * @since 2.0.0
350
- *
351
- * @param int $product_id the product ID that was created
352
- * @param array $data the data used to create the product
353
- */
354
- do_action( 'woocommerce_square_create_product', $product_id, $data );
355
-
356
- // clear cache/transients
357
- wc_delete_product_transients( $product_id );
358
-
359
- } catch ( Framework\SV_WC_Plugin_Exception $e ) {
360
-
361
- if ( $catalog_object instanceof \SquareConnect\Model\CatalogObject && $catalog_object->getItemData() instanceof \SquareConnect\Model\CatalogItem ) {
362
-
363
- $message = sprintf(
364
- /* translators: Placeholders: %1$s - Square item name, %2$s - failure reason */
365
- __( 'Could not import "%1$s" from Square. %2$s', 'woocommerce-square' ),
366
- $catalog_object->getItemData()->getName(),
367
- $e->getMessage()
368
- );
369
-
370
- // use a generic alert for invalid data
371
- } else {
372
-
373
- $message = sprintf(
374
- /* translators: Placeholders: %s - failure reason */
375
- __( 'Could not import item from Square. %s', 'woocommerce-square' ),
376
- $e->getMessage()
377
- );
378
- }
379
-
380
- // alert for failed product imports
381
- Records::set_record( [
382
- 'type' => 'alert',
383
- 'message' => $message,
384
- ] );
385
-
386
- wc_square()->log( 'Error creating product during import: ' . $e->getMessage() );
387
-
388
- // remove the product when creation fails
389
- $this->clear_product( $product_id );
390
- $product_id = 0;
391
- }
392
-
393
- return $product_id;
394
- }
395
-
396
-
397
- /**
398
- * Extracts product data from a CatalogObject to an array of data.
399
- *
400
- * @since 2.0.0
401
- *
402
- * @param \SquareConnect\Model\CatalogObject $catalog_object the catalog object
403
- * @return array|null
404
- * @throws Framework\SV_WC_Plugin_Exception
405
- */
406
- protected function extract_product_data( $catalog_object ) {
407
-
408
- $variations = $catalog_object->getItemData()->getVariations();
409
-
410
- // if there are no variations, something is wrong - every catalog item has at least one
411
- if ( 0 >= count( $variations ) ) {
412
- return null;
413
- }
414
-
415
- $category_id = Category::get_category_id_by_square_id( $catalog_object->getItemData()->getCategoryId() );
416
-
417
- $data = [
418
- 'title' => $catalog_object->getItemData()->getName(),
419
- 'type' => 1 === count( $variations ) ? 'simple' : 'variable',
420
- 'description' => $catalog_object->getItemData()->getDescription(),
421
- 'image_id' => $catalog_object->getImageId(),
422
- 'categories' => [ $category_id ],
423
- 'square_meta' => [
424
- 'item_id' => $catalog_object->getId(),
425
- 'item_version' => $catalog_object->getVersion(),
426
- ],
427
- ];
428
-
429
- // variable product
430
- if ( 1 < count( $variations ) ) {
431
-
432
- $data['type'] = 'variable';
433
- $data['variations'] = [];
434
-
435
- foreach ( $variations as $variation ) {
436
-
437
- // sanity check for valid API data
438
- if ( ! $variation instanceof \SquareConnect\Model\CatalogObject || ! $variation->getItemVariationData() instanceof \SquareConnect\Model\CatalogItemVariation ) {
439
- continue;
440
- }
441
-
442
- try {
443
-
444
- $data['variations'][] = $this->extract_square_item_variation_data( $variation );
445
-
446
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
447
-
448
- // alert for failed variation imports
449
- Records::set_record( [
450
- 'type' => 'alert',
451
- 'message' => sprintf(
452
- /* translators: Placeholders: %1$s - Square item name, %2$s - Square item variation name, %3$s - failure reason */
453
- __( 'Could not import "%1$s - %2$s" from Square. %3$s', 'woocommerce-square' ),
454
- $catalog_object->getItemData()->getName(),
455
- $variation->getItemVariationData()->getName(),
456
- $exception->getMessage()
457
- ),
458
- ] );
459
- }
460
- }
461
-
462
- $data['attributes'] = [ [
463
- 'name' => 'Attribute',
464
- 'slug' => 'attribute',
465
- 'position' => 0,
466
- 'visible' => true,
467
- 'variation' => true,
468
- 'options' => wp_list_pluck( $data['variations'], 'name' ),
469
- ] ];
470
-
471
- // simple product
472
- } else {
473
-
474
- $variation = $this->extract_square_item_variation_data( $variations[0] );
475
-
476
- $data['type'] = 'simple';
477
- $data['sku'] = $variation['sku'] ?: null;
478
- $data['regular_price'] = $variation['regular_price'] ?: null;
479
- $data['stock_quantity'] = $variation['stock_quantity'] ?: null;
480
- $data['managing_stock'] = $variation['managing_stock'] ?: null;
481
-
482
- $data['square_meta']['item_variation_id'] = $variation['square_meta']['item_variation_id'] ?: null;
483
- $data['square_meta']['item_variation_version'] = $variation['square_meta']['item_variation_version'] ?: null;
484
- }
485
-
486
- return $data;
487
- }
488
-
489
-
490
- /**
491
- * Extracts data from a CatalogItemVariation for insertion into a WC product.
492
- *
493
- * @since 2.0.0
494
- *
495
- * @param \SquareConnect\Model\CatalogObject $variation the variation object
496
- * @return array
497
- * @throws Framework\SV_WC_Plugin_Exception
498
- */
499
- protected function extract_square_item_variation_data( $variation ) {
500
-
501
- $variation_data = $variation->getItemVariationData();
502
-
503
- if ( 'VARIABLE_PRICING' === $variation_data->getPricingType() ) {
504
- throw new Framework\SV_WC_Plugin_Exception( __( 'Items with variable pricing cannot be imported.', 'woocommerce-square' ) );
505
- }
506
-
507
- $data = [
508
- 'name' => $variation_data->getName() ?: '',
509
- 'sku' => $variation_data->getSku() ?: '',
510
- 'regular_price' => $variation_data->getPriceMoney() && $variation_data->getPriceMoney()->getAmount() ? Money_Utility::cents_to_float( $variation->getItemVariationData()->getPriceMoney()->getAmount() ) : null,
511
- 'stock_quantity' => null,
512
- 'managing_stock' => true,
513
- 'square_meta' => [
514
- 'item_variation_id' => $variation->getId(),
515
- 'item_variation_version' => $variation->getVersion(),
516
- ],
517
- 'attributes' => [
518
- [
519
- 'name' => 'Attribute',
520
- 'is_variation' => true,
521
- 'option' => $variation_data->getName() ?: '',
522
- ],
523
- ],
524
- ];
525
-
526
- return $data;
527
- }
528
-
529
-
530
- protected function save_product_images( $product_id, $images ) {}
531
-
532
-
533
- protected function upload_product_image( $src ) {}
534
-
535
-
536
- protected function set_product_image_as_attachment( $upload, $product_id ) {}
537
-
538
-
539
- /**
540
- * Saves product meta data for a given product.
541
- *
542
- * @since 2.0.0
543
- *
544
- * @param int $product_id the product ID
545
- * @param array $data the product data
546
- * @return bool
547
- * @throws Framework\SV_WC_Plugin_Exception
548
- */
549
- protected function save_product_meta( $product_id, $data ) {
550
-
551
- // product type
552
- $product_type = null;
553
-
554
- if ( isset( $data['type'] ) ) {
555
-
556
- $product_type = wc_clean( $data['type'] );
557
-
558
- wp_set_object_terms( $product_id, $product_type, 'product_type' );
559
-
560
- } else {
561
-
562
- $_product_type = get_the_terms( $product_id, 'product_type' );
563
-
564
- if ( is_array( $_product_type ) ) {
565
-
566
- $_product_type = current( $_product_type );
567
- $product_type = $_product_type->slug;
568
- }
569
- }
570
-
571
- // default total sales
572
- add_post_meta( $product_id, 'total_sales', '0', true );
573
-
574
- // catalog visibility
575
- if ( isset( $data['catalog_visibility'] ) ) {
576
-
577
- update_post_meta( $product_id, '_visibility', wc_clean( $data['catalog_visibility'] ) );
578
- }
579
-
580
- // sku
581
- if ( isset( $data['sku'] ) ) {
582
-
583
- $sku = get_post_meta( $product_id, '_sku', true );
584
- $new_sku = wc_clean( $data['sku'] );
585
-
586
- if ( '' === $new_sku ) {
587
-
588
- update_post_meta( $product_id, '_sku', '' );
589
-
590
- } elseif ( $new_sku !== $sku ) {
591
-
592
- if ( ! empty( $new_sku ) ) {
593
-
594
- $unique_sku = wc_product_has_unique_sku( $product_id, $new_sku );
595
-
596
- if ( $unique_sku ) {
597
-
598
- update_post_meta( $product_id, '_sku', $new_sku );
599
-
600
- } else {
601
-
602
- throw new Framework\SV_WC_Plugin_Exception( __( 'The SKU already exists on another product', 'woocommerce-square' ) );
603
- }
604
-
605
- } else {
606
-
607
- update_post_meta( $product_id, '_sku', '' );
608
- }
609
- }
610
- }
611
-
612
- // attributes
613
- if ( isset( $data['attributes'] ) ) {
614
-
615
- $attributes = [];
616
-
617
- foreach ( $data['attributes'] as $attribute ) {
618
-
619
- $is_taxonomy = 0;
620
- $taxonomy = 0;
621
-
622
- if ( ! isset( $attribute['name'] ) ) {
623
- continue;
624
- }
625
-
626
- $attribute_slug = sanitize_title( $attribute['name'] );
627
-
628
- if ( isset( $attribute['slug'] ) ) {
629
-
630
- $taxonomy = $this->get_attribute_taxonomy_by_slug( $attribute['slug'] );
631
- $attribute_slug = sanitize_title( $attribute['slug'] );
632
- }
633
-
634
- if ( $taxonomy ) {
635
-
636
- $is_taxonomy = 1;
637
- }
638
-
639
- if ( $is_taxonomy ) {
640
-
641
- if ( isset( $attribute['options'] ) ) {
642
-
643
- $options = $attribute['options'];
644
-
645
- if ( ! is_array( $attribute['options'] ) ) {
646
-
647
- // text based attributes - Posted values are term names
648
- $options = explode( WC_DELIMITER, $options );
649
- }
650
-
651
- $values = array_map( 'wc_sanitize_term_text_based', $options );
652
- $values = array_filter( $values, 'strlen' );
653
-
654
- } else {
655
-
656
- $values = [];
657
- }
658
-
659
- // update post terms
660
- if ( taxonomy_exists( $taxonomy ) ) {
661
-
662
- wp_set_object_terms( $product_id, $values, $taxonomy );
663
- }
664
-
665
- if ( ! empty( $values ) ) {
666
-
667
- // add attribute to array, but don't set values
668
- $attributes[ $taxonomy ] = [
669
- 'name' => $taxonomy,
670
- 'value' => '',
671
- 'position' => isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0',
672
- 'is_visible' => ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0,
673
- 'is_variation' => ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0,
674
- 'is_taxonomy' => $is_taxonomy,
675
- ];
676
- }
677
-
678
- } elseif ( isset( $attribute['options'] ) ) {
679
-
680
- // array based
681
- if ( is_array( $attribute['options'] ) ) {
682
-
683
- $values = implode( ' ' . WC_DELIMITER . ' ', array_map( 'wc_clean', $attribute['options'] ) );
684
-
685
- } else {
686
-
687
- $values = implode( ' ' . WC_DELIMITER . ' ', array_map( 'wc_clean', explode( WC_DELIMITER, $attribute['options'] ) ) );
688
- }
689
-
690
- // custom attribute - add attribute to array and set the values
691
- $attributes[ $attribute_slug ] = [
692
- 'name' => wc_clean( $attribute['name'] ),
693
- 'value' => $values,
694
- 'position' => isset( $attribute['position'] ) ? (string) absint( $attribute['position'] ) : '0',
695
- 'is_visible' => ( isset( $attribute['visible'] ) && $attribute['visible'] ) ? 1 : 0,
696
- 'is_variation' => ( isset( $attribute['variation'] ) && $attribute['variation'] ) ? 1 : 0,
697
- 'is_taxonomy' => $is_taxonomy,
698
- ];
699
- }
700
- }
701
-
702
- uasort( $attributes, 'wc_product_attribute_uasort_comparison' );
703
-
704
- update_post_meta( $product_id, '_product_attributes', $attributes );
705
- }
706
-
707
- // sales and prices
708
- if ( in_array( $product_type, [ 'variable', 'grouped' ] ) ) {
709
-
710
- // variable and grouped products have no prices
711
- update_post_meta( $product_id, '_regular_price', '' );
712
- update_post_meta( $product_id, '_sale_price', '' );
713
- update_post_meta( $product_id, '_sale_price_dates_from', '' );
714
- update_post_meta( $product_id, '_sale_price_dates_to', '' );
715
- update_post_meta( $product_id, '_price', '' );
716
-
717
- } else {
718
-
719
- $this->wc_save_product_price( $product_id, $data['regular_price'] );
720
- }
721
-
722
- // product categories
723
- if ( isset( $data['categories'] ) && is_array( $data['categories'] ) ) {
724
-
725
- $term_ids = array_unique( array_map( 'intval', $data['categories'] ) );
726
-
727
- wp_set_object_terms( $product_id, $term_ids, 'product_cat' );
728
- }
729
-
730
- // square item id
731
- if ( isset( $data['square_meta']['item_id'] ) ) {
732
- Product::set_square_item_id( $product_id, $data['square_meta']['item_id'] );
733
- }
734
-
735
- // square item version
736
- if ( isset( $data['square_meta']['item_version'] ) ) {
737
- Product::set_square_version( $product_id, $data['square_meta']['item_version'] );
738
- }
739
-
740
- // square item variation id
741
- if ( isset( $data['square_meta']['item_variation_id'] ) ) {
742
- Product::set_square_item_variation_id( $product_id, $data['square_meta']['item_variation_id'] );
743
- }
744
-
745
- // square item variation version
746
- if ( isset( $data['square_meta']['item_variation_version'] ) ) {
747
- Product::set_square_variation_version( $product_id, $data['square_meta']['item_variation_version'] );
748
- }
749
-
750
- /**
751
- * Fires after processing product meta for a product imported from Square.
752
- *
753
- * @since 2.0.0
754
- *
755
- * @param int $product_id the product ID
756
- * @param array $data the product data
757
- */
758
- do_action( 'woocommerce_square_process_product_meta_' . $product_type, $product_id, $data );
759
-
760
- return true;
761
- }
762
-
763
-
764
- /**
765
- * Saves the variations for a given product.
766
- *
767
- * @since 2.0.0
768
- *
769
- * @param int $product_id the product ID
770
- * @param array $data the product data, including a 'variations' key
771
- * @return bool
772
- * @throws Framework\SV_WC_Plugin_Exception
773
- */
774
- protected function save_variations( $product_id, $data ) {
775
- global $wpdb;
776
-
777
- $variations = $data['variations'];
778
- $attributes = (array) maybe_unserialize( get_post_meta( $product_id, '_product_attributes', true ) );
779
-
780
- foreach ( $variations as $menu_order => $variation ) {
781
-
782
- $variation_id = isset( $variation['id'] ) ? absint( $variation['id'] ) : 0;
783
-
784
- if ( ! $variation_id && isset( $variation['sku'] ) ) {
785
-
786
- $variation_sku = wc_clean( $variation['sku'] );
787
- $variation_id = wc_get_product_id_by_sku( $variation_sku );
788
- }
789
-
790
- $variation_post_title = sprintf( __( 'Variation #%1$s of %2$s', 'woocommerce-square' ), $variation_id, esc_html( get_the_title( $product_id ) ) );
791
-
792
- // update or add post
793
- if ( ! $variation_id ) {
794
-
795
- $post_status = ( isset( $variation['visible'] ) && false === $variation['visible'] ) ? 'private' : 'publish';
796
- $new_variation = [
797
- 'post_title' => $variation_post_title,
798
- 'post_content' => '',
799
- 'post_status' => $post_status,
800
- 'post_author' => get_current_user_id(),
801
- 'post_parent' => $product_id,
802
- 'post_type' => 'product_variation',
803
- 'menu_order' => $menu_order,
804
- ];
805
-
806
- $variation_id = wp_insert_post( $new_variation );
807
-
808
- /**
809
- * Fired after creating a product variation during an import from Square.
810
- *
811
- * @since 2.0.0
812
- *
813
- * @param int $variation_id the new variation ID
814
- */
815
- do_action( 'woocommerce_square_create_product_variation', $variation_id );
816
-
817
- } else {
818
-
819
- $update_variation = [ 'post_title' => $variation_post_title, 'menu_order' => $menu_order ];
820
-
821
- if ( isset( $variation['visible'] ) ) {
822
-
823
- $post_status = ( false === $variation['visible'] ) ? 'private' : 'publish';
824
-
825
- $update_variation['post_status'] = $post_status;
826
- }
827
-
828
- $wpdb->update( $wpdb->posts, $update_variation, [ 'ID' => $variation_id ] );
829
-
830
- /**
831
- * Fired after updating a product variation during an import from Square.
832
- *
833
- * @since 2.0.0
834
- *
835
- * @param int $variation_id the updated variation ID
836
- */
837
- do_action( 'woocommerce_square_update_product_variation', $variation_id );
838
- }
839
-
840
- // stop if we don't have a variation ID
841
- if ( is_wp_error( $variation_id ) ) {
842
-
843
- throw new Framework\SV_WC_Plugin_Exception( $variation_id->get_error_message() );
844
- }
845
-
846
- // SKU
847
- if ( isset( $variation['sku'] ) ) {
848
-
849
- $sku = get_post_meta( $variation_id, '_sku', true );
850
- $new_sku = wc_clean( $variation['sku'] );
851
-
852
- if ( '' === $new_sku ) {
853
-
854
- update_post_meta( $variation_id, '_sku', '' );
855
-
856
- } elseif ( $new_sku !== $sku ) {
857
-
858
- if ( ! empty( $new_sku ) ) {
859
-
860
- if ( wc_product_has_unique_sku( $variation_id, $new_sku ) ) {
861
-
862
- update_post_meta( $variation_id, '_sku', $new_sku );
863
-
864
- } else {
865
-
866
- throw new Framework\SV_WC_Plugin_Exception( __( 'The SKU already exists on another product', 'woocommerce-square' ) );
867
- }
868
-
869
- } else {
870
-
871
- update_post_meta( $variation_id, '_sku', '' );
872
- }
873
- }
874
- }
875
-
876
- update_post_meta( $variation_id, '_manage_stock', 'yes' );
877
-
878
- $this->wc_save_product_price( $variation_id, $variation['regular_price'] );
879
-
880
- update_post_meta( $variation_id, '_download_limit', '' );
881
- update_post_meta( $variation_id, '_download_expiry', '' );
882
- update_post_meta( $variation_id, '_downloadable_files', '' );
883
-
884
- // description
885
- if ( isset( $variation['description'] ) ) {
886
- update_post_meta( $variation_id, '_variation_description', wp_kses_post( $variation['description'] ) );
887
- }
888
-
889
- // update taxonomies
890
- if ( isset( $variation['attributes'] ) ) {
891
-
892
- $updated_attribute_keys = [];
893
-
894
- foreach ( $variation['attributes'] as $attribute_key => $attribute ) {
895
-
896
- if ( ! isset( $attribute['name'] ) ) {
897
- continue;
898
- }
899
-
900
- $taxonomy = 0;
901
- $_attribute = [];
902
-
903
- if ( isset( $attribute['slug'] ) ) {
904
-
905
- $taxonomy = $this->get_attribute_taxonomy_by_slug( $attribute['slug'] );
906
- }
907
-
908
- if ( ! $taxonomy ) {
909
-
910
- $taxonomy = sanitize_title( $attribute['name'] );
911
- }
912
-
913
- if ( isset( $attributes[ $taxonomy ] ) ) {
914
-
915
- $_attribute = $attributes[ $taxonomy ];
916
- }
917
-
918
- if ( isset( $_attribute['is_variation'] ) && $_attribute['is_variation'] ) {
919
-
920
- $_attribute_key = 'attribute_' . sanitize_title( $_attribute['name'] );
921
- $updated_attribute_keys[] = $_attribute_key;
922
-
923
- if ( isset( $_attribute['is_taxonomy'] ) && $_attribute['is_taxonomy'] ) {
924
-
925
- // Don't use wc_clean as it destroys sanitized characters
926
- $_attribute_value = isset( $attribute['option'] ) ? sanitize_title( stripslashes( $attribute['option'] ) ) : '';
927
-
928
- } else {
929
-
930
- $_attribute_value = isset( $attribute['option'] ) ? wc_clean( stripslashes( $attribute['option'] ) ) : '';
931
- }
932
-
933
- update_post_meta( $variation_id, $_attribute_key, $_attribute_value );
934
- }
935
- }
936
-
937
- // remove old taxonomies attributes so data is kept up to date - first get attribute key names
938
- $delete_attribute_keys = $wpdb->get_col( $wpdb->prepare( "SELECT meta_key FROM {$wpdb->postmeta} WHERE meta_key LIKE 'attribute_%%' AND meta_key NOT IN ( '" . implode( "','", $updated_attribute_keys ) . "' ) AND post_id = %d;", $variation_id ) );
939
-
940
- foreach ( $delete_attribute_keys as $key ) {
941
-
942
- delete_post_meta( $variation_id, $key );
943
- }
944
- }
945
-
946
- // square item variation id
947
- if ( isset( $variation['square_meta']['item_variation_id'] ) ) {
948
- Product::set_square_item_variation_id( $variation_id, $variation['square_meta']['item_variation_id'] );
949
- }
950
-
951
- // square item variation version
952
- if ( isset( $variation['square_meta']['item_variation_version'] ) ) {
953
- Product::set_square_variation_version( $variation_id, $variation['square_meta']['item_variation_version'] );
954
- }
955
-
956
- /**
957
- * Fired after saving a product variation during a Square product import.
958
- *
959
- * @since 2.0.0
960
- *
961
- * @param int $variation_id the variation ID
962
- * @param int $menu_order the menu order
963
- * @param array $variation the variation data
964
- */
965
- do_action( 'woocommerce_square_save_product_variation', $variation_id, $menu_order, $variation );
966
- }
967
-
968
- // update parent if variable so price sorting works and stays in sync with the cheapest child
969
- \WC_Product_Variable::sync( $product_id );
970
-
971
- // update default attributes options setting
972
- if ( isset( $data['default_attribute'] ) ) {
973
-
974
- $data['default_attributes'] = $data['default_attribute'];
975
- }
976
-
977
- if ( isset( $data['default_attributes'] ) && is_array( $data['default_attributes'] ) ) {
978
-
979
- $default_attributes = [];
980
-
981
- foreach ( $data['default_attributes'] as $default_attr_key => $default_attr ) {
982
-
983
- if ( ! isset( $default_attr['name'] ) ) {
984
- continue;
985
- }
986
-
987
- $taxonomy = sanitize_title( $default_attr['name'] );
988
-
989
- if ( isset( $default_attr['slug'] ) ) {
990
- $taxonomy = $this->get_attribute_taxonomy_by_slug( $default_attr['slug'] );
991
- }
992
-
993
- if ( isset( $attributes[ $taxonomy ] ) ) {
994
-
995
- $_attribute = $attributes[ $taxonomy ];
996
-
997
- if ( $_attribute['is_variation'] ) {
998
-
999
- $value = '';
1000
-
1001
- if ( isset( $default_attr['option'] ) ) {
1002
-
1003
- if ( $_attribute['is_taxonomy'] ) {
1004
-
1005
- // Don't use wc_clean as it destroys sanitized characters
1006
- $value = sanitize_title( trim( stripslashes( $default_attr['option'] ) ) );
1007
-
1008
- } else {
1009
-
1010
- $value = wc_clean( trim( stripslashes( $default_attr['option'] ) ) );
1011
- }
1012
- }
1013
-
1014
- if ( $value ) {
1015
-
1016
- $default_attributes[ $taxonomy ] = $value;
1017
- }
1018
- }
1019
- }
1020
- }
1021
-
1022
- update_post_meta( $product_id, '_default_attributes', $default_attributes );
1023
- }
1024
-
1025
- return true;
1026
- }
1027
-
1028
-
1029
- /**
1030
- * Gets an attribute taxonomy by its slug.
1031
- *
1032
- * @since 2.0.0
1033
- *
1034
- * @param string $slug
1035
- * @return string|null
1036
- */
1037
- protected function get_attribute_taxonomy_by_slug( $slug ) {
1038
-
1039
- $taxonomy = null;
1040
- $attribute_taxonomies = wc_get_attribute_taxonomies();
1041
-
1042
- foreach ( $attribute_taxonomies as $key => $tax ) {
1043
-
1044
- if ( $slug === $tax->attribute_name ) {
1045
-
1046
- $taxonomy = 'pa_' . $tax->attribute_name;
1047
- break;
1048
- }
1049
- }
1050
-
1051
- return $taxonomy;
1052
- }
1053
-
1054
-
1055
- /**
1056
- * Saves the product price.
1057
- *
1058
- * @since 2.0.0
1059
- *
1060
- * @param int $product_id
1061
- * @param float $regular_price
1062
- * @param float $sale_price
1063
- * @param string $date_from
1064
- * @param string $date_to
1065
- */
1066
- public function wc_save_product_price( $product_id, $regular_price, $sale_price = '', $date_from = '', $date_to = '' ) {
1067
-
1068
- $product_id = absint( $product_id );
1069
- $regular_price = wc_format_decimal( $regular_price );
1070
- $sale_price = '' === $sale_price ? '' : wc_format_decimal( $sale_price );
1071
- $date_from = wc_clean( $date_from );
1072
- $date_to = wc_clean( $date_to );
1073
-
1074
- update_post_meta( $product_id, '_regular_price', $regular_price );
1075
- update_post_meta( $product_id, '_sale_price', $sale_price );
1076
-
1077
- // Save Dates
1078
- update_post_meta( $product_id, '_sale_price_dates_from', $date_from ? strtotime( $date_from ) : '' );
1079
- update_post_meta( $product_id, '_sale_price_dates_to', $date_to ? strtotime( $date_to ) : '' );
1080
-
1081
- if ( $date_to && ! $date_from ) {
1082
-
1083
- $date_from = strtotime( 'NOW', current_time( 'timestamp' ) );
1084
-
1085
- update_post_meta( $product_id, '_sale_price_dates_from', $date_from );
1086
- }
1087
-
1088
- // Update price if on sale
1089
- if ( '' !== $sale_price && '' === $date_to && '' === $date_from ) {
1090
-
1091
- update_post_meta( $product_id, '_price', $sale_price );
1092
-
1093
- } else {
1094
-
1095
- update_post_meta( $product_id, '_price', $regular_price );
1096
- }
1097
-
1098
- if ( '' !== $sale_price && $date_from && strtotime( $date_from ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
1099
-
1100
- update_post_meta( $product_id, '_price', $sale_price );
1101
- }
1102
-
1103
- if ( $date_to && strtotime( $date_to ) < strtotime( 'NOW', current_time( 'timestamp' ) ) ) {
1104
-
1105
- update_post_meta( $product_id, '_price', $regular_price );
1106
- update_post_meta( $product_id, '_sale_price_dates_from', '' );
1107
- update_post_meta( $product_id, '_sale_price_dates_to', '' );
1108
- }
1109
- }
1110
-
1111
-
1112
- /**
1113
- * Clears a product from WooCommerce - used when product creation fails partially through the creation process.
1114
- *
1115
- * @since 2.0.0
1116
- *
1117
- * @param int $product_id the product ID
1118
- */
1119
- protected function clear_product( $product_id ) {
1120
-
1121
- if ( ! is_numeric( $product_id ) || 0 >= $product_id ) {
1122
- return;
1123
- }
1124
-
1125
- // Delete product attachments
1126
- $attachments = get_children( [
1127
- 'post_parent' => $product_id,
1128
- 'post_status' => 'any',
1129
- 'post_type' => 'attachment',
1130
- ] );
1131
-
1132
- foreach ( $attachments as $attachment ) {
1133
- wp_delete_attachment( $attachment->ID, true );
1134
- }
1135
-
1136
- // Delete product
1137
- wp_delete_post( $product_id, true );
1138
- }
1139
-
1140
-
1141
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Records.php DELETED
@@ -1,390 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Sync\Records\Record;
30
-
31
- /**
32
- * The sync records handler.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Records {
37
-
38
-
39
- /** @var string WordPress option key where sync records are stored */
40
- private static $records_option_key = 'wc_square_sync_records';
41
-
42
-
43
- /**
44
- * Checks if there are existing records.
45
- *
46
- * @since 2.0.0
47
- *
48
- * @return bool
49
- */
50
- public static function has_records() {
51
-
52
- return ! empty( self::has_records() );
53
- }
54
-
55
-
56
- /**
57
- * Gets a specific sync record.
58
- *
59
- * @since 2.0.0
60
- *
61
- * @param int $id the record's identifier
62
- * @return null|Record
63
- */
64
- public static function get_record( $id ) {
65
-
66
- $records = self::get_records( [ 'id' => $id ] );
67
-
68
- return ! empty( $records ) ? current( $records ) : null;
69
- }
70
-
71
-
72
- /**
73
- * Gets an array of record objects.
74
- *
75
- * @since 2.0.0
76
- *
77
- * @param array $args associative array of arguments to query records
78
- * @return Record[]
79
- */
80
- public static function get_records( array $args = [] ) {
81
-
82
- $args = wp_parse_args( $args, [
83
- 'id' => null,
84
- 'type' => null,
85
- 'product' => null,
86
- 'orderby' => 'date',
87
- 'sort' => 'DESC',
88
- 'limit' => 50,
89
- ] );
90
-
91
- $records = [];
92
- $raw_records = get_option( self::$records_option_key, [] );
93
-
94
- foreach ( $raw_records as $raw_record_data ) {
95
-
96
- $record = new Record( $raw_record_data );
97
-
98
- if ( ! empty( $args['id'] ) ) {
99
-
100
- $id = is_array( $args['id'] ) ? $args['id'] : explode( ',', $args['id'] );
101
-
102
- if ( ! in_array( $record->get_id(), $id, false ) ) {
103
- continue;
104
- }
105
- }
106
-
107
- if ( ! empty( $args['type'] ) ) {
108
-
109
- $type = is_array( $args['type'] ) ? $args['type'] : explode( ',', $args['type'] );
110
-
111
- if ( ! $record->is_type( $type ) ) {
112
- continue;
113
- }
114
- }
115
-
116
- if ( ! empty( $args['product'] ) ) {
117
-
118
- $product = is_array( $args['product'] ) ? $args['product'] : explode( ',', $args['product'] );
119
-
120
- if ( ! in_array( $record->get_product_id(), $product, false ) ) {
121
- continue;
122
- }
123
- }
124
-
125
- $records[ $record->get_id() ] = $record;
126
- }
127
-
128
- if ( ! empty( $records ) ) {
129
-
130
- switch ( $args['orderby'] ) {
131
- case 'date' :
132
- uasort( $records, [ 'self', 'sort_records_by_date' ] );
133
- break;
134
- case 'type' :
135
- uasort( $records, [ 'self', 'sort_records_by_type' ] );
136
- break;
137
- }
138
-
139
- if ( 'DESC' === $args['sort'] ) {
140
- $records = array_reverse( $records, true );
141
- }
142
-
143
- $records = array_slice( $records, 0, max( 50, absint( $args['limit'] ) ) );
144
- }
145
-
146
- return $records;
147
- }
148
-
149
-
150
- /**
151
- * Compares two records for sorting by date.
152
- *
153
- * @see usort() callback
154
- * @see Records::get_records()
155
- *
156
- * @since 2.0.0
157
- *
158
- * @param Record $record_1 first record
159
- * @param Record $record_2 second record
160
- * @return int should return 0, -1 or +1
161
- */
162
- private static function sort_records_by_date( $record_1, $record_2 ) {
163
-
164
- $compare = 0;
165
-
166
- if ( $record_1 instanceof Record && $record_2 instanceof Record ) {
167
-
168
- $timestamp_1 = $record_1->get_timestamp();
169
- $timestamp_2 = $record_2->get_timestamp();
170
-
171
- if ( $timestamp_1 > $timestamp_2 ) {
172
- $compare = 1;
173
- } elseif ( $timestamp_1 < $timestamp_2 ) {
174
- $compare = -1;
175
- } else { // compare by ID as a fallback to keep order consistency
176
- $compare = strnatcmp( $record_1->get_id(), $record_2->get_id() );
177
- }
178
- }
179
-
180
- return $compare;
181
- }
182
-
183
-
184
- /**
185
- * Compares two records for sorting by type.
186
- *
187
- * @see usort() callback
188
- * @see Records::get_records()
189
- *
190
- * @since 2.0.0
191
- *
192
- * @param Record $record_1 first record
193
- * @param Record $record_2 second record
194
- * @return int should return 0, -1 or +1
195
- */
196
- private static function sort_records_by_type( $record_1, $record_2 ) {
197
-
198
- $compare = 0;
199
-
200
- if ( $record_1 instanceof Record && $record_2 instanceof Record ) {
201
-
202
- $compare = strnatcmp( $record_1->get_type(), $record_2->get_type() );
203
-
204
- // if they are equal, sort by date within the same type group
205
- if ( 0 === $compare ) {
206
-
207
- $timestamp_1 = $record_1->get_timestamp();
208
- $timestamp_2 = $record_2->get_timestamp();
209
-
210
- if ( $timestamp_1 > $timestamp_2 ) {
211
- $compare = 1;
212
- } elseif ( $timestamp_1 < $timestamp_2 ) {
213
- $compare = -1;
214
- } else { // compare by ID as a fallback to keep order consistency
215
- $compare = strnatcmp( $record_1->get_id(), $record_2->get_id() );
216
- }
217
- }
218
- }
219
-
220
- return $compare;
221
- }
222
-
223
-
224
- /**
225
- * Saves a new record.
226
- *
227
- * @since 2.0.0
228
- *
229
- * @param array|Record $data raw data or record object
230
- * @return bool success
231
- */
232
- public static function set_record( $data ) {
233
-
234
- if ( is_array( $data ) ) {
235
- $new_record = new Record( $data );
236
- } else {
237
- $new_record = $data;
238
- }
239
-
240
- if ( $new_record instanceof Record ) {
241
-
242
- // ensures there are never more than 50 records, leaving behind the older ones
243
- $existing_records = self::get_records( [ 'limit' => 49 ] );
244
- $raw_records = [];
245
-
246
- foreach ( $existing_records as $existing_record ) {
247
- $raw_records[ $existing_record->get_id() ] = $existing_record->get_data();
248
- }
249
-
250
- $raw_records[ $new_record->get_id() ] = $new_record->get_data();
251
-
252
- $success = update_option( self::$records_option_key, $raw_records );
253
-
254
- } else {
255
-
256
- $success = false;
257
- }
258
-
259
- return $success;
260
- }
261
-
262
-
263
- /**
264
- * Saves multiple records.
265
- *
266
- * @since 2.0.0
267
- *
268
- * @param array|Record[] $data array of raw record data or array of record objects
269
- * @return bool success
270
- */
271
- public static function set_records( array $data ) {
272
-
273
- $success = false;
274
- $raw_records = [];
275
-
276
- foreach ( $data as $record ) {
277
-
278
- if ( is_array( $record ) ) {
279
- $record = new Record( $record );
280
- }
281
-
282
- if ( $record instanceof Record ) {
283
- $raw_records[ $record->get_id() ] = $record->get_data();
284
- }
285
- }
286
-
287
- if ( ! empty( $raw_records ) ) {
288
-
289
- $records = self::get_records( [ 'limit' => 50 - count( $raw_records ) ] );
290
-
291
- foreach ( $records as $record ) {
292
- $raw_records[ $record->get_id() ] = $record->get_data();
293
- }
294
-
295
- $success = update_option( self::$records_option_key, $raw_records );
296
- }
297
-
298
- return $success;
299
- }
300
-
301
-
302
- /**
303
- * Removes a record permanently.
304
- *
305
- * @since 2.0.0
306
- *
307
- * @param int $id record identifier
308
- * @return bool success
309
- */
310
- public static function delete_record( $id ) {
311
-
312
- $success = false;
313
- $raw_records = get_option( self::$records_option_key, [] );
314
-
315
- if ( array_key_exists( $id, $raw_records ) ) {
316
-
317
- unset( $raw_records[ $id ] );
318
-
319
- $success = update_option( self::$records_option_key, $raw_records );
320
- }
321
-
322
- return $success;
323
- }
324
-
325
-
326
- /**
327
- * Delete multiple records.
328
- *
329
- * @since 2.0.0
330
- *
331
- * @param array $args query arguments
332
- * @return int count of records removed
333
- */
334
- public static function delete_records( array $args ) {
335
-
336
- $removed = 0;
337
- $raw_records = get_option( self::$records_option_key, [] );
338
-
339
- foreach( $raw_records as $raw_record ) {
340
-
341
- $record = new Record( $raw_record );
342
-
343
- if ( isset( $args['id'] ) ) {
344
-
345
- $id = is_array( $args['id'] ) ? $args['id'] : explode( ',', $args['id'] );
346
-
347
- if ( in_array( $record->get_id(), $id, false ) ) {
348
- unset( $raw_records[ $record->get_id() ] );
349
- $removed++;
350
- }
351
- }
352
-
353
- if ( isset( $args['type'] ) ) {
354
-
355
- $type = $args['type'];
356
-
357
- if ( $record->is_type( $type ) ) {
358
- unset( $raw_records[ $record->get_id() ] );
359
- $removed++;
360
- }
361
- }
362
- }
363
-
364
- if ( $removed > 0 ) {
365
-
366
- $success = update_option( self::$records_option_key, $raw_records );
367
-
368
- if ( ! $success ) {
369
- $removed = 0;
370
- }
371
- }
372
-
373
- return $removed;
374
- }
375
-
376
-
377
- /**
378
- * Removes all records.
379
- *
380
- * @since 2.0.0
381
- *
382
- * @return bool
383
- */
384
- public static function clean_records() {
385
-
386
- return update_option( self::$records_option_key, [] );
387
- }
388
-
389
-
390
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Records/Record.php DELETED
@@ -1,603 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync\Records;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
- use WooCommerce\Square\Sync\Records;
30
-
31
- /**
32
- * The sync record object.
33
- *
34
- * @since 2.0.0
35
- */
36
- class Record {
37
-
38
-
39
- /** @var string unique identifier */
40
- private $id = '';
41
-
42
- /** @var string date in UTC */
43
- private $date = '';
44
-
45
- /** @var string the record status */
46
- private $type = '';
47
-
48
- /** @var string message (optional, may contain HTML) */
49
- private $message = '';
50
-
51
- /** @var int associated product ID (optional) */
52
- private $product_id = 0;
53
-
54
- /** @var bool whether the associated product was hidden when the record was created */
55
- private $product_hidden = false;
56
-
57
-
58
- /**
59
- * Sync record constructor.
60
- *
61
- * @since 2.0.0
62
- *
63
- * @param array|int $data raw data or related product ID
64
- */
65
- public function __construct( $data ) {
66
-
67
- foreach ( $this->parse_data( $data ) as $key => $value ) {
68
- $this->$key = $value;
69
- }
70
- }
71
-
72
-
73
- /**
74
- * Parses data from the store into the object properties
75
- *
76
- * @since 2.0.0
77
- *
78
- * @param int|array $data associative array or product ID
79
- * @return array
80
- */
81
- private function parse_data( $data ) {
82
-
83
- if ( is_numeric( $data ) ) {
84
- $data = [
85
- 'type' => 'alert',
86
- 'product_id' => absint( $data ),
87
- ];
88
- }
89
-
90
- $date = date( 'Y-m-d H:i:s', current_time( 'timestamp', true ) );
91
- $data = wp_parse_args( (array) $data, [
92
- 'type' => $this->get_default_type(),
93
- 'date' => $date,
94
- 'message' => '',
95
- 'product_id' => 0,
96
- 'product_hidden' => false,
97
- ] );
98
-
99
- if ( empty( $data['id'] ) ) {
100
- $data['id'] = uniqid( 'wc_square_sync_record_', false );
101
- }
102
-
103
- if ( ! strtotime( $data['date'] ) ) {
104
- $data['date'] = $date;
105
- }
106
-
107
- if ( ! is_string( $data['message'] ) ) {
108
- $data['message'] = '';
109
- }
110
-
111
- if ( ! is_numeric( $data['product_id'] ) ) {
112
- $data['product_id'] = $data['product_id'] instanceof \WC_Product ? $data['product_id']->get_id() : 0;
113
- }
114
-
115
- if ( 0 === $data['product_id'] ) {
116
- $data['product_hidden'] = false;
117
- }
118
-
119
- return $data;
120
- }
121
-
122
-
123
- /**
124
- * Gets the record's raw data.
125
- *
126
- * @since 2.0.0
127
- *
128
- * @return array associative array
129
- */
130
- public function get_data() {
131
-
132
- return [
133
- 'id' => (string) $this->id,
134
- 'type' => (string) $this->type,
135
- 'date' => (string) $this->date,
136
- 'message' => (string) $this->message,
137
- 'product_id' => (int) $this->product_id,
138
- 'product_hidden' => (bool) $this->product_hidden,
139
- ];
140
- }
141
-
142
-
143
- /**
144
- * Gets the record's ID.
145
- *
146
- * @since 2.0.0
147
- *
148
- * @return string
149
- */
150
- public function get_id() {
151
-
152
- return (string) $this->id;
153
- }
154
-
155
-
156
- /**
157
- * Sets an ID for the record.
158
- *
159
- * @since 2.0.0
160
- *
161
- * @param null|string $id
162
- * @return string set ID
163
- */
164
- public function set_id( $id = null ) {
165
-
166
- if ( is_string( $id ) ) {
167
- $id = trim( $id );
168
- } else {
169
- $id = null;
170
- }
171
-
172
- if ( empty( $id ) ) {
173
- $id = uniqid( 'wc_square_sync_record_', false );
174
- }
175
-
176
- return (string) $this->id = $id;
177
- }
178
-
179
-
180
- /**
181
- * Gets a record's default status.
182
- *
183
- * @since 2.0.0
184
- *
185
- * @return string
186
- */
187
- private function get_default_type() {
188
-
189
- return 'info';
190
- }
191
-
192
-
193
- /**
194
- * Gets a record's possible statuses.
195
- *
196
- * @since 2.0.0
197
- *
198
- * @return array associative array of types and labels
199
- */
200
- private function get_valid_types() {
201
-
202
- return [
203
- 'info' => __( 'Info', 'woocommerce-square' ),
204
- 'notice' => __( 'Notice', 'woocommerce-square' ),
205
- 'alert' => __( 'Alert', 'woocommerce-square' ),
206
- 'resolved' => __( 'Resolved', 'woocommerce-square' ),
207
- ];
208
- }
209
-
210
-
211
- /**
212
- * Gets the record's label.
213
- *
214
- * @since 2.0.0
215
- *
216
- * @return string
217
- */
218
- public function get_label() {
219
-
220
- $type = $this->get_type();
221
- $types = $this->get_valid_types();
222
-
223
- return isset( $types[ $type ] ) ? $types[ $type ] : $types[ $this->get_default_type() ];
224
- }
225
-
226
-
227
- /**
228
- * Gets the record status.
229
- *
230
- * @since 2.0.0
231
- *
232
- * @return string
233
- */
234
- public function get_type() {
235
-
236
- return array_key_exists( $this->type, $this->get_valid_types() ) ? $this->type : $this->get_default_type();
237
- }
238
-
239
-
240
- /**
241
- * Set's the record status.
242
- *
243
- * @since 2.0.0
244
- *
245
- * @param string $type a known type
246
- * @return string set type
247
- */
248
- public function set_type( $type ) {
249
-
250
- if ( array_key_exists( $type, $this->get_valid_types() ) ) {
251
- $this->type = $type;
252
- } else {
253
- $this->type = $this->get_default_type();
254
- }
255
-
256
- return $this->type;
257
- }
258
-
259
-
260
- /**
261
- * Checks if the record is of a given type.
262
- *
263
- * @since 2.0.0
264
- *
265
- * @param array|string $type one or more types to check
266
- * @return bool
267
- */
268
- public function is_type( $type ) {
269
-
270
- return is_array( $type ) ? in_array( $this->type, $type, true ) : $this->type === $type;
271
- }
272
-
273
-
274
- /**
275
- * Checks whether the record is resolved.
276
- *
277
- * @since 2.0.0
278
- *
279
- * @return bool
280
- */
281
- public function is_resolved() {
282
-
283
- return $this->is_type( 'resolved' );
284
- }
285
-
286
-
287
- /**
288
- * Resolves the record.
289
- *
290
- * @since 2.0.0
291
- */
292
- public function resolve() {
293
-
294
- $this->set_type( 'resolved' );
295
- }
296
-
297
-
298
- /**
299
- * Gets the record's timestamp, in UTC.
300
- *
301
- * @since 2.0.0
302
- *
303
- if (
304
- * @return int
305
- */
306
- public function get_timestamp() {
307
-
308
- return (int) strtotime( $this->date );
309
- }
310
-
311
-
312
- /**
313
- * Gets the record's date, in UTC.
314
- *
315
- * @since 2.0.0
316
- *
317
- * @param string $format defaults to MySQL format
318
- * @return string
319
- */
320
- public function get_date( $format = 'Y-m-d H:i:s' ) {
321
-
322
- return date( (string) $format, $this->get_timestamp() );
323
- }
324
-
325
-
326
- /**
327
- * Gets the record's date, in the local timezone.
328
- *
329
- * @since 2.0.0
330
- *
331
- * @param null|string $format optional PHP date format (defaults to the site date/time format)
332
- * @return string
333
- */
334
- public function get_local_date( $format = null ) {
335
-
336
- if ( ! is_string( $format ) ) {
337
- $format = wc_date_format() . ' ' . wc_time_format();
338
- }
339
-
340
- try {
341
-
342
- $date = new \DateTime( date( (string) $format, $this->get_timestamp() ), new \DateTimeZone( 'UTC' ) );
343
- $timezone = new \DateTimeZone( wc_timezone_string() );
344
- $offset = $timezone->getOffset( $date );
345
- $timestamp = $date->getTimestamp() + $offset;
346
-
347
- } catch ( \Exception $e ) {
348
-
349
- $timestamp = $this->get_timestamp();
350
- }
351
-
352
- return date( (string) $format, $timestamp );
353
- }
354
-
355
-
356
- /**
357
- * Gets the record's message.
358
- *
359
- * @since 2.0.0
360
- *
361
- * @return string
362
- */
363
- public function get_message() {
364
-
365
- $message = trim( $this->message );
366
-
367
- if ( '' === $message && ( $product = $this->get_product() ) ) {
368
-
369
- $message = sprintf(
370
- /* translators: Placeholder: %s - product name */
371
- esc_html__( '%s not found in Square.', 'woocommerce-square' ),
372
- '<a href="' . esc_url( get_edit_post_link( $product->get_id() ) ) . '">' . $product->get_formatted_name() . '</a>'
373
- );
374
- }
375
-
376
- return $message;
377
- }
378
-
379
-
380
- /**
381
- * Sets the record's message.
382
- *
383
- * @since 2.0.0
384
- *
385
- * @param string $message may contain HTML
386
- * @return bool success
387
- */
388
- public function set_message( $message ) {
389
-
390
- if ( is_string( $message ) ) {
391
- $this->message = trim( $message );
392
- } else {
393
- $this->message = '';
394
- }
395
-
396
- return ! empty( $this->message );
397
- }
398
-
399
-
400
- /**
401
- * Removes the record's message.
402
- *
403
- * @since 2.0.0
404
- */
405
- public function remove_message() {
406
-
407
- $this->message = '';
408
- }
409
-
410
-
411
- /**
412
- * Sets the record's product.
413
- *
414
- * @since 2.0.0
415
- *
416
- * @param int|\WC_Product $product
417
- * @return bool success
418
- */
419
- public function set_product( $product ) {
420
-
421
- if ( $product instanceof \WC_Product ) {
422
- $product_id = $product->get_id();
423
- } else {
424
- $product_id = $product;
425
- }
426
-
427
- if ( is_numeric( $product_id ) ) {
428
- $this->product_id = $product_id;
429
- } else {
430
- $this->product_id = 0;
431
- }
432
-
433
- return $this->product_id > 0;
434
- }
435
-
436
-
437
- /**
438
- * Removes a related product from the record.
439
- *
440
- * @since 2.0.0
441
- */
442
- public function remove_product() {
443
-
444
- $this->product_id = 0;
445
- }
446
-
447
-
448
- /**
449
- * Checks whether there is a valid product associated with the record.
450
- *
451
- * @since 2.0.0
452
- *
453
- * @return bool
454
- */
455
- public function has_product() {
456
-
457
- return $this->get_product() instanceof \WC_Product;
458
- }
459
-
460
-
461
- /**
462
- * Gets the product associated with the record.
463
- *
464
- * @since 2.0.0
465
- *
466
- * @return null|\WC_Product
467
- */
468
- public function get_product() {
469
-
470
- $product = wc_get_product( $this->get_product_id() );
471
-
472
- return $product instanceof \WC_Product ? $product : null;
473
- }
474
-
475
-
476
- /**
477
- * Gets the product ID associated with the record.
478
- *
479
- * @since 2.0.0
480
- *
481
- * @return int
482
- */
483
- public function get_product_id() {
484
-
485
- return absint( $this->product_id );
486
- }
487
-
488
-
489
- /**
490
- * Sets a flag whether when adding the record the product was contextually hidden from catalog.
491
- *
492
- * Note: this is for historical record purposes and may not correspond to the effective product visibility, nor does not affect the product visibility when called.
493
- *
494
- * @since 2.0.0
495
- *
496
- * @param bool $was_hidden whether product was hidden when creating the record
497
- * @return bool success
498
- */
499
- public function set_product_hidden( $was_hidden = true ) {
500
-
501
- $set = false;
502
-
503
- if ( is_bool( $was_hidden ) ) {
504
- $this->product_hidden = $was_hidden;
505
- $set = true;
506
- }
507
-
508
- return $set;
509
- }
510
-
511
-
512
- /**
513
- * Checks whether a flag was set for hiding the product from catalog when the record was created.
514
- *
515
- * This may not reflect the actual product visibility status, it is only for historical purposes.
516
- *
517
- * @since 2.0.0
518
- *
519
- * @return bool
520
- */
521
- public function was_product_hidden() {
522
-
523
- return true === $this->product_hidden;
524
- }
525
-
526
-
527
- /**
528
- * Gets the record's actions.
529
- *
530
- * @since 2.0.0
531
- *
532
- * @return \stdClass[] associative array of action names and action properties as objects
533
- */
534
- public function get_actions() {
535
-
536
- $actions = [];
537
-
538
- if ( ! $this->is_resolved() ) {
539
-
540
- $actions['delete'] = (object) [
541
- 'name' => 'delete',
542
- 'label' => __( 'Delete', 'woocommerce-square' ),
543
- 'icon' => '<span class="dashicons dashicons-trash"></span>',
544
- ];
545
-
546
- if ( ! $this->is_type( 'info' ) ) {
547
-
548
- $actions['resolve'] = (object) [
549
- 'name' => 'resolve',
550
- 'label' => __( 'Ignore', 'woocommerce-square' ),
551
- 'icon' => '<span class="dashicons dashicons-hidden"></span>',
552
- ];
553
- }
554
-
555
- if ( $this->has_product() ) {
556
-
557
- $actions['unsync'] = (object) [
558
- 'name' => 'unsync',
559
- 'label' => __( 'Unlink', 'woocommerce-square' ),
560
- 'icon' => '<span class="dashicons dashicons-editor-unlink"></span>',
561
- ];
562
- }
563
- }
564
-
565
- /**
566
- * Filters the sync record action.
567
- *
568
- * @since 2.0.0
569
- *
570
- * @param \stdClass[] array of action names and objects
571
- * @param Record instance of the current record object
572
- */
573
- return (array) apply_filters( 'wc_square_sync_record_actions', $actions, $this );
574
- }
575
-
576
-
577
- /**
578
- * Saves the record to storage.
579
- *
580
- * @since 2.0.0
581
- *
582
- * @return bool success
583
- */
584
- public function save() {
585
-
586
- return Records::set_record( $this );
587
- }
588
-
589
-
590
- /**
591
- * Deletes the record from storage.
592
- *
593
- * @since 2.0.0
594
- *
595
- * @return bool success
596
- */
597
- public function destroy() {
598
-
599
- return Records::delete_record( $this->get_id() );
600
- }
601
-
602
-
603
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Sync/Stepped_Job.php DELETED
@@ -1,233 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Sync;
25
-
26
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
27
-
28
- defined( 'ABSPATH' ) or exit;
29
-
30
- /**
31
- * Stepped Job abstract.
32
- *
33
- * Adds multi-step management to the job class.
34
- *
35
- * @since 2.0.0
36
- */
37
- abstract class Stepped_Job extends Job {
38
-
39
-
40
- /**
41
- * Executes the next step of this job.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @return \stdClass the job object
46
- */
47
- public function run() {
48
-
49
- parent::run();
50
-
51
- if ( empty( $this->get_attr( 'next_steps' ) ) && empty( $this->get_attr( 'completed_steps' ) ) ) {
52
- $this->assign_next_steps();
53
- }
54
-
55
- $this->do_next_step();
56
-
57
- return $this->job;
58
- }
59
-
60
-
61
- /**
62
- * Assigns the next steps needed for this sync job.
63
- *
64
- * Adds the next steps to the 'next_steps' attribute.
65
- *
66
- * @since 2.0.0
67
- */
68
- abstract protected function assign_next_steps();
69
-
70
-
71
- /**
72
- * Gets the next step in the sync process.
73
- *
74
- * @since 2.0.0
75
- *
76
- * @return string|null
77
- */
78
- protected function get_next_step() {
79
-
80
- $next_steps = $this->get_next_steps();
81
-
82
- return isset( $next_steps[0] ) ? $next_steps[0] : null;
83
- }
84
-
85
-
86
- /**
87
- * Gets the next steps for the sync process.
88
- *
89
- * @since 2.0.0
90
- *
91
- * @return string[]
92
- */
93
- protected function get_next_steps() {
94
-
95
- return $this->get_attr( 'next_steps' );
96
- }
97
-
98
-
99
- /**
100
- * Performs the next step in the sync process.
101
- *
102
- * @since 2.0.0
103
- */
104
- protected function do_next_step() {
105
-
106
- $next_step = $this->get_next_step();
107
-
108
- if ( is_callable( [ $this, $next_step ] ) ) {
109
-
110
- $this->start_step_cycle( $next_step );
111
-
112
- try {
113
-
114
- $this->$next_step();
115
- $this->complete_step_cycle( $next_step );
116
-
117
- } catch ( Framework\SV_WC_Plugin_Exception $exception ) {
118
-
119
- $this->complete_step_cycle( $next_step, false, $exception->getMessage() );
120
- $this->fail( $exception->getMessage() );
121
- return;
122
- }
123
- }
124
-
125
- if ( ! $this->get_next_step() ) {
126
-
127
- $this->complete();
128
- }
129
- }
130
-
131
-
132
- /**
133
- * Records the beginning of a new step cycle, meaning a new loop on the job for a given step.
134
- *
135
- * @since 2.0.0
136
- *
137
- * @param string $step_name the step name
138
- */
139
- protected function start_step_cycle( $step_name ) {
140
-
141
- $current_step_cycle = [
142
- 'step_name' => $step_name,
143
- 'start_time' => microtime( true ),
144
- ];
145
-
146
- wc_square()->log( "Starting step cycle: $step_name" );
147
-
148
- $this->set_attr( 'current_step_cycle', $current_step_cycle );
149
- }
150
-
151
-
152
- /**
153
- * Records the completion of a step cycle.
154
- *
155
- * @since 2.0.0
156
- *
157
- * @param string $step_name the step name
158
- * @param bool $is_successful (optional) whether the step completion is from a success or not
159
- * @param string $error_message (optional) error message to include with failed step log
160
- */
161
- protected function complete_step_cycle( $step_name, $is_successful = true, $error_message = '' ) {
162
-
163
- $current_step_cycle = $this->get_attr( 'current_step_cycle', [] );
164
-
165
- if ( ! empty( $current_step_cycle ) ) {
166
-
167
- $current_step_cycle['end_time'] = microtime( true );
168
- $current_step_cycle['runtime'] = number_format( $current_step_cycle['end_time'] - $current_step_cycle['start_time'], 2 ) . 's';
169
- $current_step_cycle['success'] = true === $is_successful;
170
-
171
- if ( true === $is_successful ) {
172
-
173
- wc_square()->log( "Completed step cycle: $step_name (${current_step_cycle['runtime']})" );
174
-
175
- } else {
176
-
177
- wc_square()->log( "Failed step cycle: $step_name (${current_step_cycle['runtime']}) - $error_message" );
178
- }
179
-
180
- $completed_cycles = $this->get_attr( 'completed_step_cycles', [] );
181
- $completed_cycles[] = $current_step_cycle;
182
- $this->set_attr( 'completed_step_cycles', $completed_cycles );
183
- }
184
- }
185
-
186
-
187
- /**
188
- * Completes the specified step (if it's the next step).
189
- *
190
- * @since 2.0.0
191
- *
192
- * @param string $step_name
193
- */
194
- protected function complete_step( $step_name ) {
195
-
196
- $next_steps = $this->get_next_steps();
197
-
198
- if ( isset( $next_steps[0] ) && $step_name === $next_steps[0] ) {
199
-
200
- $this->add_completed_step( $step_name );
201
- array_shift( $next_steps );
202
- $this->set_attr( 'next_steps', $next_steps );
203
- }
204
- }
205
-
206
-
207
- /**
208
- * Adds a step to the completed steps array.
209
- *
210
- * @since 2.0.0
211
- *
212
- * @param string $step_name
213
- */
214
- protected function add_completed_step( $step_name ) {
215
-
216
- if ( empty( $step_name ) ) {
217
- return;
218
- }
219
-
220
- $completed_steps = $this->get_attr( 'completed_steps', [] );
221
-
222
- $completed_steps[] = [
223
- 'name' => $step_name,
224
- 'completion_time' => current_time( 'mysql' ),
225
- ];
226
-
227
- $this->set_attr( 'completed_steps', $completed_steps );
228
-
229
- wc_square()->log( 'Completed job step: ' . $step_name );
230
- }
231
-
232
-
233
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Utilities/Encryption_Utility.php DELETED
@@ -1,265 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Utilities;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * The encryption utility class.
32
- *
33
- * Requires OpenSSL by default.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Encryption_Utility {
38
-
39
-
40
- /** @var string default cipher method */
41
- protected $default_cipher_method = 'AES-128-CBC';
42
-
43
- /** @var string cipher method */
44
- protected $cipher_method;
45
-
46
-
47
- /**
48
- * Constructs the class.
49
- *
50
- * @param string $preferred_cipher_method cipher method
51
- */
52
- public function __construct( $preferred_cipher_method = '' ) {
53
-
54
- // bail entirely if openssl isn't available
55
- if ( ! self::is_encryption_supported() ) {
56
- wc_doing_it_wrong( __CLASS__, __( 'Encryption is not supported on this site.', 'woocommerce-square' ), Framework\SV_WC_Plugin::VERSION );
57
- return;
58
- }
59
-
60
- $this->cipher_method = $this->get_default_cipher_method();
61
-
62
- // if a preferred cipher method is set, check and set it
63
- if ( is_string( $preferred_cipher_method ) && ! empty( $preferred_cipher_method ) ) {
64
-
65
- // only use what's preferred if it's supported
66
- if ( $this->is_cipher_method_supported( $preferred_cipher_method ) ) {
67
-
68
- $this->cipher_method = $preferred_cipher_method;
69
-
70
- // otherwise, throw a notice and continue with the default
71
- } else {
72
-
73
- $message = sprintf(
74
- __( '%1$s encryption is not available on this site. %2$s will be used instead.', 'woocommerce-square' ),
75
- $preferred_cipher_method,
76
- $this->cipher_method
77
- );
78
-
79
- wc_doing_it_wrong( __CLASS__, $message, Framework\SV_WC_Plugin::VERSION );
80
- }
81
- }
82
- }
83
-
84
-
85
- /**
86
- * Encrypts data.
87
- *
88
- * @since 2.0.0
89
- *
90
- * @param string|array $data data to encrypt
91
- * @param string $key encryption key
92
- * @return string
93
- * @throws Framework\SV_WC_Plugin_Exception
94
- */
95
- public function encrypt_data( $data, $key = '' ) {
96
-
97
- // sanity check to ensure encryption can happen
98
- if ( ! $this->get_cipher_method() ) {
99
- throw new Framework\SV_WC_Plugin_Exception( __( 'No encryption method available', 'woocommerce-square' ) );
100
- }
101
-
102
- if ( empty( $data ) || ( ! is_string( $data ) && ! is_array( $data ) ) ) {
103
- throw new Framework\SV_WC_Plugin_Exception( __( 'Data must be a non-empty string or array', 'woocommerce-square' ) );
104
- }
105
-
106
- if ( ! is_string( $key ) ) {
107
- throw new Framework\SV_WC_Plugin_Exception( __( 'Encryption key must be a string', 'woocommerce-square' ) );
108
- }
109
-
110
- // default to the WP salt
111
- if ( empty( $key ) ) {
112
- $key = $this->get_default_key();
113
- }
114
-
115
- $vector = openssl_random_pseudo_bytes( $this->get_vector_length(), $crypto_strong );
116
-
117
- // bail if a strong vector wasn't generated
118
- if ( false === $vector || false === $crypto_strong ) {
119
- throw new Framework\SV_WC_Plugin_Exception( __( 'Could not generate encryption vector.', 'woocommerce-square' ) );
120
- }
121
-
122
- $encrypted_data = openssl_encrypt( json_encode( $data ), $this->get_cipher_method(), $key, 0, $vector );
123
-
124
- return base64_encode( $vector . $encrypted_data );
125
- }
126
-
127
-
128
- /**
129
- * Decrypts data.
130
- *
131
- * @since 2.0.0
132
- *
133
- * @param string $data data to decrypt
134
- * @param string $key decryption key
135
- * @return string|array
136
- * @throws Framework\SV_WC_Plugin_Exception
137
- */
138
- public function decrypt_data( $data, $key = '' ) {
139
-
140
- // sanity check to ensure decryption can happen
141
- if ( ! $this->get_cipher_method() ) {
142
- throw new Framework\SV_WC_Plugin_Exception( __( 'No decryption method available', 'woocommerce-square' ) );
143
- }
144
-
145
- if ( empty( $data ) || ! is_string( $data ) ) {
146
- throw new Framework\SV_WC_Plugin_Exception( __( 'Data must be a non-empty string', 'woocommerce-square' ) );
147
- }
148
-
149
- if ( ! is_string( $key ) ) {
150
- throw new Framework\SV_WC_Plugin_Exception( __( 'Encryption key must be a string', 'woocommerce-square' ) );
151
- }
152
-
153
- // default to the WP salt
154
- if ( empty( $key ) ) {
155
- $key = $this->get_default_key();
156
- }
157
-
158
- $data = base64_decode( $data );
159
-
160
- $vector_length = $this->get_vector_length();
161
- $vector = substr( $data, 0, $vector_length );
162
- $data = substr( $data, $vector_length );
163
- $data = openssl_decrypt( $data, $this->get_cipher_method(), $key, 0, $vector );
164
-
165
- return json_decode( $data, true );
166
- }
167
-
168
-
169
- /**
170
- * Gets the vector length.
171
- *
172
- * @since 2.0.0
173
- *
174
- * @return int
175
- */
176
- protected function get_vector_length() {
177
-
178
- return openssl_cipher_iv_length( $this->get_cipher_method() );
179
- }
180
-
181
-
182
- /**
183
- * Determines if a cipher method is supported by the server.
184
- *
185
- * @since 2.0.0
186
- *
187
- * @param string $method cipher method to check
188
- * @return bool
189
- */
190
- protected function is_cipher_method_supported( $method ) {
191
-
192
- return in_array( $method, $this->get_supported_cipher_methods(), true );
193
- }
194
-
195
-
196
- /**
197
- * Determines if encryption is supported at all.
198
- *
199
- * @since 2.0.0
200
- *
201
- * @return bool
202
- */
203
- public static function is_encryption_supported() {
204
-
205
- return extension_loaded( 'openssl' );
206
- }
207
-
208
-
209
- /**
210
- * Gets the cipher method.
211
- *
212
- * @since 2.0.0
213
- *
214
- * @return string
215
- */
216
- protected function get_cipher_method() {
217
-
218
- return $this->cipher_method;
219
- }
220
-
221
-
222
- /**
223
- * Gets the default cipher method.
224
- *
225
- * Checks the list of supported methods first, and if the default isn't supported, uses the first available.
226
- *
227
- * @since 2.0.0
228
- *
229
- * @return string
230
- */
231
- protected function get_default_cipher_method() {
232
-
233
- $available_methods = $this->get_supported_cipher_methods();
234
-
235
- return in_array( $this->default_cipher_method, $available_methods, true ) ? $this->default_cipher_method : $available_methods[0];
236
- }
237
-
238
-
239
- /**
240
- * Gets the supported cipher methods.
241
- *
242
- * @since 2.0.0
243
- *
244
- * @return array
245
- */
246
- protected function get_supported_cipher_methods() {
247
-
248
- return openssl_get_cipher_methods();
249
- }
250
-
251
-
252
- /**
253
- * Gets the default encryption key.
254
- *
255
- * @since 2.0.0
256
- *
257
- * @return string
258
- */
259
- protected function get_default_key() {
260
-
261
- return md5( wp_salt(), true );
262
- }
263
-
264
-
265
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/includes/Utilities/Money_Utility.php DELETED
@@ -1,161 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- namespace WooCommerce\Square\Utilities;
25
-
26
- defined( 'ABSPATH' ) or exit;
27
-
28
- use SkyVerge\WooCommerce\PluginFramework\v5_4_0 as Framework;
29
-
30
- /**
31
- * Helper for converting money values.
32
- *
33
- * Square deals in cents, and Woo deals in floats so this methods help conversion between the two.
34
- *
35
- * @since 2.0.0
36
- */
37
- class Money_Utility {
38
-
39
-
40
- /**
41
- * Converts a WooCommerce amount to a Square money object.
42
- *
43
- * @since 2.0.0
44
- *
45
- * @param float $amount amount to convert
46
- * @param string $currency currency code
47
- *
48
- * @return \SquareConnect\Model\Money
49
- */
50
- public static function amount_to_money( $amount, $currency ) {
51
-
52
- return new \SquareConnect\Model\Money( [
53
- 'amount' => self::amount_to_cents( $amount, $currency ),
54
- 'currency' => $currency,
55
- ] );
56
- }
57
-
58
-
59
- /**
60
- * Converts a float amount to cents.
61
- *
62
- * @since 2.0.0
63
- *
64
- * @param float $amount float amount to convert
65
- * @param string $currency currency code for the amount
66
- * @return int
67
- */
68
- public static function amount_to_cents( $amount, $currency = '' ) {
69
-
70
- if ( ! $currency ) {
71
- $currency = get_woocommerce_currency();
72
- }
73
-
74
- $cents_factor = 10 ** self::get_currency_decimals( $currency );
75
- return (int) ( round( $cents_factor * $amount ) );
76
- }
77
-
78
-
79
- /**
80
- * Converts an amount in cents to a float.
81
- *
82
- * @since 2.0.0
83
- *
84
- * @param int $cents amount in cents
85
- * @param string $currency currency code for the amount
86
- * @return float
87
- */
88
- public static function cents_to_float( $cents, $currency = '' ) {
89
-
90
- if ( ! $currency ) {
91
- $currency = get_woocommerce_currency();
92
- }
93
-
94
- $cents_factor = 10 ** self::get_currency_decimals( $currency );
95
- return (float) ( $cents / $cents_factor );
96
- }
97
-
98
-
99
- /**
100
- * Gets the standard number of decimals for the given currency.
101
- *
102
- * @since 2.0.2
103
- *
104
- * @param string $currency currency code
105
- * @return int
106
- */
107
- public static function get_currency_decimals( $currency ) {
108
-
109
- $other_currencies = [
110
- 'BIF' => 0,
111
- 'CLP' => 0,
112
- 'DJF' => 0,
113
- 'GNF' => 0,
114
- 'HUF' => 0,
115
- 'JPY' => 0,
116
- 'KMF' => 0,
117
- 'KRW' => 0,
118
- 'MGA' => 0,
119
- 'PYG' => 0,
120
- 'RWF' => 0,
121
- 'VND' => 0,
122
- 'VUV' => 0,
123
- 'XAF' => 0,
124
- 'XOF' => 0,
125
- 'XPF' => 0,
126
- ];
127
-
128
- if ( Framework\SV_WC_Plugin_Compatibility::is_wc_version_gte( '3.5' ) ) {
129
-
130
- $locale_info = include( WC()->plugin_path() . '/i18n/locale-info.php' );
131
-
132
- $currencies = wp_list_pluck( $locale_info, 'num_decimals', 'currency_code' );
133
-
134
- // ensure the values set in local-info.php always override the above
135
- $currencies = array_merge( $other_currencies, $currencies );
136
-
137
- } else {
138
-
139
- $currencies = [];
140
- $currency_codes = get_woocommerce_currencies();
141
-
142
- foreach ( $currency_codes as $code => $name ) {
143
- $currencies[ $code ] = 2;
144
- }
145
-
146
- $currencies = array_merge( $currencies, $other_currencies );
147
- }
148
-
149
- /**
150
- * Filters the number of decimals to use for a given currency when converting to or from its smallest denomination.
151
- *
152
- * @since 2.0.2
153
- *
154
- * @param int $decimals number of decimals
155
- * @param string $currency currency code
156
- */
157
- return apply_filters( 'wc_square_currency_decimals', isset( $currencies[ $currency ] ) ? $currencies[ $currency ] : 2, $currency );
158
- }
159
-
160
-
161
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/readme.txt DELETED
@@ -1,181 +0,0 @@
1
- === WooCommerce Square ===
2
- Contributors: automattic, royho, woothemes, bor0
3
- Tags: credit card, square, woocommerce, inventory sync
4
- Requires at least: 4.6
5
- Tested up to: 5.3
6
- Requires PHP: 5.6
7
- Stable tag: 2.0.8
8
- License: GPLv3
9
- License URI: https://www.gnu.org/licenses/gpl-3.0.html
10
-
11
- Sync inventory and product data between WooCommerce and Square POS. Securely accept payments via the Square payment gateway.
12
-
13
- == Description ==
14
-
15
- Sync inventory and product data between WooCommerce and Square POS. Securely accept payments via the Square payment gateway.
16
-
17
- = Accept credit card payments easily and directly on your store =
18
-
19
- The Square plugin extends WooCommerce to allow you to accept payments via Square. Benefit from a **PCI compliant** payment processing option that meets SAQ A levels of compliance.
20
-
21
- You can also use these advanced features:
22
-
23
- - Support for [WooCommerce Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/)
24
- - Support for [WooCommerce Pre-Orders](https://woocommerce.com/products/woocommerce-pre-orders/)
25
- - Allow customers to save payment methods and use them at checkout
26
- - Use an enhanced payment form with automatic formatting, mobile-friendly inputs, and retina card icons
27
-
28
- = Sync your product catalog with Square =
29
-
30
- You can sync your product data automatically between WooCommerce and Square.
31
-
32
- - If you sell mainly online, you can choose WooCommerce as your system of record. This will push the WooCommerce product name, inventory, prices, categories, and images to Square. Note that inventory will still be fetched periodically from Square and you must refresh inventory in WooCommerce before editing.
33
- - If you sell in multiple locations and online, you can choose Square as your system of record. This will pull product name, inventory, and prices from Square into your WooCommerce catalog. Product images will also be synced if not already set in WooCommerce.
34
-
35
- == Installation ==
36
-
37
- You can download an [older version of this gateway for older versions of WooCommerce from here](https://wordpress.org/plugins/woocommerce-square/developers/).
38
-
39
- = Automatic installation =
40
-
41
- Automatic installation is the easiest option as WordPress handles the file transfers itself and you don’t need to leave your web browser. To
42
- automatically install WooCommerce Square, log in to your WordPress dashboard, navigate to the Plugins menu, and click **Add New**.
43
-
44
- In the search field type "WooCommerce Square" and click **Search Plugins**. Once you've found our plugin you can install it by clicking **Install Now**, as well as view details about it such as the point release, rating, and description.
45
-
46
- = Manual installation =
47
-
48
- The manual installation method involves downloading our plugin and uploading it to your web server via your favorite FTP application. The WordPress codex contains [instructions on how to do this here](http://codex.wordpress.org/Managing_Plugins#Manual_Plugin_Installation).
49
-
50
- = Updating =
51
-
52
- Automatic updates should work like a charm; as always though, ensure you backup your site just in case.
53
-
54
- == Frequently Asked Questions ==
55
-
56
- = Does this require an SSL certificate? =
57
-
58
- Yes! An SSL certificate must be installed on your site to use Square.
59
-
60
- = Where can I find documentation? =
61
-
62
- For help setting up and configuring the plugin, please refer to our [user guide](https://docs.woocommerce.com/document/woocommerce-square/).
63
-
64
- = Where can I get support or talk to other users? =
65
-
66
- If you get stuck, you can ask for help in the [Plugin Forum](https://wordpress.org/support/plugin/woocommerce-square/).
67
-
68
- == Screenshots ==
69
-
70
- 1. The main plugin settings.
71
- 2. The payment gateway settings.
72
-
73
- == Changelog ==
74
-
75
- = 2.0.8 - 2019.12.09 =
76
- * Fix - Inventory changes through payments and refunds from other gateways not reflected on Square.
77
- * Fix - Fatal error on versions of WooCommerce before 4.3.
78
- * Fix - Sandbox API calls by passing is_sandbox flag to the Gateway API.
79
- * Fix - Quick edit view when editing a variable product without all variations SKU.
80
- * Fix - Verify if the product can be synced with Square before enabling sync when bulk/quick updating.
81
- * Fix - Disable sync for products that should not be synced after a REST API update.
82
- * Fix - Unable to create products during import.
83
- * Fix - Product inventory sync issuse when WooCommerce is set as the Source of Record.
84
- * Fix - Inventory not updated when purchased through another gateway.
85
- * Fix - Category and description data not updated in a sync from Square.
86
- * Fix - Transactions on multiple stores connected to the same Square account would appear to succeed without actually charging the customer.
87
- * Fix - When making multiple partial refunds on the same order, only the first one would work.
88
- * Tweak - Include product ID on failed sync record message.
89
- * Tweak - Remove notices for refresh token when sanbox is enabled.
90
- * Tweak - Prevent refreshing a token token when sanbox is enabled.
91
-
92
-
93
-
94
- = 2.0.7 - 2019.11.18 =
95
- * Fix - No longer automatically disconnect on unexpected authorization errors
96
- * Fix - Bump compatibility for WooCommerce 3.8 and WordPress 5.3
97
- * Fix - Correct cents rounding that was causing invalid value errors
98
- * Fix - Fix encrypted token handling
99
- * Fix - No longer call revoke when disconnecting - just disconnect the site
100
-
101
- = 2.0.6 - 2019.11.07 =
102
- * Fix - Access token renewal schedule action duplication.
103
-
104
- = 2.0.5 - 2019.10.16 =
105
- * Fix - Access token renewal by adding support for refresh tokens as per the new Square API
106
- * Fix - Variable pricing import and adding an alert when these type of products are ignored.
107
- * Fix - Line item discounts and other adjustments being ignored.
108
- * Tweak - Add a notice when a refresh token is not present to warn users to re-connect their accounts.
109
- * Feature - Added support for Sandbox accounts.
110
-
111
- = 2.0.4 - 2019.09.03 =
112
- * Fix - Add adjustments to Square order in the event of discrepancy with WooCommerce total
113
-
114
- = 2.0.3 - 2019.08.19 =
115
- * Tweak - Re-introduce the "inventory sync" toggle to allow syncing product data without affecting inventory
116
- * Fix - Adjust v1 upgrades to properly toggle inventory sync when not enabled in v1
117
- * Fix - Ensure product prices are correctly converted to and from cents regardless of the decimal place setting
118
- * Fix - Don't block the product stock management UI when product sync is disabled
119
- * Fix - Ensure products that have multiple attributes that aren't used for variations can be synced
120
- * Misc - Add support for WooCommerce 3.7
121
-
122
- = 2.0.2 - 2019.08.13 =
123
- * Tweak – WC 3.7 compatibility.
124
-
125
- = 2.0.1 - 2019.07.23 =
126
- * Fix - Don't display the "unsupported" payment processing admin notice for UK-based merchants
127
-
128
- = 2.0.0 - 2019.07.22 =
129
- * Feature - Support Square customer profiles for saved payment methods
130
- * Feature - Customers can label their saved payment methods for easy identification when choosing how to pay
131
- * Feature - Support enhanced payment form with auto formatting and retina card icons
132
- * Feature - Show detailed decline messages when possible in place of generic errors
133
- * Feature - Add support for WooCommerce Subscriptions
134
- * Feature - Add support for WooCommerce Pre-Orders
135
- * Feature - Orders with only virtual items can force a charge instead of authorization
136
- * Feature - Void authorizations from WooCommerce
137
- * Feature - Itemize Square transactions for improved reporting in Square
138
- * Feature - Add sync records to notify admins of failed product syncs
139
- * Feature - Changed "Synced with Square" option while bulk editing products
140
- * Tweak - Introduce "System of Record" settings to control product data sync
141
- * Tweak - Remove items from Square locations when deleted in WooCommerce (if WC is the system of record)
142
- * Tweak - Allow users to hide WooCommerce products if removed from the linked Square location (if Square is the system of record)
143
- * Tweak - Import images from Square when not set in WooCommerce (if Square is the system of record)
144
- * Tweak - Remove Square postcode field when a postcode can be used from the checkout form
145
- * Fix - Ensure connection tokens are refreshed ahead of expiration
146
- * Fix - Always ensure settings are displayed in multisite
147
- * Fix - Ensure Square prices update WooCommerce regular price, not sale price
148
- * Fix - Remove usages of `$HTTP_RAW_POST_DATA`, which is deprecated
149
- * Fix - Do not allow multiple sync processes to run simultaneously
150
- * Fix - Avoid submitting duplicate orders with Checkout for WC plugin
151
- * Misc - Upgrade to Square Connect v2 APIs
152
- * Misc - Background process product sync for improved scalability
153
- * Misc - Refactor for other miscellaneous fixes and improved reliability
154
-
155
- = 1.0.38 - 2019-07-05 =
156
- * Fix - Re-deploy due to erroneous inclusion of trunk folder
157
-
158
- = 1.0.37 – 2019-04-16 =
159
- * Fix – Use correct assets loading scheme.
160
-
161
- = 1.0.36 – 2019-04-15 =
162
- * Tweak – WC 3.6 compatibility.
163
-
164
- = 1.0.35 - 2019-02-01 =
165
- * Fix - Idempotency key reuse issue when checking out.
166
-
167
- = 1.0.34 - 2018-11-07 =
168
- * Update - Fieldset tag to div tag in payment box to prevent unwanted styling.
169
- * Fix - Provide unique idempotency ID to the order instead of random unique number.
170
- * Update - WP tested up to version 5.0
171
-
172
- = 1.0.33 - 2018-09-27 =
173
- * Update - WC tested up to version 3.5
174
-
175
- = 1.0.32 - 2018-08-23 =
176
- * Fix - UK/GB localed does not support Diners/Discover, so do not show these brands on checkout.
177
-
178
- == Upgrade Notice ==
179
-
180
- = 1.0.25 =
181
- * Public Release!
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/templates/emails/plain/square-sync-completed.php DELETED
@@ -1,46 +0,0 @@
1
- <?php
2
- /**
3
- * WooCommerce Square
4
- *
5
- * This source file is subject to the GNU General Public License v3.0
6
- * that is bundled with this package in the file license.txt.
7
- * It is also available through the world-wide-web at this URL:
8
- * http://www.gnu.org/licenses/gpl-3.0.html
9
- * If you did not receive a copy of the license and are unable to
10
- * obtain it through the world-wide-web, please send an email
11
- * to license@woocommerce.com so we can send you a copy immediately.
12
- *
13
- * DISCLAIMER
14
- *
15
- * Do not edit or add to this file if you wish to upgrade WooCommerce Square to newer
16
- * versions in the future. If you wish to customize WooCommerce Square for your
17
- * needs please refer to https://docs.woocommerce.com/document/woocommerce-square/
18
- *
19
- * @author WooCommerce
20
- * @copyright Copyright: (c) 2019, Automattic, Inc.
21
- * @license http://www.gnu.org/licenses/gpl-3.0.html GNU General Public License v3.0
22
- */
23
-
24
- defined( 'ABSPATH' ) or exit;
25
-
26
- /**
27
- * Square sync completed plain email template.
28
- *
29
- * @type string $email_heading email heading
30
- * @type string $email_body email body
31
- * @type \WooCommerce\Square\Emails\Sync_Completed $email email object
32
- * @type \stdClass $sync_job background job object
33
- *
34
- * @version 2.0.0
35
- * @since 2.0.0
36
- */
37
-
38
- echo $email_heading . "\n\n";
39
-
40
- echo "----------\n\n";
41
-
42
- echo wptexturize( $email_body );
43
-
44
- echo "----------\n\n";
45
-
46
- echo (string) apply_filters( 'woocommerce_email_footer_text', get_option( 'woocommerce_email_footer_text', '' ) );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/autoload.php DELETED
@@ -1,7 +0,0 @@
1
- <?php
2
-
3
- // autoload.php @generated by Composer
4
-
5
- require_once __DIR__ . '/composer/autoload_real.php';
6
-
7
- return ComposerAutoloaderInit5fe3bee6c088a59752379ee4b9b38ccc::getLoader();
 
 
 
 
 
 
 
trunk/vendor/composer/ClassLoader.php DELETED
@@ -1,445 +0,0 @@
1
- <?php
2
-
3
- /*
4
- * This file is part of Composer.
5
- *
6
- * (c) Nils Adermann <naderman@naderman.de>
7
- * Jordi Boggiano <j.boggiano@seld.be>
8
- *
9
- * For the full copyright and license information, please view the LICENSE
10
- * file that was distributed with this source code.
11
- */
12
-
13
- namespace Composer\Autoload;
14
-
15
- /**
16
- * ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
17
- *
18
- * $loader = new \Composer\Autoload\ClassLoader();
19
- *
20
- * // register classes with namespaces
21
- * $loader->add('Symfony\Component', __DIR__.'/component');
22
- * $loader->add('Symfony', __DIR__.'/framework');
23
- *
24
- * // activate the autoloader
25
- * $loader->register();
26
- *
27
- * // to enable searching the include path (eg. for PEAR packages)
28
- * $loader->setUseIncludePath(true);
29
- *
30
- * In this example, if you try to use a class in the Symfony\Component
31
- * namespace or one of its children (Symfony\Component\Console for instance),
32
- * the autoloader will first look for the class under the component/
33
- * directory, and it will then fallback to the framework/ directory if not
34
- * found before giving up.
35
- *
36
- * This class is loosely based on the Symfony UniversalClassLoader.
37
- *
38
- * @author Fabien Potencier <fabien@symfony.com>
39
- * @author Jordi Boggiano <j.boggiano@seld.be>
40
- * @see http://www.php-fig.org/psr/psr-0/
41
- * @see http://www.php-fig.org/psr/psr-4/
42
- */
43
- class ClassLoader
44
- {
45
- // PSR-4
46
- private $prefixLengthsPsr4 = array();
47
- private $prefixDirsPsr4 = array();
48
- private $fallbackDirsPsr4 = array();
49
-
50
- // PSR-0
51
- private $prefixesPsr0 = array();
52
- private $fallbackDirsPsr0 = array();
53
-
54
- private $useIncludePath = false;
55
- private $classMap = array();
56
- private $classMapAuthoritative = false;
57
- private $missingClasses = array();
58
- private $apcuPrefix;
59
-
60
- public function getPrefixes()
61
- {
62
- if (!empty($this->prefixesPsr0)) {
63
- return call_user_func_array('array_merge', $this->prefixesPsr0);
64
- }
65
-
66
- return array();
67
- }
68
-
69
- public function getPrefixesPsr4()
70
- {
71
- return $this->prefixDirsPsr4;
72
- }
73
-
74
- public function getFallbackDirs()
75
- {
76
- return $this->fallbackDirsPsr0;
77
- }
78
-
79
- public function getFallbackDirsPsr4()
80
- {
81
- return $this->fallbackDirsPsr4;
82
- }
83
-
84
- public function getClassMap()
85
- {
86
- return $this->classMap;
87
- }
88
-
89
- /**
90
- * @param array $classMap Class to filename map
91
- */
92
- public function addClassMap(array $classMap)
93
- {
94
- if ($this->classMap) {
95
- $this->classMap = array_merge($this->classMap, $classMap);
96
- } else {
97
- $this->classMap = $classMap;
98
- }
99
- }
100
-
101
- /**
102
- * Registers a set of PSR-0 directories for a given prefix, either
103
- * appending or prepending to the ones previously set for this prefix.
104
- *
105
- * @param string $prefix The prefix
106
- * @param array|string $paths The PSR-0 root directories
107
- * @param bool $prepend Whether to prepend the directories
108
- */
109
- public function add($prefix, $paths, $prepend = false)
110
- {
111
- if (!$prefix) {
112
- if ($prepend) {
113
- $this->fallbackDirsPsr0 = array_merge(
114
- (array) $paths,
115
- $this->fallbackDirsPsr0
116
- );
117
- } else {
118
- $this->fallbackDirsPsr0 = array_merge(
119
- $this->fallbackDirsPsr0,
120
- (array) $paths
121
- );
122
- }
123
-
124
- return;
125
- }
126
-
127
- $first = $prefix[0];
128
- if (!isset($this->prefixesPsr0[$first][$prefix])) {
129
- $this->prefixesPsr0[$first][$prefix] = (array) $paths;
130
-
131
- return;
132
- }
133
- if ($prepend) {
134
- $this->prefixesPsr0[$first][$prefix] = array_merge(
135
- (array) $paths,
136
- $this->prefixesPsr0[$first][$prefix]
137
- );
138
- } else {
139
- $this->prefixesPsr0[$first][$prefix] = array_merge(
140
- $this->prefixesPsr0[$first][$prefix],
141
- (array) $paths
142
- );
143
- }
144
- }
145
-
146
- /**
147
- * Registers a set of PSR-4 directories for a given namespace, either
148
- * appending or prepending to the ones previously set for this namespace.
149
- *
150
- * @param string $prefix The prefix/namespace, with trailing '\\'
151
- * @param array|string $paths The PSR-4 base directories
152
- * @param bool $prepend Whether to prepend the directories
153
- *
154
- * @throws \InvalidArgumentException
155
- */
156
- public function addPsr4($prefix, $paths, $prepend = false)
157
- {
158
- if (!$prefix) {
159
- // Register directories for the root namespace.
160
- if ($prepend) {
161
- $this->fallbackDirsPsr4 = array_merge(
162
- (array) $paths,
163
- $this->fallbackDirsPsr4
164
- );
165
- } else {
166
- $this->fallbackDirsPsr4 = array_merge(
167
- $this->fallbackDirsPsr4,
168
- (array) $paths
169
- );
170
- }
171
- } elseif (!isset($this->prefixDirsPsr4[$prefix])) {
172
- // Register directories for a new namespace.
173
- $length = strlen($prefix);
174
- if ('\\' !== $prefix[$length - 1]) {
175
- throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
176
- }
177
- $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
178
- $this->prefixDirsPsr4[$prefix] = (array) $paths;
179
- } elseif ($prepend) {
180
- // Prepend directories for an already registered namespace.
181
- $this->prefixDirsPsr4[$prefix] = array_merge(
182
- (array) $paths,
183
- $this->prefixDirsPsr4[$prefix]
184
- );
185
- } else {
186
- // Append directories for an already registered namespace.
187
- $this->prefixDirsPsr4[$prefix] = array_merge(
188
- $this->prefixDirsPsr4[$prefix],
189
- (array) $paths
190
- );
191
- }
192
- }
193
-
194
- /**
195
- * Registers a set of PSR-0 directories for a given prefix,
196
- * replacing any others previously set for this prefix.
197
- *
198
- * @param string $prefix The prefix
199
- * @param array|string $paths The PSR-0 base directories
200
- */
201
- public function set($prefix, $paths)
202
- {
203
- if (!$prefix) {
204
- $this->fallbackDirsPsr0 = (array) $paths;
205
- } else {
206
- $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
207
- }
208
- }
209
-
210
- /**
211
- * Registers a set of PSR-4 directories for a given namespace,
212
- * replacing any others previously set for this namespace.
213
- *
214
- * @param string $prefix The prefix/namespace, with trailing '\\'
215
- * @param array|string $paths The PSR-4 base directories
216
- *
217
- * @throws \InvalidArgumentException
218
- */
219
- public function setPsr4($prefix, $paths)
220
- {
221
- if (!$prefix) {
222
- $this->fallbackDirsPsr4 = (array) $paths;
223
- } else {
224
- $length = strlen($prefix);
225
- if ('\\' !== $prefix[$length - 1]) {
226
- throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
227
- }
228
- $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
229
- $this->prefixDirsPsr4[$prefix] = (array) $paths;
230
- }
231
- }
232
-
233
- /**
234
- * Turns on searching the include path for class files.
235
- *
236
- * @param bool $useIncludePath
237
- */
238
- public function setUseIncludePath($useIncludePath)
239
- {
240
- $this->useIncludePath = $useIncludePath;
241
- }
242
-
243
- /**
244
- * Can be used to check if the autoloader uses the include path to check
245
- * for classes.
246
- *
247
- * @return bool
248
- */
249
- public function getUseIncludePath()
250
- {
251
- return $this->useIncludePath;
252
- }
253
-
254
- /**
255
- * Turns off searching the prefix and fallback directories for classes
256
- * that have not been registered with the class map.
257
- *
258
- * @param bool $classMapAuthoritative
259
- */
260
- public function setClassMapAuthoritative($classMapAuthoritative)
261
- {
262
- $this->classMapAuthoritative = $classMapAuthoritative;
263
- }
264
-
265
- /**
266
- * Should class lookup fail if not found in the current class map?
267
- *
268
- * @return bool
269
- */
270
- public function isClassMapAuthoritative()
271
- {
272
- return $this->classMapAuthoritative;
273
- }
274
-
275
- /**
276
- * APCu prefix to use to cache found/not-found classes, if the extension is enabled.
277
- *
278
- * @param string|null $apcuPrefix
279
- */
280
- public function setApcuPrefix($apcuPrefix)
281
- {
282
- $this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
283
- }
284
-
285
- /**
286
- * The APCu prefix in use, or null if APCu caching is not enabled.
287
- *
288
- * @return string|null
289
- */
290
- public function getApcuPrefix()
291
- {
292
- return $this->apcuPrefix;
293
- }
294
-
295
- /**
296
- * Registers this instance as an autoloader.
297
- *
298
- * @param bool $prepend Whether to prepend the autoloader or not
299
- */
300
- public function register($prepend = false)
301
- {
302
- spl_autoload_register(array($this, 'loadClass'), true, $prepend);
303
- }
304
-
305
- /**
306
- * Unregisters this instance as an autoloader.
307
- */
308
- public function unregister()
309
- {
310
- spl_autoload_unregister(array($this, 'loadClass'));
311
- }
312
-
313
- /**
314
- * Loads the given class or interface.
315
- *
316
- * @param string $class The name of the class
317
- * @return bool|null True if loaded, null otherwise
318
- */
319
- public function loadClass($class)
320
- {
321
- if ($file = $this->findFile($class)) {
322
- includeFile($file);
323
-
324
- return true;
325
- }
326
- }
327
-
328
- /**
329
- * Finds the path to the file where the class is defined.
330
- *
331
- * @param string $class The name of the class
332
- *
333
- * @return string|false The path if found, false otherwise
334
- */
335
- public function findFile($class)
336
- {
337
- // class map lookup
338
- if (isset($this->classMap[$class])) {
339
- return $this->classMap[$class];
340
- }
341
- if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
342
- return false;
343
- }
344
- if (null !== $this->apcuPrefix) {
345
- $file = apcu_fetch($this->apcuPrefix.$class, $hit);
346
- if ($hit) {
347
- return $file;
348
- }
349
- }
350
-
351
- $file = $this->findFileWithExtension($class, '.php');
352
-
353
- // Search for Hack files if we are running on HHVM
354
- if (false === $file && defined('HHVM_VERSION')) {
355
- $file = $this->findFileWithExtension($class, '.hh');
356
- }
357
-
358
- if (null !== $this->apcuPrefix) {
359
- apcu_add($this->apcuPrefix.$class, $file);
360
- }
361
-
362
- if (false === $file) {
363
- // Remember that this class does not exist.
364
- $this->missingClasses[$class] = true;
365
- }
366
-
367
- return $file;
368
- }
369
-
370
- private function findFileWithExtension($class, $ext)
371
- {
372
- // PSR-4 lookup
373
- $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
374
-
375
- $first = $class[0];
376
- if (isset($this->prefixLengthsPsr4[$first])) {
377
- $subPath = $class;
378
- while (false !== $lastPos = strrpos($subPath, '\\')) {
379
- $subPath = substr($subPath, 0, $lastPos);
380
- $search = $subPath . '\\';
381
- if (isset($this->prefixDirsPsr4[$search])) {
382
- $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
383
- foreach ($this->prefixDirsPsr4[$search] as $dir) {
384
- if (file_exists($file = $dir . $pathEnd)) {
385
- return $file;
386
- }
387
- }
388
- }
389
- }
390
- }
391
-
392
- // PSR-4 fallback dirs
393
- foreach ($this->fallbackDirsPsr4 as $dir) {
394
- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
395
- return $file;
396
- }
397
- }
398
-
399
- // PSR-0 lookup
400
- if (false !== $pos = strrpos($class, '\\')) {
401
- // namespaced class name
402
- $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
403
- . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
404
- } else {
405
- // PEAR-like class name
406
- $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
407
- }
408
-
409
- if (isset($this->prefixesPsr0[$first])) {
410
- foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
411
- if (0 === strpos($class, $prefix)) {
412
- foreach ($dirs as $dir) {
413
- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
414
- return $file;
415
- }
416
- }
417
- }
418
- }
419
- }
420
-
421
- // PSR-0 fallback dirs
422
- foreach ($this->fallbackDirsPsr0 as $dir) {
423
- if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
424
- return $file;
425
- }
426
- }
427
-
428
- // PSR-0 include paths.
429
- if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
430
- return $file;
431
- }
432
-
433
- return false;
434
- }
435
- }
436
-
437
- /**
438
- * Scope isolated include.
439
- *
440
- * Prevents access to $this/self from included files.
441
- */
442
- function includeFile($file)
443
- {
444
- include $file;
445
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/LICENSE DELETED
@@ -1,21 +0,0 @@
1
-
2
- Copyright (c) Nils Adermann, Jordi Boggiano
3
-
4
- Permission is hereby granted, free of charge, to any person obtaining a copy
5
- of this software and associated documentation files (the "Software"), to deal
6
- in the Software without restriction, including without limitation the rights
7
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
- copies of the Software, and to permit persons to whom the Software is furnished
9
- to do so, subject to the following conditions:
10
-
11
- The above copyright notice and this permission notice shall be included in all
12
- copies or substantial portions of the Software.
13
-
14
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
- THE SOFTWARE.
21
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/autoload_classmap.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- // autoload_classmap.php @generated by Composer
4
-
5
- $vendorDir = dirname(dirname(__FILE__));
6
- $baseDir = dirname($vendorDir);
7
-
8
- return array(
9
- );
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/autoload_namespaces.php DELETED
@@ -1,9 +0,0 @@
1
- <?php
2
-
3
- // autoload_namespaces.php @generated by Composer
4
-
5
- $vendorDir = dirname(dirname(__FILE__));
6
- $baseDir = dirname($vendorDir);
7
-
8
- return array(
9
- );
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/autoload_psr4.php DELETED
@@ -1,10 +0,0 @@
1
- <?php
2
-
3
- // autoload_psr4.php @generated by Composer
4
-
5
- $vendorDir = dirname(dirname(__FILE__));
6
- $baseDir = dirname($vendorDir);
7
-
8
- return array(
9
- 'SquareConnect\\' => array($vendorDir . '/square/connect/lib'),
10
- );
 
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/autoload_real.php DELETED
@@ -1,52 +0,0 @@
1
- <?php
2
-
3
- // autoload_real.php @generated by Composer
4
-
5
- class ComposerAutoloaderInit5fe3bee6c088a59752379ee4b9b38ccc
6
- {
7
- private static $loader;
8
-
9
- public static function loadClassLoader($class)
10
- {
11
- if ('Composer\Autoload\ClassLoader' === $class) {
12
- require __DIR__ . '/ClassLoader.php';
13
- }
14
- }
15
-
16
- public static function getLoader()
17
- {
18
- if (null !== self::$loader) {
19
- return self::$loader;
20
- }
21
-
22
- spl_autoload_register(array('ComposerAutoloaderInit5fe3bee6c088a59752379ee4b9b38ccc', 'loadClassLoader'), true, true);
23
- self::$loader = $loader = new \Composer\Autoload\ClassLoader();
24
- spl_autoload_unregister(array('ComposerAutoloaderInit5fe3bee6c088a59752379ee4b9b38ccc', 'loadClassLoader'));
25
-
26
- $useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
27
- if ($useStaticLoader) {
28
- require_once __DIR__ . '/autoload_static.php';
29
-
30
- call_user_func(\Composer\Autoload\ComposerStaticInit5fe3bee6c088a59752379ee4b9b38ccc::getInitializer($loader));
31
- } else {
32
- $map = require __DIR__ . '/autoload_namespaces.php';
33
- foreach ($map as $namespace => $path) {
34
- $loader->set($namespace, $path);
35
- }
36
-
37
- $map = require __DIR__ . '/autoload_psr4.php';
38
- foreach ($map as $namespace => $path) {
39
- $loader->setPsr4($namespace, $path);
40
- }
41
-
42
- $classMap = require __DIR__ . '/autoload_classmap.php';
43
- if ($classMap) {
44
- $loader->addClassMap($classMap);
45
- }
46
- }
47
-
48
- $loader->register(true);
49
-
50
- return $loader;
51
- }
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/autoload_static.php DELETED
@@ -1,31 +0,0 @@
1
- <?php
2
-
3
- // autoload_static.php @generated by Composer
4
-
5
- namespace Composer\Autoload;
6
-
7
- class ComposerStaticInit5fe3bee6c088a59752379ee4b9b38ccc
8
- {
9
- public static $prefixLengthsPsr4 = array (
10
- 'S' =>
11
- array (
12
- 'SquareConnect\\' => 14,
13
- ),
14
- );
15
-
16
- public static $prefixDirsPsr4 = array (
17
- 'SquareConnect\\' =>
18
- array (
19
- 0 => __DIR__ . '/..' . '/square/connect/lib',
20
- ),
21
- );
22
-
23
- public static function getInitializer(ClassLoader $loader)
24
- {
25
- return \Closure::bind(function () use ($loader) {
26
- $loader->prefixLengthsPsr4 = ComposerStaticInit5fe3bee6c088a59752379ee4b9b38ccc::$prefixLengthsPsr4;
27
- $loader->prefixDirsPsr4 = ComposerStaticInit5fe3bee6c088a59752379ee4b9b38ccc::$prefixDirsPsr4;
28
-
29
- }, null, ClassLoader::class);
30
- }
31
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/composer/installed.json DELETED
@@ -1,109 +0,0 @@
1
- [
2
- {
3
- "name": "prospress/action-scheduler",
4
- "version": "2.2.0",
5
- "version_normalized": "2.2.0.0",
6
- "source": {
7
- "type": "git",
8
- "url": "https://github.com/Prospress/action-scheduler.git",
9
- "reference": "641337c7e28ab4be6856483d4ec436ec0063e414"
10
- },
11
- "dist": {
12
- "type": "zip",
13
- "url": "https://api.github.com/repos/Prospress/action-scheduler/zipball/641337c7e28ab4be6856483d4ec436ec0063e414",
14
- "reference": "641337c7e28ab4be6856483d4ec436ec0063e414",
15
- "shasum": ""
16
- },
17
- "require-dev": {
18
- "wp-cli/wp-cli": "^1.3"
19
- },
20
- "time": "2019-01-31T04:16:52+00:00",
21
- "type": "wordpress-plugin",
22
- "installation-source": "dist",
23
- "notification-url": "https://packagist.org/downloads/",
24
- "license": [
25
- "GPL-3.0"
26
- ],
27
- "description": "Action Scheduler for WordPress and WooCommerce"
28
- },
29
- {
30
- "name": "skyverge/wc-plugin-framework",
31
- "version": "5.4.0",
32
- "version_normalized": "5.4.0.0",
33
- "source": {
34
- "type": "git",
35
- "url": "https://github.com/skyverge/wc-plugin-framework.git",
36
- "reference": "0e9f013e9841e5d231e3e5b817d2be30688e77e5"
37
- },
38
- "dist": {
39
- "type": "zip",
40
- "url": "https://api.github.com/repos/skyverge/wc-plugin-framework/zipball/0e9f013e9841e5d231e3e5b817d2be30688e77e5",
41
- "reference": "0e9f013e9841e5d231e3e5b817d2be30688e77e5",
42
- "shasum": ""
43
- },
44
- "require-dev": {
45
- "lucatume/wp-browser": "^2.1"
46
- },
47
- "time": "2019-03-13T16:34:44+00:00",
48
- "type": "library",
49
- "installation-source": "dist",
50
- "description": "The official SkyVerge WooCommerce plugin framework",
51
- "support": {
52
- "source": "https://github.com/skyverge/wc-plugin-framework/tree/5.4.0",
53
- "issues": "https://github.com/skyverge/wc-plugin-framework/issues"
54
- }
55
- },
56
- {
57
- "name": "square/connect",
58
- "version": "2.20190814.2",
59
- "version_normalized": "2.20190814.2.0",
60
- "source": {
61
- "type": "git",
62
- "url": "https://github.com/square/connect-php-sdk.git",
63
- "reference": "d778579a9f42c06d4eb68bcd78e7371f1b2f8f94"
64
- },
65
- "dist": {
66
- "type": "zip",
67
- "url": "https://api.github.com/repos/square/connect-php-sdk/zipball/d778579a9f42c06d4eb68bcd78e7371f1b2f8f94",
68
- "reference": "d778579a9f42c06d4eb68bcd78e7371f1b2f8f94",
69
- "shasum": ""
70
- },
71
- "require": {
72
- "ext-curl": "*",
73
- "ext-json": "*",
74
- "ext-mbstring": "*",
75
- "php": ">=5.3.3"
76
- },
77
- "require-dev": {
78
- "phpunit/phpunit": "~4.0",
79
- "satooshi/php-coveralls": "~0.6.1",
80
- "squizlabs/php_codesniffer": "~2.0"
81
- },
82
- "time": "2019-08-23T19:44:40+00:00",
83
- "type": "library",
84
- "installation-source": "dist",
85
- "autoload": {
86
- "psr-4": {
87
- "SquareConnect\\": "lib/"
88
- }
89
- },
90
- "notification-url": "https://packagist.org/downloads/",
91
- "license": [
92
- "Apache-2.0"
93
- ],
94
- "authors": [
95
- {
96
- "name": "Square, Inc.",
97
- "homepage": "https://squareup.com/developers"
98
- }
99
- ],
100
- "description": "PHP client library for the Square Connect v2 API",
101
- "homepage": "https://github.com/square/connect-php-sdk",
102
- "keywords": [
103
- "api",
104
- "php",
105
- "sdk",
106
- "swagger"
107
- ]
108
- }
109
- ]
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/.github/release-drafter.yml DELETED
@@ -1,15 +0,0 @@
1
- template: |
2
- ## next release &ndash; date
3
-
4
- <!-- Move the individual changes below into the appropriate section -->
5
-
6
- $CHANGES
7
-
8
- **Added**
9
- **Changed**
10
- **Deprecated**
11
- **Removed**
12
- **Fixed**
13
- **Security**
14
-
15
- change-template: '* $TITLE (PR #$NUMBER)'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- phpunit.xml
2
- vendor
3
- .idea
 
 
 
trunk/vendor/prospress/action-scheduler/.travis.yml DELETED
@@ -1,37 +0,0 @@
1
- # Travis CI Configuration File
2
-
3
- # Tell Travis CI we're using PHP
4
- language: php
5
-
6
- # We nee to use Precise, not Trusty, to test against PHP 5.3, see https://github.com/travis-ci/travis-ci/issues/8219
7
- dist: precise
8
-
9
- # Versions of PHP to test against
10
- php:
11
- - "5.3"
12
- - "5.4"
13
- - "5.5"
14
- - "5.6"
15
- - "7.0"
16
- - "7.1"
17
-
18
- # Specify versions of WordPress to test against
19
- # WP_VERSION = WordPress version number (use "master" for SVN trunk)
20
- # WP_MULTISITE = whether to test multisite (use either "0" or "1")
21
- env:
22
- - WP_VERSION=4.8 WP_MULTISITE=0
23
- - WP_VERSION=4.7 WP_MULTISITE=0
24
- - WP_VERSION=4.6 WP_MULTISITE=0
25
- - WP_VERSION=4.8 WP_MULTISITE=1
26
- - WP_VERSION=4.7 WP_MULTISITE=1
27
- - WP_VERSION=4.6 WP_MULTISITE=1
28
-
29
- # Grab the setup script and execute
30
- before_script:
31
- - source tests/travis/setup.sh $TRAVIS_PHP_VERSION
32
-
33
- script:
34
- - if [[ "$TRAVIS_PHP_VERSION" == "7.1" ]] && [[ "$WP_VERSION" == "4.8" ]] && [[ "$WP_MULTISITE" == "0" ]] && [[ "$TRAVIS_BRANCH" == "master" ]]; then phpunit --configuration tests/phpunit.xml.dist --coverage-clover clover.xml; else phpunit --configuration tests/phpunit.xml.dist; fi
35
-
36
- after_script:
37
- - bash <(curl -s https://codecov.io/bash)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/README.md DELETED
@@ -1,41 +0,0 @@
1
- # Action Scheduler - Job Queue for WordPress [![Build Status](https://travis-ci.org/Prospress/action-scheduler.png?branch=master)](https://travis-ci.org/Prospress/action-scheduler) [![codecov](https://codecov.io/gh/Prospress/action-scheduler/branch/master/graph/badge.svg)](https://codecov.io/gh/Prospress/action-scheduler)
2
-
3
- Action Scheduler is a scalable, traceable job queue for background processing large sets of actions in WordPress. It's specially designed to be distributed in WordPress plugins.
4
-
5
- Action Scheduler works by triggering an action hook to run at some time in the future. Each hook can be scheduled with unique data, to allow callbacks to perform operations on that data. The hook can also be scheduled to run on one or more occassions.
6
-
7
- Think of it like an extension to `do_action()` which adds the ability to delay and repeat a hook.
8
-
9
- ## Battle-Tested Background Processing
10
-
11
- Every month, Action Scheduler processes millions of payments for [Subscriptions](https://woocommerce.com/products/woocommerce-subscriptions/), webhooks for [WooCommerce](https://wordpress.org/plugins/woocommerce/), as well as emails and other events for a range of other plugins.
12
-
13
- It's been seen on live sites processing queues in excess of 50,000 jobs and doing resource intensive operations, like processing payments and creating orders, at a sustained rate of over 10,000 / hour without negatively impacting normal site operations.
14
-
15
- This is all on infrastructure and WordPress sites outside the control of the plugin author.
16
-
17
- If your plugin needs background processing, especially of large sets of tasks, Action Scheduler can help.
18
-
19
- ## Learn More
20
-
21
- To learn more about how to Action Scheduler works, and how to use it in your plugin, check out the docs on [ActionScheduler.org](https://actionscheduler.org).
22
-
23
- There you will find:
24
-
25
- * [Usage guide](https://actionscheduler.org/usage/): instructions on installing and using Action Scheduler
26
- * [WP CLI guide](https://actionscheduler.org/wp-cli/): instructions on running Action Scheduler at scale via WP CLI
27
- * [API Reference](https://actionscheduler.org/api/): complete reference guide for all API functions
28
- * [Administration Guide](https://actionscheduler.org/admin/): guide to managing scheduled actions via the administration screen
29
- * [Guide to Background Processing at Scale](https://actionscheduler.org/perf/): instructions for running Action Scheduler at scale via the default WP Cron queue runner
30
-
31
- ## Credits
32
-
33
- Action Scheduler is developed and maintained by [Prospress](http://prospress.com/) in collaboration with [Flightless](https://flightless.us/).
34
-
35
- Collaboration is cool. We'd love to work with you to improve Action Scheduler. [Pull Requests](https://github.com/prospress/action-scheduler/pulls) welcome.
36
-
37
- ---
38
-
39
- <p align="center">
40
- <img src="https://cloud.githubusercontent.com/assets/235523/11986380/bb6a0958-a983-11e5-8e9b-b9781d37c64a.png" width="160">
41
- </p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/action-scheduler.php DELETED
@@ -1,47 +0,0 @@
1
- <?php
2
- /*
3
- * Plugin Name: Action Scheduler
4
- * Plugin URI: https://github.com/prospress/action-scheduler
5
- * Description: A robust scheduling library for use in WordPress plugins.
6
- * Author: Prospress
7
- * Author URI: http://prospress.com/
8
- * Version: 2.2.0
9
- * License: GPLv3
10
- *
11
- * Copyright 2018 Prospress, Inc. (email : freedoms@prospress.com)
12
- *
13
- * This program is free software: you can redistribute it and/or modify
14
- * it under the terms of the GNU General Public License as published by
15
- * the Free Software Foundation, either version 3 of the License, or
16
- * (at your option) any later version.
17
- *
18
- * This program is distributed in the hope that it will be useful,
19
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21
- * GNU General Public License for more details.
22
- *
23
- * You should have received a copy of the GNU General Public License
24
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
25
- *
26
- */
27
-
28
- if ( ! function_exists( 'action_scheduler_register_2_dot_2_dot_0' ) ) {
29
-
30
- if ( ! class_exists( 'ActionScheduler_Versions' ) ) {
31
- require_once( 'classes/ActionScheduler_Versions.php' );
32
- add_action( 'plugins_loaded', array( 'ActionScheduler_Versions', 'initialize_latest_version' ), 1, 0 );
33
- }
34
-
35
- add_action( 'plugins_loaded', 'action_scheduler_register_2_dot_2_dot_0', 0, 0 );
36
-
37
- function action_scheduler_register_2_dot_2_dot_0() {
38
- $versions = ActionScheduler_Versions::instance();
39
- $versions->register( '2.2.0', 'action_scheduler_initialize_2_dot_2_dot_0' );
40
- }
41
-
42
- function action_scheduler_initialize_2_dot_2_dot_0() {
43
- require_once( 'classes/ActionScheduler.php' );
44
- ActionScheduler::init( __FILE__ );
45
- }
46
-
47
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler.php DELETED
@@ -1,133 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler {
8
- private static $plugin_file = '';
9
- /** @var ActionScheduler_ActionFactory */
10
- private static $factory = NULL;
11
-
12
- public static function factory() {
13
- if ( !isset(self::$factory) ) {
14
- self::$factory = new ActionScheduler_ActionFactory();
15
- }
16
- return self::$factory;
17
- }
18
-
19
- public static function store() {
20
- return ActionScheduler_Store::instance();
21
- }
22
-
23
- public static function logger() {
24
- return ActionScheduler_Logger::instance();
25
- }
26
-
27
- public static function runner() {
28
- return ActionScheduler_QueueRunner::instance();
29
- }
30
-
31
- public static function admin_view() {
32
- return ActionScheduler_AdminView::instance();
33
- }
34
-
35
- /**
36
- * Get the absolute system path to the plugin directory, or a file therein
37
- * @static
38
- * @param string $path
39
- * @return string
40
- */
41
- public static function plugin_path( $path ) {
42
- $base = dirname(self::$plugin_file);
43
- if ( $path ) {
44
- return trailingslashit($base).$path;
45
- } else {
46
- return untrailingslashit($base);
47
- }
48
- }
49
-
50
- /**
51
- * Get the absolute URL to the plugin directory, or a file therein
52
- * @static
53
- * @param string $path
54
- * @return string
55
- */
56
- public static function plugin_url( $path ) {
57
- return plugins_url($path, self::$plugin_file);
58
- }
59
-
60
- public static function autoload( $class ) {
61
- $d = DIRECTORY_SEPARATOR;
62
- if ( 'Deprecated' === substr( $class, -10 ) ) {
63
- $dir = self::plugin_path('deprecated'.$d);
64
- } elseif ( strpos( $class, 'ActionScheduler' ) === 0 ) {
65
- $dir = self::plugin_path('classes'.$d);
66
- } elseif ( strpos( $class, 'CronExpression' ) === 0 ) {
67
- $dir = self::plugin_path('lib'.$d.'cron-expression'.$d);
68
- } else {
69
- return;
70
- }
71
-
72
- if ( file_exists( "{$dir}{$class}.php" ) ) {
73
- include( "{$dir}{$class}.php" );
74
- return;
75
- }
76
- }
77
-
78
- /**
79
- * Initialize the plugin
80
- *
81
- * @static
82
- * @param string $plugin_file
83
- */
84
- public static function init( $plugin_file ) {
85
- self::$plugin_file = $plugin_file;
86
- spl_autoload_register( array( __CLASS__, 'autoload' ) );
87
-
88
- /**
89
- * Fires in the early stages of Action Scheduler init hook.
90
- */
91
- do_action( 'action_scheduler_pre_init' );
92
-
93
- $store = self::store();
94
- add_action( 'init', array( $store, 'init' ), 1, 0 );
95
-
96
- $logger = self::logger();
97
- add_action( 'init', array( $logger, 'init' ), 1, 0 );
98
-
99
- $runner = self::runner();
100
- add_action( 'init', array( $runner, 'init' ), 1, 0 );
101
-
102
- $admin_view = self::admin_view();
103
- add_action( 'init', array( $admin_view, 'init' ), 0, 0 ); // run before $store::init()
104
-
105
- require_once( self::plugin_path('functions.php') );
106
-
107
- if ( apply_filters( 'action_scheduler_load_deprecated_functions', true ) ) {
108
- require_once( self::plugin_path('deprecated/functions.php') );
109
- }
110
-
111
- if ( defined( 'WP_CLI' ) && WP_CLI ) {
112
- WP_CLI::add_command( 'action-scheduler', 'ActionScheduler_WPCLI_Scheduler_command' );
113
- }
114
- }
115
-
116
-
117
- final public function __clone() {
118
- trigger_error("Singleton. No cloning allowed!", E_USER_ERROR);
119
- }
120
-
121
- final public function __wakeup() {
122
- trigger_error("Singleton. No serialization allowed!", E_USER_ERROR);
123
- }
124
-
125
- final private function __construct() {}
126
-
127
- /** Deprecated **/
128
-
129
- public static function get_datetime_object( $when = null, $timezone = 'UTC' ) {
130
- _deprecated_function( __METHOD__, '2.0', 'wcs_add_months()' );
131
- return as_get_datetime_object( $when, $timezone );
132
- }
133
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Abstract_ListTable.php DELETED
@@ -1,656 +0,0 @@
1
- <?php
2
-
3
- if ( ! class_exists( 'WP_List_Table' ) ) {
4
- require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
5
- }
6
-
7
- /**
8
- * Action Scheduler Abstract List Table class
9
- *
10
- * This abstract class enhances WP_List_Table making it ready to use.
11
- *
12
- * By extending this class we can focus on describing how our table looks like,
13
- * which columns needs to be shown, filter, ordered by and more and forget about the details.
14
- *
15
- * This class supports:
16
- * - Bulk actions
17
- * - Search
18
- * - Sortable columns
19
- * - Automatic translations of the columns
20
- *
21
- * @codeCoverageIgnore
22
- * @since 2.0.0
23
- */
24
- abstract class ActionScheduler_Abstract_ListTable extends WP_List_Table {
25
-
26
- /**
27
- * The table name
28
- */
29
- protected $table_name;
30
-
31
- /**
32
- * Package name, used in translations
33
- */
34
- protected $package;
35
-
36
- /**
37
- * How many items do we render per page?
38
- */
39
- protected $items_per_page = 10;
40
-
41
- /**
42
- * Enables search in this table listing. If this array
43
- * is empty it means the listing is not searchable.
44
- */
45
- protected $search_by = array();
46
-
47
- /**
48
- * Columns to show in the table listing. It is a key => value pair. The
49
- * key must much the table column name and the value is the label, which is
50
- * automatically translated.
51
- */
52
- protected $columns = array();
53
-
54
- /**
55
- * Defines the row-actions. It expects an array where the key
56
- * is the column name and the value is an array of actions.
57
- *
58
- * The array of actions are key => value, where key is the method name
59
- * (with the prefix row_action_<key>) and the value is the label
60
- * and title.
61
- */
62
- protected $row_actions = array();
63
-
64
- /**
65
- * The Primary key of our table
66
- */
67
- protected $ID = 'ID';
68
-
69
- /**
70
- * Enables sorting, it expects an array
71
- * of columns (the column names are the values)
72
- */
73
- protected $sort_by = array();
74
-
75
- protected $filter_by = array();
76
-
77
- /**
78
- * @var array The status name => count combinations for this table's items. Used to display status filters.
79
- */
80
- protected $status_counts = array();
81
-
82
- /**
83
- * @var array Notices to display when loading the table. Array of arrays of form array( 'class' => {updated|error}, 'message' => 'This is the notice text display.' ).
84
- */
85
- protected $admin_notices = array();
86
-
87
- /**
88
- * @var string Localised string displayed in the <h1> element above the able.
89
- */
90
- protected $table_header;
91
-
92
- /**
93
- * Enables bulk actions. It must be an array where the key is the action name
94
- * and the value is the label (which is translated automatically). It is important
95
- * to notice that it will check that the method exists (`bulk_$name`) and will throw
96
- * an exception if it does not exists.
97
- *
98
- * This class will automatically check if the current request has a bulk action, will do the
99
- * validations and afterwards will execute the bulk method, with two arguments. The first argument
100
- * is the array with primary keys, the second argument is a string with a list of the primary keys,
101
- * escaped and ready to use (with `IN`).
102
- */
103
- protected $bulk_actions = array();
104
-
105
- /**
106
- * Makes translation easier, it basically just wraps
107
- * `_x` with some default (the package name)
108
- */
109
- protected function translate( $text, $context = '' ) {
110
- return _x( $text, $context, $this->package );
111
- }
112
-
113
- /**
114
- * Reads `$this->bulk_actions` and returns an array that WP_List_Table understands. It
115
- * also validates that the bulk method handler exists. It throws an exception because
116
- * this is a library meant for developers and missing a bulk method is a development-time error.
117
- */
118
- protected function get_bulk_actions() {
119
- $actions = array();
120
-
121
- foreach ( $this->bulk_actions as $action => $label ) {
122
- if ( ! is_callable( array( $this, 'bulk_' . $action ) ) ) {
123
- throw new RuntimeException( "The bulk action $action does not have a callback method" );
124
- }
125
-
126
- $actions[ $action ] = $this->translate( $label );
127
- }
128
-
129
- return $actions;
130
- }
131
-
132
- /**
133
- * Checks if the current request has a bulk action. If that is the case it will validate and will
134
- * execute the bulk method handler. Regardless if the action is valid or not it will redirect to
135
- * the previous page removing the current arguments that makes this request a bulk action.
136
- */
137
- protected function process_bulk_action() {
138
- global $wpdb;
139
- // Detect when a bulk action is being triggered.
140
- $action = $this->current_action();
141
-
142
- if ( ! $action ) {
143
- return;
144
- }
145
-
146
- check_admin_referer( 'bulk-' . $this->_args['plural'] );
147
-
148
- $method = 'bulk_' . $action;
149
- if ( array_key_exists( $action, $this->bulk_actions ) && is_callable( array( $this, $method ) ) && ! empty( $_GET['ID'] ) && is_array( $_GET['ID'] ) ) {
150
- $ids_sql = '(' . implode( ',', array_fill( 0, count( $_GET['ID'] ), '%s' ) ) . ')';
151
- $this->$method( $_GET['ID'], $wpdb->prepare( $ids_sql, $_GET['ID'] ) );
152
- }
153
-
154
- wp_redirect( remove_query_arg(
155
- array( '_wp_http_referer', '_wpnonce', 'ID', 'action', 'action2' ),
156
- wp_unslash( $_SERVER['REQUEST_URI'] )
157
- ) );
158
- exit;
159
- }
160
-
161
- /**
162
- * Default code for deleting entries. We trust ids_sql because it is
163
- * validated already by process_bulk_action()
164
- */
165
- protected function bulk_delete( array $ids, $ids_sql ) {
166
- global $wpdb;
167
-
168
- $wpdb->query( "DELETE FROM {$this->table_name} WHERE {$this->ID} IN $ids_sql" );
169
- }
170
-
171
- /**
172
- * Prepares the _column_headers property which is used by WP_Table_List at rendering.
173
- * It merges the columns and the sortable columns.
174
- */
175
- protected function prepare_column_headers() {
176
- $this->_column_headers = array(
177
- $this->get_columns(),
178
- array(),
179
- $this->get_sortable_columns(),
180
- );
181
- }
182
-
183
- /**
184
- * Reads $this->sort_by and returns the columns name in a format that WP_Table_List
185
- * expects
186
- */
187
- public function get_sortable_columns() {
188
- $sort_by = array();
189
- foreach ( $this->sort_by as $column ) {
190
- $sort_by[ $column ] = array( $column, true );
191
- }
192
- return $sort_by;
193
- }
194
-
195
- /**
196
- * Returns the columns names for rendering. It adds a checkbox for selecting everything
197
- * as the first column
198
- */
199
- public function get_columns() {
200
- $columns = array_merge(
201
- array( 'cb' => '<input type="checkbox" />' ),
202
- array_map( array( $this, 'translate' ), $this->columns )
203
- );
204
-
205
- return $columns;
206
- }
207
-
208
- /**
209
- * Get prepared LIMIT clause for items query
210
- *
211
- * @global wpdb $wpdb
212
- *
213
- * @return string Prepared LIMIT clause for items query.
214
- */
215
- protected function get_items_query_limit() {
216
- global $wpdb;
217
-
218
- $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
219
- return $wpdb->prepare( 'LIMIT %d', $per_page );
220
- }
221
-
222
- /**
223
- * Returns the number of items to offset/skip for this current view.
224
- *
225
- * @return int
226
- */
227
- protected function get_items_offset() {
228
- $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
229
- $current_page = $this->get_pagenum();
230
- if ( 1 < $current_page ) {
231
- $offset = $per_page * ( $current_page - 1 );
232
- } else {
233
- $offset = 0;
234
- }
235
-
236
- return $offset;
237
- }
238
-
239
- /**
240
- * Get prepared OFFSET clause for items query
241
- *
242
- * @global wpdb $wpdb
243
- *
244
- * @return string Prepared OFFSET clause for items query.
245
- */
246
- protected function get_items_query_offset() {
247
- global $wpdb;
248
-
249
- return $wpdb->prepare( 'OFFSET %d', $this->get_items_offset() );
250
- }
251
-
252
- /**
253
- * Prepares the ORDER BY sql statement. It uses `$this->sort_by` to know which
254
- * columns are sortable. This requests validates the orderby $_GET parameter is a valid
255
- * column and sortable. It will also use order (ASC|DESC) using DESC by default.
256
- */
257
- protected function get_items_query_order() {
258
- if ( empty( $this->sort_by ) ) {
259
- return '';
260
- }
261
-
262
- $orderby = esc_sql( $this->get_request_orderby() );
263
- $order = esc_sql( $this->get_request_order() );
264
-
265
- return "ORDER BY {$orderby} {$order}";
266
- }
267
-
268
- /**
269
- * Return the sortable column specified for this request to order the results by, if any.
270
- *
271
- * @return string
272
- */
273
- protected function get_request_orderby() {
274
-
275
- $valid_sortable_columns = array_values( $this->sort_by );
276
-
277
- if ( ! empty( $_GET['orderby'] ) && in_array( $_GET['orderby'], $valid_sortable_columns ) ) {
278
- $orderby = sanitize_text_field( $_GET['orderby'] );
279
- } else {
280
- $orderby = $valid_sortable_columns[0];
281
- }
282
-
283
- return $orderby;
284
- }
285
-
286
- /**
287
- * Return the sortable column order specified for this request.
288
- *
289
- * @return string
290
- */
291
- protected function get_request_order() {
292
-
293
- if ( ! empty( $_GET['order'] ) && 'desc' === strtolower( $_GET['order'] ) ) {
294
- $order = 'DESC';
295
- } else {
296
- $order = 'ASC';
297
- }
298
-
299
- return $order;
300
- }
301
-
302
- /**
303
- * Return the status filter for this request, if any.
304
- *
305
- * @return string
306
- */
307
- protected function get_request_status() {
308
- $status = ( ! empty( $_GET['status'] ) ) ? $_GET['status'] : '';
309
- return $status;
310
- }
311
-
312
- /**
313
- * Return the search filter for this request, if any.
314
- *
315
- * @return string
316
- */
317
- protected function get_request_search_query() {
318
- $search_query = ( ! empty( $_GET['s'] ) ) ? $_GET['s'] : '';
319
- return $search_query;
320
- }
321
-
322
- /**
323
- * Process and return the columns name. This is meant for using with SQL, this means it
324
- * always includes the primary key.
325
- *
326
- * @return array
327
- */
328
- protected function get_table_columns() {
329
- $columns = array_keys( $this->columns );
330
- if ( ! in_array( $this->ID, $columns ) ) {
331
- $columns[] = $this->ID;
332
- }
333
-
334
- return $columns;
335
- }
336
-
337
- /**
338
- * Check if the current request is doing a "full text" search. If that is the case
339
- * prepares the SQL to search texts using LIKE.
340
- *
341
- * If the current request does not have any search or if this list table does not support
342
- * that feature it will return an empty string.
343
- *
344
- * TODO:
345
- * - Improve search doing LIKE by word rather than by phrases.
346
- *
347
- * @return string
348
- */
349
- protected function get_items_query_search() {
350
- global $wpdb;
351
-
352
- if ( empty( $_GET['s'] ) || empty( $this->search_by ) ) {
353
- return '';
354
- }
355
-
356
- $filter = array();
357
- foreach ( $this->search_by as $column ) {
358
- $filter[] = '`' . $column . '` like "%' . $wpdb->esc_like( $_GET['s'] ) . '%"';
359
- }
360
- return implode( ' OR ', $filter );
361
- }
362
-
363
- /**
364
- * Prepares the SQL to filter rows by the options defined at `$this->filter_by`. Before trusting
365
- * any data sent by the user it validates that it is a valid option.
366
- */
367
- protected function get_items_query_filters() {
368
- global $wpdb;
369
-
370
- if ( ! $this->filter_by || empty( $_GET['filter_by'] ) || ! is_array( $_GET['filter_by'] ) ) {
371
- return '';
372
- }
373
-
374
- $filter = array();
375
-
376
- foreach ( $this->filter_by as $column => $options ) {
377
- if ( empty( $_GET['filter_by'][ $column ] ) || empty( $options[ $_GET['filter_by'][ $column ] ] ) ) {
378
- continue;
379
- }
380
-
381
- $filter[] = $wpdb->prepare( "`$column` = %s", $_GET['filter_by'][ $column ] );
382
- }
383
-
384
- return implode( ' AND ', $filter );
385
-
386
- }
387
-
388
- /**
389
- * Prepares the data to feed WP_Table_List.
390
- *
391
- * This has the core for selecting, sorting and filting data. To keep the code simple
392
- * its logic is split among many methods (get_items_query_*).
393
- *
394
- * Beside populating the items this function will also count all the records that matches
395
- * the filtering criteria and will do fill the pagination variables.
396
- */
397
- public function prepare_items() {
398
- global $wpdb;
399
-
400
- $this->process_bulk_action();
401
-
402
- $this->process_row_actions();
403
-
404
- if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
405
- // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
406
- wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
407
- exit;
408
- }
409
-
410
- $this->prepare_column_headers();
411
-
412
- $limit = $this->get_items_query_limit();
413
- $offset = $this->get_items_query_offset();
414
- $order = $this->get_items_query_order();
415
- $where = array_filter(array(
416
- $this->get_items_query_search(),
417
- $this->get_items_query_filters(),
418
- ));
419
- $columns = '`' . implode( '`, `', $this->get_table_columns() ) . '`';
420
-
421
- if ( ! empty( $where ) ) {
422
- $where = 'WHERE ('. implode( ') AND (', $where ) . ')';
423
- } else {
424
- $where = '';
425
- }
426
-
427
- $sql = "SELECT $columns FROM {$this->table_name} {$where} {$order} {$limit} {$offset}";
428
-
429
- $this->set_items( $wpdb->get_results( $sql, ARRAY_A ) );
430
-
431
- $query_count = "SELECT COUNT({$this->ID}) FROM {$this->table_name} {$where}";
432
- $total_items = $wpdb->get_var( $query_count );
433
- $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
434
- $this->set_pagination_args( array(
435
- 'total_items' => $total_items,
436
- 'per_page' => $per_page,
437
- 'total_pages' => ceil( $total_items / $per_page ),
438
- ) );
439
- }
440
-
441
- public function extra_tablenav( $which ) {
442
- if ( ! $this->filter_by || 'top' !== $which ) {
443
- return;
444
- }
445
-
446
- echo '<div class="alignleft actions">';
447
-
448
- foreach ( $this->filter_by as $id => $options ) {
449
- $default = ! empty( $_GET['filter_by'][ $id ] ) ? $_GET['filter_by'][ $id ] : '';
450
- if ( empty( $options[ $default ] ) ) {
451
- $default = '';
452
- }
453
-
454
- echo '<select name="filter_by[' . esc_attr( $id ) . ']" class="first" id="filter-by-' . esc_attr( $id ) . '">';
455
-
456
- foreach ( $options as $value => $label ) {
457
- echo '<option value="' . esc_attr( $value ) . '" ' . esc_html( $value == $default ? 'selected' : '' ) .'>'
458
- . esc_html( $this->translate( $label ) )
459
- . '</option>';
460
- }
461
-
462
- echo '</select>';
463
- }
464
-
465
- submit_button( $this->translate( 'Filter' ), '', 'filter_action', false, array( 'id' => 'post-query-submit' ) );
466
- echo '</div>';
467
- }
468
-
469
- /**
470
- * Set the data for displaying. It will attempt to unserialize (There is a chance that some columns
471
- * are serialized). This can be override in child classes for futher data transformation.
472
- */
473
- protected function set_items( array $items ) {
474
- $this->items = array();
475
- foreach ( $items as $item ) {
476
- $this->items[ $item[ $this->ID ] ] = array_map( 'maybe_unserialize', $item );
477
- }
478
- }
479
-
480
- /**
481
- * Renders the checkbox for each row, this is the first column and it is named ID regardless
482
- * of how the primary key is named (to keep the code simpler). The bulk actions will do the proper
483
- * name transformation though using `$this->ID`.
484
- */
485
- public function column_cb( $row ) {
486
- return '<input name="ID[]" type="checkbox" value="' . esc_attr( $row[ $this->ID ] ) .'" />';
487
- }
488
-
489
- /**
490
- * Renders the row-actions.
491
- *
492
- * This method renders the action menu, it reads the definition from the $row_actions property,
493
- * and it checks that the row action method exists before rendering it.
494
- *
495
- * @param array $row Row to render
496
- * @param $column_name Current row
497
- * @return
498
- */
499
- protected function maybe_render_actions( $row, $column_name ) {
500
- if ( empty( $this->row_actions[ $column_name ] ) ) {
501
- return;
502
- }
503
-
504
- $row_id = $row[ $this->ID ];
505
-
506
- $actions = '<div class="row-actions">';
507
- $action_count = 0;
508
- foreach ( $this->row_actions[ $column_name ] as $action_key => $action ) {
509
-
510
- $action_count++;
511
-
512
- if ( ! method_exists( $this, 'row_action_' . $action_key ) ) {
513
- continue;
514
- }
515
-
516
- $action_link = ! empty( $action['link'] ) ? $action['link'] : add_query_arg( array( 'row_action' => $action_key, 'row_id' => $row_id, 'nonce' => wp_create_nonce( $action_key . '::' . $row_id ) ) );
517
- $span_class = ! empty( $action['class'] ) ? $action['class'] : $action_key;
518
- $separator = ( $action_count < count( $this->row_actions[ $column_name ] ) ) ? ' | ' : '';
519
-
520
- $actions .= sprintf( '<span class="%s">', esc_attr( $span_class ) );
521
- $actions .= sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', esc_url( $action_link ), esc_attr( $action['desc'] ), esc_html( $action['name'] ) );
522
- $actions .= sprintf( '%s</span>', $separator );
523
- }
524
- $actions .= '</div>';
525
- return $actions;
526
- }
527
-
528
- protected function process_row_actions() {
529
- $parameters = array( 'row_action', 'row_id', 'nonce' );
530
- foreach ( $parameters as $parameter ) {
531
- if ( empty( $_REQUEST[ $parameter ] ) ) {
532
- return;
533
- }
534
- }
535
-
536
- $method = 'row_action_' . $_REQUEST['row_action'];
537
-
538
- if ( $_REQUEST['nonce'] === wp_create_nonce( $_REQUEST[ 'row_action' ] . '::' . $_REQUEST[ 'row_id' ] ) && method_exists( $this, $method ) ) {
539
- $this->$method( $_REQUEST['row_id'] );
540
- }
541
-
542
- wp_redirect( remove_query_arg(
543
- array( 'row_id', 'row_action', 'nonce' ),
544
- wp_unslash( $_SERVER['REQUEST_URI'] )
545
- ) );
546
- exit;
547
- }
548
-
549
- /**
550
- * Default column formatting, it will escape everythig for security.
551
- */
552
- public function column_default( $item, $column_name ) {
553
- $column_html = esc_html( $item[ $column_name ] );
554
- $column_html .= $this->maybe_render_actions( $item, $column_name );
555
- return $column_html;
556
- }
557
-
558
- /**
559
- * Display the table heading and search query, if any
560
- */
561
- protected function display_header() {
562
- echo '<h1 class="wp-heading-inline">' . esc_attr( $this->table_header ) . '</h1>';
563
- if ( $this->get_request_search_query() ) {
564
- echo '<span class="subtitle">' . esc_attr( $this->translate( sprintf( 'Search results for "%s"', $this->get_request_search_query() ) ) ) . '</span>';
565
- }
566
- echo '<hr class="wp-header-end">';
567
- }
568
-
569
- /**
570
- * Display the table heading and search query, if any
571
- */
572
- protected function display_admin_notices() {
573
- foreach ( $this->admin_notices as $notice ) {
574
- echo '<div id="message" class="' . $notice['class'] . '">';
575
- echo ' <p>' . wp_kses_post( $notice['message'] ) . '</p>';
576
- echo '</div>';
577
- }
578
- }
579
-
580
- /**
581
- * Prints the available statuses so the user can click to filter.
582
- */
583
- protected function display_filter_by_status() {
584
-
585
- $status_list_items = array();
586
- $request_status = $this->get_request_status();
587
-
588
- // Helper to set 'all' filter when not set on status counts passed in
589
- if ( ! isset( $this->status_counts['all'] ) ) {
590
- $this->status_counts = array( 'all' => array_sum( $this->status_counts ) ) + $this->status_counts;
591
- }
592
-
593
- foreach ( $this->status_counts as $status_name => $count ) {
594
-
595
- if ( 0 === $count ) {
596
- continue;
597
- }
598
-
599
- if ( $status_name === $request_status || ( empty( $request_status ) && 'all' === $status_name ) ) {
600
- $status_list_item = '<li class="%1$s"><strong>%3$s</strong> (%4$d)</li>';
601
- } else {
602
- $status_list_item = '<li class="%1$s"><a href="%2$s">%3$s</a> (%4$d)</li>';
603
- }
604
-
605
- $status_filter_url = ( 'all' === $status_name ) ? remove_query_arg( 'status' ) : add_query_arg( 'status', $status_name );
606
- $status_list_items[] = sprintf( $status_list_item, esc_attr( $status_name ), esc_url( $status_filter_url ), esc_html( ucfirst( $status_name ) ), absint( $count ) );
607
- }
608
-
609
- if ( $status_list_items ) {
610
- echo '<ul class="subsubsub">';
611
- echo implode( " | \n", $status_list_items );
612
- echo '</ul>';
613
- }
614
- }
615
-
616
- /**
617
- * Renders the table list, we override the original class to render the table inside a form
618
- * and to render any needed HTML (like the search box). By doing so the callee of a function can simple
619
- * forget about any extra HTML.
620
- */
621
- protected function display_table() {
622
- echo '<form id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="get">';
623
- foreach ( $_GET as $key => $value ) {
624
- if ( '_' === $key[0] || 'paged' === $key ) {
625
- continue;
626
- }
627
- echo '<input type="hidden" name="' . esc_attr( $key ) . '" value="' . esc_attr( $value ) . '" />';
628
- }
629
- if ( ! empty( $this->search_by ) ) {
630
- echo $this->search_box( $this->get_search_box_button_text(), 'plugin' ); // WPCS: XSS OK
631
- }
632
- parent::display();
633
- echo '</form>';
634
- }
635
-
636
- /**
637
- * Render the list table page, including header, notices, status filters and table.
638
- */
639
- public function display_page() {
640
- $this->prepare_items();
641
-
642
- echo '<div class="wrap">';
643
- $this->display_header();
644
- $this->display_admin_notices();
645
- $this->display_filter_by_status();
646
- $this->display_table();
647
- echo '</div>';
648
- }
649
-
650
- /**
651
- * Get the text to display in the search box on the list table.
652
- */
653
- protected function get_search_box_placeholder() {
654
- return $this->translate( 'Search' );
655
- }
656
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Abstract_QueueRunner.php DELETED
@@ -1,216 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Abstract class with common Queue Cleaner functionality.
5
- */
6
- abstract class ActionScheduler_Abstract_QueueRunner extends ActionScheduler_Abstract_QueueRunner_Deprecated {
7
-
8
- /** @var ActionScheduler_QueueCleaner */
9
- protected $cleaner;
10
-
11
- /** @var ActionScheduler_FatalErrorMonitor */
12
- protected $monitor;
13
-
14
- /** @var ActionScheduler_Store */
15
- protected $store;
16
-
17
- /**
18
- * The created time.
19
- *
20
- * Represents when the queue runner was constructed and used when calculating how long a PHP request has been running.
21
- * For this reason it should be as close as possible to the PHP request start time.
22
- *
23
- * @var int
24
- */
25
- private $created_time;
26
-
27
- /**
28
- * ActionScheduler_Abstract_QueueRunner constructor.
29
- *
30
- * @param ActionScheduler_Store $store
31
- * @param ActionScheduler_FatalErrorMonitor $monitor
32
- * @param ActionScheduler_QueueCleaner $cleaner
33
- */
34
- public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
35
-
36
- $this->created_time = microtime( true );
37
-
38
- $this->store = $store ? $store : ActionScheduler_Store::instance();
39
- $this->monitor = $monitor ? $monitor : new ActionScheduler_FatalErrorMonitor( $this->store );
40
- $this->cleaner = $cleaner ? $cleaner : new ActionScheduler_QueueCleaner( $this->store );
41
- }
42
-
43
- /**
44
- * Process an individual action.
45
- *
46
- * @param int $action_id The action ID to process.
47
- */
48
- public function process_action( $action_id ) {
49
- try {
50
- do_action( 'action_scheduler_before_execute', $action_id );
51
-
52
- if ( ActionScheduler_Store::STATUS_PENDING !== $this->store->get_status( $action_id ) ) {
53
- do_action( 'action_scheduler_execution_ignored', $action_id );
54
- return;
55
- }
56
-
57
- $action = $this->store->fetch_action( $action_id );
58
- $this->store->log_execution( $action_id );
59
- $action->execute();
60
- do_action( 'action_scheduler_after_execute', $action_id, $action );
61
- $this->store->mark_complete( $action_id );
62
- } catch ( Exception $e ) {
63
- $this->store->mark_failure( $action_id );
64
- do_action( 'action_scheduler_failed_execution', $action_id, $e );
65
- }
66
- $this->schedule_next_instance( $action );
67
- }
68
-
69
- /**
70
- * Schedule the next instance of the action if necessary.
71
- *
72
- * @param ActionScheduler_Action $action
73
- */
74
- protected function schedule_next_instance( ActionScheduler_Action $action ) {
75
- $schedule = $action->get_schedule();
76
- $next = $schedule->next( as_get_datetime_object() );
77
-
78
- if ( ! is_null( $next ) && $schedule->is_recurring() ) {
79
- $this->store->save_action( $action, $next );
80
- }
81
- }
82
-
83
- /**
84
- * Run the queue cleaner.
85
- *
86
- * @author Jeremy Pry
87
- */
88
- protected function run_cleanup() {
89
- $this->cleaner->clean( 10 * $this->get_time_limit() );
90
- }
91
-
92
- /**
93
- * Get the number of concurrent batches a runner allows.
94
- *
95
- * @return int
96
- */
97
- public function get_allowed_concurrent_batches() {
98
- return apply_filters( 'action_scheduler_queue_runner_concurrent_batches', 5 );
99
- }
100
-
101
- /**
102
- * Get the maximum number of seconds a batch can run for.
103
- *
104
- * @return int The number of seconds.
105
- */
106
- protected function get_time_limit() {
107
-
108
- $time_limit = 30;
109
-
110
- // Apply deprecated filter from deprecated get_maximum_execution_time() method
111
- if ( has_filter( 'action_scheduler_maximum_execution_time' ) ) {
112
- _deprecated_function( 'action_scheduler_maximum_execution_time', '2.1.1', 'action_scheduler_queue_runner_time_limit' );
113
- $time_limit = apply_filters( 'action_scheduler_maximum_execution_time', $time_limit );
114
- }
115
-
116
- return absint( apply_filters( 'action_scheduler_queue_runner_time_limit', $time_limit ) );
117
- }
118
-
119
- /**
120
- * Get the number of seconds the process has been running.
121
- *
122
- * @return int The number of seconds.
123
- */
124
- protected function get_execution_time() {
125
- $execution_time = microtime( true ) - $this->created_time;
126
-
127
- // Get the CPU time if the hosting environment uses it rather than wall-clock time to calculate a process's execution time.
128
- if ( function_exists( 'getrusage' ) && apply_filters( 'action_scheduler_use_cpu_execution_time', defined( 'PANTHEON_ENVIRONMENT' ) ) ) {
129
- $resource_usages = getrusage();
130
-
131
- if ( isset( $resource_usages['ru_stime.tv_usec'], $resource_usages['ru_stime.tv_usec'] ) ) {
132
- $execution_time = $resource_usages['ru_stime.tv_sec'] + ( $resource_usages['ru_stime.tv_usec'] / 1000000 );
133
- }
134
- }
135
-
136
- return $execution_time;
137
- }
138
-
139
- /**
140
- * Check if the host's max execution time is (likely) to be exceeded if processing more actions.
141
- *
142
- * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action
143
- * @return bool
144
- */
145
- protected function time_likely_to_be_exceeded( $processed_actions ) {
146
-
147
- $execution_time = $this->get_execution_time();
148
- $max_execution_time = $this->get_time_limit();
149
- $time_per_action = $execution_time / $processed_actions;
150
- $estimated_time = $execution_time + ( $time_per_action * 3 );
151
- $likely_to_be_exceeded = $estimated_time > $max_execution_time;
152
-
153
- return apply_filters( 'action_scheduler_maximum_execution_time_likely_to_be_exceeded', $likely_to_be_exceeded, $this, $processed_actions, $execution_time, $max_execution_time );
154
- }
155
-
156
- /**
157
- * Get memory limit
158
- *
159
- * Based on WP_Background_Process::get_memory_limit()
160
- *
161
- * @return int
162
- */
163
- protected function get_memory_limit() {
164
- if ( function_exists( 'ini_get' ) ) {
165
- $memory_limit = ini_get( 'memory_limit' );
166
- } else {
167
- $memory_limit = '128M'; // Sensible default, and minimum required by WooCommerce
168
- }
169
-
170
- if ( ! $memory_limit || -1 === $memory_limit || '-1' === $memory_limit ) {
171
- // Unlimited, set to 32GB.
172
- $memory_limit = '32G';
173
- }
174
-
175
- return ActionScheduler_Compatibility::convert_hr_to_bytes( $memory_limit );
176
- }
177
-
178
- /**
179
- * Memory exceeded
180
- *
181
- * Ensures the batch process never exceeds 90% of the maximum WordPress memory.
182
- *
183
- * Based on WP_Background_Process::memory_exceeded()
184
- *
185
- * @return bool
186
- */
187
- protected function memory_exceeded() {
188
-
189
- $memory_limit = $this->get_memory_limit() * 0.90;
190
- $current_memory = memory_get_usage( true );
191
- $memory_exceeded = $current_memory >= $memory_limit;
192
-
193
- return apply_filters( 'action_scheduler_memory_exceeded', $memory_exceeded, $this );
194
- }
195
-
196
- /**
197
- * See if the batch limits have been exceeded, which is when memory usage is almost at
198
- * the maximum limit, or the time to process more actions will exceed the max time limit.
199
- *
200
- * Based on WC_Background_Process::batch_limits_exceeded()
201
- *
202
- * @param int $processed_actions The number of actions processed so far - used to determine the likelihood of exceeding the time limit if processing another action
203
- * @return bool
204
- */
205
- protected function batch_limits_exceeded( $processed_actions ) {
206
- return $this->memory_exceeded() || $this->time_likely_to_be_exceeded( $processed_actions );
207
- }
208
-
209
- /**
210
- * Process actions in the queue.
211
- *
212
- * @author Jeremy Pry
213
- * @return int The number of actions processed.
214
- */
215
- abstract public function run();
216
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Action.php DELETED
@@ -1,75 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Action
5
- */
6
- class ActionScheduler_Action {
7
- protected $hook = '';
8
- protected $args = array();
9
- /** @var ActionScheduler_Schedule */
10
- protected $schedule = NULL;
11
- protected $group = '';
12
-
13
- public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = NULL, $group = '' ) {
14
- $schedule = empty( $schedule ) ? new ActionScheduler_NullSchedule() : $schedule;
15
- $this->set_hook($hook);
16
- $this->set_schedule($schedule);
17
- $this->set_args($args);
18
- $this->set_group($group);
19
- }
20
-
21
- public function execute() {
22
- return do_action_ref_array($this->get_hook(), $this->get_args());
23
- }
24
-
25
- /**
26
- * @param string $hook
27
- */
28
- protected function set_hook( $hook ) {
29
- $this->hook = $hook;
30
- }
31
-
32
- public function get_hook() {
33
- return $this->hook;
34
- }
35
-
36
- protected function set_schedule( ActionScheduler_Schedule $schedule ) {
37
- $this->schedule = $schedule;
38
- }
39
-
40
- /**
41
- * @return ActionScheduler_Schedule
42
- */
43
- public function get_schedule() {
44
- return $this->schedule;
45
- }
46
-
47
- protected function set_args( array $args ) {
48
- $this->args = $args;
49
- }
50
-
51
- public function get_args() {
52
- return $this->args;
53
- }
54
-
55
- /**
56
- * @param string $group
57
- */
58
- protected function set_group( $group ) {
59
- $this->group = $group;
60
- }
61
-
62
- /**
63
- * @return string
64
- */
65
- public function get_group() {
66
- return $this->group;
67
- }
68
-
69
- /**
70
- * @return bool If the action has been finished
71
- */
72
- public function is_finished() {
73
- return FALSE;
74
- }
75
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ActionClaim.php DELETED
@@ -1,23 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_ActionClaim
5
- */
6
- class ActionScheduler_ActionClaim {
7
- private $id = '';
8
- private $action_ids = array();
9
-
10
- public function __construct( $id, array $action_ids ) {
11
- $this->id = $id;
12
- $this->action_ids = $action_ids;
13
- }
14
-
15
- public function get_id() {
16
- return $this->id;
17
- }
18
-
19
- public function get_actions() {
20
- return $this->action_ids;
21
- }
22
- }
23
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ActionFactory.php DELETED
@@ -1,111 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_ActionFactory
5
- */
6
- class ActionScheduler_ActionFactory {
7
-
8
- /**
9
- * @param string $status The action's status in the data store
10
- * @param string $hook The hook to trigger when this action runs
11
- * @param array $args Args to pass to callbacks when the hook is triggered
12
- * @param ActionScheduler_Schedule $schedule The action's schedule
13
- * @param string $group A group to put the action in
14
- *
15
- * @return ActionScheduler_Action An instance of the stored action
16
- */
17
- public function get_stored_action( $status, $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
18
-
19
- switch ( $status ) {
20
- case ActionScheduler_Store::STATUS_PENDING :
21
- $action_class = 'ActionScheduler_Action';
22
- break;
23
- case ActionScheduler_Store::STATUS_CANCELED :
24
- $action_class = 'ActionScheduler_CanceledAction';
25
- break;
26
- default :
27
- $action_class = 'ActionScheduler_FinishedAction';
28
- break;
29
- }
30
-
31
- $action_class = apply_filters( 'action_scheduler_stored_action_class', $action_class, $status, $hook, $args, $schedule, $group );
32
-
33
- $action = new $action_class( $hook, $args, $schedule, $group );
34
-
35
- /**
36
- * Allow 3rd party code to change the instantiated action for a given hook, args, schedule and group.
37
- *
38
- * @param ActionScheduler_Action $action The instantiated action.
39
- * @param string $hook The instantiated action's hook.
40
- * @param array $args The instantiated action's args.
41
- * @param ActionScheduler_Schedule $schedule The instantiated action's schedule.
42
- * @param string $group The instantiated action's group.
43
- */
44
- return apply_filters( 'action_scheduler_stored_action_instance', $action, $hook, $args, $schedule, $group );
45
- }
46
-
47
- /**
48
- * @param string $hook The hook to trigger when this action runs
49
- * @param array $args Args to pass when the hook is triggered
50
- * @param int $when Unix timestamp when the action will run
51
- * @param string $group A group to put the action in
52
- *
53
- * @return string The ID of the stored action
54
- */
55
- public function single( $hook, $args = array(), $when = null, $group = '' ) {
56
- $date = as_get_datetime_object( $when );
57
- $schedule = new ActionScheduler_SimpleSchedule( $date );
58
- $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
59
- return $this->store( $action );
60
- }
61
-
62
- /**
63
- * @param string $hook The hook to trigger when this action runs
64
- * @param array $args Args to pass when the hook is triggered
65
- * @param int $first Unix timestamp for the first run
66
- * @param int $interval Seconds between runs
67
- * @param string $group A group to put the action in
68
- *
69
- * @return string The ID of the stored action
70
- */
71
- public function recurring( $hook, $args = array(), $first = null, $interval = null, $group = '' ) {
72
- if ( empty($interval) ) {
73
- return $this->single( $hook, $args, $first, $group );
74
- }
75
- $date = as_get_datetime_object( $first );
76
- $schedule = new ActionScheduler_IntervalSchedule( $date, $interval );
77
- $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
78
- return $this->store( $action );
79
- }
80
-
81
-
82
- /**
83
- * @param string $hook The hook to trigger when this action runs
84
- * @param array $args Args to pass when the hook is triggered
85
- * @param int $first Unix timestamp for the first run
86
- * @param int $schedule A cron definition string
87
- * @param string $group A group to put the action in
88
- *
89
- * @return string The ID of the stored action
90
- */
91
- public function cron( $hook, $args = array(), $first = null, $schedule = null, $group = '' ) {
92
- if ( empty($schedule) ) {
93
- return $this->single( $hook, $args, $first, $group );
94
- }
95
- $date = as_get_datetime_object( $first );
96
- $cron = CronExpression::factory( $schedule );
97
- $schedule = new ActionScheduler_CronSchedule( $date, $cron );
98
- $action = new ActionScheduler_Action( $hook, $args, $schedule, $group );
99
- return $this->store( $action );
100
- }
101
-
102
- /**
103
- * @param ActionScheduler_Action $action
104
- *
105
- * @return string The ID of the stored action
106
- */
107
- protected function store( ActionScheduler_Action $action ) {
108
- $store = ActionScheduler_Store::instance();
109
- return $store->save_action( $action );
110
- }
111
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_AdminView.php DELETED
@@ -1,78 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_AdminView
5
- * @codeCoverageIgnore
6
- */
7
- class ActionScheduler_AdminView extends ActionScheduler_AdminView_Deprecated {
8
-
9
- private static $admin_view = NULL;
10
-
11
- /**
12
- * @return ActionScheduler_QueueRunner
13
- * @codeCoverageIgnore
14
- */
15
- public static function instance() {
16
-
17
- if ( empty( self::$admin_view ) ) {
18
- $class = apply_filters('action_scheduler_admin_view_class', 'ActionScheduler_AdminView');
19
- self::$admin_view = new $class();
20
- }
21
-
22
- return self::$admin_view;
23
- }
24
-
25
- /**
26
- * @codeCoverageIgnore
27
- */
28
- public function init() {
29
- if ( is_admin() && ( ! defined( 'DOING_AJAX' ) || false == DOING_AJAX ) ) {
30
-
31
- if ( class_exists( 'WooCommerce' ) ) {
32
- add_action( 'woocommerce_admin_status_content_action-scheduler', array( $this, 'render_admin_ui' ) );
33
- add_filter( 'woocommerce_admin_status_tabs', array( $this, 'register_system_status_tab' ) );
34
- }
35
-
36
- add_action( 'admin_menu', array( $this, 'register_menu' ) );
37
- }
38
- }
39
-
40
-
41
- /**
42
- * Registers action-scheduler into WooCommerce > System status.
43
- *
44
- * @param array $tabs An associative array of tab key => label.
45
- * @return array $tabs An associative array of tab key => label, including Action Scheduler's tabs
46
- */
47
- public function register_system_status_tab( array $tabs ) {
48
- $tabs['action-scheduler'] = __( 'Scheduled Actions', 'action-scheduler' );
49
-
50
- return $tabs;
51
- }
52
-
53
- /**
54
- * Include Action Scheduler's administration under the Tools menu.
55
- *
56
- * A menu under the Tools menu is important for backward compatibility (as that's
57
- * where it started), and also provides more convenient access than the WooCommerce
58
- * System Status page, and for sites where WooCommerce isn't active.
59
- */
60
- public function register_menu() {
61
- add_submenu_page(
62
- 'tools.php',
63
- __( 'Scheduled Actions', 'action-scheduler' ),
64
- __( 'Scheduled Actions', 'action-scheduler' ),
65
- 'manage_options',
66
- 'action-scheduler',
67
- array( $this, 'render_admin_ui' )
68
- );
69
- }
70
-
71
- /**
72
- * Renders the Admin UI
73
- */
74
- public function render_admin_ui() {
75
- $table = new ActionScheduler_ListTable( ActionScheduler::store(), ActionScheduler::logger(), ActionScheduler::runner() );
76
- $table->display_page();
77
- }
78
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_CanceledAction.php DELETED
@@ -1,21 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_CanceledAction
5
- *
6
- * Stored action which was canceled and therefore acts like a finished action but should always return a null schedule,
7
- * regardless of schedule passed to its constructor.
8
- */
9
- class ActionScheduler_CanceledAction extends ActionScheduler_FinishedAction {
10
-
11
- /**
12
- * @param string $hook
13
- * @param array $args
14
- * @param ActionScheduler_Schedule $schedule
15
- * @param string $group
16
- */
17
- public function __construct( $hook, array $args = array(), ActionScheduler_Schedule $schedule = null, $group = '' ) {
18
- parent::__construct( $hook, $args, $schedule, $group );
19
- $this->set_schedule( new ActionScheduler_NullSchedule() );
20
- }
21
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Compatibility.php DELETED
@@ -1,99 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Compatibility
5
- */
6
- class ActionScheduler_Compatibility {
7
-
8
- /**
9
- * Converts a shorthand byte value to an integer byte value.
10
- *
11
- * Wrapper for wp_convert_hr_to_bytes(), moved to load.php in WordPress 4.6 from media.php
12
- *
13
- * @link https://secure.php.net/manual/en/function.ini-get.php
14
- * @link https://secure.php.net/manual/en/faq.using.php#faq.using.shorthandbytes
15
- *
16
- * @param string $value A (PHP ini) byte value, either shorthand or ordinary.
17
- * @return int An integer byte value.
18
- */
19
- public static function convert_hr_to_bytes( $value ) {
20
- if ( function_exists( 'wp_convert_hr_to_bytes' ) ) {
21
- return wp_convert_hr_to_bytes( $value );
22
- }
23
-
24
- $value = strtolower( trim( $value ) );
25
- $bytes = (int) $value;
26
-
27
- if ( false !== strpos( $value, 'g' ) ) {
28
- $bytes *= GB_IN_BYTES;
29
- } elseif ( false !== strpos( $value, 'm' ) ) {
30
- $bytes *= MB_IN_BYTES;
31
- } elseif ( false !== strpos( $value, 'k' ) ) {
32
- $bytes *= KB_IN_BYTES;
33
- }
34
-
35
- // Deal with large (float) values which run into the maximum integer size.
36
- return min( $bytes, PHP_INT_MAX );
37
- }
38
-
39
- /**
40
- * Attempts to raise the PHP memory limit for memory intensive processes.
41
- *
42
- * Only allows raising the existing limit and prevents lowering it.
43
- *
44
- * Wrapper for wp_raise_memory_limit(), added in WordPress v4.6.0
45
- *
46
- * @return bool|int|string The limit that was set or false on failure.
47
- */
48
- public static function raise_memory_limit() {
49
- if ( function_exists( 'wp_raise_memory_limit' ) ) {
50
- return wp_raise_memory_limit( 'admin' );
51
- }
52
-
53
- $current_limit = @ini_get( 'memory_limit' );
54
- $current_limit_int = self::convert_hr_to_bytes( $current_limit );
55
-
56
- if ( -1 === $current_limit_int ) {
57
- return false;
58
- }
59
-
60
- $wp_max_limit = WP_MAX_MEMORY_LIMIT;
61
- $wp_max_limit_int = self::convert_hr_to_bytes( $wp_max_limit );
62
- $filtered_limit = apply_filters( 'admin_memory_limit', $wp_max_limit );
63
- $filtered_limit_int = self::convert_hr_to_bytes( $filtered_limit );
64
-
65
- if ( -1 === $filtered_limit_int || ( $filtered_limit_int > $wp_max_limit_int && $filtered_limit_int > $current_limit_int ) ) {
66
- if ( false !== @ini_set( 'memory_limit', $filtered_limit ) ) {
67
- return $filtered_limit;
68
- } else {
69
- return false;
70
- }
71
- } elseif ( -1 === $wp_max_limit_int || $wp_max_limit_int > $current_limit_int ) {
72
- if ( false !== @ini_set( 'memory_limit', $wp_max_limit ) ) {
73
- return $wp_max_limit;
74
- } else {
75
- return false;
76
- }
77
- }
78
- return false;
79
- }
80
-
81
- /**
82
- * Attempts to raise the PHP timeout for time intensive processes.
83
- *
84
- * Only allows raising the existing limit and prevents lowering it. Wrapper for wc_set_time_limit(), when available.
85
- *
86
- * @param int The time limit in seconds.
87
- */
88
- public static function raise_time_limit( $limit = 0 ) {
89
- if ( $limit < ini_get( 'max_execution_time' ) ) {
90
- return;
91
- }
92
-
93
- if ( function_exists( 'wc_set_time_limit' ) ) {
94
- wc_set_time_limit( $limit );
95
- } elseif ( function_exists( 'set_time_limit' ) && false === strpos( ini_get( 'disable_functions' ), 'set_time_limit' ) && ! ini_get( 'safe_mode' ) ) {
96
- @set_time_limit( $limit );
97
- }
98
- }
99
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_CronSchedule.php DELETED
@@ -1,57 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_CronSchedule
5
- */
6
- class ActionScheduler_CronSchedule implements ActionScheduler_Schedule {
7
- /** @var DateTime */
8
- private $start = NULL;
9
- private $start_timestamp = 0;
10
- /** @var CronExpression */
11
- private $cron = NULL;
12
-
13
- public function __construct( DateTime $start, CronExpression $cron ) {
14
- $this->start = $start;
15
- $this->cron = $cron;
16
- }
17
-
18
- /**
19
- * @param DateTime $after
20
- * @return DateTime|null
21
- */
22
- public function next( DateTime $after = NULL ) {
23
- $after = empty($after) ? clone $this->start : clone $after;
24
- return $this->cron->getNextRunDate($after, 0, false);
25
- }
26
-
27
- /**
28
- * @return bool
29
- */
30
- public function is_recurring() {
31
- return true;
32
- }
33
-
34
- /**
35
- * @return string
36
- */
37
- public function get_recurrence() {
38
- return strval($this->cron);
39
- }
40
-
41
- /**
42
- * For PHP 5.2 compat, since DateTime objects can't be serialized
43
- * @return array
44
- */
45
- public function __sleep() {
46
- $this->start_timestamp = $this->start->getTimestamp();
47
- return array(
48
- 'start_timestamp',
49
- 'cron'
50
- );
51
- }
52
-
53
- public function __wakeup() {
54
- $this->start = as_get_datetime_object($this->start_timestamp);
55
- }
56
- }
57
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_DateTime.php DELETED
@@ -1,76 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * ActionScheduler DateTime class.
5
- *
6
- * This is a custom extension to DateTime that
7
- */
8
- class ActionScheduler_DateTime extends DateTime {
9
-
10
- /**
11
- * UTC offset.
12
- *
13
- * Only used when a timezone is not set. When a timezone string is
14
- * used, this will be set to 0.
15
- *
16
- * @var int
17
- */
18
- protected $utcOffset = 0;
19
-
20
- /**
21
- * Get the unix timestamp of the current object.
22
- *
23
- * Missing in PHP 5.2 so just here so it can be supported consistently.
24
- *
25
- * @return int
26
- */
27
- public function getTimestamp() {
28
- return method_exists( 'DateTime', 'getTimestamp' ) ? parent::getTimestamp() : $this->format( 'U' );
29
- }
30
-
31
- /**
32
- * Set the UTC offset.
33
- *
34
- * This represents a fixed offset instead of a timezone setting.
35
- *
36
- * @param $offset
37
- */
38
- public function setUtcOffset( $offset ) {
39
- $this->utcOffset = intval( $offset );
40
- }
41
-
42
- /**
43
- * Returns the timezone offset.
44
- *
45
- * @return int
46
- * @link http://php.net/manual/en/datetime.getoffset.php
47
- */
48
- public function getOffset() {
49
- return $this->utcOffset ? $this->utcOffset : parent::getOffset();
50
- }
51
-
52
- /**
53
- * Set the TimeZone associated with the DateTime
54
- *
55
- * @param DateTimeZone $timezone
56
- *
57
- * @return static
58
- * @link http://php.net/manual/en/datetime.settimezone.php
59
- */
60
- public function setTimezone( $timezone ) {
61
- $this->utcOffset = 0;
62
- parent::setTimezone( $timezone );
63
-
64
- return $this;
65
- }
66
-
67
- /**
68
- * Get the timestamp with the WordPress timezone offset added or subtracted.
69
- *
70
- * @since 3.0.0
71
- * @return int
72
- */
73
- public function getOffsetTimestamp() {
74
- return $this->getTimestamp() + $this->getOffset();
75
- }
76
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Exception.php DELETED
@@ -1,11 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * ActionScheduler Exception Interface.
5
- *
6
- * Facilitates catching Exceptions unique to Action Scheduler.
7
- *
8
- * @package Prospress\ActionScheduler
9
- * @since %VERSION%
10
- */
11
- interface ActionScheduler_Exception {}
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_FatalErrorMonitor.php DELETED
@@ -1,55 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_FatalErrorMonitor
5
- */
6
- class ActionScheduler_FatalErrorMonitor {
7
- /** @var ActionScheduler_ActionClaim */
8
- private $claim = NULL;
9
- /** @var ActionScheduler_Store */
10
- private $store = NULL;
11
- private $action_id = 0;
12
-
13
- public function __construct( ActionScheduler_Store $store ) {
14
- $this->store = $store;
15
- }
16
-
17
- public function attach( ActionScheduler_ActionClaim $claim ) {
18
- $this->claim = $claim;
19
- add_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
20
- add_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0, 1 );
21
- add_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0, 0 );
22
- add_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0, 0 );
23
- add_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0, 0 );
24
- }
25
-
26
- public function detach() {
27
- $this->claim = NULL;
28
- $this->untrack_action();
29
- remove_action( 'shutdown', array( $this, 'handle_unexpected_shutdown' ) );
30
- remove_action( 'action_scheduler_before_execute', array( $this, 'track_current_action' ), 0 );
31
- remove_action( 'action_scheduler_after_execute', array( $this, 'untrack_action' ), 0 );
32
- remove_action( 'action_scheduler_execution_ignored', array( $this, 'untrack_action' ), 0 );
33
- remove_action( 'action_scheduler_failed_execution', array( $this, 'untrack_action' ), 0 );
34
- }
35
-
36
- public function track_current_action( $action_id ) {
37
- $this->action_id = $action_id;
38
- }
39
-
40
- public function untrack_action() {
41
- $this->action_id = 0;
42
- }
43
-
44
- public function handle_unexpected_shutdown() {
45
- if ( $error = error_get_last() ) {
46
- if ( in_array( $error['type'], array( E_ERROR, E_PARSE, E_COMPILE_ERROR, E_USER_ERROR, E_RECOVERABLE_ERROR ) ) ) {
47
- if ( !empty($this->action_id) ) {
48
- $this->store->mark_failure( $this->action_id );
49
- do_action( 'action_scheduler_unexpected_shutdown', $this->action_id, $error );
50
- }
51
- }
52
- $this->store->release_claim( $this->claim );
53
- }
54
- }
55
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_FinishedAction.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_FinishedAction
5
- */
6
- class ActionScheduler_FinishedAction extends ActionScheduler_Action {
7
-
8
- public function execute() {
9
- // don't execute
10
- }
11
-
12
- public function is_finished() {
13
- return TRUE;
14
- }
15
- }
16
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_IntervalSchedule.php DELETED
@@ -1,60 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_IntervalSchedule
5
- */
6
- class ActionScheduler_IntervalSchedule implements ActionScheduler_Schedule {
7
- /** @var DateTime */
8
- private $start = NULL;
9
- private $start_timestamp = 0;
10
- private $interval_in_seconds = 0;
11
-
12
- public function __construct( DateTime $start, $interval ) {
13
- $this->start = $start;
14
- $this->interval_in_seconds = (int)$interval;
15
- }
16
-
17
- /**
18
- * @param DateTime $after
19
- *
20
- * @return DateTime|null
21
- */
22
- public function next( DateTime $after = NULL ) {
23
- $after = empty($after) ? as_get_datetime_object('@0') : clone $after;
24
- if ( $after > $this->start ) {
25
- $after->modify('+'.$this->interval_in_seconds.' seconds');
26
- return $after;
27
- }
28
- return clone $this->start;
29
- }
30
-
31
- /**
32
- * @return bool
33
- */
34
- public function is_recurring() {
35
- return true;
36
- }
37
-
38
- /**
39
- * @return int
40
- */
41
- public function interval_in_seconds() {
42
- return $this->interval_in_seconds;
43
- }
44
-
45
- /**
46
- * For PHP 5.2 compat, since DateTime objects can't be serialized
47
- * @return array
48
- */
49
- public function __sleep() {
50
- $this->start_timestamp = $this->start->getTimestamp();
51
- return array(
52
- 'start_timestamp',
53
- 'interval_in_seconds'
54
- );
55
- }
56
-
57
- public function __wakeup() {
58
- $this->start = as_get_datetime_object($this->start_timestamp);
59
- }
60
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_InvalidActionException.php DELETED
@@ -1,28 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * InvalidAction Exception.
5
- *
6
- * Used for identifying actions that are invalid in some way.
7
- *
8
- * @package Prospress\ActionScheduler
9
- */
10
- class ActionScheduler_InvalidActionException extends \InvalidArgumentException implements ActionScheduler_Exception {
11
-
12
- /**
13
- * Create a new exception when the action's args cannot be decoded to an array.
14
- *
15
- * @author Jeremy Pry
16
- *
17
- * @param string $action_id The action ID with bad args.
18
- * @return static
19
- */
20
- public static function from_decoding_args( $action_id ) {
21
- $message = sprintf(
22
- __( 'Action [%s] has invalid arguments. It cannot be JSON decoded to an array.', 'action-scheduler' ),
23
- $action_id
24
- );
25
-
26
- return new static( $message );
27
- }
28
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_ListTable.php DELETED
@@ -1,533 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Implements the admin view of the actions.
5
- * @codeCoverageIgnore
6
- */
7
- class ActionScheduler_ListTable extends ActionScheduler_Abstract_ListTable {
8
-
9
- /**
10
- * The package name.
11
- *
12
- * @var string
13
- */
14
- protected $package = 'action-scheduler';
15
-
16
- /**
17
- * Columns to show (name => label).
18
- *
19
- * @var array
20
- */
21
- protected $columns = array();
22
-
23
- /**
24
- * Actions (name => label).
25
- *
26
- * @var array
27
- */
28
- protected $row_actions = array();
29
-
30
- /**
31
- * The active data stores
32
- *
33
- * @var ActionScheduler_Store
34
- */
35
- protected $store;
36
-
37
- /**
38
- * A logger to use for getting action logs to display
39
- *
40
- * @var ActionScheduler_Logger
41
- */
42
- protected $logger;
43
-
44
- /**
45
- * A ActionScheduler_QueueRunner runner instance (or child class)
46
- *
47
- * @var ActionScheduler_QueueRunner
48
- */
49
- protected $runner;
50
-
51
- /**
52
- * Bulk actions. The key of the array is the method name of the implementation:
53
- *
54
- * bulk_<key>(array $ids, string $sql_in).
55
- *
56
- * See the comments in the parent class for further details
57
- *
58
- * @var array
59
- */
60
- protected $bulk_actions = array();
61
-
62
- /**
63
- * Flag variable to render our notifications, if any, once.
64
- *
65
- * @var bool
66
- */
67
- protected static $did_notification = false;
68
-
69
- /**
70
- * Array of seconds for common time periods, like week or month, alongside an internationalised string representation, i.e. "Day" or "Days"
71
- *
72
- * @var array
73
- */
74
- private static $time_periods;
75
-
76
- /**
77
- * Sets the current data store object into `store->action` and initialises the object.
78
- *
79
- * @param ActionScheduler_Store $store
80
- * @param ActionScheduler_Logger $logger
81
- * @param ActionScheduler_QueueRunner $runner
82
- */
83
- public function __construct( ActionScheduler_Store $store, ActionScheduler_Logger $logger, ActionScheduler_QueueRunner $runner ) {
84
-
85
- $this->store = $store;
86
- $this->logger = $logger;
87
- $this->runner = $runner;
88
-
89
- $this->table_header = __( 'Scheduled Actions', 'action-scheduler' );
90
-
91
- $this->bulk_actions = array(
92
- 'delete' => __( 'Delete', 'action-scheduler' ),
93
- );
94
-
95
- $this->columns = array(
96
- 'hook' => __( 'Hook', 'action-scheduler' ),
97
- 'status' => __( 'Status', 'action-scheduler' ),
98
- 'args' => __( 'Arguments', 'action-scheduler' ),
99
- 'group' => __( 'Group', 'action-scheduler' ),
100
- 'recurrence' => __( 'Recurrence', 'action-scheduler' ),
101
- 'schedule' => __( 'Scheduled Date', 'action-scheduler' ),
102
- 'log_entries' => __( 'Log', 'action-scheduler' ),
103
- );
104
-
105
- $this->sort_by = array(
106
- 'schedule',
107
- 'hook',
108
- 'group',
109
- );
110
-
111
- $this->search_by = array(
112
- 'hook',
113
- 'args',
114
- 'claim_id',
115
- );
116
-
117
- $request_status = $this->get_request_status();
118
-
119
- if ( empty( $request_status ) ) {
120
- $this->sort_by[] = 'status';
121
- } elseif ( in_array( $request_status, array( 'in-progress', 'failed' ) ) ) {
122
- $this->columns += array( 'claim_id' => __( 'Claim ID', 'action-scheduler' ) );
123
- $this->sort_by[] = 'claim_id';
124
- }
125
-
126
- $this->row_actions = array(
127
- 'hook' => array(
128
- 'run' => array(
129
- 'name' => __( 'Run', 'action-scheduler' ),
130
- 'desc' => __( 'Process the action now as if it were run as part of a queue', 'action-scheduler' ),
131
- ),
132
- 'cancel' => array(
133
- 'name' => __( 'Cancel', 'action-scheduler' ),
134
- 'desc' => __( 'Cancel the action now to avoid it being run in future', 'action-scheduler' ),
135
- 'class' => 'cancel trash',
136
- ),
137
- ),
138
- );
139
-
140
- self::$time_periods = array(
141
- array(
142
- 'seconds' => YEAR_IN_SECONDS,
143
- 'names' => _n_noop( '%s year', '%s years', 'action-scheduler' ),
144
- ),
145
- array(
146
- 'seconds' => MONTH_IN_SECONDS,
147
- 'names' => _n_noop( '%s month', '%s months', 'action-scheduler' ),
148
- ),
149
- array(
150
- 'seconds' => WEEK_IN_SECONDS,
151
- 'names' => _n_noop( '%s week', '%s weeks', 'action-scheduler' ),
152
- ),
153
- array(
154
- 'seconds' => DAY_IN_SECONDS,
155
- 'names' => _n_noop( '%s day', '%s days', 'action-scheduler' ),
156
- ),
157
- array(
158
- 'seconds' => HOUR_IN_SECONDS,
159
- 'names' => _n_noop( '%s hour', '%s hours', 'action-scheduler' ),
160
- ),
161
- array(
162
- 'seconds' => MINUTE_IN_SECONDS,
163
- 'names' => _n_noop( '%s minute', '%s minutes', 'action-scheduler' ),
164
- ),
165
- array(
166
- 'seconds' => 1,
167
- 'names' => _n_noop( '%s second', '%s seconds', 'action-scheduler' ),
168
- ),
169
- );
170
-
171
- parent::__construct( array(
172
- 'singular' => 'action-scheduler',
173
- 'plural' => 'action-scheduler',
174
- 'ajax' => false,
175
- ) );
176
- }
177
-
178
- /**
179
- * Convert an interval of seconds into a two part human friendly string.
180
- *
181
- * The WordPress human_time_diff() function only calculates the time difference to one degree, meaning
182
- * even if an action is 1 day and 11 hours away, it will display "1 day". This function goes one step
183
- * further to display two degrees of accuracy.
184
- *
185
- * Inspired by the Crontrol::interval() function by Edward Dale: https://wordpress.org/plugins/wp-crontrol/
186
- *
187
- * @param int $interval A interval in seconds.
188
- * @param int $periods_to_include Depth of time periods to include, e.g. for an interval of 70, and $periods_to_include of 2, both minutes and seconds would be included. With a value of 1, only minutes would be included.
189
- * @return string A human friendly string representation of the interval.
190
- */
191
- private static function human_interval( $interval, $periods_to_include = 2 ) {
192
-
193
- if ( $interval <= 0 ) {
194
- return __( 'Now!', 'action-scheduler' );
195
- }
196
-
197
- $output = '';
198
-
199
- for ( $time_period_index = 0, $periods_included = 0, $seconds_remaining = $interval; $time_period_index < count( self::$time_periods ) && $seconds_remaining > 0 && $periods_included < $periods_to_include; $time_period_index++ ) {
200
-
201
- $periods_in_interval = floor( $seconds_remaining / self::$time_periods[ $time_period_index ]['seconds'] );
202
-
203
- if ( $periods_in_interval > 0 ) {
204
- if ( ! empty( $output ) ) {
205
- $output .= ' ';
206
- }
207
- $output .= sprintf( _n( self::$time_periods[ $time_period_index ]['names'][0], self::$time_periods[ $time_period_index ]['names'][1], $periods_in_interval, 'action-scheduler' ), $periods_in_interval );
208
- $seconds_remaining -= $periods_in_interval * self::$time_periods[ $time_period_index ]['seconds'];
209
- $periods_included++;
210
- }
211
- }
212
-
213
- return $output;
214
- }
215
-
216
- /**
217
- * Returns the recurrence of an action or 'Non-repeating'. The output is human readable.
218
- *
219
- * @param ActionScheduler_Action $action
220
- *
221
- * @return string
222
- */
223
- protected function get_recurrence( $action ) {
224
- $recurrence = $action->get_schedule();
225
- if ( $recurrence->is_recurring() ) {
226
- if ( method_exists( $recurrence, 'interval_in_seconds' ) ) {
227
- return sprintf( __( 'Every %s', 'action-scheduler' ), self::human_interval( $recurrence->interval_in_seconds() ) );
228
- }
229
-
230
- if ( method_exists( $recurrence, 'get_recurrence' ) ) {
231
- return sprintf( __( 'Cron %s', 'action-scheduler' ), $recurrence->get_recurrence() );
232
- }
233
- }
234
-
235
- return __( 'Non-repeating', 'action-scheduler' );
236
- }
237
-
238
- /**
239
- * Serializes the argument of an action to render it in a human friendly format.
240
- *
241
- * @param array $row The array representation of the current row of the table
242
- *
243
- * @return string
244
- */
245
- public function column_args( array $row ) {
246
- if ( empty( $row['args'] ) ) {
247
- return '';
248
- }
249
-
250
- $row_html = '<ul>';
251
- foreach ( $row['args'] as $key => $value ) {
252
- $row_html .= sprintf( '<li><code>%s => %s</code></li>', esc_html( var_export( $key, true ) ), esc_html( var_export( $value, true ) ) );
253
- }
254
- $row_html .= '</ul>';
255
-
256
- return apply_filters( 'action_scheduler_list_table_column_args', $row_html, $row );
257
- }
258
-
259
- /**
260
- * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
261
- *
262
- * @param array $row Action array.
263
- * @return string
264
- */
265
- public function column_log_entries( array $row ) {
266
-
267
- $log_entries_html = '<ol>';
268
-
269
- $timezone = new DateTimezone( 'UTC' );
270
-
271
- foreach ( $row['log_entries'] as $log_entry ) {
272
- $log_entries_html .= $this->get_log_entry_html( $log_entry, $timezone );
273
- }
274
-
275
- $log_entries_html .= '</ol>';
276
-
277
- return $log_entries_html;
278
- }
279
-
280
- /**
281
- * Prints the logs entries inline. We do so to avoid loading Javascript and other hacks to show it in a modal.
282
- *
283
- * @param ActionScheduler_LogEntry $log_entry
284
- * @param DateTimezone $timezone
285
- * @return string
286
- */
287
- protected function get_log_entry_html( ActionScheduler_LogEntry $log_entry, DateTimezone $timezone ) {
288
- $date = $log_entry->get_date();
289
- $date->setTimezone( $timezone );
290
- return sprintf( '<li><strong>%s</strong><br/>%s</li>', esc_html( $date->format( 'Y-m-d H:i:s O' ) ), esc_html( $log_entry->get_message() ) );
291
- }
292
-
293
- /**
294
- * Only display row actions for pending actions.
295
- *
296
- * @param array $row Row to render
297
- * @param string $column_name Current row
298
- *
299
- * @return string
300
- */
301
- protected function maybe_render_actions( $row, $column_name ) {
302
- if ( 'pending' === strtolower( $row['status'] ) ) {
303
- return parent::maybe_render_actions( $row, $column_name );
304
- }
305
-
306
- return '';
307
- }
308
-
309
- /**
310
- * Renders admin notifications
311
- *
312
- * Notifications:
313
- * 1. When the maximum number of tasks are being executed simultaneously
314
- * 2. Notifications when a task us manually executed
315
- */
316
- public function display_admin_notices() {
317
-
318
- if ( $this->store->get_claim_count() >= $this->runner->get_allowed_concurrent_batches() ) {
319
- $this->admin_notices[] = array(
320
- 'class' => 'updated',
321
- 'message' => sprintf( __( 'Maximum simultaneous batches already in progress (%s queues). No actions will be processed until the current batches are complete.', 'action-scheduler' ), $this->store->get_claim_count() ),
322
- );
323
- }
324
-
325
- $notification = get_transient( 'action_scheduler_admin_notice' );
326
-
327
- if ( is_array( $notification ) ) {
328
- delete_transient( 'action_scheduler_admin_notice' );
329
-
330
- $action = $this->store->fetch_action( $notification['action_id'] );
331
- $action_hook_html = '<strong><code>' . $action->get_hook() . '</code></strong>';
332
- if ( 1 == $notification['success'] ) {
333
- $class = 'updated';
334
- switch ( $notification['row_action_type'] ) {
335
- case 'run' :
336
- $action_message_html = sprintf( __( 'Successfully executed action: %s', 'action-scheduler' ), $action_hook_html );
337
- break;
338
- case 'cancel' :
339
- $action_message_html = sprintf( __( 'Successfully canceled action: %s', 'action-scheduler' ), $action_hook_html );
340
- break;
341
- default :
342
- $action_message_html = sprintf( __( 'Successfully processed change for action: %s', 'action-scheduler' ), $action_hook_html );
343
- break;
344
- }
345
- } else {
346
- $class = 'error';
347
- $action_message_html = sprintf( __( 'Could not process change for action: "%s" (ID: %d). Error: %s', 'action-scheduler' ), $action_hook_html, esc_html( $notification['action_id'] ), esc_html( $notification['error_message'] ) );
348
- }
349
-
350
- $action_message_html = apply_filters( 'action_scheduler_admin_notice_html', $action_message_html, $action, $notification );
351
-
352
- $this->admin_notices[] = array(
353
- 'class' => $class,
354
- 'message' => $action_message_html,
355
- );
356
- }
357
-
358
- parent::display_admin_notices();
359
- }
360
-
361
- /**
362
- * Prints the scheduled date in a human friendly format.
363
- *
364
- * @param array $row The array representation of the current row of the table
365
- *
366
- * @return string
367
- */
368
- public function column_schedule( $row ) {
369
- return $this->get_schedule_display_string( $row['schedule'] );
370
- }
371
-
372
- /**
373
- * Get the scheduled date in a human friendly format.
374
- *
375
- * @param ActionScheduler_Schedule $schedule
376
- * @return string
377
- */
378
- protected function get_schedule_display_string( ActionScheduler_Schedule $schedule ) {
379
-
380
- $schedule_display_string = '';
381
-
382
- if ( ! $schedule->next() ) {
383
- return $schedule_display_string;
384
- }
385
-
386
- $next_timestamp = $schedule->next()->getTimestamp();
387
-
388
- $schedule_display_string .= $schedule->next()->format( 'Y-m-d H:i:s O' );
389
- $schedule_display_string .= '<br/>';
390
-
391
- if ( gmdate( 'U' ) > $next_timestamp ) {
392
- $schedule_display_string .= sprintf( __( ' (%s ago)', 'action-scheduler' ), self::human_interval( gmdate( 'U' ) - $next_timestamp ) );
393
- } else {
394
- $schedule_display_string .= sprintf( __( ' (%s)', 'action-scheduler' ), self::human_interval( $next_timestamp - gmdate( 'U' ) ) );
395
- }
396
-
397
- return $schedule_display_string;
398
- }
399
-
400
- /**
401
- * Bulk delete
402
- *
403
- * Deletes actions based on their ID. This is the handler for the bulk delete. It assumes the data
404
- * properly validated by the callee and it will delete the actions without any extra validation.
405
- *
406
- * @param array $ids
407
- * @param string $ids_sql Inherited and unused
408
- */
409
- protected function bulk_delete( array $ids, $ids_sql ) {
410
- foreach ( $ids as $id ) {
411
- $this->store->delete_action( $id );
412
- }
413
- }
414
-
415
- /**
416
- * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their
417
- * parameters are valid.
418
- *
419
- * @param int $action_id
420
- */
421
- protected function row_action_cancel( $action_id ) {
422
- $this->process_row_action( $action_id, 'cancel' );
423
- }
424
-
425
- /**
426
- * Implements the logic behind running an action. ActionScheduler_Abstract_ListTable validates the request and their
427
- * parameters are valid.
428
- *
429
- * @param int $action_id
430
- */
431
- protected function row_action_run( $action_id ) {
432
- $this->process_row_action( $action_id, 'run' );
433
- }
434
-
435
- /**
436
- * Implements the logic behind processing an action once an action link is clicked on the list table.
437
- *
438
- * @param int $action_id
439
- * @param string $row_action_type The type of action to perform on the action.
440
- */
441
- protected function process_row_action( $action_id, $row_action_type ) {
442
- try {
443
- switch ( $row_action_type ) {
444
- case 'run' :
445
- $this->runner->process_action( $action_id );
446
- break;
447
- case 'cancel' :
448
- $this->store->cancel_action( $action_id );
449
- break;
450
- }
451
- $success = 1;
452
- $error_message = '';
453
- } catch ( Exception $e ) {
454
- $success = 0;
455
- $error_message = $e->getMessage();
456
- }
457
-
458
- set_transient( 'action_scheduler_admin_notice', compact( 'action_id', 'success', 'error_message', 'row_action_type' ), 30 );
459
- }
460
-
461
- /**
462
- * {@inheritDoc}
463
- */
464
- public function prepare_items() {
465
- $this->process_bulk_action();
466
-
467
- $this->process_row_actions();
468
-
469
- if ( ! empty( $_REQUEST['_wp_http_referer'] ) ) {
470
- // _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter
471
- wp_redirect( remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), wp_unslash( $_SERVER['REQUEST_URI'] ) ) );
472
- exit;
473
- }
474
-
475
- $this->prepare_column_headers();
476
-
477
- $per_page = $this->get_items_per_page( $this->package . '_items_per_page', $this->items_per_page );
478
- $query = array(
479
- 'per_page' => $per_page,
480
- 'offset' => $this->get_items_offset(),
481
- 'status' => $this->get_request_status(),
482
- 'orderby' => $this->get_request_orderby(),
483
- 'order' => $this->get_request_order(),
484
- 'search' => $this->get_request_search_query(),
485
- );
486
-
487
- $this->items = array();
488
-
489
- $total_items = $this->store->query_actions( $query, 'count' );
490
-
491
- $status_labels = $this->store->get_status_labels();
492
-
493
- foreach ( $this->store->query_actions( $query ) as $action_id ) {
494
- try {
495
- $action = $this->store->fetch_action( $action_id );
496
- } catch ( Exception $e ) {
497
- continue;
498
- }
499
- $this->items[ $action_id ] = array(
500
- 'ID' => $action_id,
501
- 'hook' => $action->get_hook(),
502
- 'status' => $status_labels[ $this->store->get_status( $action_id ) ],
503
- 'args' => $action->get_args(),
504
- 'group' => $action->get_group(),
505
- 'log_entries' => $this->logger->get_logs( $action_id ),
506
- 'claim_id' => $this->store->get_claim_id( $action_id ),
507
- 'recurrence' => $this->get_recurrence( $action ),
508
- 'schedule' => $action->get_schedule(),
509
- );
510
- }
511
-
512
- $this->set_pagination_args( array(
513
- 'total_items' => $total_items,
514
- 'per_page' => $per_page,
515
- 'total_pages' => ceil( $total_items / $per_page ),
516
- ) );
517
- }
518
-
519
- /**
520
- * Prints the available statuses so the user can click to filter.
521
- */
522
- protected function display_filter_by_status() {
523
- $this->status_counts = $this->store->action_counts();
524
- parent::display_filter_by_status();
525
- }
526
-
527
- /**
528
- * Get the text to display in the search box on the list table.
529
- */
530
- protected function get_search_box_button_text() {
531
- return __( 'Search hook, args and claim ID', 'action-scheduler' );
532
- }
533
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_LogEntry.php DELETED
@@ -1,67 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_LogEntry
5
- */
6
- class ActionScheduler_LogEntry {
7
-
8
- /**
9
- * @var int $action_id
10
- */
11
- protected $action_id = '';
12
-
13
- /**
14
- * @var string $message
15
- */
16
- protected $message = '';
17
-
18
- /**
19
- * @var Datetime $date
20
- */
21
- protected $date;
22
-
23
- /**
24
- * Constructor
25
- *
26
- * @param mixed $action_id Action ID
27
- * @param string $message Message
28
- * @param Datetime $date Datetime object with the time when this log entry was created. If this parameter is
29
- * not provided a new Datetime object (with current time) will be created.
30
- */
31
- public function __construct( $action_id, $message, $date = null ) {
32
-
33
- /*
34
- * ActionScheduler_wpCommentLogger::get_entry() previously passed a 3rd param of $comment->comment_type
35
- * to ActionScheduler_LogEntry::__construct(), goodness knows why, and the Follow-up Emails plugin
36
- * hard-codes loading its own version of ActionScheduler_wpCommentLogger with that out-dated method,
37
- * goodness knows why, so we need to guard against that here instead of using a DateTime type declaration
38
- * for the constructor's 3rd param of $date and causing a fatal error with older versions of FUE.
39
- */
40
- if ( null !== $date && ! is_a( $date, 'DateTime' ) ) {
41
- _doing_it_wrong( __METHOD__, 'The third parameter must be a valid DateTime instance, or null.', '2.0.0' );
42
- $date = null;
43
- }
44
-
45
- $this->action_id = $action_id;
46
- $this->message = $message;
47
- $this->date = $date ? $date : new Datetime;
48
- }
49
-
50
- /**
51
- * Returns the date when this log entry was created
52
- *
53
- * @return Datetime
54
- */
55
- public function get_date() {
56
- return $this->date;
57
- }
58
-
59
- public function get_action_id() {
60
- return $this->action_id;
61
- }
62
-
63
- public function get_message() {
64
- return $this->message;
65
- }
66
- }
67
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Logger.php DELETED
@@ -1,98 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Logger
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler_Logger {
8
- private static $logger = NULL;
9
-
10
- /**
11
- * @return ActionScheduler_Logger
12
- */
13
- public static function instance() {
14
- if ( empty(self::$logger) ) {
15
- $class = apply_filters('action_scheduler_logger_class', 'ActionScheduler_wpCommentLogger');
16
- self::$logger = new $class();
17
- }
18
- return self::$logger;
19
- }
20
-
21
- /**
22
- * @param string $action_id
23
- * @param string $message
24
- * @param DateTime $date
25
- *
26
- * @return string The log entry ID
27
- */
28
- abstract public function log( $action_id, $message, DateTime $date = NULL );
29
-
30
- /**
31
- * @param string $entry_id
32
- *
33
- * @return ActionScheduler_LogEntry
34
- */
35
- abstract public function get_entry( $entry_id );
36
-
37
- /**
38
- * @param string $action_id
39
- *
40
- * @return ActionScheduler_LogEntry[]
41
- */
42
- abstract public function get_logs( $action_id );
43
-
44
-
45
- /**
46
- * @codeCoverageIgnore
47
- */
48
- public function init() {
49
- add_action( 'action_scheduler_stored_action', array( $this, 'log_stored_action' ), 10, 1 );
50
- add_action( 'action_scheduler_canceled_action', array( $this, 'log_canceled_action' ), 10, 1 );
51
- add_action( 'action_scheduler_before_execute', array( $this, 'log_started_action' ), 10, 1 );
52
- add_action( 'action_scheduler_after_execute', array( $this, 'log_completed_action' ), 10, 1 );
53
- add_action( 'action_scheduler_failed_execution', array( $this, 'log_failed_action' ), 10, 2 );
54
- add_action( 'action_scheduler_failed_action', array( $this, 'log_timed_out_action' ), 10, 2 );
55
- add_action( 'action_scheduler_unexpected_shutdown', array( $this, 'log_unexpected_shutdown' ), 10, 2 );
56
- add_action( 'action_scheduler_reset_action', array( $this, 'log_reset_action' ), 10, 1 );
57
- add_action( 'action_scheduler_execution_ignored', array( $this, 'log_ignored_action' ), 10, 1 );
58
- }
59
-
60
- public function log_stored_action( $action_id ) {
61
- $this->log( $action_id, __( 'action created', 'action-scheduler' ) );
62
- }
63
-
64
- public function log_canceled_action( $action_id ) {
65
- $this->log( $action_id, __( 'action canceled', 'action-scheduler' ) );
66
- }
67
-
68
- public function log_started_action( $action_id ) {
69
- $this->log( $action_id, __( 'action started', 'action-scheduler' ) );
70
- }
71
-
72
- public function log_completed_action( $action_id ) {
73
- $this->log( $action_id, __( 'action complete', 'action-scheduler' ) );
74
- }
75
-
76
- public function log_failed_action( $action_id, Exception $exception ) {
77
- $this->log( $action_id, sprintf( __( 'action failed: %s', 'action-scheduler' ), $exception->getMessage() ) );
78
- }
79
-
80
- public function log_timed_out_action( $action_id, $timeout ) {
81
- $this->log( $action_id, sprintf( __( 'action timed out after %s seconds', 'action-scheduler' ), $timeout ) );
82
- }
83
-
84
- public function log_unexpected_shutdown( $action_id, $error ) {
85
- if ( ! empty( $error ) ) {
86
- $this->log( $action_id, sprintf( __( 'unexpected shutdown: PHP Fatal error %s in %s on line %s', 'action-scheduler' ), $error['message'], $error['file'], $error['line'] ) );
87
- }
88
- }
89
-
90
- public function log_reset_action( $action_id ) {
91
- $this->log( $action_id, __( 'action reset', 'action_scheduler' ) );
92
- }
93
-
94
- public function log_ignored_action( $action_id ) {
95
- $this->log( $action_id, __( 'action ignored', 'action-scheduler' ) );
96
- }
97
- }
98
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullAction.php DELETED
@@ -1,16 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_NullAction
5
- */
6
- class ActionScheduler_NullAction extends ActionScheduler_Action {
7
-
8
- public function __construct( $hook = '', array $args = array(), ActionScheduler_Schedule $schedule = NULL ) {
9
- $this->set_schedule( new ActionScheduler_NullSchedule() );
10
- }
11
-
12
- public function execute() {
13
- // don't execute
14
- }
15
- }
16
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullLogEntry.php DELETED
@@ -1,11 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_NullLogEntry
5
- */
6
- class ActionScheduler_NullLogEntry extends ActionScheduler_LogEntry {
7
- public function __construct( $action_id = '', $message = '' ) {
8
- // nothing to see here
9
- }
10
- }
11
-
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_NullSchedule.php DELETED
@@ -1,19 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_NullSchedule
5
- */
6
- class ActionScheduler_NullSchedule implements ActionScheduler_Schedule {
7
-
8
- public function next( DateTime $after = NULL ) {
9
- return NULL;
10
- }
11
-
12
- /**
13
- * @return bool
14
- */
15
- public function is_recurring() {
16
- return false;
17
- }
18
- }
19
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_QueueCleaner.php DELETED
@@ -1,155 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_QueueCleaner
5
- */
6
- class ActionScheduler_QueueCleaner {
7
-
8
- /** @var int */
9
- protected $batch_size;
10
-
11
- /** @var ActionScheduler_Store */
12
- private $store = null;
13
-
14
- /**
15
- * 31 days in seconds.
16
- *
17
- * @var int
18
- */
19
- private $month_in_seconds = 2678400;
20
-
21
- /**
22
- * ActionScheduler_QueueCleaner constructor.
23
- *
24
- * @param ActionScheduler_Store $store The store instance.
25
- * @param int $batch_size The batch size.
26
- */
27
- public function __construct( ActionScheduler_Store $store = null, $batch_size = 20 ) {
28
- $this->store = $store ? $store : ActionScheduler_Store::instance();
29
- $this->batch_size = $batch_size;
30
- }
31
-
32
- public function delete_old_actions() {
33
- $lifespan = apply_filters( 'action_scheduler_retention_period', $this->month_in_seconds );
34
- $cutoff = as_get_datetime_object($lifespan.' seconds ago');
35
-
36
- $statuses_to_purge = array(
37
- ActionScheduler_Store::STATUS_COMPLETE,
38
- ActionScheduler_Store::STATUS_CANCELED,
39
- );
40
-
41
- foreach ( $statuses_to_purge as $status ) {
42
- $actions_to_delete = $this->store->query_actions( array(
43
- 'status' => $status,
44
- 'modified' => $cutoff,
45
- 'modified_compare' => '<=',
46
- 'per_page' => $this->get_batch_size(),
47
- ) );
48
-
49
- foreach ( $actions_to_delete as $action_id ) {
50
- try {
51
- $this->store->delete_action( $action_id );
52
- } catch ( Exception $e ) {
53
-
54
- /**
55
- * Notify 3rd party code of exceptions when deleting a completed action older than the retention period
56
- *
57
- * This hook provides a way for 3rd party code to log or otherwise handle exceptions relating to their
58
- * actions.
59
- *
60
- * @since 2.0.0
61
- *
62
- * @param int $action_id The scheduled actions ID in the data store
63
- * @param Exception $e The exception thrown when attempting to delete the action from the data store
64
- * @param int $lifespan The retention period, in seconds, for old actions
65
- * @param int $count_of_actions_to_delete The number of old actions being deleted in this batch
66
- */
67
- do_action( 'action_scheduler_failed_old_action_deletion', $action_id, $e, $lifespan, count( $actions_to_delete ) );
68
- }
69
- }
70
- }
71
- }
72
-
73
- /**
74
- * Unclaim pending actions that have not been run within a given time limit.
75
- *
76
- * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
77
- * as a parameter is 10x the time limit used for queue processing.
78
- *
79
- * @param int $time_limit The number of seconds to allow a queue to run before unclaiming its pending actions. Default 300 (5 minutes).
80
- */
81
- public function reset_timeouts( $time_limit = 300 ) {
82
- $timeout = apply_filters( 'action_scheduler_timeout_period', $time_limit );
83
- if ( $timeout < 0 ) {
84
- return;
85
- }
86
- $cutoff = as_get_datetime_object($timeout.' seconds ago');
87
- $actions_to_reset = $this->store->query_actions( array(
88
- 'status' => ActionScheduler_Store::STATUS_PENDING,
89
- 'modified' => $cutoff,
90
- 'modified_compare' => '<=',
91
- 'claimed' => true,
92
- 'per_page' => $this->get_batch_size(),
93
- ) );
94
-
95
- foreach ( $actions_to_reset as $action_id ) {
96
- $this->store->unclaim_action( $action_id );
97
- do_action( 'action_scheduler_reset_action', $action_id );
98
- }
99
- }
100
-
101
- /**
102
- * Mark actions that have been running for more than a given time limit as failed, based on
103
- * the assumption some uncatachable and unloggable fatal error occurred during processing.
104
- *
105
- * When called by ActionScheduler_Abstract_QueueRunner::run_cleanup(), the time limit passed
106
- * as a parameter is 10x the time limit used for queue processing.
107
- *
108
- * @param int $time_limit The number of seconds to allow an action to run before it is considered to have failed. Default 300 (5 minutes).
109
- */
110
- public function mark_failures( $time_limit = 300 ) {
111
- $timeout = apply_filters( 'action_scheduler_failure_period', $time_limit );
112
- if ( $timeout < 0 ) {
113
- return;
114
- }
115
- $cutoff = as_get_datetime_object($timeout.' seconds ago');
116
- $actions_to_reset = $this->store->query_actions( array(
117
- 'status' => ActionScheduler_Store::STATUS_RUNNING,
118
- 'modified' => $cutoff,
119
- 'modified_compare' => '<=',
120
- 'per_page' => $this->get_batch_size(),
121
- ) );
122
-
123
- foreach ( $actions_to_reset as $action_id ) {
124
- $this->store->mark_failure( $action_id );
125
- do_action( 'action_scheduler_failed_action', $action_id, $timeout );
126
- }
127
- }
128
-
129
- /**
130
- * Do all of the cleaning actions.
131
- *
132
- * @param int $time_limit The number of seconds to use as the timeout and failure period. Default 300 (5 minutes).
133
- * @author Jeremy Pry
134
- */
135
- public function clean( $time_limit = 300 ) {
136
- $this->delete_old_actions();
137
- $this->reset_timeouts( $time_limit );
138
- $this->mark_failures( $time_limit );
139
- }
140
-
141
- /**
142
- * Get the batch size for cleaning the queue.
143
- *
144
- * @author Jeremy Pry
145
- * @return int
146
- */
147
- protected function get_batch_size() {
148
- /**
149
- * Filter the batch size when cleaning the queue.
150
- *
151
- * @param int $batch_size The number of actions to clean in one batch.
152
- */
153
- return absint( apply_filters( 'action_scheduler_cleanup_batch_size', $this->batch_size ) );
154
- }
155
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_QueueRunner.php DELETED
@@ -1,115 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_QueueRunner
5
- */
6
- class ActionScheduler_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
7
- const WP_CRON_HOOK = 'action_scheduler_run_queue';
8
-
9
- const WP_CRON_SCHEDULE = 'every_minute';
10
-
11
- /** @var ActionScheduler_QueueRunner */
12
- private static $runner = null;
13
-
14
- /**
15
- * @return ActionScheduler_QueueRunner
16
- * @codeCoverageIgnore
17
- */
18
- public static function instance() {
19
- if ( empty(self::$runner) ) {
20
- $class = apply_filters('action_scheduler_queue_runner_class', 'ActionScheduler_QueueRunner');
21
- self::$runner = new $class();
22
- }
23
- return self::$runner;
24
- }
25
-
26
- /**
27
- * ActionScheduler_QueueRunner constructor.
28
- *
29
- * @param ActionScheduler_Store $store
30
- * @param ActionScheduler_FatalErrorMonitor $monitor
31
- * @param ActionScheduler_QueueCleaner $cleaner
32
- */
33
- public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
34
- parent::__construct( $store, $monitor, $cleaner );
35
- }
36
-
37
- /**
38
- * @codeCoverageIgnore
39
- */
40
- public function init() {
41
-
42
- add_filter( 'cron_schedules', array( self::instance(), 'add_wp_cron_schedule' ) );
43
-
44
- if ( !wp_next_scheduled(self::WP_CRON_HOOK) ) {
45
- $schedule = apply_filters( 'action_scheduler_run_schedule', self::WP_CRON_SCHEDULE );
46
- wp_schedule_event( time(), $schedule, self::WP_CRON_HOOK );
47
- }
48
-
49
- add_action( self::WP_CRON_HOOK, array( self::instance(), 'run' ) );
50
- }
51
-
52
- public function run() {
53
- ActionScheduler_Compatibility::raise_memory_limit();
54
- ActionScheduler_Compatibility::raise_time_limit( $this->get_time_limit() );
55
- do_action( 'action_scheduler_before_process_queue' );
56
- $this->run_cleanup();
57
- $processed_actions = 0;
58
- if ( $this->store->get_claim_count() < $this->get_allowed_concurrent_batches() ) {
59
- $batch_size = apply_filters( 'action_scheduler_queue_runner_batch_size', 25 );
60
- do {
61
- $processed_actions_in_batch = $this->do_batch( $batch_size );
62
- $processed_actions += $processed_actions_in_batch;
63
- } while ( $processed_actions_in_batch > 0 && ! $this->batch_limits_exceeded( $processed_actions ) ); // keep going until we run out of actions, time, or memory
64
- }
65
-
66
- do_action( 'action_scheduler_after_process_queue' );
67
- return $processed_actions;
68
- }
69
-
70
- protected function do_batch( $size = 100 ) {
71
- $claim = $this->store->stake_claim($size);
72
- $this->monitor->attach($claim);
73
- $processed_actions = 0;
74
-
75
- foreach ( $claim->get_actions() as $action_id ) {
76
- // bail if we lost the claim
77
- if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $claim->get_id() ) ) ) {
78
- break;
79
- }
80
- $this->process_action( $action_id );
81
- $processed_actions++;
82
-
83
- if ( $this->batch_limits_exceeded( $processed_actions ) ) {
84
- break;
85
- }
86
- }
87
- $this->store->release_claim($claim);
88
- $this->monitor->detach();
89
- $this->clear_caches();
90
- return $processed_actions;
91
- }
92
-
93
- /**
94
- * Running large batches can eat up memory, as WP adds data to its object cache.
95
- *
96
- * If using a persistent object store, this has the side effect of flushing that
97
- * as well, so this is disabled by default. To enable:
98
- *
99
- * add_filter( 'action_scheduler_queue_runner_flush_cache', '__return_true' );
100
- */
101
- protected function clear_caches() {
102
- if ( ! wp_using_ext_object_cache() || apply_filters( 'action_scheduler_queue_runner_flush_cache', false ) ) {
103
- wp_cache_flush();
104
- }
105
- }
106
-
107
- public function add_wp_cron_schedule( $schedules ) {
108
- $schedules['every_minute'] = array(
109
- 'interval' => 60, // in seconds
110
- 'display' => __( 'Every minute' ),
111
- );
112
-
113
- return $schedules;
114
- }
115
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Schedule.php DELETED
@@ -1,18 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Schedule
5
- */
6
- interface ActionScheduler_Schedule {
7
- /**
8
- * @param DateTime $after
9
- * @return DateTime|null
10
- */
11
- public function next( DateTime $after = NULL );
12
-
13
- /**
14
- * @return bool
15
- */
16
- public function is_recurring();
17
- }
18
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_SimpleSchedule.php DELETED
@@ -1,44 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_SimpleSchedule
5
- */
6
- class ActionScheduler_SimpleSchedule implements ActionScheduler_Schedule {
7
- private $date = NULL;
8
- private $timestamp = 0;
9
- public function __construct( DateTime $date ) {
10
- $this->date = clone $date;
11
- }
12
-
13
- /**
14
- * @param DateTime $after
15
- *
16
- * @return DateTime|null
17
- */
18
- public function next( DateTime $after = NULL ) {
19
- $after = empty($after) ? as_get_datetime_object('@0') : $after;
20
- return ( $after > $this->date ) ? NULL : clone $this->date;
21
- }
22
-
23
- /**
24
- * @return bool
25
- */
26
- public function is_recurring() {
27
- return false;
28
- }
29
-
30
- /**
31
- * For PHP 5.2 compat, since DateTime objects can't be serialized
32
- * @return array
33
- */
34
- public function __sleep() {
35
- $this->timestamp = $this->date->getTimestamp();
36
- return array(
37
- 'timestamp',
38
- );
39
- }
40
-
41
- public function __wakeup() {
42
- $this->date = as_get_datetime_object($this->timestamp);
43
- }
44
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Store.php DELETED
@@ -1,212 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Store
5
- * @codeCoverageIgnore
6
- */
7
- abstract class ActionScheduler_Store {
8
- const STATUS_COMPLETE = 'complete';
9
- const STATUS_PENDING = 'pending';
10
- const STATUS_RUNNING = 'in-progress';
11
- const STATUS_FAILED = 'failed';
12
- const STATUS_CANCELED = 'canceled';
13
-
14
- /** @var ActionScheduler_Store */
15
- private static $store = NULL;
16
-
17
- /**
18
- * @param ActionScheduler_Action $action
19
- * @param DateTime $scheduled_date Optional Date of the first instance
20
- * to store. Otherwise uses the first date of the action's
21
- * schedule.
22
- *
23
- * @return string The action ID
24
- */
25
- abstract public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL );
26
-
27
- /**
28
- * @param string $action_id
29
- *
30
- * @return ActionScheduler_Action
31
- */
32
- abstract public function fetch_action( $action_id );
33
-
34
- /**
35
- * @param string $hook
36
- * @param array $params
37
- * @return string ID of the next action matching the criteria
38
- */
39
- abstract public function find_action( $hook, $params = array() );
40
-
41
- /**
42
- * @param array $query
43
- * @return array The IDs of actions matching the query
44
- */
45
- abstract public function query_actions( $query = array() );
46
-
47
- /**
48
- * Get a count of all actions in the store, grouped by status
49
- *
50
- * @return array
51
- */
52
- abstract public function action_counts();
53
-
54
- /**
55
- * @param string $action_id
56
- */
57
- abstract public function cancel_action( $action_id );
58
-
59
- /**
60
- * @param string $action_id
61
- */
62
- abstract public function delete_action( $action_id );
63
-
64
- /**
65
- * @param string $action_id
66
- *
67
- * @return DateTime The date the action is schedule to run, or the date that it ran.
68
- */
69
- abstract public function get_date( $action_id );
70
-
71
-
72
- /**
73
- * @param int $max_actions
74
- * @param DateTime $before_date Claim only actions schedule before the given date. Defaults to now.
75
- * @param array $hooks Claim only actions with a hook or hooks.
76
- * @param string $group Claim only actions in the given group.
77
- *
78
- * @return ActionScheduler_ActionClaim
79
- */
80
- abstract public function stake_claim( $max_actions = 10, DateTime $before_date = null, $hooks = array(), $group = '' );
81
-
82
- /**
83
- * @return int
84
- */
85
- abstract public function get_claim_count();
86
-
87
- /**
88
- * @param ActionScheduler_ActionClaim $claim
89
- */
90
- abstract public function release_claim( ActionScheduler_ActionClaim $claim );
91
-
92
- /**
93
- * @param string $action_id
94
- */
95
- abstract public function unclaim_action( $action_id );
96
-
97
- /**
98
- * @param string $action_id
99
- */
100
- abstract public function mark_failure( $action_id );
101
-
102
- /**
103
- * @param string $action_id
104
- */
105
- abstract public function log_execution( $action_id );
106
-
107
- /**
108
- * @param string $action_id
109
- */
110
- abstract public function mark_complete( $action_id );
111
-
112
- /**
113
- * @param string $action_id
114
- *
115
- * @return string
116
- */
117
- abstract public function get_status( $action_id );
118
-
119
- /**
120
- * @param string $action_id
121
- * @return mixed
122
- */
123
- abstract public function get_claim_id( $action_id );
124
-
125
- /**
126
- * @param string $claim_id
127
- * @return array
128
- */
129
- abstract public function find_actions_by_claim_id( $claim_id );
130
-
131
- /**
132
- * @param string $comparison_operator
133
- * @return string
134
- */
135
- protected function validate_sql_comparator( $comparison_operator ) {
136
- if ( in_array( $comparison_operator, array('!=', '>', '>=', '<', '<=', '=') ) ) {
137
- return $comparison_operator;
138
- }
139
- return '=';
140
- }
141
-
142
- /**
143
- * Get the time MySQL formated date/time string for an action's (next) scheduled date.
144
- *
145
- * @param ActionScheduler_Action $action
146
- * @param DateTime $scheduled_date (optional)
147
- * @return string
148
- */
149
- protected function get_scheduled_date_string( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
150
- $next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
151
- if ( ! $next ) {
152
- throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
153
- }
154
- $next->setTimezone( new DateTimeZone( 'UTC' ) );
155
-
156
- return $next->format( 'Y-m-d H:i:s' );
157
- }
158
-
159
- /**
160
- * Get the time MySQL formated date/time string for an action's (next) scheduled date.
161
- *
162
- * @param ActionScheduler_Action $action
163
- * @param DateTime $scheduled_date (optional)
164
- * @return string
165
- */
166
- protected function get_scheduled_date_string_local( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
167
- $next = null === $scheduled_date ? $action->get_schedule()->next() : $scheduled_date;
168
- if ( ! $next ) {
169
- throw new InvalidArgumentException( __( 'Invalid schedule. Cannot save action.', 'action-scheduler' ) );
170
- }
171
-
172
- ActionScheduler_TimezoneHelper::set_local_timezone( $next );
173
- return $next->format( 'Y-m-d H:i:s' );
174
- }
175
-
176
- /**
177
- * @return array
178
- */
179
- public function get_status_labels() {
180
- return array(
181
- self::STATUS_COMPLETE => __( 'Complete', 'action-scheduler' ),
182
- self::STATUS_PENDING => __( 'Pending', 'action-scheduler' ),
183
- self::STATUS_RUNNING => __( 'In-progress', 'action-scheduler' ),
184
- self::STATUS_FAILED => __( 'Failed', 'action-scheduler' ),
185
- self::STATUS_CANCELED => __( 'Canceled', 'action-scheduler' ),
186
- );
187
- }
188
-
189
- public function init() {}
190
-
191
- /**
192
- * @return ActionScheduler_Store
193
- */
194
- public static function instance() {
195
- if ( empty(self::$store) ) {
196
- $class = apply_filters('action_scheduler_store_class', 'ActionScheduler_wpPostStore');
197
- self::$store = new $class();
198
- }
199
- return self::$store;
200
- }
201
-
202
- /**
203
- * Get the site's local time.
204
- *
205
- * @deprecated 2.1.0
206
- * @return DateTimeZone
207
- */
208
- protected function get_local_timezone() {
209
- _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
210
- return ActionScheduler_TimezoneHelper::get_local_timezone();
211
- }
212
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_TimezoneHelper.php DELETED
@@ -1,152 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_TimezoneHelper
5
- */
6
- abstract class ActionScheduler_TimezoneHelper {
7
- private static $local_timezone = NULL;
8
-
9
- /**
10
- * Set a DateTime's timezone to the WordPress site's timezone, or a UTC offset
11
- * if no timezone string is available.
12
- *
13
- * @since 2.1.0
14
- *
15
- * @param DateTime $date
16
- * @return ActionScheduler_DateTime
17
- */
18
- public static function set_local_timezone( DateTime $date ) {
19
-
20
- // Accept a DateTime for easier backward compatibility, even though we require methods on ActionScheduler_DateTime
21
- if ( ! is_a( $date, 'ActionScheduler_DateTime' ) ) {
22
- $date = as_get_datetime_object( $date->format( 'U' ) );
23
- }
24
-
25
- if ( get_option( 'timezone_string' ) ) {
26
- $date->setTimezone( new DateTimeZone( self::get_local_timezone_string() ) );
27
- } else {
28
- $date->setUtcOffset( self::get_local_timezone_offset() );
29
- }
30
-
31
- return $date;
32
- }
33
-
34
- /**
35
- * Helper to retrieve the timezone string for a site until a WP core method exists
36
- * (see https://core.trac.wordpress.org/ticket/24730).
37
- *
38
- * Adapted from wc_timezone_string() and https://secure.php.net/manual/en/function.timezone-name-from-abbr.php#89155.
39
- *
40
- * If no timezone string is set, and its not possible to match the UTC offset set for the site to a timezone
41
- * string, then an empty string will be returned, and the UTC offset should be used to set a DateTime's
42
- * timezone.
43
- *
44
- * @since 2.1.0
45
- * @return string PHP timezone string for the site or empty if no timezone string is available.
46
- */
47
- protected static function get_local_timezone_string( $reset = false ) {
48
- // If site timezone string exists, return it.
49
- $timezone = get_option( 'timezone_string' );
50
- if ( $timezone ) {
51
- return $timezone;
52
- }
53
-
54
- // Get UTC offset, if it isn't set then return UTC.
55
- $utc_offset = intval( get_option( 'gmt_offset', 0 ) );
56
- if ( 0 === $utc_offset ) {
57
- return 'UTC';
58
- }
59
-
60
- // Adjust UTC offset from hours to seconds.
61
- $utc_offset *= 3600;
62
-
63
- // Attempt to guess the timezone string from the UTC offset.
64
- $timezone = timezone_name_from_abbr( '', $utc_offset );
65
- if ( $timezone ) {
66
- return $timezone;
67
- }
68
-
69
- // Last try, guess timezone string manually.
70
- foreach ( timezone_abbreviations_list() as $abbr ) {
71
- foreach ( $abbr as $city ) {
72
- if ( (bool) date( 'I' ) === (bool) $city['dst'] && $city['timezone_id'] && intval( $city['offset'] ) === $utc_offset ) {
73
- return $city['timezone_id'];
74
- }
75
- }
76
- }
77
-
78
- // No timezone string
79
- return '';
80
- }
81
-
82
- /**
83
- * Get timezone offset in seconds.
84
- *
85
- * @since 2.1.0
86
- * @return float
87
- */
88
- protected static function get_local_timezone_offset() {
89
- $timezone = get_option( 'timezone_string' );
90
-
91
- if ( $timezone ) {
92
- $timezone_object = new DateTimeZone( $timezone );
93
- return $timezone_object->getOffset( new DateTime( 'now' ) );
94
- } else {
95
- return floatval( get_option( 'gmt_offset', 0 ) ) * HOUR_IN_SECONDS;
96
- }
97
- }
98
-
99
- /**
100
- * @deprecated 2.1.0
101
- */
102
- public static function get_local_timezone( $reset = FALSE ) {
103
- _deprecated_function( __FUNCTION__, '2.1.0', 'ActionScheduler_TimezoneHelper::set_local_timezone()' );
104
- if ( $reset ) {
105
- self::$local_timezone = NULL;
106
- }
107
- if ( !isset(self::$local_timezone) ) {
108
- $tzstring = get_option('timezone_string');
109
-
110
- if ( empty($tzstring) ) {
111
- $gmt_offset = get_option('gmt_offset');
112
- if ( $gmt_offset == 0 ) {
113
- $tzstring = 'UTC';
114
- } else {
115
- $gmt_offset *= HOUR_IN_SECONDS;
116
- $tzstring = timezone_name_from_abbr( '', $gmt_offset, 1 );
117
-
118
- // If there's no timezone string, try again with no DST.
119
- if ( false === $tzstring ) {
120
- $tzstring = timezone_name_from_abbr( '', $gmt_offset, 0 );
121
- }
122
-
123
- // Try mapping to the first abbreviation we can find.
124
- if ( false === $tzstring ) {
125
- $is_dst = date( 'I' );
126
- foreach ( timezone_abbreviations_list() as $abbr ) {
127
- foreach ( $abbr as $city ) {
128
- if ( $city['dst'] == $is_dst && $city['offset'] == $gmt_offset ) {
129
- // If there's no valid timezone ID, keep looking.
130
- if ( null === $city['timezone_id'] ) {
131
- continue;
132
- }
133
-
134
- $tzstring = $city['timezone_id'];
135
- break 2;
136
- }
137
- }
138
- }
139
- }
140
-
141
- // If we still have no valid string, then fall back to UTC.
142
- if ( false === $tzstring ) {
143
- $tzstring = 'UTC';
144
- }
145
- }
146
- }
147
-
148
- self::$local_timezone = new DateTimeZone($tzstring);
149
- }
150
- return self::$local_timezone;
151
- }
152
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_Versions.php DELETED
@@ -1,62 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_Versions
5
- */
6
- class ActionScheduler_Versions {
7
- /**
8
- * @var ActionScheduler_Versions
9
- */
10
- private static $instance = NULL;
11
-
12
- private $versions = array();
13
-
14
- public function register( $version_string, $initialization_callback ) {
15
- if ( isset($this->versions[$version_string]) ) {
16
- return FALSE;
17
- }
18
- $this->versions[$version_string] = $initialization_callback;
19
- return TRUE;
20
- }
21
-
22
- public function get_versions() {
23
- return $this->versions;
24
- }
25
-
26
- public function latest_version() {
27
- $keys = array_keys($this->versions);
28
- if ( empty($keys) ) {
29
- return false;
30
- }
31
- uasort( $keys, 'version_compare' );
32
- return end($keys);
33
- }
34
-
35
- public function latest_version_callback() {
36
- $latest = $this->latest_version();
37
- if ( empty($latest) || !isset($this->versions[$latest]) ) {
38
- return '__return_null';
39
- }
40
- return $this->versions[$latest];
41
- }
42
-
43
- /**
44
- * @return ActionScheduler_Versions
45
- * @codeCoverageIgnore
46
- */
47
- public static function instance() {
48
- if ( empty(self::$instance) ) {
49
- self::$instance = new self();
50
- }
51
- return self::$instance;
52
- }
53
-
54
- /**
55
- * @codeCoverageIgnore
56
- */
57
- public static function initialize_latest_version() {
58
- $self = self::instance();
59
- call_user_func($self->latest_version_callback());
60
- }
61
- }
62
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_QueueRunner.php DELETED
@@ -1,210 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * WP CLI Queue runner.
5
- *
6
- * This class can only be called from within a WP CLI instance.
7
- */
8
- class ActionScheduler_WPCLI_QueueRunner extends ActionScheduler_Abstract_QueueRunner {
9
-
10
- /** @var array */
11
- protected $actions;
12
-
13
- /** @var ActionScheduler_ActionClaim */
14
- protected $claim;
15
-
16
- /** @var \cli\progress\Bar */
17
- protected $progress_bar;
18
-
19
- /**
20
- * ActionScheduler_WPCLI_QueueRunner constructor.
21
- *
22
- * @param ActionScheduler_Store $store
23
- * @param ActionScheduler_FatalErrorMonitor $monitor
24
- * @param ActionScheduler_QueueCleaner $cleaner
25
- *
26
- * @throws Exception When this is not run within WP CLI
27
- */
28
- public function __construct( ActionScheduler_Store $store = null, ActionScheduler_FatalErrorMonitor $monitor = null, ActionScheduler_QueueCleaner $cleaner = null ) {
29
- if ( ! ( defined( 'WP_CLI' ) && WP_CLI ) ) {
30
- /* translators: %s php class name */
31
- throw new Exception( sprintf( __( 'The %s class can only be run within WP CLI.', 'action-scheduler' ), __CLASS__ ) );
32
- }
33
-
34
- parent::__construct( $store, $monitor, $cleaner );
35
- }
36
-
37
- /**
38
- * Set up the Queue before processing.
39
- *
40
- * @author Jeremy Pry
41
- *
42
- * @param int $batch_size The batch size to process.
43
- * @param array $hooks The hooks being used to filter the actions claimed in this batch.
44
- * @param string $group The group of actions to claim with this batch.
45
- * @param bool $force Whether to force running even with too many concurrent processes.
46
- *
47
- * @return int The number of actions that will be run.
48
- * @throws \WP_CLI\ExitException When there are too many concurrent batches.
49
- */
50
- public function setup( $batch_size, $hooks = array(), $group = '', $force = false ) {
51
- $this->run_cleanup();
52
- $this->add_hooks();
53
-
54
- // Check to make sure there aren't too many concurrent processes running.
55
- $claim_count = $this->store->get_claim_count();
56
- $too_many = $claim_count >= $this->get_allowed_concurrent_batches();
57
- if ( $too_many ) {
58
- if ( $force ) {
59
- WP_CLI::warning( __( 'There are too many concurrent batches, but the run is forced to continue.', 'action-scheduler' ) );
60
- } else {
61
- WP_CLI::error( __( 'There are too many concurrent batches.', 'action-scheduler' ) );
62
- }
63
- }
64
-
65
- // Stake a claim and store it.
66
- $this->claim = $this->store->stake_claim( $batch_size, null, $hooks, $group );
67
- $this->monitor->attach( $this->claim );
68
- $this->actions = $this->claim->get_actions();
69
-
70
- return count( $this->actions );
71
- }
72
-
73
- /**
74
- * Add our hooks to the appropriate actions.
75
- *
76
- * @author Jeremy Pry
77
- */
78
- protected function add_hooks() {
79
- add_action( 'action_scheduler_before_execute', array( $this, 'before_execute' ) );
80
- add_action( 'action_scheduler_after_execute', array( $this, 'after_execute' ), 10, 2 );
81
- add_action( 'action_scheduler_failed_execution', array( $this, 'action_failed' ), 10, 2 );
82
- }
83
-
84
- /**
85
- * Set up the WP CLI progress bar.
86
- *
87
- * @author Jeremy Pry
88
- */
89
- protected function setup_progress_bar() {
90
- $count = count( $this->actions );
91
- $this->progress_bar = \WP_CLI\Utils\make_progress_bar(
92
- sprintf( _n( 'Running %d action', 'Running %d actions', $count, 'action-scheduler' ), number_format_i18n( $count ) ),
93
- $count
94
- );
95
- }
96
-
97
- /**
98
- * Process actions in the queue.
99
- *
100
- * @author Jeremy Pry
101
- * @return int The number of actions processed.
102
- */
103
- public function run() {
104
- do_action( 'action_scheduler_before_process_queue' );
105
- $this->setup_progress_bar();
106
- foreach ( $this->actions as $action_id ) {
107
- // Error if we lost the claim.
108
- if ( ! in_array( $action_id, $this->store->find_actions_by_claim_id( $this->claim->get_id() ) ) ) {
109
- WP_CLI::warning( __( 'The claim has been lost. Aborting current batch.', 'action-scheduler' ) );
110
- break;
111
- }
112
-
113
- $this->process_action( $action_id );
114
- $this->progress_bar->tick();
115
-
116
- // Free up memory after every 50 items
117
- if ( 0 === $this->progress_bar->current() % 50 ) {
118
- $this->stop_the_insanity();
119
- }
120
- }
121
-
122
- $completed = $this->progress_bar->current();
123
- $this->progress_bar->finish();
124
- $this->store->release_claim( $this->claim );
125
- do_action( 'action_scheduler_after_process_queue' );
126
-
127
- return $completed;
128
- }
129
-
130
- /**
131
- * Handle WP CLI message when the action is starting.
132
- *
133
- * @author Jeremy Pry
134
- *
135
- * @param $action_id
136
- */
137
- public function before_execute( $action_id ) {
138
- /* translators: %s refers to the action ID */
139
- WP_CLI::log( sprintf( __( 'Started processing action %s', 'action-scheduler' ), $action_id ) );
140
- }
141
-
142
- /**
143
- * Handle WP CLI message when the action has completed.
144
- *
145
- * @author Jeremy Pry
146
- *
147
- * @param int $action_id
148
- * @param null|ActionScheduler_Action $action The instance of the action. Default to null for backward compatibility.
149
- */
150
- public function after_execute( $action_id, $action = null ) {
151
- // backward compatibility
152
- if ( null === $action ) {
153
- $action = $this->store->fetch_action( $action_id );
154
- }
155
- /* translators: %s refers to the action ID */
156
- WP_CLI::log( sprintf( __( 'Completed processing action %s with hook: %s', 'action-scheduler' ), $action_id, $action->get_hook() ) );
157
- }
158
-
159
- /**
160
- * Handle WP CLI message when the action has failed.
161
- *
162
- * @author Jeremy Pry
163
- *
164
- * @param int $action_id
165
- * @param Exception $exception
166
- * @throws \WP_CLI\ExitException With failure message.
167
- */
168
- public function action_failed( $action_id, $exception ) {
169
- WP_CLI::error(
170
- /* translators: %1$s refers to the action ID, %2$s refers to the Exception message */
171
- sprintf( __( 'Error processing action %1$s: %2$s', 'action-scheduler' ), $action_id, $exception->getMessage() ),
172
- false
173
- );
174
- }
175
-
176
- /**
177
- * Sleep and help avoid hitting memory limit
178
- *
179
- * @param int $sleep_time Amount of seconds to sleep
180
- */
181
- protected function stop_the_insanity( $sleep_time = 0 ) {
182
- if ( 0 < $sleep_time ) {
183
- WP_CLI::warning( sprintf( 'Stopped the insanity for %d %s', $sleep_time, _n( 'second', 'seconds', $sleep_time ) ) );
184
- sleep( $sleep_time );
185
- }
186
-
187
- WP_CLI::warning( __( 'Attempting to reduce used memory...', 'action-scheduler' ) );
188
-
189
- /**
190
- * @var $wpdb \wpdb
191
- * @var $wp_object_cache \WP_Object_Cache
192
- */
193
- global $wpdb, $wp_object_cache;
194
-
195
- $wpdb->queries = array();
196
-
197
- if ( ! is_object( $wp_object_cache ) ) {
198
- return;
199
- }
200
-
201
- $wp_object_cache->group_ops = array();
202
- $wp_object_cache->stats = array();
203
- $wp_object_cache->memcache_debug = array();
204
- $wp_object_cache->cache = array();
205
-
206
- if ( is_callable( array( $wp_object_cache, '__remoteset' ) ) ) {
207
- call_user_func( array( $wp_object_cache, '__remoteset' ) ); // important
208
- }
209
- }
210
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_WPCLI_Scheduler_command.php DELETED
@@ -1,145 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Commands for the Action Scheduler by Prospress.
5
- */
6
- class ActionScheduler_WPCLI_Scheduler_command extends WP_CLI_Command {
7
-
8
- /**
9
- * Run the Action Scheduler
10
- *
11
- * ## OPTIONS
12
- *
13
- * [--batch-size=<size>]
14
- * : The maximum number of actions to run. Defaults to 100.
15
- *
16
- * [--batches=<size>]
17
- * : Limit execution to a number of batches. Defaults to 0, meaning batches will continue being executed until all actions are complete.
18
- *
19
- * [--cleanup-batch-size=<size>]
20
- * : The maximum number of actions to clean up. Defaults to the value of --batch-size.
21
- *
22
- * [--hooks=<hooks>]
23
- * : Only run actions with the specified hook. Omitting this option runs actions with any hook. Define multiple hooks as a comma separated string (without spaces), e.g. `--hooks=hook_one,hook_two,hook_three`
24
- *
25
- * [--group=<group>]
26
- * : Only run actions from the specified group. Omitting this option runs actions from all groups.
27
- *
28
- * [--force]
29
- * : Whether to force execution despite the maximum number of concurrent processes being exceeded.
30
- *
31
- * @param array $args Positional arguments.
32
- * @param array $assoc_args Keyed arguments.
33
- * @throws \WP_CLI\ExitException When an error occurs.
34
- */
35
- public function run( $args, $assoc_args ) {
36
- // Handle passed arguments.
37
- $batch = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batch-size', 100 ) );
38
- $batches = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'batches', 0 ) );
39
- $clean = absint( \WP_CLI\Utils\get_flag_value( $assoc_args, 'cleanup-batch-size', $batch ) );
40
- $hooks = explode( ',', WP_CLI\Utils\get_flag_value( $assoc_args, 'hooks', '' ) );
41
- $hooks = array_filter( array_map( 'trim', $hooks ) );
42
- $group = \WP_CLI\Utils\get_flag_value( $assoc_args, 'group', '' );
43
- $force = \WP_CLI\Utils\get_flag_value( $assoc_args, 'force', false );
44
-
45
- $batches_completed = 0;
46
- $actions_completed = 0;
47
- $unlimited = $batches === 0;
48
-
49
- try {
50
- // Custom queue cleaner instance.
51
- $cleaner = new ActionScheduler_QueueCleaner( null, $clean );
52
-
53
- // Get the queue runner instance
54
- $runner = new ActionScheduler_WPCLI_QueueRunner( null, null, $cleaner );
55
-
56
- // Determine how many tasks will be run in the first batch.
57
- $total = $runner->setup( $batch, $hooks, $group, $force );
58
-
59
- // Run actions for as long as possible.
60
- while ( $total > 0 ) {
61
- $this->print_total_actions( $total );
62
- $actions_completed += $runner->run();
63
- $batches_completed++;
64
-
65
- // Maybe set up tasks for the next batch.
66
- $total = ( $unlimited || $batches_completed < $batches ) ? $runner->setup( $batch, $hooks, $group, $force ) : 0;
67
- }
68
- } catch ( Exception $e ) {
69
- $this->print_error( $e );
70
- }
71
-
72
- $this->print_total_batches( $batches_completed );
73
- $this->print_success( $actions_completed );
74
- }
75
-
76
- /**
77
- * Print WP CLI message about how many actions are about to be processed.
78
- *
79
- * @author Jeremy Pry
80
- *
81
- * @param int $total
82
- */
83
- protected function print_total_actions( $total ) {
84
- WP_CLI::log(
85
- sprintf(
86
- /* translators: %d refers to how many scheduled taks were found to run */
87
- _n( 'Found %d scheduled task', 'Found %d scheduled tasks', $total, 'action-scheduler' ),
88
- number_format_i18n( $total )
89
- )
90
- );
91
- }
92
-
93
- /**
94
- * Print WP CLI message about how many batches of actions were processed.
95
- *
96
- * @author Jeremy Pry
97
- *
98
- * @param int $batches_completed
99
- */
100
- protected function print_total_batches( $batches_completed ) {
101
- WP_CLI::log(
102
- sprintf(
103
- /* translators: %d refers to the total number of batches executed */
104
- _n( '%d batch executed.', '%d batches executed.', $batches_completed, 'action-scheduler' ),
105
- number_format_i18n( $batches_completed )
106
- )
107
- );
108
- }
109
-
110
- /**
111
- * Convert an exception into a WP CLI error.
112
- *
113
- * @author Jeremy Pry
114
- *
115
- * @param Exception $e The error object.
116
- *
117
- * @throws \WP_CLI\ExitException
118
- */
119
- protected function print_error( Exception $e ) {
120
- WP_CLI::error(
121
- sprintf(
122
- /* translators: %s refers to the exception error message. */
123
- __( 'There was an error running the action scheduler: %s', 'action-scheduler' ),
124
- $e->getMessage()
125
- )
126
- );
127
- }
128
-
129
- /**
130
- * Print a success message with the number of completed actions.
131
- *
132
- * @author Jeremy Pry
133
- *
134
- * @param int $actions_completed
135
- */
136
- protected function print_success( $actions_completed ) {
137
- WP_CLI::success(
138
- sprintf(
139
- /* translators: %d refers to the total number of taskes completed */
140
- _n( '%d scheduled task completed.', '%d scheduled tasks completed.', $actions_completed, 'action-scheduler' ),
141
- number_format_i18n( $actions_completed )
142
- )
143
- );
144
- }
145
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_wpCommentLogger.php DELETED
@@ -1,240 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_wpCommentLogger
5
- */
6
- class ActionScheduler_wpCommentLogger extends ActionScheduler_Logger {
7
- const AGENT = 'ActionScheduler';
8
- const TYPE = 'action_log';
9
-
10
- /**
11
- * @param string $action_id
12
- * @param string $message
13
- * @param DateTime $date
14
- *
15
- * @return string The log entry ID
16
- */
17
- public function log( $action_id, $message, DateTime $date = NULL ) {
18
- if ( empty($date) ) {
19
- $date = as_get_datetime_object();
20
- } else {
21
- $date = as_get_datetime_object( clone $date );
22
- }
23
- $comment_id = $this->create_wp_comment( $action_id, $message, $date );
24
- return $comment_id;
25
- }
26
-
27
- protected function create_wp_comment( $action_id, $message, DateTime $date ) {
28
-
29
- $comment_date_gmt = $date->format('Y-m-d H:i:s');
30
- ActionScheduler_TimezoneHelper::set_local_timezone( $date );
31
- $comment_data = array(
32
- 'comment_post_ID' => $action_id,
33
- 'comment_date' => $date->format('Y-m-d H:i:s'),
34
- 'comment_date_gmt' => $comment_date_gmt,
35
- 'comment_author' => self::AGENT,
36
- 'comment_content' => $message,
37
- 'comment_agent' => self::AGENT,
38
- 'comment_type' => self::TYPE,
39
- );
40
- return wp_insert_comment($comment_data);
41
- }
42
-
43
- /**
44
- * @param string $entry_id
45
- *
46
- * @return ActionScheduler_LogEntry
47
- */
48
- public function get_entry( $entry_id ) {
49
- $comment = $this->get_comment( $entry_id );
50
- if ( empty($comment) || $comment->comment_type != self::TYPE ) {
51
- return new ActionScheduler_NullLogEntry();
52
- }
53
-
54
- $date = as_get_datetime_object( $comment->comment_date_gmt );
55
- ActionScheduler_TimezoneHelper::set_local_timezone( $date );
56
- return new ActionScheduler_LogEntry( $comment->comment_post_ID, $comment->comment_content, $date );
57
- }
58
-
59
- /**
60
- * @param string $action_id
61
- *
62
- * @return ActionScheduler_LogEntry[]
63
- */
64
- public function get_logs( $action_id ) {
65
- $status = 'all';
66
- if ( get_post_status($action_id) == 'trash' ) {
67
- $status = 'post-trashed';
68
- }
69
- $comments = get_comments(array(
70
- 'post_id' => $action_id,
71
- 'orderby' => 'comment_date_gmt',
72
- 'order' => 'ASC',
73
- 'type' => self::TYPE,
74
- 'status' => $status,
75
- ));
76
- $logs = array();
77
- foreach ( $comments as $c ) {
78
- $entry = $this->get_entry( $c );
79
- if ( !empty($entry) ) {
80
- $logs[] = $entry;
81
- }
82
- }
83
- return $logs;
84
- }
85
-
86
- protected function get_comment( $comment_id ) {
87
- return get_comment( $comment_id );
88
- }
89
-
90
-
91
-
92
- /**
93
- * @param WP_Comment_Query $query
94
- */
95
- public function filter_comment_queries( $query ) {
96
- foreach ( array('ID', 'parent', 'post_author', 'post_name', 'post_parent', 'type', 'post_type', 'post_id', 'post_ID') as $key ) {
97
- if ( !empty($query->query_vars[$key]) ) {
98
- return; // don't slow down queries that wouldn't include action_log comments anyway
99
- }
100
- }
101
- $query->query_vars['action_log_filter'] = TRUE;
102
- add_filter( 'comments_clauses', array( $this, 'filter_comment_query_clauses' ), 10, 2 );
103
- }
104
-
105
- /**
106
- * @param array $clauses
107
- * @param WP_Comment_Query $query
108
- *
109
- * @return array
110
- */
111
- public function filter_comment_query_clauses( $clauses, $query ) {
112
- if ( !empty($query->query_vars['action_log_filter']) ) {
113
- $clauses['where'] .= $this->get_where_clause();
114
- }
115
- return $clauses;
116
- }
117
-
118
- /**
119
- * Make sure Action Scheduler logs are excluded from comment feeds, which use WP_Query, not
120
- * the WP_Comment_Query class handled by @see self::filter_comment_queries().
121
- *
122
- * @param string $where
123
- * @param WP_Query $query
124
- *
125
- * @return string
126
- */
127
- public function filter_comment_feed( $where, $query ) {
128
- if ( is_comment_feed() ) {
129
- $where .= $this->get_where_clause();
130
- }
131
- return $where;
132
- }
133
-
134
- /**
135
- * Return a SQL clause to exclude Action Scheduler comments.
136
- *
137
- * @return string
138
- */
139
- protected function get_where_clause() {
140
- global $wpdb;
141
- return sprintf( " AND {$wpdb->comments}.comment_type != '%s'", self::TYPE );
142
- }
143
-
144
- /**
145
- * Remove action log entries from wp_count_comments()
146
- *
147
- * @param array $stats
148
- * @param int $post_id
149
- *
150
- * @return object
151
- */
152
- public function filter_comment_count( $stats, $post_id ) {
153
- global $wpdb;
154
-
155
- if ( 0 === $post_id ) {
156
- $stats = $this->get_comment_count();
157
- }
158
-
159
- return $stats;
160
- }
161
-
162
- /**
163
- * Retrieve the comment counts from our cache, or the database if the cached version isn't set.
164
- *
165
- * @return object
166
- */
167
- protected function get_comment_count() {
168
- global $wpdb;
169
-
170
- $stats = get_transient( 'as_comment_count' );
171
-
172
- if ( ! $stats ) {
173
- $stats = array();
174
-
175
- $count = $wpdb->get_results( "SELECT comment_approved, COUNT( * ) AS num_comments FROM {$wpdb->comments} WHERE comment_type NOT IN('order_note','action_log') GROUP BY comment_approved", ARRAY_A );
176
-
177
- $total = 0;
178
- $stats = array();
179
- $approved = array( '0' => 'moderated', '1' => 'approved', 'spam' => 'spam', 'trash' => 'trash', 'post-trashed' => 'post-trashed' );
180
-
181
- foreach ( (array) $count as $row ) {
182
- // Don't count post-trashed toward totals
183
- if ( 'post-trashed' != $row['comment_approved'] && 'trash' != $row['comment_approved'] ) {
184
- $total += $row['num_comments'];
185
- }
186
- if ( isset( $approved[ $row['comment_approved'] ] ) ) {
187
- $stats[ $approved[ $row['comment_approved'] ] ] = $row['num_comments'];
188
- }
189
- }
190
-
191
- $stats['total_comments'] = $total;
192
- $stats['all'] = $total;
193
-
194
- foreach ( $approved as $key ) {
195
- if ( empty( $stats[ $key ] ) ) {
196
- $stats[ $key ] = 0;
197
- }
198
- }
199
-
200
- $stats = (object) $stats;
201
- set_transient( 'as_comment_count', $stats );
202
- }
203
-
204
- return $stats;
205
- }
206
-
207
- /**
208
- * Delete comment count cache whenever there is new comment or the status of a comment changes. Cache
209
- * will be regenerated next time ActionScheduler_wpCommentLogger::filter_comment_count() is called.
210
- */
211
- public function delete_comment_count_cache() {
212
- delete_transient( 'as_comment_count' );
213
- }
214
-
215
- /**
216
- * @codeCoverageIgnore
217
- */
218
- public function init() {
219
- add_action( 'action_scheduler_before_process_queue', array( $this, 'disable_comment_counting' ), 10, 0 );
220
- add_action( 'action_scheduler_after_process_queue', array( $this, 'enable_comment_counting' ), 10, 0 );
221
-
222
- parent::init();
223
-
224
- add_action( 'pre_get_comments', array( $this, 'filter_comment_queries' ), 10, 1 );
225
- add_action( 'wp_count_comments', array( $this, 'filter_comment_count' ), 20, 2 ); // run after WC_Comments::wp_count_comments() to make sure we exclude order notes and action logs
226
- add_action( 'comment_feed_where', array( $this, 'filter_comment_feed' ), 10, 2 );
227
-
228
- // Delete comments count cache whenever there is a new comment or a comment status changes
229
- add_action( 'wp_insert_comment', array( $this, 'delete_comment_count_cache' ) );
230
- add_action( 'wp_set_comment_status', array( $this, 'delete_comment_count_cache' ) );
231
- }
232
-
233
- public function disable_comment_counting() {
234
- wp_defer_comment_counting(true);
235
- }
236
- public function enable_comment_counting() {
237
- wp_defer_comment_counting(false);
238
- }
239
-
240
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
trunk/vendor/prospress/action-scheduler/classes/ActionScheduler_wpPostStore.php DELETED
@@ -1,798 +0,0 @@
1
- <?php
2
-
3
- /**
4
- * Class ActionScheduler_wpPostStore
5
- */
6
- class ActionScheduler_wpPostStore extends ActionScheduler_Store {
7
- const POST_TYPE = 'scheduled-action';
8
- const GROUP_TAXONOMY = 'action-group';
9
- const SCHEDULE_META_KEY = '_action_manager_schedule';
10
-
11
- /** @var DateTimeZone */
12
- protected $local_timezone = NULL;
13
-
14
- /** @var int */
15
- private static $max_index_length = 191;
16
-
17
- public function save_action( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ){
18
- try {
19
- $this->validate_action( $action );
20
- $post_array = $this->create_post_array( $action, $scheduled_date );
21
- $post_id = $this->save_post_array( $post_array );
22
- $this->save_post_schedule( $post_id, $action->get_schedule() );
23
- $this->save_action_group( $post_id, $action->get_group() );
24
- do_action( 'action_scheduler_stored_action', $post_id );
25
- return $post_id;
26
- } catch ( Exception $e ) {
27
- throw new RuntimeException( sprintf( __('Error saving action: %s', 'action-scheduler'), $e->getMessage() ), 0 );
28
- }
29
- }
30
-
31
- protected function create_post_array( ActionScheduler_Action $action, DateTime $scheduled_date = NULL ) {
32
- $post = array(
33
- 'post_type' => self::POST_TYPE,
34
- 'post_title' => $action->get_hook(),
35
- 'post_content' => json_encode($action->get_args()),
36
- 'post_status' => ( $action->is_finished() ? 'publish' : 'pending' ),
37
- 'pos