PluginProbe ʕ •ᴥ•ʔ
WooCommerce Square / 5.4.2
WooCommerce Square v5.4.2
5.4.2 5.4.1 5.4.0 trunk 1.0.25 1.0.26 1.0.27 1.0.28 1.0.29 1.0.30 1.0.31 1.0.32 1.0.33 1.0.34 1.0.35 1.0.36 1.0.37 1.0.38 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.0.6 2.0.7 2.0.8 2.1.0 2.1.1 2.1.2 2.1.3 2.1.4 2.1.5 2.1.6 2.2.0 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3.0 2.3.1 2.3.2 2.3.3 2.3.4 2.4.0 2.4.1 2.5.0 2.5.1 2.5.2 2.5.3 2.6.0 2.7.0 2.8.0 2.9.0 2.9.1 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.2.0 3.3.0 3.4.0 3.4.1 3.4.2 3.5.0 3.6.0 3.6.1 3.7.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.9.0 4.0.0 4.1.0 4.2.0 4.2.1 4.2.2 4.2.3 4.3.0 4.3.1 4.3.2 4.4.0 4.4.1 4.4.2 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.6.2 4.6.3 4.6.4 4.7.0 4.7.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.1 4.8.2 4.8.3 4.8.4 4.8.5 4.8.6 4.8.7 4.8.8 4.9.0 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 4.9.6 4.9.7 4.9.8 4.9.9 5.0.0 5.0.1 5.1.0 5.1.1 5.1.2 5.2.0 5.3.0 5.3.1 5.3.2 5.3.3
woocommerce-square / includes / Handlers / Sync.php
woocommerce-square / includes / Handlers Last commit date
Product 1 month ago Async_Request.php 2 years ago Background_Job.php 2 months ago Category.php 1 month ago Connection.php 4 months ago Email.php 1 year ago Order.php 1 day ago Order_Sync.php 10 months ago Product.php 1 month ago Products.php 1 day ago Sync.php 3 years ago
Sync.php
445 lines
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 GNU General Public License v3.0 or later
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 or later
22 */
23
24 namespace WooCommerce\Square\Handlers;
25
26 use WooCommerce\Square\Plugin;
27 use WooCommerce\Square\Sync\Records;
28
29 defined( 'ABSPATH' ) || exit;
30
31 /**
32 * Synchronization handler class
33 *
34 * @since 2.0.0
35 */
36 class Sync {
37
38
39 /** @var string key of the option that stores a timestamp when the last sync job completed */
40 private $last_synced_at_option_key = 'wc_square_last_synced_at';
41
42 /** @var string name of the Action Scheduler event name for syncing with Square */
43 private $sync_scheduled_event_name;
44
45 /** @var Plugin plugin instance */
46 private $plugin;
47
48
49 /**
50 * Constructs the class.
51 *
52 * @since 2.0.0
53 *
54 * @param Plugin $plugin
55 */
56 public function __construct( Plugin $plugin ) {
57
58 $this->plugin = $plugin;
59
60 $this->sync_scheduled_event_name = 'wc_square_sync';
61
62 $this->add_hooks();
63 }
64
65
66 /**
67 * Adds the action & filter hooks.
68 *
69 * @since 2.0.0
70 */
71 private function add_hooks() {
72
73 // schedule the interval sync
74 add_action( 'init', array( $this, 'schedule_sync' ) );
75
76 // run the interval sync when fired by Action Scheduler
77 add_action( $this->sync_scheduled_event_name, array( $this, 'start_interval_sync' ) );
78
79 add_action( 'admin_notices', array( $this, 'render_import_no_navigation_warning' ) );
80 }
81
82 /**
83 * Returns array of post types supported for sync.
84 *
85 * Since 3.8.3
86 *
87 * @return array
88 */
89 public function supported_product_types() {
90 return array(
91 'simple',
92 'variable',
93 );
94 }
95
96 /**
97 * Schedules the interval sync.
98 *
99 * @param bool $change_interval (optional) whether to change the interval
100 * @since 2.0.0
101 */
102 public function schedule_sync( $change_interval = false ) {
103
104 // bail if product sync is not enabled or there hasn't been a previous sync
105 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() ) {
106 return;
107 }
108
109 $plugin_id = $this->get_plugin()->get_id();
110 $interval = wc_square()->get_settings_handler()->get_sync_interval();
111
112 if ( false === as_next_scheduled_action( $this->sync_scheduled_event_name, array(), $plugin_id ) || $change_interval ) {
113 as_unschedule_all_actions( $this->sync_scheduled_event_name, array(), $plugin_id );
114 as_schedule_recurring_action( time() + $interval, $interval, $this->sync_scheduled_event_name, array(), $plugin_id );
115 }
116 }
117
118
119 /**
120 * Unschedules the interval sync.
121 *
122 * @since 2.0.0
123 */
124 public function unschedule_sync() {
125
126 as_unschedule_action( $this->sync_scheduled_event_name, array(), 'square' );
127 }
128
129 /**
130 * Performs a product import from Square.
131 *
132 * @since 2.0.0
133 *
134 * @param bool $update_during_import whether the store manager has ticked to update products during an import
135 * @return \stdClass|null
136 */
137 public function start_product_import( $update_during_import = false ) {
138
139 $job = $this->get_plugin()->get_background_job_handler()->create_job(
140 array(
141 'action' => 'product_import',
142 'update_products_during_import' => $update_during_import,
143 )
144 );
145
146 if ( $job ) {
147 as_enqueue_async_action( 'wc_square_job_runner' );
148 }
149
150 return $job;
151 }
152
153 /**
154 * Performs a manual sync.
155 *
156 * @since 2.0.0
157 *
158 * @param int[] $product_ids (optional) array of product IDs to sync
159 * @return \stdClass|null
160 */
161 public function start_manual_sync( array $product_ids = array() ) {
162
163 $product_ids = empty( $product_ids ) ? Product::get_products_synced_with_square() : $product_ids;
164
165 $job = $this->get_plugin()->get_background_job_handler()->create_job(
166 array(
167 'action' => 'sync',
168 'manual' => true,
169 'product_ids' => $product_ids,
170 )
171 );
172
173 if ( $job ) {
174 as_enqueue_async_action( 'wc_square_job_runner' );
175 }
176
177 return $job;
178 }
179
180 /**
181 * Performs a manual product deletion.
182 *
183 * @since 2.0.0
184 *
185 * @param int[] $product_ids array of product IDs to delete
186 * @return \stdClass|null
187 */
188 public function start_manual_deletion( array $product_ids ) {
189
190 $job = $this->get_plugin()->get_background_job_handler()->create_job(
191 array(
192 'action' => 'delete',
193 'manual' => true,
194 'product_ids' => $product_ids,
195 )
196 );
197
198 if ( $job ) {
199 as_enqueue_async_action( 'wc_square_job_runner' );
200 }
201
202 return $job;
203 }
204
205 /**
206 * Performs an interval sync with Square.
207 *
208 * @since 2.0.0
209 */
210 public function start_interval_sync() {
211
212 // bail if there is already a sync in progress
213 if ( ! $this->is_sync_enabled() || $this->is_sync_in_progress() ) {
214 return;
215 }
216
217 // use this opportunity to clear old background jobs
218 $this->get_plugin()->get_background_job_handler()->clear_all_jobs();
219
220 $job = $this->get_plugin()->get_background_job_handler()->create_job(
221 array(
222 'action' => 'poll',
223 'manual' => false,
224 'catalog_last_synced_at' => $this->get_last_synced_at(),
225 'inventory_last_synced_at' => $this->get_inventory_last_synced_at(),
226 )
227 );
228
229 if ( $job ) {
230 as_enqueue_async_action( 'wc_square_job_runner' );
231 }
232 }
233
234
235 /** Conditional methods *******************************************************************************************/
236
237
238 /**
239 * Determines whether a sync, scheduled or manual, is in progress.
240 *
241 * @since 2.0.0
242 *
243 * @return bool
244 */
245 public function is_sync_in_progress() {
246
247 return ( defined( 'DOING_SQUARE_SYNC' ) && true === DOING_SQUARE_SYNC )
248 || null !== $this->get_job_in_progress();
249 }
250
251
252 /**
253 * Determines if sync is enabled.
254 *
255 * @since 2.0.0
256 *
257 * @return bool
258 */
259 public function is_sync_enabled() {
260
261 return $this->get_plugin()->get_settings_handler()->is_product_sync_enabled();
262 }
263
264
265 /** Setter methods ************************************************************************************************/
266
267
268 /**
269 * Records a successful sync.
270 *
271 * @since 2.0.0
272 *
273 * @param int[] $product_ids IDs of products synced
274 * @param null|\stdClass $job optional sync job, may be used to set the job ID to prevent duplicates
275 */
276 public function record_sync( array $product_ids, $job = null ) {
277
278 $products = count( $product_ids );
279
280 // only add a record of some products were synced
281 if ( $products ) {
282
283 Records::set_record(
284 array(
285 'id' => $job && isset( $job->id ) ? $job->id : null,
286 'message' => sprintf(
287 /* translators: Placeholder: %d number of products processed */
288 _n( 'Updated data for %d product.', 'Updated data for %d products.', $products, 'woocommerce-square' ),
289 $products
290 ),
291 )
292 );
293 }
294
295 /**
296 * Fires after a set of products are synced with square.
297 *
298 * @since 2.0.0
299 *
300 * @param int[] $product_ids IDs for products that were synced
301 */
302 do_action( 'wc_square_products_synced', $product_ids );
303 }
304
305
306 /**
307 * Updates the time when the last sync job occurred.
308 *
309 * @since 2.0.0
310 *
311 * @param int|string|null $timestamp a valid timestamp in UTC (optional, will default to now)
312 * @return bool success
313 */
314 public function set_last_synced_at( $timestamp = null ) {
315
316 if ( null === $timestamp ) {
317 $timestamp = time();
318 }
319
320 return is_numeric( $timestamp ) && update_option( $this->last_synced_at_option_key, (int) $timestamp );
321 }
322
323
324 /** Getter methods ************************************************************************************************/
325
326
327 /**
328 * Gets a job that is currently in progress.
329 *
330 * @since 2.0.0
331 *
332 * @return null|\stdClass background job object or null if not found
333 */
334 public function get_job_in_progress() {
335
336 $handler = $this->get_plugin()->get_background_job_handler();
337
338 try {
339 $job = $handler->get_job();
340 } catch ( \Exception $e ) {
341 $job = null;
342 }
343
344 return $job && isset( $job->status ) && in_array( $job->status, array( 'created', 'queued', 'processing' ), true ) ? $job : null;
345 }
346
347 /**
348 * Gets the timestamp when the next sync job should start.
349 *
350 * @since 2.0.0
351 *
352 * @return int
353 */
354 public function get_next_sync_at() {
355
356 $timestamp = null;
357 $scheduled = as_next_scheduled_action( $this->sync_scheduled_event_name );
358
359 if ( $scheduled ) {
360 $timestamp = $scheduled;
361 }
362
363 return (int) $timestamp > 1 ? $timestamp : null;
364 }
365
366
367 /**
368 * Gets the timestamp for when the last sync job completed.
369 *
370 * @since 2.0.0
371 *
372 * @return int
373 */
374 public function get_last_synced_at() {
375
376 $timestamp = get_option( $this->last_synced_at_option_key, null );
377
378 return (int) $timestamp > 1 ? $timestamp : null;
379 }
380
381
382 /**
383 * Sets the timestamp for when the last inventory sync job started.
384 *
385 * @since 2.0.0
386 *
387 * @param int|string|null $timestamp a valid timestamp in UTC (optional, will default to now)
388 * @return bool success
389 */
390 public function set_inventory_last_synced_at( $timestamp = null ) {
391
392 if ( null === $timestamp ) {
393 $timestamp = time();
394 }
395
396 return is_numeric( $timestamp ) && update_option( $this->last_synced_at_option_key . '_inventory', $timestamp );
397 }
398
399
400 /**
401 * Gets the timestamp for when the last inventory sync job completed.
402 *
403 * @since 2.0.0
404 *
405 * @return int
406 */
407 public function get_inventory_last_synced_at() {
408
409 $timestamp = get_option( $this->last_synced_at_option_key . '_inventory', null );
410
411 return (int) $timestamp > 1 ? $timestamp : null;
412 }
413
414
415 /**
416 * Gets the plugin instance.
417 *
418 * @since 2.0.0
419 *
420 * @return Plugin
421 */
422 private function get_plugin() {
423
424 return $this->plugin;
425 }
426
427 /**
428 * Show warning not to close or navigate away from the current
429 * page when product import is in progress.
430 */
431 public function render_import_no_navigation_warning() {
432 $job_in_progress = wc_square()->get_sync_handler()->get_job_in_progress();
433
434 if ( $job_in_progress && 'product_import' === $job_in_progress->action ) {
435 wc_square()->get_admin_notice_handler()->add_admin_notice(
436 __( 'Please do not close or navigate away from this page as the product import job is in progress. This page may load several times during the course of sync.', 'woocommerce-square' ),
437 'wc-square-sync-in-progress-message',
438 array(
439 'notice_class' => 'notice-warning',
440 )
441 );
442 }
443 }
444 }
445