PluginProbe
AliNext – WooCommerce Dropshipping Plugin for AliExpress / trunk
AliNext – WooCommerce Dropshipping Plugin for AliExpress vtrunk
ali2woo-lite / includes / classes / controller / SynchProductController.php

SynchProductController.php in AliNext – WooCommerce Dropshipping Plugin for AliExpress trunk, at includes/classes/controller/SynchProductController.php

469 lines 16.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Description of SynchProductController
5 *
6 * @author Ali2Woo Team
7 *
8 * @autoload: a2wl_init
9 *
10 * @cron: true
11 */
12
13 namespace AliNext_Lite;;
14
15 use Throwable;
16
17 class SynchProductController extends AbstractController
18 {
19
20 protected ProductService $ProductService;
21 protected ProductReviewsService $ProductReviewsService;
22 protected Woocommerce $WoocommerceModel;
23 protected PriceFormulaService $PriceFormulaService;
24 protected WoocommerceService $WoocommerceService;
25
26 private $update_per_schedule = 100;
27 private $update_per_request = 5;
28 private $update_period_delay = 60 * 60 * 24;
29
30 public function __construct(
31 ProductService $ProductService,
32 ProductReviewsService $ProductReviewsService,
33 Woocommerce $WoocommerceModel,
34 PriceFormulaService $PriceFormulaService,
35 WoocommerceService $WoocommerceService
36 ) {
37 parent::__construct();
38
39 $this->ProductService = $ProductService;
40 $this->ProductReviewsService = $ProductReviewsService;
41 $this->WoocommerceModel = $WoocommerceModel;
42 $this->PriceFormulaService = $PriceFormulaService;
43 $this->WoocommerceService = $WoocommerceService;
44
45 add_action('a2wl_install', array($this, 'install'));
46
47 add_action('a2wl_uninstall', array($this, 'uninstall'));
48
49 add_filter('cron_schedules', array($this, 'init_reccurences'));
50
51 add_action('admin_init', array($this, 'init'));
52
53 add_action('a2wl_synch_event_check', array($this, 'synch_event_check'));
54
55 if (get_setting('auto_update')) {
56 add_action('a2wl_update_products_event', array($this, 'update_products_event'));
57
58 if (get_setting('email_alerts')) {
59 add_action('a2wl_email_alerts_event', array($this, 'email_alerts_event'));
60 }
61 }
62
63 if (get_setting('load_review') && get_setting('review_status')) {
64 add_action('a2wl_update_reviews_event', array($this, 'update_reviews_event'));
65 }
66 }
67
68 public function init_reccurences($schedules)
69 {
70 $schedules['a2wl_5_mins'] = array('interval' => 5 * 60, 'display' => esc_html__('Every 5 Minutes', 'ali2woo'));
71 $schedules['a2wl_15_mins'] = array('interval' => 15 * 60, 'display' => esc_html__('Every 15 Minutes', 'ali2woo'));
72 return $schedules;
73 }
74
75 public function init()
76 {
77 add_action('a2wl_set_setting_email_alerts', array($this, 'toggle_email_alerts'), 10, 3);
78
79 add_action('a2wl_set_setting_auto_update', array($this, 'togle_auto_update'), 10, 3);
80
81 add_action('a2wl_set_setting_review_status', array($this, 'togle_update_reviews'), 10, 3);
82
83 if (!wp_next_scheduled('a2wl_synch_event_check')) {
84 wp_schedule_event(time(), 'a2wl_5_mins', 'a2wl_synch_event_check');
85 }
86 }
87
88 public function synch_event_check()
89 {
90 // check: is a2wl_update_products_event, update_reviews_event exist. if no, create it.
91
92 if (!wp_next_scheduled('a2wl_update_products_event') && get_setting('auto_update')) {
93 $this->schedule_event();
94 }
95
96 if (!wp_next_scheduled('a2wl_update_reviews_event') && get_setting('load_review') && get_setting('review_status')) {
97 $this->schedule_reviews_event();
98 }
99
100 if (!wp_next_scheduled('a2wl_email_alerts_event') && get_setting('auto_update') && get_setting('email_alerts')) {
101 $this->schedule_email_alerts_event();
102 }
103 }
104
105 public function install()
106 {
107
108 $this->unschedule_event();
109 if (get_setting('auto_update')) {
110 $this->schedule_event();
111 }
112
113 $this->unschedule_email_alerts_event();
114 if (get_setting('auto_update') && get_setting('email_alerts')) {
115 $this->schedule_email_alerts_event();
116 }
117
118 $this->unschedule_reviews_event();
119 if (get_setting('load_review') && get_setting('review_status')) {
120 $this->schedule_reviews_event();
121 }
122
123 // reset a2wl_synch_event_check
124 wp_clear_scheduled_hook('a2wl_synch_event_check');
125 }
126
127 public function uninstall()
128 {
129 $this->unschedule_event();
130 $this->schedule_email_alerts_event();
131 $this->unschedule_reviews_event();
132
133 // reset a2wl_synch_event_check
134 wp_clear_scheduled_hook('a2wl_synch_event_check');
135 }
136
137 public function toggle_email_alerts($old_value, $value, $option)
138 {
139 if ($old_value !== $value) {
140 $this->unschedule_email_alerts_event();
141 if ($value) {
142 $this->schedule_email_alerts_event();
143 }
144 }
145 }
146
147 public function togle_auto_update($old_value, $value, $option)
148 {
149 if ($old_value !== $value) {
150 $this->unschedule_event();
151 if ($value) {
152 $this->schedule_event();
153 }
154 }
155 }
156
157 public function togle_update_reviews($old_value, $value, $option)
158 {
159 if ($old_value !== $value) {
160 $this->unschedule_reviews_event();
161 if ($value) {
162 $this->schedule_reviews_event();
163 }
164 }
165
166 }
167
168 // Cron auto update event
169 public function update_products_event(): void
170 {
171 if (!get_setting('auto_update') || $this->is_process_running('a2wl_update_products_event')) {
172 return;
173 }
174
175 $this->lock_process('a2wl_update_products_event');
176
177 a2wl_init_error_handler();
178 try {
179 $update_per_schedule = apply_filters('a2wl_update_per_schedule',
180 a2wl_check_defined('A2WL_UPDATE_PER_SCHEDULE') ? intval(A2WL_UPDATE_PER_SCHEDULE) : $this->update_per_schedule
181 );
182
183 $update_per_request = apply_filters('a2wl_update_per_request',
184 a2wl_check_defined('A2WL_UPDATE_PER_REQUEST') ? intval(A2WL_UPDATE_PER_REQUEST) : $this->update_per_request
185 );
186
187 $update_period_delay = apply_filters('a2wl_update_period_delay',
188 a2wl_check_defined('A2WL_UPDATE_PERIOD_DELAY') ? intval(A2WL_UPDATE_PERIOD_DELAY) : $this->update_period_delay
189 );
190
191 $product_ids = $this->WoocommerceModel->get_sorted_products_ids(
192 "_a2w_last_update",
193 $update_per_schedule,
194 ['value' => time() - $update_period_delay, 'compare' => '<'],
195 get_setting('untrash_product')
196 );
197
198 $on_price_changes = get_setting('on_price_changes');
199 $on_stock_changes = get_setting('on_stock_changes');
200
201 $product_map = array();
202 foreach ($product_ids as $product_id) {
203 try {
204 $product = $this->WoocommerceService->getProduct($product_id);
205 } catch (RepositoryException|ServiceException $Exception) {
206 continue;
207 }
208
209 if (!$product['disable_sync']) {
210 $product['disable_var_price_change'] = $product['disable_var_price_change'] || $on_price_changes !== "update";
211 $product['disable_var_quantity_change'] = $product['disable_var_quantity_change'] || $on_stock_changes !== "update";
212 $product_map[strval($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID])] = $product;
213 } else {
214 // update meta for skipped products
215 update_post_meta($product['post_id'], '_a2w_last_update', time());
216 }
217
218 unset($product);
219 }
220
221 while ($product_map) {
222 $tmp_product_map = array_slice($product_map, 0, $update_per_request, true);
223 $product_map = array_diff_key($product_map, $tmp_product_map);
224
225 if (count($tmp_product_map) > 0) {
226 $result = $this->ProductService->synchronizeProducts($tmp_product_map);
227
228 if ($result['state'] !== 'error') {
229 foreach ($result['products'] as $product) {
230 if (!empty($tmp_product_map[$product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID]])) {
231 try {
232 $product = array_replace_recursive($tmp_product_map[strval($product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID])], $product);
233 $product = $this->PriceFormulaService->applyFormula($product);
234 $this->WoocommerceModel->upd_product($product['post_id'], $product);
235 if ($result['state'] !== 'ok') {
236 $errorLogMessage = sprintf(
237 "Automatically synced product (ID: %d) at %s - failed: %s!",
238 $product['post_id'], date("j, Y, g:i a"), $result['error']
239 );
240 a2wl_error_log($errorLogMessage);
241 } else {
242 $infoLogMessage = sprintf(
243 "Automatically synced product (ID: %d) at %s - success!",
244 $product['post_id'],
245 date("j, Y, g:i a")
246 );
247 a2wl_info_log($infoLogMessage);
248 }
249 unset($tmp_product_map[$product[ImportedProductService::FIELD_EXTERNAL_PRODUCT_ID]]);
250 } catch (Throwable $e) {
251 a2wl_print_throwable($e);
252 }
253 }
254 }
255
256 delete_transient('_a2w_daily_limits_warning');
257 } else {
258 // update daily limit warning
259 $limitIsReached = isset($result['error_code']) &&
260 $result['error_code'] == 5001 &&
261 isset($result['time_left']);
262 if ($limitIsReached) {
263 set_transient(
264 '_a2w_daily_limits_warning',
265 [
266 'limit' => $result['call_limit'],
267 'until' => time() + $result['time_left']
268 ],
269 time() + $result['time_left']
270 );
271 } else {
272 a2wl_error_log($result['message']);
273 }
274 }
275
276 unset($result);
277 }
278 }
279 } catch (Throwable $e) {
280 a2wl_print_throwable($e);
281 }
282
283 $this->unlock_process('a2wl_update_products_event');
284
285 if (get_setting('auto_update')) {
286 $this->schedule_event();
287 } else {
288 $this->unschedule_event();
289 }
290 }
291
292 public function email_alerts_event()
293 {
294
295 if (!get_setting('auto_update') || !get_setting('email_alerts') || $this->is_process_running('a2wl_email_alerts_event')) {
296 return;
297 }
298
299 $this->lock_process('a2wl_email_alerts_event');
300
301 a2wl_init_error_handler();
302 try {
303 $product_change_model = new ProductChange();
304
305 $to = get_setting('email_alerts_email');
306
307 if ($to) {
308
309 $items = $product_change_model->get_all();
310 //we update data of product_change_model in the add_variation method in AliNext_Lite\Woocommerce
311 //the collision of these two events is almost unreal, therefore we neglect it
312 $product_change_model->clear_all();
313
314 if ($items) {
315
316 $items_per_email = 100;
317 $chunks = array_chunk($items, $items_per_email, true);
318
319 a2wl_info_log('Total changes: ' . count($items) . ', total emails: ' . count($chunks));
320
321 foreach ($chunks as $chunk_items) {
322 $result = $this->send_email_alert($to, $chunk_items);
323 }
324
325 }
326
327 }
328
329 } catch (Throwable $e) {
330 a2wl_print_throwable($e);
331 }
332
333 $this->unlock_process('a2wl_email_alerts_event');
334
335 if (get_setting('auto_update') && get_setting('email_alerts')) {
336 $this->schedule_email_alerts_event();
337 } else {
338 $this->unschedule_email_alerts_event();
339 }
340
341 }
342
343 private function send_email_alert($to, $items)
344 {
345
346 $items = $this->format_items_for_email_alert($items);
347
348 $this->model_put("email_heading", esc_html__('AliNext (Lite version) report: Changes in your products', 'ali2woo'));
349 $this->model_put("email_subheading", esc_html__('Changes occurred in the last half-hour in your store', 'ali2woo'));
350 $this->model_put("items", $items);
351 $this->model_put("email_footer_text", esc_html__('The report is generated by the Email alerts module in AliNext (Lite version) at', 'ali2woo') . ' ' . gmdate("F j, Y, g:i a"));
352
353 ob_start();
354 $this->include_view(
355 array("emails/email-header.php", "emails/product-changes.php", "emails/email-footer.php"));
356
357 $message = ob_get_clean();
358
359 $result = wc_mail($to, esc_html__('AliNext (Lite version) report: Changes in your products', 'ali2woo'), $message);
360 a2wl_info_log('Email with product changes: ' . ($result ? ' is sent' : ' isn`t sent'));
361
362 return $result;
363
364 }
365
366 private function format_items_for_email_alert($items)
367 {
368
369 $formatted_items = array();
370
371 foreach ($items as $product_id => $item) {
372
373 $product = wc_get_product($product_id);
374
375 $formatted_items[$product_id] = $item;
376
377 $formatted_items[$product_id]['image-src'] = $product->get_image();
378 $formatted_items[$product_id]['title'] = $product->get_formatted_name();
379 $formatted_items[$product_id]['url'] = get_permalink($product_id);
380 $formatted_items[$product_id]['original_url'] = get_post_meta($product_id, '_a2w_product_url', true);
381
382 }
383
384 return $formatted_items;
385
386 }
387
388 public function update_reviews_event(): void
389 {
390 if (!get_setting('load_review') || !get_setting('review_status')
391 || $this->is_process_running('a2wl_update_reviews_event')) {
392 return;
393 }
394
395 $this->lock_process('a2wl_update_reviews_event');
396
397 a2wl_init_error_handler();
398 try {
399 $this->ProductReviewsService->loadReviewsForOldestUpdatedProducts();
400 } catch (Throwable $e) {
401 a2wl_print_throwable($e);
402 }
403
404 $this->unlock_process('a2wl_update_reviews_event');
405
406 if (get_setting('load_review') && get_setting('review_status')) {
407 $this->schedule_reviews_event();
408 } else {
409 $this->unschedule_reviews_event();
410 }
411 }
412
413 private function schedule_event()
414 {
415 if (!($timestamp = wp_next_scheduled('a2wl_update_products_event'))) {
416 wp_schedule_single_event(time() + MINUTE_IN_SECONDS * 5, 'a2wl_update_products_event');
417 }
418 }
419
420 private function unschedule_event()
421 {
422 wp_clear_scheduled_hook('a2wl_update_products_event');
423 }
424
425 private function schedule_email_alerts_event()
426 {
427 if (!($timestamp = wp_next_scheduled('a2wl_email_alerts_event'))) {
428 wp_schedule_single_event(time() + MINUTE_IN_SECONDS * 30, 'a2wl_email_alerts_event');
429 }
430 }
431
432 private function unschedule_email_alerts_event()
433 {
434 wp_clear_scheduled_hook('a2wl_email_alerts_event');
435 }
436
437 private function schedule_reviews_event()
438 {
439 if (!($timestamp = wp_next_scheduled('a2wl_update_reviews_event'))) {
440 wp_schedule_single_event(time() + MINUTE_IN_SECONDS * 30, 'a2wl_update_reviews_event');
441 }
442 }
443
444 private function unschedule_reviews_event()
445 {
446 wp_clear_scheduled_hook('a2wl_update_reviews_event');
447 }
448
449 protected function is_process_running($process)
450 {
451 if (get_site_transient($process . '_process_lock')) {
452 return true;
453 }
454
455 return false;
456 }
457
458 protected function lock_process($process)
459 {
460 set_site_transient($process . '_process_lock', microtime(), MINUTE_IN_SECONDS * 2);
461 }
462
463 protected function unlock_process($process)
464 {
465 delete_site_transient($process . '_process_lock');
466 }
467
468 }
469