PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.5.1
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.5.1
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 / zoho-inventory / class-import-items.php
commercebird / includes / classes / zoho-inventory Last commit date
class-cmbird-categories-zi.php 9 months ago class-cmbird-image-zi.php 9 months ago class-import-items.php 9 months ago class-import-price-list.php 9 months ago class-multi-currency.php 9 months ago class-order-sync.php 9 months ago class-product.php 9 months ago class-users-contact.php 9 months ago index.php 1 year ago
class-import-items.php
1785 lines
1 <?php
2
3 /**
4 * Class to import Products from Zoho to WooCommerce
5 *
6 * @package zoho_inventory_api
7 */
8 if ( ! defined( 'ABSPATH' ) ) {
9 exit;
10 }
11
12 use Automattic\WooCommerce\Internal\ProductAttributesLookup\LookupDataStore;
13
14 class CMBIRD_Products_ZI {
15
16
17 private $config;
18 private $is_tax_enabled;
19
20 private $wc_decimal_separator;
21 private $wc_thousand_separator;
22
23 private $wc_price_decimal_separator;
24
25 public function __construct() {
26 $this->initialize_config();
27 add_action( 'init', array( $this, 'initialize_config' ) );
28 }
29
30 public function initialize_config() {
31 if ( ! function_exists( 'wc_get_price_decimal_separator' ) ) {
32 return; // Prevents error if WooCommerce is not active.
33 }
34
35 $this->config = array(
36 'ProductZI' => array(
37 'OID' => get_option( 'cmbird_zoho_inventory_oid' ),
38 'APIURL' => get_option( 'cmbird_zoho_inventory_url' ),
39 ),
40 'Settings' => array(
41 'disable_description' => get_option( 'cmbird_zoho_disable_description_sync_status' ),
42 'disable_name' => get_option( 'cmbird_zoho_disable_name_sync_status' ),
43 'disable_price' => get_option( 'cmbird_zoho_disable_price_sync_status' ),
44 'disable_stock' => get_option( 'cmbird_zoho_disable_stock_sync_status' ),
45 'enable_accounting_stock' => get_option( 'cmbird_zoho_enable_accounting_stock_status' ),
46 'enable_location_stock' => get_option( 'cmbird_zoho_enable_locationstock_status' ),
47 'zoho_location_id' => get_option( 'cmbird_zoho_location_id_status' ),
48 'disable_image' => get_option( 'cmbird_zoho_disable_image_sync_status' ),
49 ),
50 // Get WooCommerce settings.
51 'WooCommerce' => array(
52 'decimal_separator' => wc_get_price_decimal_separator(),
53 'thousand_separator' => wc_get_price_thousand_separator(),
54 'price_decimal_separator' => wc_get_price_decimals(),
55 'tax_enabled' => 'yes' === get_option( 'woocommerce_calc_taxes' ),
56 ),
57 );
58
59 // Check if WooCommerce taxes are enabled and store the result.
60 $this->is_tax_enabled = $this->config['WooCommerce']['tax_enabled'];
61
62 // Check the WooCommerce settings for decimal and thousand separators.
63 $this->wc_decimal_separator = $this->config['WooCommerce']['decimal_separator'];
64 $this->wc_thousand_separator = $this->config['WooCommerce']['thousand_separator'];
65 $this->wc_price_decimal_separator = $this->config['WooCommerce']['price_decimal_separator'];
66 }
67
68 /**
69 * Function to retrieve item details and sync items.
70 *
71 * @param string $url - URL to get details.
72 * @return mixed return true if data false if error.
73 */
74 public function zi_item_bulk_sync( $url ) {
75 // $fd = fopen( __DIR__ . '/zi_item_bulk_sync.txt', 'a+' );
76
77 global $wpdb;
78 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
79 $json = $execute_curl_call->execute_curl_call_get( $url );
80 $code = $json->code;
81
82 $is_tax_enabled = $this->is_tax_enabled;
83
84 // Memory management: Set memory limit if needed.
85 if ( function_exists( 'wp_raise_memory_limit' ) ) {
86 wp_raise_memory_limit();
87 }
88
89 // $message = $json->message;
90 // fwrite($fd, PHP_EOL . '$json->item : ' . print_r($json, true));
91
92 if ( 0 === $code || '0' === $code ) {
93 $processed_count = 0;
94
95 foreach ( $json->items as $arr ) {
96 // Memory cleanup every 50 items.
97 if ( $processed_count > 0 && $processed_count % 50 === 0 ) {
98 wp_cache_flush();
99 if ( function_exists( 'gc_collect_cycles' ) ) {
100 gc_collect_cycles();
101 }
102 }
103
104 // fwrite( $fd, PHP_EOL . '$arr : ' . print_r( $arr, true ) );
105 if ( ( ! empty( $arr->item_id ) ) && ! ( $arr->is_combo_product ) ) {
106 // fwrite($fd, PHP_EOL . 'Item Id found : ' . $arr->item_id);
107
108 $product_res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key='zi_item_id' AND meta_value=%s", $arr->item_id ) );
109
110 if ( $product_res && ! empty( $product_res->post_id ) ) {
111 $pdt_id = $product_res->post_id;
112 // Load the Product Object.
113 $product = wc_get_product( $pdt_id );
114 if ( empty( $product ) || ! $product ) {
115 continue;
116 }
117
118 $zi_disable_item_description_sync = $this->config['Settings']['disable_description'];
119 if ( ! empty( $arr->description ) && ! $zi_disable_item_description_sync ) {
120 $product->set_short_description( $arr->description );
121 }
122
123 if ( ! empty( $arr->status ) ) {
124 $status = 'active' === $arr->status ? 'publish' : 'draft';
125 $product->set_status( $status );
126 }
127
128 $zi_disable_itemname_sync = $this->config['Settings']['disable_name'];
129 if ( ( ! $zi_disable_itemname_sync ) && ! empty( $arr->name ) ) {
130 $product->set_name( $arr->name );
131 // set slug but use sanitize_title to ensure it is safe.
132 $product->set_slug( sanitize_title( $arr->name ) );
133 }
134
135 if ( ! empty( $arr->sku ) ) {
136 $product->set_sku( $arr->sku );
137 }
138
139 $zi_disable_itemprice_sync = $this->config['Settings']['disable_price'];
140 if ( ! empty( $arr->rate ) && ! $zi_disable_itemprice_sync ) {
141 $product->set_regular_price( $arr->rate );
142 $sale_price = $product->get_sale_price();
143 if ( empty( $sale_price ) ) {
144 $product->set_price( $arr->rate );
145 }
146 }
147
148 if ( isset( $arr->package_details ) ) {
149 $details = $arr->package_details;
150 if ( is_object( $details ) ) {
151 $product->set_weight( floatval( $details->weight ) );
152 $product->set_length( floatval( $details->length ) );
153 $product->set_width( floatval( $details->width ) );
154 $product->set_height( floatval( $details->height ) );
155 }
156 }
157
158 // Update Purchase Rate as Cost Price.
159 $product->update_meta_data( '_cost_price', $arr->purchase_rate );
160
161 // To check status of stock sync option.
162 $zi_disable_stock_sync = $this->config['Settings']['disable_stock'];
163 if ( ! $zi_disable_stock_sync && isset( $arr->available_for_sale_stock ) ) {
164 $stock = '';
165 // Update stock.
166 $accounting_stock = $this->config['Settings']['enable_accounting_stock'];
167 // Sync from specific location check.
168 $zi_enable_locationstock = $this->config['Settings']['enable_location_stock'];
169 if ( $zi_enable_locationstock && isset( $arr->locations ) ) {
170 $locations = $arr->locations;
171 $location_id = $this->config['Settings']['zoho_location_id'];
172 foreach ( $locations as $location ) {
173 if ( $location->location_id === $location_id ) {
174 if ( $accounting_stock ) {
175 $stock = $location->location_available_for_sale_stock;
176 } else {
177 $stock = $location->location_actual_available_for_sale_stock;
178 }
179 }
180 }
181 } elseif ( $accounting_stock ) {
182 $stock = $arr->available_for_sale_stock;
183 } else {
184 $stock = $arr->actual_available_for_sale_stock;
185 }
186
187 if ( is_numeric( $stock ) ) {
188 $product->set_manage_stock( true );
189 $product->set_stock_quantity( $stock );
190 if ( $stock > 0 ) {
191 $product->set_stock_status( 'instock' );
192 } else {
193 $backorder_status = $product->backorders_allowed();
194 $status = ( 'yes' === $backorder_status ) ? 'onbackorder' : 'outofstock';
195 $product->set_stock_status( $status );
196 }
197 }
198 }
199
200 if ( ! empty( $arr->tax_id ) && ! $is_tax_enabled ) {
201 $zi_common_class = new CMBIRD_Common_Functions();
202 $woo_tax_class = $zi_common_class->get_tax_class_by_percentage( $arr->tax_percentage );
203 $product->set_tax_status( 'taxable' );
204 $product->set_tax_class( $woo_tax_class );
205 }
206 $product->save();
207 // Sync ACF Fields.
208 $this->sync_item_custom_fields( $arr->custom_fields, $pdt_id );
209 // Clear/refresh cache.
210 wc_delete_product_transients( $pdt_id );
211 }
212 }
213
214 ++$processed_count;
215 }
216
217 // Final memory cleanup after processing all items.
218 wp_cache_flush();
219 if ( function_exists( 'gc_collect_cycles' ) ) {
220 gc_collect_cycles();
221 }
222
223 // Clear any temporary variables.
224 unset( $json, $execute_curl_call );
225 } else {
226 return false;
227 }
228 // fclose( $fd );
229 // Return if synced.
230 return true;
231 }
232
233 /**
234 * Function to add items recursively by cron job.
235 *
236 * @param number $page - Page number for getting item with pagination.
237 * @param number $category - Category id to get item of specific category.
238 * @return mixed
239 */
240 public function sync_item_recursively() {
241 // $fd = fopen( __DIR__ . '/simple-items-sync.txt', 'a+' );
242
243 $args = func_get_args();
244 // fwrite( $fd, PHP_EOL . 'Args ' . print_r( $args, true ) );
245 if ( is_array( $args ) ) {
246 if ( isset( $args['page'] ) && isset( $args['category'] ) ) {
247 $page = $args['page'];
248 $category = $args['category'];
249 } elseif ( isset( $args[0] ) && isset( $args[1] ) ) {
250 $page = $args[0];
251 $category = $args[1];
252 } elseif ( isset( $args[0] ) && ! isset( $args[1] ) ) {
253 $page = $args[0]['page'];
254 $category = $args[0]['category'];
255 } else {
256 return;
257 }
258 } else {
259 return;
260 }
261
262 $zoho_inventory_oid = $this->config['ProductZI']['OID'];
263 $zoho_inventory_url = $this->config['ProductZI']['APIURL'];
264 $timeout = ini_get( 'max_execution_time' ) ? ini_get( 'max_execution_time' ) : 60;
265 // Dynamically set per_page based on timeout.
266 if ( $timeout <= 30 ) {
267 $per_page = 20;
268 } elseif ( $timeout <= 60 ) {
269 $per_page = 50;
270 } else {
271 $per_page = 100;
272 }
273
274 $url = sprintf(
275 '%sinventory/v1/items?organization_id=%s&category_id=%s&page=%d&per_page=%d&sort_column=last_modified_time',
276 $zoho_inventory_url,
277 $zoho_inventory_oid,
278 $category,
279 $page,
280 $per_page
281 );
282 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
283 $json = $execute_curl_call->execute_curl_call_get( $url );
284 $code = (int) property_exists( $json, 'code' ) ? $json->code : '0';
285
286 global $wpdb;
287
288 /* Response for item sync with sync button. For cron sync blank array will return. */
289 $response_msg = array();
290 if ( empty( $code ) && property_exists( $json, 'items' ) ) {
291 $item_ids = array();
292 // log items.
293 // fwrite( $fd, PHP_EOL . 'Items : ' . print_r( $json, true ) );
294 // before your foreach, initialize once:
295 $logger = wc_get_logger();
296 $context = array( 'source' => 'cmbird_item_sync' );
297
298 foreach ( $json->items as $arr ) {
299 $prod_id = wc_get_product_id_by_sku( $arr->sku );
300 $is_bundle = $arr->is_combo_product;
301 if ( isset( $arr->group_id ) ) {
302 $is_grouped = $arr->group_id;
303 }
304 // Flag to enable or disable sync.
305 $allow_to_import = false;
306 // Check if product exists with same sku.
307 if ( $prod_id ) {
308 $zi_item_id = get_post_meta( $prod_id, 'zi_item_id', true );
309 if ( empty( $zi_item_id ) ) {
310 // Map existing item with zoho id.
311 update_post_meta( $prod_id, 'zi_item_id', $arr->item_id );
312 $allow_to_import = true;
313 }
314 }
315 if ( '' == $is_bundle && empty( $is_grouped ) ) {
316 // If product not exists normal behavior of item sync.
317 $allow_to_import = true;
318 }
319 if ( ! empty( $is_grouped ) ) {
320 $this->sync_variation_of_group( $arr );
321 continue;
322 }
323
324 // Remove duplicated product based on the sku, remove also postmeta.
325 // run query to check if product exists twice with same sku. Check based on SKU.
326 if ( $prod_id && ! empty( $arr->sku ) ) {
327 $duplicate_product = $wpdb->get_row( $wpdb->prepare( "SELECT post_id FROM {$wpdb->prefix}postmeta WHERE meta_key = '_sku' AND meta_value = %s AND post_id != %d LIMIT 1", $arr->sku, $prod_id ) );
328 if ( $duplicate_product ) {
329 // Remove the duplicate product.
330 wp_delete_post( $duplicate_product->post_id, true );
331 }
332 }
333
334 // Get the post id by doing a meta query on the postmeta table.
335 if ( empty( $prod_id ) ) {
336 $pdt = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s LIMIT 1", $arr->item_id ) );
337 $pdt_id = $pdt ? $pdt->post_id : '';
338 } else {
339 $pdt_id = $prod_id;
340 }
341
342 if ( empty( $pdt_id ) && $allow_to_import && 'active' === $arr->status ) {
343 // Create the product if it does not exist.
344 try {
345 $product = new WC_Product();
346 $product->set_name( $arr->name );
347 $product->set_status( 'publish' );
348 if ( isset( $arr->sku ) && ! empty( $arr->sku ) ) {
349 $product->set_sku( $arr->sku );
350 }
351 $product->set_regular_price( $arr->rate );
352 $pdt_id = $product->save();
353 if ( $pdt_id ) {
354 update_post_meta( $pdt_id, 'zi_item_id', $arr->item_id );
355 }
356 } catch ( Exception $e ) {
357 // Log the error so you can inspect it in WooCommerce > Status > Logs.
358 $message = sprintf(
359 'Error creating product for Zoho Item # %s (SKU: %s): %s',
360 $arr->item_id,
361 isset( $arr->sku ) ? $arr->sku : '(no sku)',
362 $e->getMessage()
363 );
364 $logger->error( $message, $context );
365 continue;
366 }
367 }
368
369 if ( $pdt_id ) {
370 if ( ! empty( $arr->category_name ) ) {
371 $term = get_term_by( 'name', $arr->category_name, 'product_cat' );
372 $term_id = $term->term_id;
373 if ( empty( $term_id ) ) {
374 $term = wp_insert_term(
375 $arr->category_name,
376 'product_cat',
377 array(
378 'parent' => 0,
379 )
380 );
381 $term_id = $term['term_id'];
382 }
383 if ( $term_id ) {
384 $existing_terms = wp_get_object_terms( $pdt_id, 'product_cat' );
385 if ( $existing_terms && count( $existing_terms ) > 0 ) {
386 $is_terms_exist = $this->zi_check_terms_exists( $existing_terms, $term_id );
387 if ( ! $is_terms_exist ) {
388 update_post_meta( $pdt_id, 'zi_category_id', $category );
389 wp_add_object_terms( $pdt_id, $term_id, 'product_cat' );
390 }
391 } else {
392 update_post_meta( $pdt_id, 'zi_category_id', $category );
393 wp_set_object_terms( $pdt_id, $term_id, 'product_cat' );
394 }
395 }
396 // Remove "uncategorized" category if assigned.
397 $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
398 if ( $uncategorized_term && has_term( $uncategorized_term->term_id, 'product_cat', $pdt_id ) ) {
399 wp_remove_object_terms( $pdt_id, $uncategorized_term->term_id, 'product_cat' );
400 }
401 }
402
403 if ( ! empty( $arr->brand ) ) {
404 // check if the Brand taxonomy exists and then update the term.
405 if ( taxonomy_exists( 'product_brand' ) ) {
406 wp_set_object_terms( $pdt_id, $arr->brand, 'product_brand' );
407 }
408 }
409 // Sync Featured Image if not disabled.
410 $zi_disable_image_sync = $this->config['Settings']['disable_image'];
411 if ( ! empty( $arr->image_document_id ) && ! $zi_disable_image_sync ) {
412 $image_class = new CMBIRD_Image_ZI();
413 $image_class->cmbird_zi_get_image( $arr->item_id, $arr->name, $pdt_id, $arr->image_name );
414 }
415
416 $item_ids[] = $arr->item_id;
417 } // end of wpdb post_id check.
418 }
419 if ( ! empty( $item_ids ) ) {
420 $item_id_str = implode( ',', $item_ids );
421 // fwrite($fd, PHP_EOL . 'Before Bulk sync');
422 $item_details_url = "{$zoho_inventory_url}inventory/v1/itemdetails?item_ids={$item_id_str}&organization_id={$zoho_inventory_oid}";
423 $this->zi_item_bulk_sync( $item_details_url );
424
425 if ( isset( $json->page_context ) && $json->page_context->has_more_page ) {
426 $data = array(
427 'page' => $page + 1,
428 'category' => $category,
429 );
430 // fwrite( $fd, PHP_EOL . 'Data: ' . print_r( $data, true ) );
431 $existing_schedule = as_has_scheduled_action( 'import_simple_items_cron', array( $data ) );
432 if ( ! $existing_schedule ) {
433 as_schedule_single_action( time(), 'import_simple_items_cron', array( $data ) );
434 // fwrite( $fd, PHP_EOL . 'Scheduled' );
435 }
436 }
437 array_push( $response_msg, $this->zi_response_message( $code, $json->message ) );
438 }
439 }
440 // fclose( $fd );
441 return $response_msg;
442 }
443
444 /**
445 * Update or Create Custom Fields of Product
446 *
447 * @param array|object $custom_fields - item object coming in from simple item recursive
448 * @param int $pdt_id - product id
449 * @return void
450 */
451 public function sync_item_custom_fields( $custom_fields, $pdt_id ) {
452 if ( empty( $custom_fields ) || empty( $pdt_id ) ) {
453 return;
454 }
455
456 foreach ( $custom_fields as $custom_field ) {
457 // Extract data from custom field.
458 $api_name = isset( $custom_field->api_name ) ? $custom_field->api_name : $custom_field['api_name'];
459 $value = isset( $custom_field->value ) ? $custom_field->value : $custom_field['value'];
460
461 // Check if both API name and value are present.
462 if ( ! empty( $api_name ) && ! empty( $value ) ) {
463 // Check if ACF function exists.
464 if ( function_exists( 'update_field' ) ) {
465 // Update ACF field.
466 update_field( $api_name, $value, $pdt_id );
467 } else {
468 // Fall back to update post meta.
469 update_post_meta( $pdt_id, $api_name, $value );
470 }
471 }
472 }
473 }
474
475
476 /**
477 * Function to add group items recursively by manual sync
478 *
479 * @param [number] $page - Page number for getting group item with pagination.
480 * @param [number] $category - Category id to get group item of specific category.
481 * @param [string] $source - Source from where function is calling : 'cron'/'sync'.
482 * @return mixed
483 */
484 public function sync_groupitem_recursively() {
485 // $fd = fopen( __DIR__ . '/sync_groupitem_recursively.txt', 'a+' );
486
487 $args = func_get_args();
488 if ( ! empty( $args ) ) {
489 if ( is_array( $args ) ) {
490 if ( isset( $args['page'] ) && isset( $args['category'] ) ) {
491 $page = $args['page'];
492 $category = $args['category'];
493 } elseif ( isset( $args[0] ) && isset( $args[1] ) ) {
494 $page = $args[0];
495 $category = $args[1];
496 } elseif ( isset( $args[0] ) && ! isset( $args[1] ) ) {
497 $page = $args[0]['page'];
498 $category = $args[0]['category'];
499 } else {
500 return;
501 }
502 } else {
503 return;
504 }
505
506 // Memory management: Set memory limit if needed.
507 if ( function_exists( 'ini_get' ) && ini_get( 'memory_limit' ) ) {
508 $current_limit = ini_get( 'memory_limit' );
509 if ( intval( $current_limit ) < 256 ) {
510 ini_set( 'memory_limit', '256M' );
511 }
512 }
513
514 // fwrite($fd, PHP_EOL . 'Test name Update ' . print_r($data, true));
515 global $wpdb;
516 $zoho_inventory_oid = $this->config['ProductZI']['OID'];
517 $zoho_inventory_url = $this->config['ProductZI']['APIURL'];
518
519 $url = $zoho_inventory_url . 'inventory/v1/itemgroups/?organization_id=' . $zoho_inventory_oid . '&category_id=' . $category . '&page=' . $page . '&per_page=20&filter_by=Status.Active';
520 // fwrite($fd, PHP_EOL . '$url : ' . $url);
521
522 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
523 $json = $execute_curl_call->execute_curl_call_get( $url );
524
525 $code = $json->code;
526 // $message = $json->message;
527
528 $response_msg = array();
529
530 if ( '0' === $code || 0 === $code ) {
531 $zi_disable_description_sync = $this->config['Settings']['disable_description'];
532 $zi_disable_name_sync = $this->config['Settings']['disable_name'];
533 // fwrite( $fd, PHP_EOL . '$json->itemgroups : ' . print_r( $json->itemgroups, true ) );
534 $processed_count = 0;
535 foreach ( $json->itemgroups as $gp_arr ) {
536 // Memory cleanup every 10 group items.
537 if ( $processed_count > 0 && $processed_count % 10 === 0 ) {
538 wp_cache_flush();
539 if ( function_exists( 'gc_collect_cycles' ) ) {
540 gc_collect_cycles();
541 }
542 }
543 $zi_group_id = $gp_arr->group_id;
544 $zi_group_name = $gp_arr->group_name;
545 // fwrite($fd, PHP_EOL . '$itemGroup : ' . print_r($gp_arr, true));
546 // skip if there is no first attribute.
547 $zi_group_attribute1 = $gp_arr->attribute_id1;
548 if ( empty( $zi_group_attribute1 ) ) {
549 continue;
550 }
551
552 // Get Group ID.
553 $group_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s LIMIT 1", $zi_group_id ) );
554 // array_push( $response_msg, $this->zi_response_message( 'SUCCESS', 'Zoho Group Item Synced: ' . $zi_group_name, $group_id ) );
555 // end insert group product.
556 // variable items.
557 // fwrite($fd, PHP_EOL . '$group_id exists ' . $group_id);
558 if ( ! empty( $group_id ) ) {
559 $existing_parent_product = wc_get_product( $group_id );
560 // fwrite($fd, PHP_EOL . 'Existing group Id');
561 if ( ! empty( $gp_arr->description ) && ! $zi_disable_description_sync ) {
562 $existing_parent_product->set_short_description( $gp_arr->description );
563 }
564 if ( ! empty( $gp_arr->name ) && ! $zi_disable_name_sync ) {
565 $existing_parent_product->set_name( $gp_arr->name );
566 // santize the name for slug and save the slug.
567 $slug = sanitize_title( $gp_arr->name );
568 $existing_parent_product->set_slug( $slug );
569 }
570 // add zi_category_id as meta.
571 $existing_parent_product->update_meta_data( 'zi_category_id', $category );
572 // create attributes if not exists.
573 $attributes = $existing_parent_product->get_attributes();
574 if ( empty( $attributes ) ) {
575 // Create or Update the Attributes.
576 $attr_created = $this->sync_attributes_of_group( $gp_arr, $group_id );
577 // fwrite($fd, PHP_EOL . '$attr_created ' . $attr_created);
578 }
579 $variations_check = $existing_parent_product->get_children();
580 if ( empty( $variations_check ) ) {
581 // fwrite( $fd, PHP_EOL . 'No Variations found' );
582 $this->import_variable_product_variations( $gp_arr, $group_id );
583 }
584 $existing_parent_product->save();
585 // ACF Fields.
586 if ( ! empty( $gp_arr->custom_fields ) ) {
587 // fwrite($fd, PHP_EOL . 'Custom Fields : ' . print_r($gp_arr->custom_fields, true));
588 $this->sync_item_custom_fields( $gp_arr->custom_fields, $group_id );
589 }
590 // update Brand.
591 if ( ! empty( $gp_arr->brand ) ) {
592 // check if the Brand or Brands taxonomy exists and then update the term.
593 if ( taxonomy_exists( 'product_brand' ) ) {
594 wp_set_object_terms( $group_id, $gp_arr->brand, 'product_brand' );
595 } elseif ( taxonomy_exists( 'product_brand' ) ) {
596 wp_set_object_terms( $group_id, $gp_arr->brand, 'product_brand' );
597 }
598 }
599 } else {
600 // Create the parent variable product.
601 $parent_product = new WC_Product_Variable();
602 $parent_product->set_name( $zi_group_name );
603 $parent_product->set_status( 'publish' );
604 $parent_product->set_short_description( $gp_arr->description );
605 $parent_product->add_meta_data( 'zi_item_id', $zi_group_id );
606 $parent_product->add_meta_data( 'zi_category_id', $category );
607 $group_id = $parent_product->save();
608
609 // Sync category by finding it first.
610 $category_handler = new CMBIRD_Categories_ZI();
611 $term_id = $category_handler->cmbird_subcategories_term_id( $category );
612 $term = get_term_by( 'id', $term_id, 'product_cat' );
613 if ( $term ) {
614 // Assign the category to the product.
615 wp_set_object_terms( $group_id, $term->term_id, 'product_cat' );
616
617 // Remove the "uncategorized" category if it's assigned.
618 $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
619 if ( $uncategorized_term && has_term( $uncategorized_term->term_id, 'product_cat', $group_id ) ) {
620 wp_remove_object_terms( $group_id, $uncategorized_term->term_id, 'product_cat' );
621 }
622 }
623
624 // update Brand.
625 if ( ! empty( $gp_arr->brand ) ) {
626 // check if the Brand or Brands taxonomy exists and then update the term.
627 if ( taxonomy_exists( 'product_brand' ) ) {
628 wp_set_object_terms( $group_id, $gp_arr->brand, 'product_brand' );
629 } elseif ( taxonomy_exists( 'product_brand' ) ) {
630 wp_set_object_terms( $group_id, $gp_arr->brand, 'product_brand' );
631 }
632 }
633
634 // fwrite($fd, PHP_EOL . 'New $group_id ' . $group_id);
635 // ACF Fields.
636 if ( ! empty( $gp_arr->custom_fields ) ) {
637 // fwrite($fd, PHP_EOL . 'Custom Fields : ' . print_r($gp_arr->custom_fields, true));
638 $this->sync_item_custom_fields( $gp_arr->custom_fields, $group_id );
639 }
640 // Create or Update the Attributes.
641 $attr_created = $this->sync_attributes_of_group( $gp_arr, $group_id );
642
643 if ( ! empty( $group_id ) && $attr_created ) {
644 $this->import_variable_product_variations( $gp_arr, $group_id );
645 }
646 } // end of create variable product.
647
648 ++$processed_count;
649 } // end foreach group items.
650
651 // Final memory cleanup after processing all group items.
652 wp_cache_flush();
653 if ( function_exists( 'gc_collect_cycles' ) ) {
654 gc_collect_cycles();
655 }
656
657 // Clear any temporary variables.
658 unset( $json, $execute_curl_call );
659
660 if ( isset( $json->page_context ) && $json->page_context->has_more_page ) {
661 $data = array(
662 'page' => $page + 1,
663 'category' => $category,
664 );
665 $existing_schedule = as_has_scheduled_action( 'import_group_items_cron', $data );
666 // Check if the scheduled action exists.
667 if ( ! $existing_schedule ) {
668 as_schedule_single_action( time(), 'import_group_items_cron', $data );
669 }
670 }
671 array_push( $response_msg, $this->zi_response_message( $code, $json->message ) );
672 }
673 // End of logging.
674 // fclose( $fd );
675 return $response_msg;
676 } else {
677 return;
678 }
679 }
680
681 /**
682 * Callback function for importing a variable product and its variations.
683 *
684 * @param object $gp_arr - Group item object.
685 * @param int $group_id - Group item id.
686 */
687 public function import_variable_product_variations( $gp_arr, $group_id ): void {
688 // $fd = fopen( __DIR__ . '/import_variable_product_variations.txt', 'a+' );
689
690 if ( empty( $gp_arr ) || empty( $group_id ) ) {
691 return;
692 }
693
694 global $wpdb;
695 $product = wc_get_product( $group_id );
696
697 // separators.
698 $wc_decimal_separator = $this->wc_decimal_separator;
699 $wc_thousand_separator = $this->wc_thousand_separator;
700 $wc_price_decimal_separator = $this->wc_price_decimal_separator;
701
702 if ( $product ) {
703 $item_group = $gp_arr;
704 // fwrite( $fd, PHP_EOL . 'Item Group : ' . print_r( $item_group, true ) );
705 $items = $item_group->items;
706 $attribute_name1 = $item_group->attribute_name1;
707 $attribute_name2 = $item_group->attribute_name2;
708 $attribute_name3 = $item_group->attribute_name3;
709
710 // fwrite( $fd, PHP_EOL . 'Items : ' . print_r( $items, true ) );
711 // get the options for stock sync.
712 $zi_enable_locationstock = $this->config['Settings']['enable_location_stock'];
713 $location_id = $this->config['Settings']['zoho_location_id'];
714 $accounting_stock = $this->config['Settings']['enable_accounting_stock'];
715 $zi_disable_stock_sync = $this->config['Settings']['disable_stock'];
716
717 foreach ( $items as $item ) {
718 // reset this array.
719 $attribute_arr = array();
720 $variation_id = '';
721 $status = $item->status === 'active' ? 'publish' : 'draft';
722
723 $zi_item_id = $item->item_id;
724 $variation_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s LIMIT 1", $zi_item_id ) );
725
726 if ( ! empty( $variation_id ) ) {
727 $v_product = wc_get_product( $variation_id );
728 // Check if the product object is valid.
729 if ( $v_product && is_a( $v_product, 'WC_Product' ) ) {
730 if ( $v_product->is_type( 'simple' ) ) {
731 wp_delete_post( $variation_id, true );
732 }
733 }
734 }
735 // SKU check of the variation, if exits then remove it.
736 if ( ! empty( $item->sku ) ) {
737 $sku_prod_id = wc_get_product_id_by_sku( $item->sku );
738 $v_product = wc_get_product( $sku_prod_id );
739 // Check if the product object is valid.
740 if ( $v_product && is_a( $v_product, 'WC_Product' ) ) {
741 if ( $v_product->is_type( 'simple' ) ) {
742 wp_delete_post( $variation_id, true );
743 }
744 }
745 }
746 if ( ! empty( $variation_id ) ) {
747 continue;
748 }
749 // Stock mode check.
750 $locations = $item->locations;
751
752 if ( $zi_enable_locationstock && $location_id ) {
753 foreach ( $locations as $location ) {
754 if ( $location->location_id === $location_id ) {
755 if ( $accounting_stock ) {
756 $stock = isset( $location->location_available_stock );
757 } else {
758 $stock = isset( $location->location_actual_available_stock );
759 }
760 }
761 }
762 } elseif ( $accounting_stock ) {
763 $stock = $item->available_stock;
764 } else {
765 $stock = $item->actual_available_stock;
766 }
767 // number format the rate.
768 $rate = number_format( $item->rate, $wc_price_decimal_separator, $wc_decimal_separator, $wc_thousand_separator );
769
770 $attribute_name11 = $item->attribute_option_name1;
771 $attribute_name12 = $item->attribute_option_name2;
772 $attribute_name13 = $item->attribute_option_name3;
773 // Prepare the variation data.
774 if ( ! empty( $attribute_name1 ) ) {
775 $sanitized_name1 = wc_sanitize_taxonomy_name( $attribute_name1 );
776 $attribute_arr[ $sanitized_name1 ] = $attribute_name11;
777 }
778 if ( ! empty( $attribute_name2 ) ) {
779 $sanitized_name2 = wc_sanitize_taxonomy_name( $attribute_name2 );
780 $attribute_arr[ $sanitized_name2 ] = $attribute_name12;
781 }
782 if ( ! empty( $attribute_name3 ) ) {
783 $sanitized_name3 = wc_sanitize_taxonomy_name( $attribute_name3 );
784 $attribute_arr[ $sanitized_name3 ] = $attribute_name13;
785 }
786 // fwrite( $fd, PHP_EOL . '$attribute_arr : ' . print_r( $attribute_arr, true ) );
787
788 // fwrite($fd, PHP_EOL . '$variation_attributes : ' . print_r($variation_attributes, true));
789 // Loop through the variations and create them.
790 try {
791 $variation_post = array(
792 'post_title' => $product->get_name(),
793 'post_name' => 'product-' . $group_id . '-variation',
794 'post_status' => $status,
795 'post_parent' => $group_id,
796 'post_type' => 'product_variation',
797 'guid' => $product->get_permalink(),
798 );
799 // Creating the product variation.
800 $variation_id = wp_insert_post( $variation_post );
801 $variation = new WC_Product_Variation( $variation_id );
802 $variation->set_regular_price( $rate );
803 $variation->set_sku( $item->sku );
804 if ( ! $zi_disable_stock_sync && $stock > 0 ) {
805 $variation->set_stock_quantity( $stock );
806 $variation->set_manage_stock( true );
807 $variation->set_stock_status( '' );
808 } else {
809 $variation->set_manage_stock( false );
810 }
811 $variation->add_meta_data( 'zi_item_id', $item->item_id );
812 $variation_id = $variation->save();
813 } catch ( Exception $e ) {
814 // fwrite( $fd, PHP_EOL . 'Error : ' . $e->getMessage() );
815 continue;
816 }
817
818 // Get the variation attributes with correct attribute values.
819 foreach ( $attribute_arr as $attribute => $term_name ) {
820 $taxonomy = 'pa_' . $attribute;
821 // If taxonomy doesn't exists we create it.
822 if ( ! taxonomy_exists( $taxonomy ) ) {
823 register_taxonomy(
824 $taxonomy,
825 'product_variation',
826 array(
827 'hierarchical' => false,
828 'label' => ucfirst( $attribute ),
829 'query_var' => true,
830 'rewrite' => array( 'slug' => sanitize_title( $attribute ) ),
831 ),
832 );
833 }
834
835 // Check if the Term name exist and if not we create it.
836 if ( ! term_exists( $term_name, $taxonomy ) ) {
837 wp_insert_term( $term_name, $taxonomy );
838 }
839
840 $term_slug = get_term_by( 'name', $term_name, $taxonomy )->slug;
841 // Get the post Terms names from the parent variable product.
842 $post_term_names = wp_get_post_terms( $group_id, $taxonomy, array( 'fields' => 'names' ) );
843 // Check if the post term exist and if not we set it in the parent variable product.
844 if ( ! in_array( $term_name, $post_term_names, true ) ) {
845 wp_set_post_terms( $group_id, $term_name, $taxonomy, true );
846 }
847 // Set/save the attribute data in the product variation.
848 update_post_meta( $variation_id, 'attribute_' . $taxonomy, $term_slug );
849 }
850
851 // update purchase price as meta data.
852 if ( ! empty( $item->purchase_rate ) ) {
853 update_post_meta( $variation_id, '_cost_price', $item->purchase_rate );
854 }
855
856 // Featured Image of variation.
857 if ( ! empty( $item->image_name ) ) {
858 $image_class = new CMBIRD_Image_ZI();
859 $variation_image_id = $image_class->cmbird_zi_get_image( $item->item_id, $item->name, $variation_id, $item->image_name );
860 if ( ! has_post_thumbnail( $group_id ) ) {
861 if ( $variation_image_id ) {
862 set_post_thumbnail( $group_id, $variation_image_id );
863 }
864 }
865 }
866 }
867 // End group item add process.
868 // array_push($response_msg, $this->zi_response_message('SUCCESS', 'Zoho variable item created for zoho item id ' . $zi_item_id, $variation_id));
869
870 if ( $product && is_a( $product, 'WC_Product_Variable' ) ) {
871 // Sort the variations.
872 $data_store = $product->get_data_store();
873 $data_store->sort_all_product_variations( $group_id );
874 }
875 // End of Logging.
876 // fclose( $fd );
877 }
878 }
879
880 /**
881 * Update or Create the Product Attributes for the Variable Item Sync
882 *
883 * @param: $group_id - the parent product id in WooCommerce
884 * @return: bool - true if attributes were created successfully, false otherwise
885 */
886 public function sync_attributes_of_group( $gp_arr, $group_id ) {
887 // $fd = fopen(__DIR__ . '/sync_attributes_of_group.txt', 'a+');
888 // Check if the group item has attributes.
889 if ( empty( $gp_arr->attribute_name1 ) ) {
890 return false;
891 }
892 // Create attributes.
893 $success = true; // Track the success of attribute creation.
894 $attributes_data = array();
895 $attribute_count = 0;
896 $attribute_options_map = array(); // Track unique attribute options.
897
898 // Loop through the attribute names.
899 for ( $i = 1; $i <= 3; $i++ ) {
900 $attribute_name_key = 'attribute_name' . $i;
901 $attribute_option_name_key = 'attribute_option_name' . $i;
902
903 // Get the attribute name.
904 $attribute_name = $gp_arr->$attribute_name_key;
905
906 if ( ! empty( $attribute_name ) ) {
907 // Check if the attribute is already added to the attributes array.
908 if ( ! isset( $attributes_data[ $attribute_name ] ) ) {
909 // Create the attribute and add it to the attributes array.
910 $attribute = array(
911 'name' => $attribute_name,
912 'position' => $attribute_count,
913 'visible' => true,
914 'variation' => true,
915 'options' => array(),
916 );
917
918 // Loop through the items and retrieve attribute options.
919 $attribute_options = array();
920 foreach ( $gp_arr->items as $item ) {
921 $attribute_option = $item->$attribute_option_name_key;
922 if ( ! empty( $attribute_option ) && ! in_array( $attribute_option, $attribute_options_map ) ) {
923 $attribute_options[] = $attribute_option;
924 $attribute_options_map[] = $attribute_option;
925 }
926 }
927
928 // Set the attribute options.
929 $attribute['options'] = $attribute_options;
930
931 $attributes_data[] = $attribute;
932 ++$attribute_count;
933 }
934 }
935 }
936 // fwrite($fd, PHP_EOL . '$attributes : ' . print_r($attributes_data, true));
937
938 // Assign the attributes to the parent product.
939 if ( count( $attributes_data ) > 0 ) {
940 $attributes = array(); // Initializing.
941
942 // Loop through defined attribute data.
943 foreach ( $attributes_data as $key => $attribute_array ) {
944 if ( isset( $attribute_array['name'] ) && isset( $attribute_array['options'] ) ) {
945 // Clean attribute name to get the taxonomy.
946 $taxonomy = 'pa_' . wc_sanitize_taxonomy_name( $attribute_array['name'] );
947
948 $option_term_ids = array(); // Initializing.
949
950 // Create the attribute if it doesn't exist.
951 if ( ! taxonomy_exists( $taxonomy ) ) {
952 // Clean attribute label for better display.
953 $attribute_label = ucfirst( $attribute_array['name'] );
954
955 // Register the new attribute taxonomy.
956 $attribute_args = array(
957 'slug' => $taxonomy,
958 'name' => $attribute_label,
959 'type' => 'select',
960 'order_by' => 'menu_order',
961 'has_archives' => false,
962 );
963
964 $result = wc_create_attribute( $attribute_args );
965 register_taxonomy( $taxonomy, array( 'product' ), array() );
966
967 if ( ! is_wp_error( $result ) ) {
968 // fwrite($fd, PHP_EOL . 'result : ' . $result);
969 // Loop through defined attribute data options (terms values).
970 foreach ( $attribute_array['options'] as $option ) {
971 // Check if the term exists for the attribute taxonomy.
972 $term = term_exists( $result, $taxonomy );
973 if ( empty( $term ) ) {
974 // Term doesn't exist, create a new one.
975 $term_id = wp_insert_term( $option, $taxonomy );
976
977 if ( ! is_wp_error( $term_id ) ) {
978 $term_id = $term_id['term_id'];
979 } else {
980 $success = false;
981 $error_string = $term_id->get_error_message();
982 // fwrite($fd, PHP_EOL . 'error_string : ' . $error_string);
983 }
984 } else {
985 // Get the existing term ID.
986 $term_id = $term['term_id'];
987 }
988 $option_term_ids[] = $term_id;
989 }
990
991 // Add the new attribute to the product attributes array.
992 $attributes[ $taxonomy ] = array(
993 'name' => $taxonomy,
994 'value' => $option_term_ids, // Need to be term IDs.
995 'position' => $key + 1,
996 'is_visible' => $attribute_array['visible'],
997 'is_variation' => $attribute_array['variation'],
998 'is_taxonomy' => '1',
999 );
1000
1001 // Get the existing terms for the taxonomy.
1002 $existing_terms = get_terms(
1003 array(
1004 'taxonomy' => $taxonomy,
1005 'hide_empty' => false,
1006 )
1007 );
1008
1009 // Loop through existing terms and assign them to the product.
1010 foreach ( $existing_terms as $existing_term ) {
1011 $existing_term_ids[] = $existing_term->term_id;
1012 }
1013
1014 // Set the selected terms for the product.
1015 wp_set_object_terms( $group_id, $existing_term_ids, $taxonomy );
1016 } else {
1017 $success = false;
1018 }
1019 } else {
1020 // Add existing attribute with its selected terms to the product attributes array.
1021 $existing_terms = get_terms(
1022 array(
1023 'taxonomy' => $taxonomy,
1024 'hide_empty' => false,
1025 )
1026 );
1027
1028 if ( $existing_terms ) {
1029 $existing_term_ids = array();
1030 foreach ( $attribute_array['options'] as $option ) {
1031 $match_found = false;
1032 foreach ( $existing_terms as $existing_term ) {
1033 if ( $existing_term->name === $option ) {
1034 $existing_term_ids[] = $existing_term->term_id;
1035 $match_found = true;
1036 break;
1037 }
1038 }
1039 if ( ! $match_found ) {
1040 // Check if the term exists for the attribute taxonomy.
1041 $term = term_exists( $option, $taxonomy );
1042
1043 if ( empty( $term ) ) {
1044 // Term doesn't exist, create a new one.
1045 $term = wp_insert_term( $option, $taxonomy );
1046
1047 if ( ! is_wp_error( $term ) ) {
1048 // Get the term ID.
1049 $term_id = $term['term_id'];
1050 $existing_term_ids[] = $term_id;
1051 } else {
1052 $success = false;
1053 }
1054 } else {
1055 // Get the existing term ID.
1056 $term_id = $term['term_id'];
1057 $existing_term_ids[] = $term_id;
1058 }
1059 }
1060 }
1061
1062 if ( ! empty( $existing_term_ids ) ) {
1063 $attributes[ $taxonomy ] = array(
1064 'name' => $taxonomy,
1065 'value' => $existing_term_ids,
1066 'position' => $key + 1,
1067 'is_visible' => $attribute_array['visible'],
1068 'is_variation' => $attribute_array['variation'],
1069 'is_taxonomy' => '1',
1070 );
1071
1072 // Set the selected terms for the product.
1073 wp_set_object_terms( $group_id, $existing_term_ids, $taxonomy, false );
1074 }
1075 } else {
1076 $option_term_ids = array(); // Initializing.
1077
1078 // Loop through defined attribute data options (terms values).
1079 foreach ( $attribute_array['options'] as $option ) {
1080 // Check if the term exists for the attribute taxonomy.
1081 $term = term_exists( $option, $taxonomy );
1082
1083 if ( empty( $term ) ) {
1084 // Term doesn't exist, create a new one.
1085 $term = wp_insert_term( $option, $taxonomy );
1086
1087 if ( ! is_wp_error( $term ) ) {
1088 // Get the term ID.
1089 $term_id = $term['term_id'];
1090 $option_term_ids[] = $term_id;
1091 } else {
1092 $success = false;
1093 }
1094 } else {
1095 // Get the existing term ID.
1096 $term_id = $term['term_id'];
1097 $option_term_ids[] = $term_id;
1098 }
1099 }
1100
1101 // Set the selected terms for the product.
1102 wp_set_object_terms( $group_id, $option_term_ids, $taxonomy, false );
1103
1104 // Add the new attribute to the product attributes array.
1105 $attributes[ $taxonomy ] = array(
1106 'name' => $taxonomy,
1107 'value' => $option_term_ids,
1108 'position' => $key + 1,
1109 'is_visible' => $attribute_array['visible'],
1110 'is_variation' => $attribute_array['variation'],
1111 'is_taxonomy' => '1',
1112 );
1113 }
1114 }
1115 }
1116 }
1117
1118 // Save the meta entry for product attributes.
1119 update_post_meta( $group_id, '_product_attributes', $attributes );
1120 $lookup_data_store = new LookupDataStore();
1121 $lookup_data_store->create_data_for_product( $group_id );
1122 }
1123 // fclose($fd);
1124 return $success;
1125 }
1126
1127 /**
1128 * Update or create variation in WooCommerce if Group-ID already exists in wpdB
1129 *
1130 * @param: $arr - item object coming in from simple item recursive function
1131 * @return: void
1132 */
1133 public function sync_variation_of_group( $item ) {
1134 // $fd = fopen( __DIR__ . '/sync_variation_of_group.txt', 'a+' );
1135
1136 // log the item.
1137 // fwrite( $fd, PHP_EOL . 'Item : ' . print_r( $item, true ) );
1138
1139 global $wpdb;
1140 // Stock mode check.
1141 $zi_disable_stock_sync = $this->config['Settings']['disable_stock'];
1142 $accounting_stock = $this->config['Settings']['enable_accounting_stock'];
1143 $is_tax_enabled = $this->is_tax_enabled;
1144
1145 if ( $accounting_stock ) {
1146 $stock = $item->available_stock;
1147 } else {
1148 $stock = $item->actual_available_stock;
1149 }
1150
1151 $item_id = $item->item_id;
1152 // $item_category = $item->category_name;
1153 $groupid = property_exists( $item, 'group_id' ) ? $item->group_id : 0;
1154 // find parent variable product.
1155 $group_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s LIMIT 1", $groupid ) );
1156 // fwrite($fd, PHP_EOL . 'Row Data : ' . print_r($row, true));
1157 // fwrite($fd, PHP_EOL . 'Row $group_id : ' . $group_id);
1158 $stock_quantity = $stock < 0 ? 0 : $stock;
1159 // fwrite($fd, PHP_EOL . 'Before group item sync : ' . $group_id);
1160 if ( ! empty( $group_id ) ) {
1161 // fwrite( $fd, PHP_EOL . 'Inside item sync : ' . $item->name );
1162 // Brand.
1163 if ( isset( $item->brand ) && ! empty( $group_id ) ) {
1164 if ( taxonomy_exists( 'product_brand' ) ) {
1165 wp_set_object_terms( $group_id, $item->brand, 'product_brand' );
1166 }
1167 }
1168
1169 $variation_id = $wpdb->get_var( $wpdb->prepare( "SELECT post_id FROM $wpdb->postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s LIMIT 1", $item_id ) );
1170 if ( ! empty( $item->sku ) && empty( $variation_id ) ) {
1171 $variation_id = wc_get_product_id_by_sku( $item->sku );
1172 }
1173 if ( $variation_id ) {
1174 // fwrite( $fd, PHP_EOL . 'Variation ID exists : ' . $variation_id );
1175 // If variation already exists then update it.
1176 $variation = new WC_Product_Variation( $variation_id );
1177 // SKU - Imported.
1178 if ( ! empty( $item->sku ) ) {
1179 $variation->set_sku( $item->sku );
1180 }
1181 // update purchase price as meta data.
1182 if ( ! empty( $item->purchase_rate ) ) {
1183 update_post_meta( $variation_id, '_cost_price', $item->purchase_rate );
1184 }
1185 // Price - Imported.
1186 $zi_disable_price_sync = $this->config['Settings']['disable_price'];
1187 $variation_sale_price = $variation->get_sale_price();
1188 if ( empty( $variation_sale_price ) && ! $zi_disable_price_sync ) {
1189 $variation->set_sale_price( $item->rate );
1190 }
1191 $variation->set_regular_price( $item->rate );
1192 // Set Tax Class.
1193 if ( $item->tax_id && $is_tax_enabled ) {
1194 $zi_common_class = new CMBIRD_Common_Functions();
1195 $woo_tax_class = $zi_common_class->get_tax_class_by_percentage( $item->tax_percentage );
1196 $variation->set_tax_status( 'taxable' );
1197 $variation->set_tax_class( $woo_tax_class );
1198 }
1199 // Stock Imported code.
1200 if ( ! $zi_disable_stock_sync && is_numeric( $stock_quantity ) ) {
1201 // fwrite( $fd, PHP_EOL . 'Stock Quantity : ' . $stock_quantity );
1202 $variation->set_manage_stock( true );
1203 if ( $stock_quantity > 0 ) {
1204 $variation->set_manage_stock( true );
1205 $variation->set_stock_quantity( $stock_quantity );
1206 $variation->set_stock_status( 'instock' );
1207 } elseif ( $stock_quantity <= 0 ) {
1208 $variation->set_manage_stock( true );
1209 $variation->set_stock_quantity( $stock_quantity );
1210 $stock_status = $variation->backorders_allowed() ? 'onbackorder' : 'outofstock';
1211 $variation->set_stock_status( $stock_status );
1212 }
1213 }
1214 // Featured Image of variation.
1215 if ( ! empty( $item->image_document_id ) ) {
1216 $image_class = new CMBIRD_Image_ZI();
1217 $variation_image_id = $image_class->cmbird_zi_get_image( $item->item_id, $item->name, $variation_id, $item->image_name );
1218 if ( ! has_post_thumbnail( $group_id ) ) {
1219 if ( $variation_image_id ) {
1220 set_post_thumbnail( $group_id, $variation_image_id );
1221 }
1222 }
1223 }
1224 // enable or disable based on status from Zoho.
1225 $status = ( 'active' === $item->status ) ? 'publish' : 'draft';
1226 $variation->set_status( $status );
1227 $variation->save();
1228 // clear cache.
1229 wc_delete_product_transients( $variation_id );
1230 } else {
1231 // create new variation.
1232 // if status is not active then return.
1233 if ( 'active' !== $item->status ) {
1234 return;
1235 }
1236
1237 $attribute_name1 = $item->attribute_option_name1;
1238 $attribute_name2 = $item->attribute_option_name2;
1239 $attribute_name3 = $item->attribute_option_name3;
1240 // Prepare the variation data.
1241 $attribute_arr = array();
1242 if ( ! empty( $attribute_name1 ) ) {
1243 $sanitized_name1 = wc_sanitize_taxonomy_name( $item->attribute_name1 );
1244 $attribute_arr[ $sanitized_name1 ] = $attribute_name1;
1245 }
1246 if ( ! empty( $attribute_name2 ) ) {
1247 $sanitized_name2 = wc_sanitize_taxonomy_name( $item->attribute_name2 );
1248 $attribute_arr[ $sanitized_name2 ] = $attribute_name2;
1249 }
1250 if ( ! empty( $attribute_name3 ) ) {
1251 $sanitized_name3 = wc_sanitize_taxonomy_name( $item->attribute_name3 );
1252 $attribute_arr[ $sanitized_name3 ] = $attribute_name3;
1253 }
1254 // fwrite( $fd, PHP_EOL . 'Attributes_arr: ' . print_r( $attribute_arr, true ) );
1255
1256 // here actually create new variation because sku not found.
1257 $variation = new WC_Product_Variation();
1258 $variation->set_parent_id( $group_id );
1259 $variation->set_status( 'publish' );
1260 $variation->set_regular_price( $item->rate );
1261 $variation->set_sku( $item->sku );
1262 if ( ! $zi_disable_stock_sync ) {
1263 $variation->set_stock_quantity( $stock_quantity );
1264 $variation->set_manage_stock( true );
1265 $variation->set_stock_status( '' );
1266 } else {
1267 $variation->set_manage_stock( false );
1268 }
1269 $variation->add_meta_data( 'zi_item_id', $item->item_id );
1270 $variation_id = $variation->save();
1271
1272 // Get the variation attributes with correct attribute values.
1273 foreach ( $attribute_arr as $attribute => $term_name ) {
1274 $taxonomy = $attribute;
1275 // If taxonomy doesn't exists we create it.
1276 if ( ! taxonomy_exists( $taxonomy ) ) {
1277 register_taxonomy(
1278 $taxonomy,
1279 'product_variation',
1280 array(
1281 'hierarchical' => false,
1282 'label' => ucfirst( $attribute ),
1283 'query_var' => true,
1284 'rewrite' => array( 'slug' => sanitize_title( $attribute ) ),
1285 ),
1286 );
1287 }
1288
1289 // Check if the Term name exist and if not we create it.
1290 if ( ! term_exists( $term_name, $taxonomy ) ) {
1291 wp_insert_term( $term_name, $taxonomy );
1292 }
1293
1294 $term_slug = get_term_by( 'name', $term_name, $taxonomy )->slug;
1295 // Get the post Terms names from the parent variable product.
1296 $post_term_names = wp_get_post_terms( $group_id, $taxonomy, array( 'fields' => 'names' ) );
1297 // Check if the post term exist and if not we set it in the parent variable product.
1298 if ( ! in_array( $term_name, $post_term_names, true ) ) {
1299 wp_set_post_terms( $group_id, $term_name, $taxonomy, true );
1300 }
1301 // Set/save the attribute data in the product variation.
1302 update_post_meta( $variation_id, 'attribute_' . $taxonomy, $term_slug );
1303 }
1304
1305 // update purchase price as meta data.
1306 if ( ! empty( $item->purchase_rate ) ) {
1307 update_post_meta( $variation_id, '_cost_price', $item->purchase_rate );
1308 }
1309 // Stock.
1310 if ( ! empty( $stock ) && ! $zi_disable_stock_sync ) {
1311 update_post_meta( $variation_id, 'manage_stock', true );
1312 if ( $stock > 0 ) {
1313 update_post_meta( $variation_id, '_stock', $stock );
1314 update_post_meta( $variation_id, '_stock_status', 'instock' );
1315 } else {
1316 $backorder_status = get_post_meta( $group_id, '_backorders', true );
1317 update_post_meta( $variation_id, '_stock', $stock );
1318 if ( 'yes' === $backorder_status ) {
1319 update_post_meta( $variation_id, '_stock_status', 'onbackorder' );
1320 } else {
1321 update_post_meta( $variation_id, '_stock_status', 'outofstock' );
1322 }
1323 }
1324 }
1325 // Featured Image of variation.
1326 if ( ! empty( $item->image_document_id ) ) {
1327 $image_class = new CMBIRD_Image_ZI();
1328 $variation_image_id = $image_class->cmbird_zi_get_image( $item->item_id, $item->name, $variation_id, $item->image_name );
1329 if ( ! has_post_thumbnail( $group_id ) ) {
1330 if ( $variation_image_id ) {
1331 set_post_thumbnail( $group_id, $variation_image_id );
1332 }
1333 }
1334 }
1335 update_post_meta( $variation_id, 'zi_item_id', $item_id );
1336 WC_Product_Variable::sync( $group_id );
1337 // Regenerate lookup table for attributes.
1338 $lookup_data_store = new LookupDataStore();
1339 $lookup_data_store->create_data_for_product( $group_id );
1340 // End group item add process.
1341 unset( $attribute_arr );
1342 }
1343 // end of grouped item updating.
1344 } else {
1345 // fwrite($fd, PHP_EOL . 'Group item empty');
1346 return;
1347 }
1348 // fwrite($fd, PHP_EOL . 'After group item sync');
1349 // fclose( $fd );
1350 }
1351
1352 /**
1353 * Helper Function to check if child of composite items already synced or not
1354 *
1355 * @param string $composite_zoho_id - zoho composite item id to check if it's child are already synced.
1356 * @param string $zi_url - zoho api url.
1357 * @param string $zi_key - zoho access token.
1358 * @param string $zi_org_id - zoho organization id.
1359 * @return array | bool of child id and metadata if child item already synced else will return false.
1360 */
1361 public function zi_check_if_child_synced_already( $composite_zoho_id, $zi_url, $zi_org_id, $prod_id ) {
1362 if ( $prod_id ) {
1363 $bundle_childs = WC_PB_DB::query_bundled_items(
1364 array(
1365 'return' => 'id=>product_id',
1366 'bundle_id' => array( $prod_id ),
1367 )
1368 );
1369 }
1370 global $wpdb;
1371
1372 $url = $zi_url . 'inventory/v1/compositeitems/' . $composite_zoho_id . '?organization_id=' . $zi_org_id;
1373
1374 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
1375 $json = $execute_curl_call->execute_curl_call_get( $url );
1376 $code = $json->code;
1377 // Flag to allow sync of parent composite item.
1378 $allow_sync = false;
1379 // Array of child object metadata.
1380 $product_array = array(); // [{prod_id:'',metadata:{key:'',value:''}},...].
1381 if ( '0' === $code || 0 === $code ) {
1382 foreach ( $json->composite_item->mapped_items as $child_item ) {
1383 $prod_meta = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM $wpdb->postmeta WHERE meta_key = 'zi_item_id' AND meta_value = %s", $child_item->item_id ) );
1384 // If any child will not have zoho id in meta field then process will return false and syncing will be skipped for given item.
1385 if ( ! empty( $prod_meta->post_id ) ) {
1386
1387 $allow_sync = true;
1388 $product = wc_get_product( $prod_meta->post_id );
1389 $stock_status = 'out_of_stock';
1390 if ( $child_item->stock_on_hand > 0 ) {
1391 $stock_status = 'in_stock';
1392 } elseif ( $product && $product->backorders_allowed() ) {
1393 $stock_status = 'onbackorder';
1394 }
1395 $prod_obj = (object) array(
1396 'prod_id' => $prod_meta->post_id,
1397 'metadata' => (object) array(
1398 'quantity_min' => max( 1, $child_item->quantity ),
1399 'quantity_max' => max( 1, $child_item->quantity ),
1400 'stock_status' => $stock_status,
1401 'max_stock' => $child_item->stock_on_hand,
1402 ),
1403 );
1404 if ( is_array( $bundle_childs ) && ! empty( $bundle_childs ) ) {
1405 $index = array_search( $prod_meta->post_id, $bundle_childs );
1406 unset( $bundle_childs[ $index ] );
1407 }
1408 array_push( $product_array, $prod_obj );
1409 } else {
1410 continue;
1411 }
1412 }
1413 }
1414 if ( is_array( $bundle_childs ) && ! empty( $bundle_childs ) ) {
1415 foreach ( $bundle_childs as $item_id => $val ) {
1416 WC_PB_DB::delete_bundled_item( $item_id );
1417 }
1418 }
1419 if ( $allow_sync ) {
1420 return $product_array;
1421 }
1422 return false;
1423 }
1424 /**
1425 * Mapping of bundled product
1426 *
1427 * @param number $product_id - Product id of child item of bundle product.
1428 * @param number $bundle_id - Bundle id of product.
1429 * @param number $menu_order - Listing order of child product ($menu_order will useful at composite product details page).
1430 * @return number - bundle item id.
1431 */
1432 public function add_bundle_product( $product_id, $bundle_id, $menu_order = 0 ) {
1433 $bundle_items = WC_PB_DB::query_bundled_items(
1434 array(
1435 'return' => 'id=>product_id',
1436 'bundle_id' => array( $bundle_id ),
1437 'product_id' => array( $product_id ),
1438 )
1439 );
1440 $data = array(
1441 'menu_order' => $menu_order,
1442 );
1443
1444 if ( count( $bundle_items ) > 0 ) {
1445 $result = WC_PB_DB::update_bundled_item( $bundle_id, $data );
1446 return $result;
1447 } else {
1448 // create data array of bundle item.
1449 $data = array(
1450 'product_id' => $product_id,
1451 'bundle_id' => $bundle_id,
1452 'menu_order' => $menu_order,
1453 );
1454 $bundle_id = WC_PB_DB::add_bundled_item( $data );
1455 return $bundle_id;
1456 }
1457 }
1458
1459 /**
1460 * Create or update bundle item metadata
1461 *
1462 * @param number $bundle_item_id bundle item id.
1463 * @param string $meta_key - metadata key.
1464 * @param string $meta_value - metadata value.
1465 * @return void
1466 */
1467 public function zi_update_bundle_meta( $bundle_item_id, $meta_key, $meta_value ) {
1468 // first get metadata from db.
1469 $metadata = WC_PB_DB::get_bundled_item_meta( $bundle_item_id, $meta_key );
1470 if ( $metadata ) {
1471 $result = WC_PB_DB::update_bundled_item_meta( $bundle_item_id, $meta_key, $meta_value );
1472 } else {
1473 $result = WC_PB_DB::add_bundled_item_meta( $bundle_item_id, $meta_key, $meta_value );
1474 return $result;
1475 }
1476 }
1477
1478 /**
1479 * Function to sync composite item from zoho to woocommerce
1480 *
1481 * @param integer $page - Page number of composite item data.
1482 * @param string $category - Category id of composite data.
1483 * @return mixed - mostly array of response message.
1484 */
1485 public function recursively_sync_composite_item_from_zoho( $page, $category ) {
1486 // Start logging.
1487 // $fd = fopen( __DIR__ . '/recursively_sync_composite_item_from_zoho.txt', 'a+' );
1488
1489 global $wpdb;
1490 $zi_org_id = $this->config['ProductZI']['OID'];
1491 $zi_url = $this->config['ProductZI']['APIURL'];
1492
1493 $current_user = wp_get_current_user();
1494 $admin_author_id = $current_user->ID;
1495 if ( ! $admin_author_id ) {
1496 $admin_author_id = 1;
1497 }
1498
1499 $url = $zi_url . 'inventory/v1/compositeitems/?organization_id=' . $zi_org_id . '&filter_by=Status.Active&category_id=' . $category . '&page=' . $page;
1500
1501 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
1502 $json = $execute_curl_call->execute_curl_call_get( $url );
1503 $code = $json->code;
1504 // $message = $json->message;
1505 // fwrite($fd, PHP_EOL . '$json : ' . print_r($json, true));
1506 // Response for item sync with sync button. For cron sync blank array will return.
1507 $response_msg = array();
1508 if ( '0' === $code || 0 === $code ) {
1509 if ( empty( $json->composite_items ) ) {
1510 array_push( $response_msg, $this->zi_response_message( 'ERROR', 'No composite item to sync for category : ' . $category ) );
1511 return $response_msg;
1512 }
1513 // Accounting stock mode check.
1514 $accounting_stock = $this->config['Settings']['enable_accounting_stock'];
1515 foreach ( $json->composite_items as $comp_item ) {
1516 // fwrite( $fd, PHP_EOL . 'Composite Item : ' . print_r( $comp_item, true ) );
1517 // Sync stock from specific location check.
1518 $zi_enable_locationstock = $this->config['Settings']['enable_locationstock'];
1519 $location_id = $this->config['Settings']['location_id'];
1520 $locations = $comp_item->locations;
1521
1522 if ( true === $zi_enable_locationstock ) {
1523 foreach ( $locations as $location ) {
1524 if ( $location->location_id === $location_id ) {
1525 if ( $accounting_stock ) {
1526 $stock = $location->location_available_for_sale_stock;
1527 } else {
1528 $stock = $location->location_actual_available_for_sale_stock;
1529 }
1530 }
1531 }
1532 } elseif ( $accounting_stock ) {
1533 $stock = $comp_item->available_for_sale_stock;
1534 } else {
1535 $stock = $comp_item->actual_available_for_sale_stock;
1536 }
1537
1538 // ----------------- Create composite item in woocommerce--------------.
1539 // Code to skip sync with item already exists with same sku.
1540 $prod_id = wc_get_product_id_by_sku( $comp_item->sku );
1541 // Flag to enable or disable sync.
1542 $allow_to_import = false;
1543 // Check if product exists with same sku.
1544 if ( $prod_id ) {
1545 $zi_item_id = get_post_meta( $prod_id, 'zi_item_id', true );
1546 if ( $zi_item_id === $comp_item->composite_item_id ) {
1547 // If product is with same sku and zi_item_id mapped.
1548 // Do not import ...
1549 $allow_to_import = false;
1550 } else {
1551 // Map existing item with zoho id.
1552 update_post_meta( $prod_id, 'zi_item_id', $comp_item->composite_item_id );
1553 $allow_to_import = false;
1554 }
1555 } else {
1556 // If product not exists normal bahaviour of item sync.
1557 $allow_to_import = true;
1558 }
1559 $zoho_comp_item_id = $comp_item->composite_item_id;
1560 if ( $comp_item->composite_item_id ) {
1561 $child_items = $this->zi_check_if_child_synced_already( $zoho_comp_item_id, $zi_url, $zi_org_id, $prod_id );
1562 // Check if child items already synced with zoho.
1563 if ( ! $child_items ) {
1564 array_push( $response_msg, $this->zi_response_message( 'ERROR', 'Child not synced for composite item : ' . $zoho_comp_item_id ) );
1565 continue;
1566 }
1567 $product_res = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->postmeta} WHERE meta_key = 'zi_item_id' AND meta_value = %s", $zoho_comp_item_id ) );
1568 if ( ! empty( $product_res->post_id ) ) {
1569 $com_prod_id = $product_res->post_id;
1570 }
1571 // Check if item is allowed to import or not.
1572 if ( $allow_to_import ) {
1573 $product_class = new CMBIRD_Products_ZI_Export();
1574 $item_array = json_decode( wp_json_encode( $comp_item ), true );
1575 $com_prod_id = $product_class->cmbird_zi_product_to_woocommerce( $item_array, $stock, 'composite' );
1576 update_post_meta( $com_prod_id, 'zi_item_id', $zoho_comp_item_id );
1577 }
1578 }
1579 // Map composite items to database.
1580 if ( ! empty( $com_prod_id ) ) {
1581 wp_set_object_terms( $com_prod_id, 'bundle', 'product_type' );
1582 foreach ( $child_items as $child_prod ) {
1583 // Adding product to bundle.
1584 $child_bundle_id = $this->add_bundle_product( $child_prod->prod_id, $com_prod_id );
1585 if ( $child_bundle_id ) {
1586 foreach ( $child_prod->metadata as $bundle_meta_key => $bundle_meta_val ) {
1587 $this->zi_update_bundle_meta( $child_bundle_id, $bundle_meta_key, $bundle_meta_val );
1588 }
1589 }
1590 }
1591 }
1592 // --------------------------------------------------------------------.
1593
1594 $is_synced_flag = false; // loggin purpose only .
1595
1596 $product = wc_get_product( $com_prod_id );
1597 foreach ( $comp_item as $key => $value ) {
1598 if ( 'status' === $key ) {
1599 if ( ! empty( $com_prod_id ) ) {
1600 $status = 'active' === $value ? 'publish' : 'draft';
1601 $product->set_status( $status );
1602 }
1603 }
1604 if ( 'description' === $key ) {
1605 if ( ! empty( $com_prod_id ) && ! empty( $value ) ) {
1606 $product->set_short_description( $value );
1607 }
1608 }
1609 if ( 'name' === $key ) {
1610 if ( ! empty( $com_prod_id ) ) {
1611 $product->set_name( $value );
1612 }
1613 }
1614 if ( 'sku' === $key ) {
1615 if ( ! empty( $com_prod_id ) ) {
1616 $product->set_sku( $value );
1617 }
1618 }
1619 // Check if stock sync allowed by plugin.
1620 if ( 'available_stock' === $key || 'actual_available_stock' === $key ) {
1621 $zi_disable_stock_sync = $this->config['Settings']['disable_stock'];
1622 if ( ! $zi_disable_stock_sync ) {
1623 if ( $stock ) {
1624 if ( ! empty( $com_prod_id ) ) {
1625 // If value is less than 0 default 1.
1626 $stock_quantity = $stock < 0 ? 0 : $stock;
1627 $product->set_manage_stock( true );
1628 $product->set_stock_quantity( $stock_quantity );
1629 if ( $stock_quantity > 0 ) {
1630 $status = 'instock';
1631 } else {
1632 $backorder_status = $product->backorders_allowed();
1633 $status = $backorder_status ? 'onbackorder' : 'outofstock';
1634 }
1635 $product->set_stock_status( $status );
1636 update_post_meta( $com_prod_id, '_wc_pb_bundled_items_stock_status', $status );
1637 }
1638 }
1639 }
1640 }
1641 if ( 'rate' === $key ) {
1642 if ( ! empty( $com_prod_id ) ) {
1643 $sale_price = $product->get_sale_price();
1644 if ( empty( $sale_price ) ) {
1645 $product->set_regular_price( $value );
1646 $product->set_price( $value );
1647 update_post_meta( $com_prod_id, '_wc_pb_base_price', $value );
1648 update_post_meta( $com_prod_id, '_wc_pb_base_regular_price', $value );
1649 update_post_meta( $com_prod_id, '_wc_sw_max_regular_price', $value );
1650 } else {
1651 $product->set_regular_price( $value );
1652 update_post_meta( $com_prod_id, '_wc_pb_base_price', $value );
1653 update_post_meta( $com_prod_id, '_wc_pb_base_regular_price', $value );
1654 update_post_meta( $com_prod_id, '_wc_sw_max_regular_price', $value );
1655 }
1656 }
1657 }
1658 $product->save();
1659
1660 if ( 'image_document_id' === $key ) {
1661 if ( ! empty( $com_prod_id ) && ! empty( $value ) ) {
1662 $image_class = new CMBIRD_Image_ZI();
1663 $image_class->cmbird_zi_get_image( $zoho_comp_item_id, $comp_item->name, $com_prod_id, $comp_item->image_name );
1664 }
1665 }
1666 if ( 'category_name' === $key ) {
1667 if ( ! empty( $com_prod_id ) && $comp_item->category_name != '' ) {
1668 $term = get_term_by( 'name', $comp_item->category_name, 'product_cat' );
1669 $term_id = $term->term_id;
1670 if ( empty( $term_id ) ) {
1671 $term = wp_insert_term(
1672 $comp_item->category_name,
1673 'product_cat',
1674 array(
1675 'parent' => 0,
1676 )
1677 );
1678 $term_id = $term['term_id'];
1679 }
1680 if ( $term_id ) {
1681 $existing_terms = wp_get_object_terms( $com_prod_id, 'product_cat' );
1682 if ( $existing_terms && count( $existing_terms ) > 0 ) {
1683 $is_terms_exist = $this->zi_check_terms_exists( $existing_terms, $term_id );
1684 if ( ! $is_terms_exist ) {
1685 update_post_meta( $com_prod_id, 'zi_category_id', $category );
1686 wp_add_object_terms( $com_prod_id, $term_id, 'product_cat' );
1687 }
1688 } else {
1689 update_post_meta( $com_prod_id, 'zi_category_id', $category );
1690 wp_set_object_terms( $com_prod_id, $term_id, 'product_cat' );
1691 }
1692 }
1693 // Remove "uncategorized" category if assigned.
1694 $uncategorized_term = get_term_by( 'slug', 'uncategorized', 'product_cat' );
1695 if ( $uncategorized_term && has_term( $uncategorized_term->term_id, 'product_cat', $com_prod_id ) ) {
1696 wp_remove_object_terms( $com_prod_id, $uncategorized_term->term_id, 'product_cat' );
1697 }
1698 }
1699 }
1700 }
1701
1702 // sync dimensions and weight.
1703 $item_url = "{$zi_url}inventory/v1/compositeitems/{$zoho_comp_item_id}?organization_id={$zi_org_id}";
1704 $this->zi_item_dimension_weight( $item_url, $com_prod_id, true );
1705
1706 // If item synced append to log : logging purpose only.
1707 if ( $is_synced_flag ) {
1708 array_push( $response_msg, $this->zi_response_message( 'SUCCESS', 'Composite item synced for id : ' . $comp_item->composite_item_id, $com_prod_id ) );
1709 }
1710 }
1711
1712 if ( $json->page_context->has_more_page ) {
1713 ++$page;
1714 $this->recursively_sync_composite_item_from_zoho( $page, $category );
1715 }
1716 } else {
1717 array_push( $response_msg, $this->zi_response_message( $code, $json->message ) );
1718 }
1719 // fclose( $fd ); // End of logging.
1720
1721 return $response_msg;
1722 }
1723
1724 /**
1725 * Function to retrieve item details, update weight and dimensions.
1726 *
1727 * @param string $url - URL to ge details.
1728 * @return mixed return true if data false if error.
1729 */
1730 public function zi_item_dimension_weight( $url, $product_id, $is_composite = false ) {
1731 // $fd = fopen(__DIR__ . '/zi_item_dimension_weight.txt', 'a+');
1732 // Check if item is for syncing purpose.
1733 $execute_curl_call = new CMBIRD_API_Handler_Zoho();
1734 $json = $execute_curl_call->execute_curl_call_get( $url );
1735 $code = $json->code;
1736 $message = $json->message;
1737 if ( 0 === $code || '0' === $code ) {
1738 if ( $is_composite ) {
1739 // fwrite($fd, PHP_EOL . '$json : ' . print_r($json, true));
1740 $details = $json->composite_item->package_details;
1741 } else {
1742 $details = $json->item->package_details;
1743 }
1744 $product = wc_get_product( $product_id );
1745 $product->set_weight( floatval( $details->weight ) );
1746 $product->set_length( floatval( $details->length ) );
1747 $product->set_width( floatval( $details->width ) );
1748 $product->set_height( floatval( $details->height ) );
1749 $product->save();
1750 } else {
1751 false;
1752 }
1753 // fclose($fd);
1754 }
1755
1756 /**
1757 * Create response object based on data.
1758 *
1759 * @param mixed $index_col - Index value error message.
1760 * @param string $message - Response message.
1761 * @return object
1762 */
1763 public function zi_response_message( $index_col, $message, $woo_id = '' ) {
1764 return (object) array(
1765 'resp_id' => $index_col,
1766 'message' => $message,
1767 'woo_prod_id' => $woo_id,
1768 );
1769 }
1770
1771 /**
1772 * Helper Function to check if terms already exists.
1773 */
1774 public function zi_check_terms_exists( $existing_terms, $term_id ) {
1775 foreach ( $existing_terms as $woo_existing_term ) {
1776 if ( $woo_existing_term->term_id === $term_id ) {
1777 return true;
1778 } else {
1779 return false;
1780 }
1781 }
1782 }
1783 }
1784 $cmbird_products_zi = new CMBIRD_Products_ZI();
1785