PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.4.4
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.4.4
3.0.3 3.0.2 3.0.1 trunk 2.2.14 2.2.15 2.2.16 2.2.17 2.2.18 2.2.19 2.3.0 2.3.1 2.3.10 2.3.11 2.3.12 2.3.13 2.3.14 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 2.4.0 2.4.1 2.4.2 2.4.3 2.4.4 2.4.5 2.4.6 2.5.0 2.5.1 2.5.2 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.6.5 2.7.0 2.7.1 2.7.2 2.7.3 2.7.4 2.7.5 2.7.6 2.7.7 2.7.8 2.7.9 2.7.91 2.7.92 2.7.93 2.8.0 2.8.1 2.8.2 2.8.3 2.8.4 2.8.5 2.9.0 2.9.1 2.9.2 2.9.3 3.0.0
commercebird / includes / classes / apis / class-api-for-product-webhook.php
commercebird / includes / classes / apis Last commit date
class-api-for-cmbird.php 1 year ago class-api-for-exact-webhooks.php 1 year ago class-api-for-product-webhook.php 11 months ago class-api-for-shipping-status.php 1 year ago class-api-for-woo-order.php 1 year ago class-api-for-zoho-inventory.php 1 year ago class-commercebird-list-items-api-controller.php 1 year ago class-commercebird-media-api-controller.php 1 year ago class-commercebird-metadata-controller.php 1 year ago index.php 1 year ago trait-api-permission.php 11 months ago
class-api-for-product-webhook.php
657 lines
1 <?php
2
3 namespace CommerceBird\API;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use CMBIRD_Image_ZI;
10 use CMBIRD_Products_ZI;
11 use CMBIRD_Products_ZI_Export;
12 use WC_Data_Exception;
13 use WC_Product_Variation;
14 use WC_Product_Variable;
15 use WP_REST_Response;
16 use wpdb;
17 use CMBIRD_Common_Functions;
18 use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
19
20 class ProductWebhook {
21
22
23 use Api;
24
25 private static string $endpoint = 'zoho-product';
26
27 private $is_tax_enabled;
28
29 public function __construct() {
30 register_rest_route(
31 self::$namespace,
32 self::$endpoint,
33 array(
34 'methods' => 'POST',
35 'callback' => array( $this, 'handle' ),
36 'permission_callback' => '__return_true',
37 )
38 );
39 // Check if WooCommerce taxes are enabled and store the result
40 $this->is_tax_enabled = 'yes' === get_option( 'woocommerce_calc_taxes' );
41
42 // Register queue processing hook
43 add_action( 'cmbird_process_webhook_queue', array( $this, 'process_queued_requests' ) );
44
45 // Add cleanup for old rate limit data
46 add_action( 'wp_scheduled_delete', array( $this, 'cleanup_rate_limit_data' ) );
47 }
48
49 // Method to use the tax check across the class
50 public function is_tax_enabled(): bool {
51 return $this->is_tax_enabled;
52 }
53
54
55 /**
56 * @throws WC_Data_Exception
57 */
58 private function process( array $data ): WP_REST_Response {
59 $response = new WP_REST_Response();
60 $response->set_data( $this->empty_response );
61 $response->set_status( 404 );
62 if ( ! array_key_exists( 'item', $data ) && ! array_key_exists( 'inventory_adjustment', $data ) ) {
63 return $response;
64 }
65
66 // Accounting stock mode check
67 $accounting_stock = get_option( 'cmbird_zoho_enable_accounting_stock_status' );
68 $zi_enable_locationstock = get_option( 'cmbird_zoho_enable_locationstock_status' );
69 $location_id = get_option( 'cmbird_zoho_location_id_status' );
70
71 // variable item sync
72 if ( array_key_exists( 'item', $data ) ) {
73 return $this->process_product_data( $data['item'], $zi_enable_locationstock, $location_id, $accounting_stock );
74 }
75 // inventory_adjustment
76 if ( array_key_exists( 'inventory_adjustment', $data ) ) {
77 return $this->inventory_adjustment( $data['inventory_adjustment'] );
78 }
79
80 return $response;
81 }
82
83 /**
84 * @param $item
85 * @param $zi_enable_locationstock
86 * @param $location_id
87 * @param $accounting_stock
88 *
89 * @return WP_REST_Response
90 * @throws WC_Data_Exception
91 */
92 public function process_product_data( $item, $zi_enable_locationstock, $location_id, $accounting_stock ): WP_REST_Response {
93 // $fd = fopen( __DIR__ . '/process_product_data.txt', 'a+' );
94
95 // clean orphaned data from the database
96 $common_class = new CMBIRD_Common_Functions();
97 $common_class->clear_orphan_data();
98
99 global $wpdb;
100 $item_id = $item['item_id'];
101 $item_name = $item['name'];
102 $item_price = $item['rate'];
103 $item_sku = $item['sku'];
104 $item_description = $item['description'];
105 $item_status = $item['status'] === 'active' ? 'publish' : 'draft';
106 $item_brand = $item['brand'];
107 $category_id = $item['category_id'];
108 $custom_fields = $item['custom_fields'];
109 $item_image = $item['image_name'];
110 // Stock mode check
111 $locations = $item['locations'];
112 if ( $zi_enable_locationstock ) {
113 foreach ( $locations as $location ) {
114 if ( $location['location_id'] === $location_id ) {
115 if ( $accounting_stock ) {
116 $item_stock = $location['location_available_for_sale_stock'];
117 } else {
118 $item_stock = $location['location_actual_available_for_sale_stock'];
119 }
120 }
121 }
122 } elseif ( $accounting_stock && ! $zi_enable_locationstock ) {
123 $item_stock = $item['available_for_sale_stock'];
124 } else {
125 $item_stock = $item['actual_available_for_sale_stock'];
126 }
127 if ( isset( $item['group_name'] ) ) {
128 $group_name = $item['group_name'];
129 } else {
130 $group_name = '';
131 }
132 $item_category = $item['category_name'];
133 if ( isset( $item['group_id'] ) ) {
134 $groupid = $item['group_id'];
135 } else {
136 $groupid = '';
137 }
138
139 // Item package details
140 $details = $item['package_details'];
141 $weight = floatval( $details['weight'] );
142 $length = floatval( $details['length'] );
143 $width = floatval( $details['width'] );
144 $height = floatval( $details['height'] );
145
146 // fwrite($fd, PHP_EOL . '$groupid : ' . $groupid);
147 if ( ! empty( $groupid ) ) {
148 // fwrite($fd, PHP_EOL . 'Inside grouped items');
149 // find parent variable product
150 $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='zi_item_id' AND meta_value=%s", $groupid ) );
151 $group_id = $row->post_id;
152
153 if ( ! empty( $group_id ) ) {
154 $existing_parent_product = wc_get_product( $group_id );
155 $zi_disable_itemdescription_sync = get_option( 'cmbird_zoho_disable_description_sync_status' );
156 if ( ! empty( $item_description ) && ! $zi_disable_itemdescription_sync ) {
157 // fwrite($fd, PHP_EOL . 'Item description update : ' . $item_description);
158 $existing_parent_product->set_short_description( $item_description );
159 }
160 // Update the name of the variable product if allowed
161 $zi_disable_itemname_sync = get_option( 'cmbird_zoho_disable_name_sync_status' );
162 if ( ! $zi_disable_itemname_sync ) {
163 $existing_parent_product->set_name( $item['group_name'] );
164 $slug = sanitize_title( $item['group_name'] );
165 $existing_parent_product->set_slug( $slug );
166 }
167 // Brand update if taxonomy product_brand exists
168 if ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
169 wp_set_object_terms( $groupid, $item_brand, 'product_brand' );
170 } elseif ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
171 wp_set_object_terms( $groupid, $item_brand, 'product_brand' );
172 }
173 // Update the custom fields if the custom fields are not empty
174 $cmbird_product_zi = new CMBIRD_Products_ZI();
175 if ( ! empty( $custom_fields ) ) {
176 $cmbird_product_zi->sync_item_custom_fields( $custom_fields, $groupid );
177 }
178
179 // Create or Update the Attributes
180 // turn $item into array
181 $gp_arr = (array) $item;
182 $attr_created = $cmbird_product_zi->sync_attributes_of_group( $gp_arr, $group_id );
183 if ( ! empty( $group_id ) && $attr_created ) {
184 // Create the variations
185 $cmbird_product_zi->import_variable_product_variations( $item, $group_id );
186 }
187
188 // set the product status of the variable parent product
189 // $existing_parent_product->set_status( $item_status );
190 $existing_parent_product->save();
191 } else {
192 // Add in scheduler to create the Variable Product
193 $last_synced_page = get_option( 'cmbird_group_item_sync_page_cat_id_' . $category_id );
194 if ( ! intval( $last_synced_page ) ) {
195 $last_synced_page = 1;
196 }
197 $data = array(
198 'page' => $last_synced_page,
199 'category' => $category_id,
200 );
201 $existing_schedule = as_has_scheduled_action( 'import_group_items_cron', $data );
202 // Schedule the action if it doesn't exist.
203 if ( ! $existing_schedule ) {
204 as_schedule_single_action( time(), 'import_group_items_cron', $data );
205 }
206 }
207
208 $row_item = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='zi_item_id' AND meta_value=%s", $item_id ) );
209 $variation_id = $row_item->post_id;
210 if ( $variation_id ) {
211 // updating existing variations
212 $variation = new WC_Product_Variation( $variation_id );
213 // Prices
214 if ( ! empty( $item_price ) ) {
215 $variation->set_price( $item_price );
216 }
217 $variation->set_regular_price( $item_price );
218 // Stock
219 $zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
220 if ( ! empty( $item_stock ) && ! $zi_disable_stock_sync ) {
221 // fwrite($fd, PHP_EOL . 'Stock is here:'. $item_stock );
222 $variation->set_stock_quantity( $item_stock );
223 $variation->set_manage_stock( true );
224 // $variation->set_stock_status('');
225 } else {
226 // fwrite($fd, PHP_EOL . 'Available Stock : false');
227 $variation->set_manage_stock( false );
228 }
229 // featured image
230 $zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
231 if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
232 // fwrite($fd, PHP_EOL . 'Sync Image' );
233 $image_class = new CMBIRD_Image_ZI();
234 $image_class->cmbird_zi_get_image( $item_id, $item_name, $variation_id, $item_image );
235 }
236 // Disable or enable the variation based on the item_status
237 $variation->set_status( $item_status );
238 // Update Purchase price
239 $variation->update_meta_data( '_cost_price', $item['purchase_rate'] );
240
241 // Map taxes while syncing product from zoho.
242 if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
243 $zi_common_class = new CMBIRD_Common_Functions();
244 $woo_tax_class = $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
245 $variation->set_tax_status( 'taxable' );
246 $variation->set_tax_class( $woo_tax_class );
247 }
248 // weight & dimensions
249 $variation->set_weight( $weight );
250 $variation->set_length( $length );
251 $variation->set_width( $width );
252 $variation->set_height( $height );
253
254 $variation->save(); // Save the data
255 } elseif ( 'publish' === $item_status ) {
256 $attribute_name11 = $item['attribute_option_name1'];
257 $attribute_name12 = $item['attribute_option_name2'];
258 $attribute_name13 = $item['attribute_option_name3'];
259 // Prepare the variation data
260 $attribute_arr = array();
261 if ( ! empty( $attribute_name11 ) ) {
262 $sanitized_name1 = wc_sanitize_taxonomy_name( $item['attribute_name1'] );
263 $attribute_arr[ $sanitized_name1 ] = $attribute_name11;
264 }
265 if ( ! empty( $attribute_name12 ) ) {
266 $sanitized_name2 = wc_sanitize_taxonomy_name( $item['attribute_name2'] );
267 $attribute_arr[ $sanitized_name2 ] = $attribute_name12;
268 }
269 if ( ! empty( $attribute_name13 ) ) {
270 $sanitized_name3 = wc_sanitize_taxonomy_name( $item['attribute_name3'] );
271 $attribute_arr[ $sanitized_name3 ] = $attribute_name13;
272 }
273
274 // here actually create new variation because sku not found
275 $zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
276 $variation = new WC_Product_Variation();
277 $variation->set_parent_id( $group_id );
278 $variation->set_status( 'publish' );
279 $variation->set_regular_price( $item_price );
280 $variation->set_sku( $item_sku );
281 $variation->set_weight( $weight );
282 $variation->set_length( $length );
283 $variation->set_width( $width );
284 $variation->set_height( $height );
285 if ( ! $zi_disable_stock_sync ) {
286 $variation->set_stock_quantity( $item_stock );
287 $variation->set_manage_stock( true );
288 $variation->set_stock_status( '' );
289 } else {
290 $variation->set_manage_stock( false );
291 }
292 // Map taxes while syncing product from zoho.
293 if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
294 $zi_common_class = new CMBIRD_Common_Functions();
295 $woo_tax_class = $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
296 $variation->set_tax_status( 'taxable' );
297 $variation->set_tax_class( $woo_tax_class );
298 }
299 $variation->add_meta_data( 'zi_item_id', $item->item_id );
300 $variation_id = $variation->save();
301
302 // Get the variation attributes with correct attribute values
303 foreach ( $attribute_arr as $attribute => $term_name ) {
304 $taxonomy = $attribute;
305 // If taxonomy doesn't exists we create it
306 if ( ! taxonomy_exists( $taxonomy ) ) {
307 register_taxonomy(
308 $taxonomy,
309 'product_variation',
310 array(
311 'hierarchical' => false,
312 'label' => ucfirst( $attribute ),
313 'query_var' => true,
314 'rewrite' => array( 'slug' => sanitize_title( $attribute ) ),
315 ),
316 );
317 }
318
319 // Check if the Term name exist and if not we create it.
320 if ( ! term_exists( $term_name, $taxonomy ) ) {
321 wp_insert_term( $term_name, $taxonomy );
322 }
323
324 $term_slug = get_term_by( 'name', $term_name, $taxonomy )->slug;
325 // Get the post Terms names from the parent variable product.
326 $post_term_names = wp_get_post_terms( $group_id, $taxonomy, array( 'fields' => 'names' ) );
327 // Check if the post term exist and if not we set it in the parent variable product.
328 if ( ! in_array( $term_name, $post_term_names, true ) ) {
329 wp_set_post_terms( $group_id, $term_name, $taxonomy, true );
330 }
331 // Set/save the attribute data in the product variation
332 update_post_meta( $variation_id, 'attribute_' . $taxonomy, $term_slug );
333 }
334
335 // featured image
336 $zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
337 if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
338 $image_class = new CMBIRD_Image_ZI();
339 $image_class->cmbird_zi_get_image( $item_id, $item_name, $variation_id, $item_image );
340 }
341
342 update_post_meta( $variation_id, 'zi_item_id', $item_id );
343 // Sync variation data with parent variable product
344 WC_Product_Variable::sync( $group_id );
345 // Regenerate lookup table for attributes
346 $lookup_data_store = new LookupDataStore();
347 $lookup_data_store->create_data_for_product( $group_id );
348 // End group item add process
349 unset( $attribute_arr );
350 }
351 wc_delete_product_transients( $group_id ); // Clear/refresh cache
352 // end of grouped item creation
353 } else {
354 // fwrite($fd, PHP_EOL . 'Inside simple items');
355 // fwrite($fd, PHP_EOL . 'Item description Simple : ' . $item_description);
356 $row_item = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s", $item_id ) );
357 $mapped_product_id = $row_item->post_id;
358 // simple product
359 // fwrite($fd, PHP_EOL . 'Before Match check');
360 $pdt_id = '';
361 if ( ! empty( $mapped_product_id ) && null !== $mapped_product_id ) {
362 $product_found = wc_get_product( $mapped_product_id );
363 if ( ! $product_found ) {
364 // remove all postmeta of that product id.
365 $wpdb->delete( $wpdb->postmeta, array( 'post_id' => $mapped_product_id ) );
366 } else {
367 $pdt_id = $mapped_product_id;
368 }
369 } elseif ( empty( $item['is_combo_product'] ) ) {
370 // fwrite($fd, PHP_EOL . 'Inside create product');
371
372 // Check if Category is selected before creating simple item
373 if ( 'publish' === $item_status ) {
374 $opt_category = get_option( 'cmbird_zoho_item_category' );
375 $opt_category = maybe_unserialize( $opt_category );
376 $category_id = $item['category_id'];
377 if ( $opt_category ) {
378 if ( in_array( $category_id, $opt_category, true ) ) {
379 $product_class = new CMBIRD_Products_ZI_Export();
380 $pdt_id = $product_class->cmbird_zi_product_to_woocommerce( $item, $item_stock );
381 }
382 }
383 }
384 // fwrite($fd, PHP_EOL . 'After adding it : ' . $pdt_id);
385 }
386
387 // If there is product id then update metadata.
388 if ( ! empty( $pdt_id ) ) {
389 $simple_product = wc_get_product( $pdt_id );
390 // update the name if its allowed
391 $zi_disable_itemname_sync = get_option( 'cmbird_zoho_disable_name_sync_status' );
392 if ( ! $zi_disable_itemname_sync ) {
393 $simple_product->set_name( $item_name );
394 $slug = sanitize_title( $item_name );
395 $simple_product->set_slug( $slug );
396 }
397 // update the zi_item_id using the product instance
398 $simple_product->update_meta_data( 'zi_item_id', $item_id );
399 // update the status using set_status()
400 $simple_product->set_status( $item_status );
401 // Update the product SKU
402 $simple_product->set_sku( $item_sku );
403 // price
404 $sale_price = $simple_product->get_sale_price();
405 $simple_product->set_regular_price( $item_price );
406 if ( empty( $sale_price ) ) {
407 $simple_product->set_price( $item_price );
408 }
409 // Update Purchase price
410 $simple_product->update_meta_data( '_cost_price', $item['purchase_rate'] );
411 // description
412 $zi_disable_itemdescription_sync = get_option( 'cmbird_zoho_disable_description_sync_status' );
413 if ( ! empty( $item_description ) && ! $zi_disable_itemdescription_sync ) {
414 $simple_product->set_short_description( $item_description );
415 }
416 // Brand update if taxonomy product_brand(s) exists
417 if ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
418 wp_set_object_terms( $pdt_id, $item_brand, 'product_brand' );
419 } elseif ( ! empty( $item_brand ) && taxonomy_exists( 'product_brand' ) ) {
420 wp_set_object_terms( $pdt_id, $item_brand, 'product_brand' );
421 }
422 // stock
423 $zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
424 if ( ! $zi_disable_stock_sync ) {
425 // fwrite( $fd, PHP_EOL . 'Inside1' );
426 if ( 'NULL' !== gettype( $item_stock ) ) {
427 // fwrite( $fd, PHP_EOL . 'Inside1.1' );
428 // Set manage stock to yes
429 $simple_product->set_manage_stock( true );
430 // Update stock for simple product
431 $simple_product->set_stock_quantity( number_format( $item_stock, 0, '.', '' ) );
432 if ( $item_stock > 0 ) {
433 // fwrite( $fd, PHP_EOL . 'Inside2' );
434 // Update stock status
435 $simple_product->set_stock_status( 'instock' );
436 wp_set_post_terms( $pdt_id, 'instock', 'product_visibility', true );
437 } else {
438 // fwrite($fd, PHP_EOL . 'Inside3');
439 $stock_status = $simple_product->backorders_allowed() ? 'onbackorder' : 'outofstock';
440 $simple_product->set_stock_status( $stock_status );
441 wp_set_post_terms( $pdt_id, $stock_status, 'product_visibility', true );
442 }
443 }
444 }
445 // fwrite($fd, PHP_EOL . 'After stock');
446 // Update weight & dimensions of simple product
447 $simple_product->set_weight( $weight );
448 $simple_product->set_length( $length );
449 $simple_product->set_width( $width );
450 $simple_product->set_height( $height );
451
452 // featured image
453 $zi_disable_itemimage_sync = get_option( 'cmbird_zoho_disable_image_sync_status' );
454 if ( ! empty( $item_image ) && ! $zi_disable_itemimage_sync ) {
455 $image_class = new CMBIRD_Image_ZI();
456 $image_class->cmbird_zi_get_image( $item_id, $item_name, $pdt_id, $item_image );
457 }
458
459 // category
460 if ( ! empty( $item_category ) && empty( $group_name ) ) {
461 $term = get_term_by( 'name', $item_category, 'product_cat' );
462 $term_id = $term->term_id;
463 if ( empty( $term_id ) ) {
464 $term = wp_insert_term(
465 $item_category,
466 'product_cat',
467 array(
468 'parent' => 0,
469 )
470 );
471 $term_id = $term->term_id;
472 }
473 // Remove "uncategorized" category if assigned
474 $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
475 if ( $uncategorized_term && has_term( $uncategorized_term->term_id, 'product_cat', $pdt_id ) ) {
476 wp_remove_object_terms( $pdt_id, $uncategorized_term->term_id, 'product_cat' );
477 }
478 if ( ! is_wp_error( $term_id ) && isset( $term->term_id ) ) {
479 $existing_terms = wp_get_object_terms( $pdt_id, 'product_cat' );
480 if ( $existing_terms && count( $existing_terms ) > 0 ) {
481 $import_class = new CMBIRD_Products_ZI();
482 $is_term_exist = $import_class->zi_check_terms_exists( $existing_terms, $term_id );
483 if ( ! $is_term_exist ) {
484 $simple_product->update_meta_data( 'zi_category_id', $item['category_id'] );
485 wp_add_object_terms( $pdt_id, $term_id, 'product_cat' );
486 }
487 } else {
488 $simple_product->update_meta_data( 'zi_category_id', $item['category_id'] );
489 wp_set_object_terms( $pdt_id, $term_id, 'product_cat' );
490 }
491 }
492 }
493
494 // Update the custom fields if the custom fields are not empty
495 if ( ! empty( $custom_fields ) ) {
496 $import_class = new CMBIRD_Products_ZI();
497 $import_class->sync_item_custom_fields( $custom_fields, $pdt_id );
498 }
499
500 // Map taxes while syncing product from zoho.
501 if ( $item['tax_id'] && ! $this->is_tax_enabled() ) {
502 $zi_common_class = new CMBIRD_Common_Functions();
503 $woo_tax_class = $zi_common_class->get_tax_class_by_percentage( $item['tax_percentage'] );
504 $simple_product->set_tax_status( 'taxable' );
505 $simple_product->set_tax_class( $woo_tax_class );
506 }
507 $simple_product->save();
508 wc_delete_product_transients( $pdt_id );
509 }
510 }
511 $response = new WP_REST_Response();
512 $response->set_data( 'success on variable product' );
513 $response->set_status( 200 );
514
515 // fclose( $fd ); // close logfile.
516
517 return $response;
518 }
519
520 /**
521 * Process queued webhook requests
522 * Called by WordPress cron system when queue processing is scheduled
523 */
524 public function process_queued_requests() {
525 $queue_key = 'cmbird_request_queue';
526 $current_queue = get_option( $queue_key, array() );
527
528 if ( empty( $current_queue ) || ! is_array( $current_queue ) ) {
529 return;
530 }
531
532 $current_time = time();
533 $processed_count = 0;
534 $max_process_per_batch = 10; // Process up to 10 requests per batch
535
536 // Process queue items
537 foreach ( $current_queue as $index => $queue_item ) {
538 if ( $processed_count >= $max_process_per_batch ) {
539 break; // Don't process too many at once
540 }
541
542 // Check if request is too old (older than 5 minutes)
543 if ( ( $current_time - $queue_item['timestamp'] ) > 300 ) {
544 unset( $current_queue[ $index ] );
545 continue;
546 }
547
548 // Simulate the original request processing
549 try {
550 if ( isset( $queue_item['data'] ) && ! empty( $queue_item['data'] ) ) {
551 $data = $queue_item['data'];
552
553 // Convert JSONString if present
554 if ( array_key_exists( 'JSONString', $data ) ) {
555 $data = str_replace( '\\', '', $data['JSONString'] );
556 }
557
558 // Process the data
559 $this->process( $data );
560 $processed_count++;
561 }
562 } catch (Exception $e) {
563 // Log error but continue processing other items
564 error_log( 'CommerceBird Webhook Queue Processing Error: ' . $e->getMessage() );
565 }
566
567 // Remove processed item from queue
568 unset( $current_queue[ $index ] );
569 }
570
571 // Re-index array after unsetting elements
572 $current_queue = array_values( $current_queue );
573
574 // Update the queue
575 update_option( $queue_key, $current_queue );
576
577 // Schedule next processing if queue still has items
578 if ( ! empty( $current_queue ) && ! wp_next_scheduled( 'cmbird_process_webhook_queue' ) ) {
579 wp_schedule_single_event( $current_time + 30, 'cmbird_process_webhook_queue' );
580 }
581 }
582
583 /**
584 * Cleanup old rate limiting data
585 * Called by WordPress scheduled delete action
586 */
587 public function cleanup_rate_limit_data() {
588 global $wpdb;
589
590 // Clean up old transients related to rate limiting
591 $wpdb->query(
592 "DELETE FROM {$wpdb->options}
593 WHERE option_name LIKE '_transient_cmbird_rate_limit_%'
594 OR option_name LIKE '_transient_timeout_cmbird_rate_limit_%'"
595 );
596
597 // Clean up old processing locks (older than 1 hour)
598 $wpdb->query(
599 $wpdb->prepare(
600 "DELETE FROM {$wpdb->options}
601 WHERE option_name LIKE 'cmbird_processing_payload_%'
602 AND option_value < %d",
603 time() - 3600
604 )
605 );
606 }
607
608 /**
609 * @param $inventory_adjustment
610 * @param wpdb $wpdb
611 *
612 * @return WP_REST_Response
613 */
614 public function inventory_adjustment( $inventory_adjustment ): WP_REST_Response {
615 global $wpdb;
616 $item = $inventory_adjustment;
617 $line_items = $item['line_items'];
618 // get first item from line items array
619 $item_id = $line_items[0]['item_id'];
620 $adjusted_stock = $line_items[0]['quantity_adjusted'];
621
622 $row_item = $wpdb->get_row(
623 $wpdb->prepare(
624 "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s",
625 $item_id
626 )
627 );
628 $mapped_product_id = $row_item->post_id;
629
630 if ( ! empty( $mapped_product_id ) ) {
631 // stock
632 $zi_disable_stock_sync = get_option( 'cmbird_zoho_disable_stock_sync_status' );
633 $product = wc_get_product( $mapped_product_id );
634 // Check if the product is in stock
635 if ( ! $zi_disable_stock_sync ) {
636 if ( $product->is_in_stock() ) {
637 // Get stock quantity
638 $stock_quantity = $product->get_stock_quantity();
639 $new_stock = $stock_quantity + $adjusted_stock;
640 $product->set_stock_quantity( $new_stock );
641 } else {
642 $product->set_stock_quantity( $adjusted_stock );
643 $product->set_stock_status( 'instock' );
644 $product->set_manage_stock( true );
645 }
646 $product->save();
647 }
648 }
649
650 $response = new WP_REST_Response();
651 $response->set_data( 'Inventory Adjustment successful' );
652 $response->set_status( 200 );
653
654 return $response;
655 }
656 }
657