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