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