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-categories.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-categories.php
422 lines
1 <?php
2 /**
3 * Class to import categories from Zoho Inventory to WooCommerce and vice versa.
4 *
5 * @package zoho_inventory_api
6 */
7 if ( ! defined( 'ABSPATH' ) ) {
8 exit;
9 }
10 class CMBIRD_Categories_ZI {
11
12 private $config;
13 public function __construct() {
14 $this->config = array(
15 'ConnectZI' => array(
16 'OID' => get_option( 'cmbird_zoho_inventory_oid' ),
17 'APIURL' => get_option( 'cmbird_zoho_inventory_url' ),
18 ),
19 );
20 add_action( 'wp_ajax_zoho_ajax_call_category', array( $this, 'cmbird_zi_category_sync_call' ) );
21 add_action( 'wp_ajax_zoho_ajax_call_subcategory', array( $this, 'cmbird_zi_subcategory_sync_call' ) );
22 }
23
24 /**
25 * Create response object based on data.
26 *
27 * @param mixed $index_col - Index value error message.
28 * @param string $message - Response message.
29 *
30 * @return object
31 */
32 private function cmbird_zi_response_message( $index_col, $message, $woo_id = '' ) {
33 return (object) array(
34 'resp_id' => $index_col,
35 'message' => $message,
36 'woo_prod_id' => $woo_id,
37 );
38 }
39
40 /**
41 * Get Term ID from Zoho category ID
42 *
43 * @return string - Term ID
44 */
45
46 public function cmbird_subcategories_term_id( $option_value ) {
47 global $wpdb;
48 $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}options WHERE option_value = %s", $option_value ) );
49 if ( ! empty( $row->option_name ) ) {
50 $ex = explode( 'zoho_id_for_term_id_', $row->option_name );
51 $cat_id = $ex[1];
52 }
53 $term = get_term_by( 'term_id', $cat_id, 'product_cat' );
54 if ( empty( $term ) ) {
55 // remove the option from the database.
56 delete_option( $row->option_name );
57 return '';
58 } else {
59 return $cat_id;
60 }
61 }
62
63 /**
64 * Get all categories from Zoho Inventory.
65 *
66 * @return bool | string
67 */
68 public function cmbird_zi_category_sync_call() {
69 // $fd = fopen( __DIR__ . '/cmbird_zi_category_sync_call.txt', 'a+' );
70
71 $response = array(); // Response array.
72 $zoho_categories = $this->cmbird_get_zoho_item_categories();
73 // fwrite( $fd, PHP_EOL . 'categories: ' . print_r( $zoho_categories, true ) );
74 // Import category from zoho to woocommerce.
75 $response[] = $this->cmbird_zi_response_message( '-', '-', '--- Importing Category from zoho ---' );
76
77 foreach ( $zoho_categories as $category ) {
78
79 if ( '-1' === $category['category_id'] ) {
80 continue;
81 }
82
83 if ( '-1' === $category['parent_category_id'] ) {
84
85 if ( $category['category_id'] ) {
86 // sanitize category name.
87 $category_slug = wc_sanitize_taxonomy_name( $category['name'] );
88 // fwrite( $fd, PHP_EOL . 'Category Name : ' . $category_name );
89 $terms = get_terms(
90 array(
91 'taxonomy' => 'product_cat',
92 'hide_empty' => false,
93 'slug' => $category_slug,
94 )
95 );
96 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
97 $term_id = $terms[0]->term_id;
98 } else {
99 $term = wp_insert_term(
100 $category['name'],
101 'product_cat',
102 array(
103 'parent' => 0,
104 )
105 );
106 if ( is_wp_error( $term ) ) {
107 $response[] = $this->cmbird_zi_response_message( $category['category_id'], $term->get_error_message(), '-' );
108 } else {
109 $term_id = $term['term_id'];
110 }
111 }
112 if ( $term_id ) {
113 // Update zoho category id for term(category) of woocommerce.
114 // fwrite( $fd, PHP_EOL . 'Category ID : ' . $category['category_id'] . ' Term ID : ' . $term_id );
115 update_option( 'cmbird_zoho_id_for_term_id_' . $term_id, $category['category_id'] );
116 }
117 $response[] = $this->cmbird_zi_response_message( $category['category_id'], $category['name'], $term_id );
118 }
119 }
120 }
121 // fclose( $fd );
122 // Closing of import of category from woo to zoho.
123 $categories_terms = get_terms(
124 array(
125 'taxonomy' => 'product_cat',
126 'child_of' => false,
127 )
128 );
129 $log_head = '---Exporting Category to zoho---';
130 $response[] = $this->cmbird_zi_response_message( '-', '-', $log_head );
131 if ( $categories_terms && count( $categories_terms ) > 0 ) {
132
133 foreach ( $categories_terms as $term ) {
134 //remove uncategorized from loop
135 if ( $term->slug == 'uncategorized' ) {
136 continue;
137 }
138
139 $zoho_cat_id = get_option( 'cmbird_zoho_id_for_term_id_' . $term->term_id );
140 if ( empty( $zoho_cat_id ) ) {
141 // fwrite( $fd, PHP_EOL . 'Category Name : ' . $term->name );
142 $add_response = $this->cmbird_zi_category_export( $term->name, $term->term_id );
143 // fwrite( $fd, PHP_EOL . 'Response : ' . print_r( $add_response, true ) );
144 $response[] = $add_response;
145 } else {
146 $response[] = $this->cmbird_zi_response_message( $zoho_cat_id, 'Category name : "' . $term->name . '" already synced with zoho', $term->term_id );
147 }
148 }
149 } else {
150 $response[] = $this->cmbird_zi_response_message( '-', 'Categories not available to export', '-' );
151 }
152 $encoded_response = wp_json_encode( $response );
153 // fwrite( $fd, PHP_EOL . 'Final Response : ' . print_r( $encoded_response, true ) );
154 // fclose( $fd );
155
156 return $encoded_response;
157 }
158
159 public function cmbird_get_zoho_item_categories() {
160 // $fd = fopen( __DIR__ . '/cmbird_get_zoho_item_categories.txt', 'a+' );
161
162 // first remove duplicates from woocommerce categories.
163 $this->cmbird_remove_duplicate_woocommerce_categories();
164
165 $zoho_inventory_oid = $this->config['ConnectZI']['OID'];
166 $zoho_inventory_url = $this->config['ConnectZI']['APIURL'];
167
168 $url = $zoho_inventory_url . 'inventory/v1/categories/?organization_id=' . $zoho_inventory_oid;
169
170 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
171 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
172 $code = $json->code;
173 if ( '0' == $code || 0 == $code ) {
174 $response = $json->categories;
175 // Initialize an array to store unique categories
176 $unique_categories = array();
177
178 // Initialize an associative array to track category occurrences
179 $category_count = array();
180
181 // First pass: count occurrences and track the category with active items
182 foreach ( $response as $category ) {
183 $category_name = $category->name;
184
185 // skip -1 category_id
186 if ( '-1' === $category->category_id ) {
187 continue;
188 }
189 // Count occurrences
190 if ( isset( $category_count[ $category_name ] ) ) {
191 ++$category_count[ $category_name ];
192 } else {
193 $category_count[ $category_name ] = 1;
194 }
195 }
196
197 // Second pass: add categories to unique array based on the counts and active items
198 foreach ( $response as $category ) {
199 // skip -1 category_id
200 if ( '-1' === $category->category_id ) {
201 continue;
202 }
203
204 // remove the duplicated categories from Zoho by doing a check on the active item
205 if ( ! $category->has_active_items ) {
206 // if category is not in category_count array, then do DELETE call to Zoho API to delete the category
207 if ( 1 !== $category_count[ $category->name ] ) {
208 $delete_url = $zoho_inventory_url . 'inventory/v1/categories/' . $category->category_id . '/?organization_id=' . $zoho_inventory_oid;
209 $delete_response = $execute_curl_call_handle->execute_curl_call_delete( $delete_url );
210 // fwrite( $fd, PHP_EOL . 'Category Deleted : ' . print_r( $delete_response, true ) );
211 }
212 }
213
214 $category_name = $category->name;
215 if ( 1 === $category_count[ $category_name ] || $category->has_active_items ) {
216 // Add if mentioned only once
217 $unique_categories[] = $category;
218 }
219 }
220
221 // Reset keys to have a sequential array
222 $unique_categories = array_values( $unique_categories );
223
224 } else {
225 $response = array();
226 return $response;
227 }
228
229 $response = wp_json_encode( $unique_categories );
230 // fwrite( $fd, print_r( $response, true ) );
231 // fclose( $fd );
232
233 return json_decode( $response, true );
234 }
235
236 public function cmbird_zi_subcategory_sync_call() {
237 // $fd = fopen( __DIR__ . '/ajax_subcategory_sync_call.txt', 'a+' );
238 $response = array(); // Response array.
239 $zoho_subcategories = $this->cmbird_get_zoho_item_categories();
240 // Import category from zoho to woocommerce.
241 $response[] = $this->cmbird_zi_response_message( '-', '-', '--- Importing Sub Category from zoho ---' );
242 //echo '<pre>'; print_r($zoho_categories);
243 foreach ( $zoho_subcategories as $subcategory ) {
244 if ( $subcategory['parent_category_id'] > 0 ) {
245 if ( '-1' !== $subcategory['category_id'] && $subcategory['category_id'] > 0 ) {
246 $subcategory_slug = wc_sanitize_taxonomy_name( $subcategory['name'] );
247 $terms = get_terms(
248 array(
249 'taxonomy' => 'product_cat',
250 'hide_empty' => false,
251 'slug' => $subcategory_slug,
252 )
253 );
254
255 if ( $subcategory['parent_category_id'] > 0 ) {
256 $zoho_pid = intval( $this->cmbird_subcategories_term_id( $subcategory['parent_category_id'] ) );
257 }
258 if ( ! is_wp_error( $terms ) && ! empty( $terms ) ) {
259 $term_id = $terms[0]->term_id;
260 // update the term as sub category of parent category.
261 wp_update_term(
262 $term_id,
263 'product_cat',
264 array(
265 'parent' => $zoho_pid,
266 )
267 );
268 } elseif ( empty( $terms ) && $zoho_pid ) {
269 $child_term = wp_insert_term(
270 $subcategory['name'],
271 'product_cat',
272 array(
273 'parent' => $zoho_pid,
274 )
275 );
276 // Check if there is error in creating child category add message.
277 if ( is_wp_error( $child_term ) ) {
278 $response[] = $this->cmbird_zi_response_message( $subcategory['category_id'], $child_term->get_error_message(), '-' );
279 } else {
280 $term_id = $child_term['term_id'];
281 }
282 }
283
284 if ( $term_id && $zoho_pid > 0 ) {
285 // Update zoho sub category id for term(sub category) of woocommerce.
286 update_option( 'cmbird_zoho_id_for_term_id_' . $term_id, $subcategory['category_id'] );
287
288 }
289 $response[] = $this->cmbird_zi_response_message( $subcategory['category_id'], $subcategory['name'], $term_id );
290 }
291 }
292 }
293 // Closing of import of category from woo to zoho .
294
295 // Get product categories from woocommerce.
296 $categories_terms = get_terms(
297 array(
298 'taxonomy' => 'product_cat',
299 'child_of' => false,
300 )
301 );
302 $log_head = '---Exporting Sub Category to zoho---';
303 $response[] = $this->cmbird_zi_response_message( '-', '-', $log_head );
304 $c = 0;
305 if ( $categories_terms && count( $categories_terms ) > 0 ) {
306
307 foreach ( $categories_terms as $parent_term ) {
308 $parent_id = $parent_term->term_id;
309 $args = array(
310 'taxonomy' => 'product_cat',
311 'hide_empty' => false,
312 'parent' => $parent_id,
313 );
314 $subcategories_terms = get_terms( $args );
315 if ( $subcategories_terms && count( $subcategories_terms ) > 0 ) {
316 foreach ( $subcategories_terms as $term ) {
317 $zoho_cat_id = get_option( 'cmbird_zoho_id_for_term_id_' . $term->term_id );
318 if ( empty( $zoho_cat_id ) ) {
319 $zoho_cat_id = get_option( 'cmbird_zoho_id_for_term_id_' . $parent_id );
320 $pid = $zoho_cat_id;
321 $add_response = $this->cmbird_zi_category_export( $term->name, $term->term_id, $pid );
322 $response[] = $add_response;
323 } else {
324 $response[] = $this->cmbird_zi_response_message( $zoho_cat_id, 'Sub Category name : "' . $term->name . '" already synced with zoho', $term->term_id );
325 }
326 ++$c;
327 }
328 }
329 }
330 }
331 // fwrite( $fd, PHP_EOL . 'Sub Categories : ' . print_r( $response, true ) );
332 // fclose( $fd );
333
334 if ( 0 === $c ) {
335 $response[] = $this->cmbird_zi_response_message( '-', 'Sub Categories not available to export', '-' );
336 }
337 return wp_json_encode( $response );
338 }
339
340 /**
341 * Create woocommerce category in zoho inventory.
342 *
343 * @return boolean - true if category created successfully.
344 */
345 public function cmbird_zi_category_export( $cat_name, $term_id = '0', $pid = '' ) {
346
347 $zoho_inventory_oid = $this->config['ConnectZI']['OID'];
348 $zoho_inventory_url = $this->config['ConnectZI']['APIURL'];
349
350 if ( ! empty( $pid ) || $pid > 0 ) {
351 $zidata = '"name" : "' . $cat_name . '","parent_category_id" : "' . $pid . '",';
352 } else {
353 $zidata = '"name" : "' . $cat_name . '",';
354 }
355
356 $data = array(
357 'JSONString' => '{' . $zidata . '}',
358 );
359
360 $url = $zoho_inventory_url . 'inventory/v1/categories/?organization_id=' . $zoho_inventory_oid;
361
362 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
363 $json = $execute_curl_call_handle->execute_curl_call_post( $url, $data );
364
365 $code = $json->code;
366
367 if ( '0' == $code || 0 == $code ) {
368 foreach ( $json->category as $key => $value ) {
369 if ( 'category_id' === $key ) {
370 update_option( 'cmbird_zoho_id_for_term_id_' . $term_id, $value );
371 }
372 }
373 }
374 $response_msg = $json->message;
375
376 //echo '<pre>'; print_r($json);
377 $return = $this->cmbird_zi_response_message( $code, $response_msg, $term_id );
378 return wp_json_encode( $return );
379 }
380
381 /**
382 * Remove duplicate WooCommerce categories.
383 */
384 public function cmbird_remove_duplicate_woocommerce_categories() {
385 // Get all product categories, including empty ones
386 $terms = get_terms(
387 array(
388 'taxonomy' => 'product_cat',
389 'hide_empty' => false, // Include categories with zero product count
390 )
391 );
392
393 if ( is_wp_error( $terms ) || empty( $terms ) ) {
394 return; // No terms found or an error occurred
395 }
396
397 // Create an array to store category names and their associated terms
398 $categories_by_name = array();
399
400 foreach ( $terms as $term ) {
401 $name = strtolower( $term->name ); // Normalize the name for comparison
402
403 // Check if a category with this name is already processed
404 if ( isset( $categories_by_name[ $name ] ) ) {
405 $existing_term = $categories_by_name[ $name ];
406
407 if ( $term->count > 0 && $existing_term->count === 0 ) {
408 // Keep the current term, remove the existing one
409 wp_delete_term( $existing_term->term_id, 'product_cat' );
410 $categories_by_name[ $name ] = $term;
411 } elseif ( $term->count === 0 ) {
412 // Remove the current term as it has zero product count
413 wp_delete_term( $term->term_id, 'product_cat' );
414 }
415 } else {
416 // Add the term to the array if not already processed
417 $categories_by_name[ $name ] = $term;
418 }
419 }
420 }
421 }
422