PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.2.15
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.2.15
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-order-sync.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
class-order-sync.php
799 lines
1 <?php
2
3 /**
4 * Class for handling Zoho Inventory order sync related functions.
5 */
6 if ( ! defined( 'ABSPATH' ) ) {
7 exit;
8 }
9
10 class CMBIRD_Order_Sync_ZI {
11
12
13 /**
14 * Initialize the class.
15 */
16 public function __construct() {
17 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
18 if ( ! empty( $zoho_inventory_access_token ) ) {
19 add_action( 'woocommerce_rest_insert_shop_order_object', array( $this, 'on_insert_rest_api' ), 20, 3 );
20 add_filter( 'wcs_renewal_order_created', array( $this, 'cmbird_zi_sync_renewal_order' ), 10, 2 );
21 add_action( 'wp_ajax_zoho_admin_order_sync', array( $this, 'zi_order_sync' ) );
22 add_action( 'woocommerce_update_order', array( $this, 'salesorder_void' ) );
23 add_action( 'woocommerce_thankyou', array( $this, 'zi_sync_frontend_order' ) );
24 } else {
25 return;
26 }
27 }
28
29 /**
30 * Sync order when it's created via the checkout.
31 */
32 public function zi_sync_frontend_order( $order_id ) {
33 // return if the order is not coming via thank you page
34 if ( ! is_wc_endpoint_url( 'order-received' ) ) {
35 return;
36 }
37 // Check if the transient flag is set
38 if ( get_transient( 'cmbird_thankyou_callback_executed_' . $order_id ) ) {
39 return;
40 }
41 // First sync the customer to Zoho Inventory
42 $this->cmbird_zi_sync_customer_checkout( $order_id );
43
44 // Use WC Action Scheduler to sync the order to Zoho Inventory
45 $existing_schedule = as_has_scheduled_action( 'sync_zi_order', array( $order_id ) );
46 if ( ! $existing_schedule ) {
47 as_schedule_single_action( time(), 'sync_zi_order', array( $order_id ) );
48 // Set the transient flag to prevent multiple executions
49 set_transient( 'cmbird_thankyou_callback_executed_' . $order_id, true, 60 );
50 }
51 }
52 /**
53 * Sync order when its scheduled via the Action Scheduler.
54 *
55 * @param int $order_id Order ID.
56 * @return void
57 */
58 public function zi_orders_prepare_sync() {
59 $args = func_get_args();
60 $order_id = $args[0];
61 if ( ! get_option( 'cmbird_zoho_inventory_access_token' ) || ! $order_id ) {
62 return;
63 }
64 $this->zi_order_sync( $order_id );
65 }
66
67 /**
68 * Sync order when it's created via the WC API.
69 *
70 * @param WC_Data $object Inserted object.
71 * @param WP_REST_Request $request Request object.
72 * @param boolean $creating True when creating object, false when updating.
73 */
74 public function on_insert_rest_api( $object, $request, $is_creating ) {
75 if ( empty( get_option( 'cmbird_zoho_inventory_access_token' ) ) ) {
76 return;
77 }
78 // $fd = fopen(__DIR__ . '/on_insert_rest_api.txt', 'w+');
79 $request_body = $request->get_body();
80 $request_body_array = json_decode( $request_body, true );
81 $order_status = $request_body_array['status'];
82 $order_id = $object->get_id();
83
84 // Check how many keys there are in the request body array. If there are only two keys then we don't need to do anything.
85 if ( count( $request_body_array ) === 2 ) {
86 if ( in_array( $order_status, array( 'cancelled', 'wc-merged' ) ) ) {
87 $this->salesorder_void( $order_id );
88 }
89 } else {
90 $this->zi_order_sync( $order_id );
91 }
92 // fclose($fd);
93 }
94
95 /**
96 * Sync Renewal Order to Zoho once it's created.
97 */
98 public function cmbird_zi_sync_renewal_order( $renewal_order, $subscription ) {
99 if ( empty( get_option( 'cmbird_zoho_inventory_access_token' ) ) ) {
100 return $renewal_order;
101 }
102
103 $order_id = $renewal_order->get_id();
104 $this->zi_order_sync( $order_id );
105
106 return $renewal_order;
107 }
108
109 /**
110 * Function to map customer on checkout before placing order
111 * @param int $order_id Order ID.
112 *
113 */
114 public function cmbird_zi_sync_customer_checkout( $order_id ) {
115 // $fd = fopen( __DIR__ . '/cmbird_zi_sync_customer_checkout.txt', 'w+' );
116
117 $order = wc_get_order( $order_id );
118 $userid = $order->get_user_id();
119 $user_company = $order->get_billing_company();
120 $user_email = $order->get_billing_email();
121 $zi_customer_id = get_user_meta( $userid, 'zi_contact_id', true );
122
123 // Get currency code of the order
124 $currency_id = intval( get_user_meta( $userid, 'zi_currency_id', true ) );
125 if ( empty( $currency_id ) ) {
126 $currency_code = $order->get_currency();
127 $multi_currency_handle = new CMBIRD_Multicurrency_Zoho();
128 $currency_id = $multi_currency_handle->zoho_currency_data( $currency_code, $userid );
129 }
130
131 if ( $zi_customer_id ) {
132 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
133 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
134 $get_url = $zoho_inventory_url . 'inventory/v1/contacts/' . $zi_customer_id . '/?organization_id=' . $zoho_inventory_oid;
135
136 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
137 $json = $execute_curl_call_handle->execute_curl_call_get( $get_url );
138
139 // fwrite($fd,PHP_EOL.'customer_json: '.print_r($json, true));
140
141 $code = $json->code;
142 if ( $code !== 0 || $code !== '0' ) {
143 delete_user_meta( $userid, 'zi_contact_id' );
144 delete_user_meta( $userid, 'zi_billing_address_id' );
145 delete_user_meta( $userid, 'zi_primary_contact_id' );
146 delete_user_meta( $userid, 'zi_shipping_address_id' );
147 delete_user_meta( $userid, 'zi_created_time' );
148 delete_user_meta( $userid, 'zi_last_modified_time' );
149 $zi_customer_id = '';
150 }
151 }
152
153 /**
154 * syncing customer if its not in Zoho yet
155 */
156 if ( ! $zi_customer_id ) {
157
158 // First check based on customer email address
159 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
160 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
161 // fwrite($fd,PHP_EOL.'$user_mail : '.$user_email);
162 $url = $zoho_inventory_url . 'inventory/v1/contacts?organization_id=' . $zoho_inventory_oid . '&email=' . $user_email;
163
164 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
165 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
166
167 $code = $json->code;
168 $message = $json->message;
169 if ( $code === 0 || $code === '0' ) {
170 // fwrite($fd, PHP_EOL . 'customer_json: ' . print_r($json, true));
171 if ( empty( $json->contacts ) ) {
172 // Second check based on Company Name
173 if ( $user_company ) {
174 $company_name = str_replace( ' ', '%20', $user_company );
175 $url = $zoho_inventory_url . 'inventory/v1/contacts?organization_id=' . $zoho_inventory_oid . '&filter_by=Status.Active&search_text=' . $company_name;
176
177 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
178 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
179
180 $code = $json->code;
181 if ( $code == 0 || $code == '0' ) {
182 if ( empty( $json->contacts ) ) {
183 $contact_class_handle = new CMBIRD_Contact_ZI();
184 $zi_customer_id = $contact_class_handle->cmbird_contact_create_function( $userid );
185 } else {
186 foreach ( $json->contacts[0] as $key => $value ) {
187 if ( $key == 'contact_id' ) {
188 $zi_customer_id = $value;
189 update_user_meta( $userid, 'zi_contact_id', $zi_customer_id );
190 }
191 }
192 $contact_class_handle = new CMBIRD_Contact_ZI();
193 $zi_customer_id = $contact_class_handle->cmbird_create_contact_person( $userid );
194 }
195 }
196 } else {
197 $contact_class_handle = new CMBIRD_Contact_ZI();
198 $zi_customer_id = $contact_class_handle->cmbird_contact_create_function( $userid );
199 }
200 } else {
201 // fwrite($fd,PHP_EOL.'Contacts : '.print_r($json->contacts,true));
202 foreach ( $json->contacts[0] as $key => $value ) {
203 if ( $key === 'contact_id' ) {
204 $zi_customer_id = $value;
205 update_user_meta( $userid, 'zi_contact_id', $zi_customer_id );
206 }
207 }
208 }
209 }
210 // Http request not processed properly.
211 // echo $message;
212 return $zi_customer_id;
213 } else {
214 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
215 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
216 $get_url = $zoho_inventory_url . 'inventory/v1/contacts/' . $zi_customer_id . '/contactpersons/?organization_id=' . $zoho_inventory_oid;
217
218 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
219 $contactpersons_response = $execute_curl_call_handle->execute_curl_call_get( $get_url );
220
221 // fwrite( $fd, PHP_EOL . 'Contactpersons: ' . print_r($contactpersons_response, true) );
222
223 // first check within contactpersons endpoint and then map it with that contactperson if email-id matches
224 if ( $contactpersons_response->code === 0 || $contactpersons_response->code === '0' ) {
225 if ( ! empty( $contactpersons_response->contact_persons ) ) {
226 foreach ( $contactpersons_response->contact_persons as $key => $contact_persons ) {
227 $person_email = trim( $contact_persons->email );
228 if ( $person_email === trim( $user_email ) ) {
229 /* Match Contact */
230 $contactid = $contact_persons->contact_person_id;
231 update_user_meta( $userid, 'zi_contactperson_id_' . $key, $contactid );
232 if ( $contact_persons->is_primary_contact === true || $contact_persons->is_primary_contact === 1 ) {
233 $contact_class_handle = new CMBIRD_Contact_ZI();
234 $contact_class_handle->cmbird_contact_update_function( $userid, $order_id );
235 } else {
236 $contact_class_handle = new CMBIRD_Contact_ZI();
237 $contact_class_handle->cmbird_update_contact_person( $userid, $order_id );
238 }
239 }
240 }
241 } else {
242 $get_url = $zoho_inventory_url . 'inventory/v1/contacts/' . $zi_customer_id . '/?organization_id=' . $zoho_inventory_oid;
243 $contact_res = $execute_curl_call_handle->execute_curl_call_get( $get_url );
244 if ( ( $contact_res->code == 0 || $contact_res->code == '0' ) && ! empty( $contact_res->contact ) ) {
245 foreach ( $contact_res as $contact_ ) {
246 if ( trim( $contact_->email ) == trim( $user_email ) ) {
247 // fwrite( $fd, PHP_EOL . 'Inside cmbird_contact_update_function' );
248 $contact_class_handle = new CMBIRD_Contact_ZI();
249 $contact_class_handle->cmbird_contact_update_function( $userid, $order_id );
250 } else {
251 // fwrite( $fd, PHP_EOL . 'Inside cmbird_create_contact_person' );
252 $contact_class_handle = new CMBIRD_Contact_ZI();
253 $contact_class_handle->cmbird_create_contact_person( $userid );
254 }
255 }
256 }
257 }
258 }
259 // fwrite( $fd, PHP_EOL . 'No contactpersons ' );
260 }
261 // fclose( $fd );
262 }
263
264 /**
265 * Function for admin zoho sync call.
266 *
267 * @param int $order_id Order ID.
268 */
269 public function zi_order_sync( $order_id ) {
270 // $fd = fopen( __DIR__ . '/backend_order.txt', 'a+' );
271
272 if ( ! $order_id && isset( $_POST['nonce'] ) && isset( $_POST['arg_order_data'] ) ) {
273 // verify nonce
274 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['nonce'] ) ), 'zoho_admin_order_sync' ) ) {
275 wp_send_json_error( 'Nonce verification failed' );
276 }
277 $order_id = sanitize_text_field( wp_unslash( $_POST['arg_order_data'] ) );
278 }
279
280 $order = wc_get_order( $order_id );
281 // prevent multiple order syncs in a minute
282 $current_time = time();
283 $last_time = $order->get_meta( 'zi_last_order_sync_time', true );
284 if ( ! empty( $last_time ) && $current_time - $last_time < 60 ) {
285 return;
286 }
287
288 $orders_date = $order->get_date_created()->format( 'Y-m-d' );
289 $i = 1;
290 $zi_sales_order_id = $order->get_meta( 'zi_salesorder_id' );
291 $userid = $order->get_user_id();
292 $order_status = $order->get_status();
293 $note = $order->get_customer_note();
294 $notes = preg_replace( '/[^A-Za-z0-9\-]/', ' ', $note );
295 $total_shipping = $order->get_shipping_total();
296 $shipping_method = $order->get_shipping_method();
297
298 // // Get WC Subscription Signup fee
299 // $adjustment = '';
300 // if (class_exists('WC_Subscriptions_Order') && wcs_order_contains_subscription($order_id)) {
301 // $adjustment = WC_Subscriptions_Order::get_sign_up_fee($order);
302 // }
303
304 foreach ( $order->get_items() as $item_id => $item ) {
305 // fwrite($fd, PHP_EOL . '-----------------------------------');
306 $sale_order['order']['suborder'][ $i ]['order_id'] = $item_id;
307 $sale_order['order']['suborder'][ $i ]['product_id'] = $item->get_product_id();
308 $sale_order['order']['suborder'][ $i ]['variation_id'] = $item->get_variation_id();
309 $item_data = $item->get_data();
310 $sale_order['order']['suborder'][ $i ]['quantity'] = $item_data['quantity'];
311 $sale_order['order']['suborder'][ $i ]['post_order_id'] = $item_data['order_id'];
312 $sale_order['order']['suborder'][ $i ]['total'] = round( $item_data['total'], 2 );
313 $sale_order['order']['suborder'][ $i ]['subtotal'] = round( $item_data['subtotal'], 2 );
314 $sale_order['order']['suborder'][ $i ]['item_price'] = $item_data['subtotal'] / $item_data['quantity'];
315
316 // WC Product-Addons support
317 $formatted_meta_data = $item->get_formatted_meta_data();
318
319 if ( ! empty( $formatted_meta_data ) ) {
320 foreach ( $formatted_meta_data as $metavalue ) {
321
322 $meta_array[] = $metavalue->display_key . ' : ' . trim( wp_strip_all_tags( $metavalue->display_value ) ) . '\n';
323 }
324 $product_meta_str = implode( '', $meta_array );
325
326 if ( $product_meta_str ) {
327 $sale_order['order']['suborder'][ $i ]['product_desc'] = $product_meta_str;
328 } else {
329 $sale_order['order']['suborder'][ $i ]['product_desc'] = '';
330 }
331 }
332 ++$i;
333 }
334
335 if ( is_array( $sale_order ) ) {
336
337 // If user id and email is empty then break process.
338 if ( empty( $userid ) && empty( $user_email ) ) {
339 // fwrite($fd,PHP_EOL.'ALL EMPTY');
340 $order->add_order_note( 'Zoho Order Sync: guest orders are not supported' );
341 $order->save();
342 return;
343 }
344 $val_order = array_shift( $sale_order );
345 // fwrite($fd, PHP_EOL . 'USER ID : ' . $userid);
346 $zi_customer_id = get_user_meta( $userid, 'zi_contact_id', true );
347 $billing_id = get_user_meta( $userid, 'zi_billing_address_id', true );
348 $shipping_id = get_user_meta( $userid, 'zi_shipping_address_id', true );
349 $user_email = get_user_meta( $userid, 'billing_email', true );
350 $enable_incl_tax = get_option( 'woocommerce_prices_include_tax' );
351
352 if ( $order_status !== 'failed' ) {
353
354 if ( empty( $zi_customer_id ) ) {
355 $zi_customer_id = $this->cmbird_zi_sync_customer_checkout( $order_id );
356 } else {
357 $contact_class_handle = new CMBIRD_Contact_ZI();
358 $contact_class_handle->cmbird_contact_update_function( $userid, $order_id );
359 }
360 // fwrite($fd,PHP_EOL.'$zi_customer_id : '.$zi_customer_id);
361 $index = 0;
362 foreach ( $val_order['suborder'] as $key => $val ) {
363 // fwrite( $fd, PHP_EOL . 'Val: ' . print_r( $val, true ) );
364
365 $proid = $val['product_id'];
366 $proidv = $val['variation_id'];
367 if ( $proidv > 0 ) {
368 $proid = $proidv;
369 $item_id = get_post_meta( $proid, 'zi_item_id', true );
370 } else {
371 $item_id = get_post_meta( $proid, 'zi_item_id', true );
372 }
373 if ( empty( $item_id ) ) {
374 $product_handler = new CMBIRD_Products_ZI_Export();
375 $product_response = $product_handler->cmbird_zi_product_sync( $proid );
376 // fwrite($fd,PHP_EOL.'Product sync: '.print_r($product_response, true));
377 }
378 // Skip bundled order items
379 if ( function_exists( 'wc_pb_is_bundled_order_item' ) ) {
380 $order_item = $order->get_item( $val['order_id'] );
381 $is_bundled = wc_pb_is_bundled_order_item( $order_item, $order );
382 if ( $is_bundled ) {
383 continue;
384 }
385 }
386
387 $product_description = isset( $val['product_desc'] ) ? $val['product_desc'] : '';
388 if ( ! empty( $product_description ) ) {
389 $product_desc = sanitize_text_field( $product_description );
390 $product_desc = preg_replace( '/[^A-Za-z0-9 :\-]/', '', $product_desc );
391 }
392 $discount_per_item = '';
393
394 $qty = ( $val['quantity'] ) ? $val['quantity'] : 1;
395 // adding warehouse_id in line items array
396 $warehouse_id = get_option( 'cmbird_zoho_warehouse_id_status' );
397 if ( $warehouse_id > 0 ) {
398 $warehouse_id = ',"warehouse_id": "' . $warehouse_id . '"';
399 } else {
400 $warehouse_id = '';
401 }
402 // if $val['total] is lower than $val['subtotal'] then discount is applied
403 if ( $val['total'] < $val['subtotal'] ) {
404 $discount = $val['subtotal'] - $val['total'];
405 $discount_per_item = '"discount": "' . $discount . '",';
406 }
407
408 $item_price = $val['subtotal'] / $qty;
409 // Format item price upto two decimal places.
410 $item_price1 = round( $item_price, 2 );
411
412 // if there is vat exempt tax
413 $order_id = $val['post_order_id'];
414 $tax_value = $order->get_total_tax();
415 $tax_rates = array();
416 // Apply tax rates zero only if order has no values
417 if ( ! empty( $tax_value ) ) {
418 foreach ( $order->get_items( 'tax' ) as $item ) {
419 $tax_rates[ $item->get_rate_id()] = $item->get_rate_percent();
420 }
421 $order_item = $order->get_item( $val['order_id'] );
422 $item_taxes = $order_item->get_taxes();
423 $tax_rate_id = current( array_keys( $item_taxes['subtotal'] ) );
424 $tax_percent = $tax_rates[ $tax_rate_id ];
425 // get zoho tax id
426 $zi_tax_id = $this->zi_get_tax_id( $tax_percent );
427 $taxid = '"tax_percentage": "' . $tax_percent . '", "tax_id": "' . $zi_tax_id . '",';
428
429 $item_price = $item_price1 * ( $tax_percent / 100 + 1 );
430 $item_price = round( $item_price, 2 );
431 }
432 if ( $enable_incl_tax === 'yes' ) {
433 $pdt_items[] = '{"item_id": "' . $item_id . '","description": "' . $product_desc . '","quantity": "' . $qty . '",' . $taxid . '' . $discount_per_item . '"rate": "' . $item_price . '"' . $warehouse_id . '}';
434 } else {
435 $pdt_items[] = '{"item_id": "' . $item_id . '","description": "' . $product_desc . '","quantity": "' . $qty . '",' . $taxid . '' . $discount_per_item . '"rate": "' . $item_price1 . '"' . $warehouse_id . '}';
436 }
437 ++$index;
438 }
439
440 // Shipping Tax
441 $shipping_tax_id = '';
442 $shipping_tax = $order->get_shipping_tax();
443 $shipping_tax_total = $order->get_shipping_total();
444
445 if ( ! empty( $shipping_tax ) && ! empty( $shipping_tax_total ) ) {
446
447 $tax_percentage = ( ( $shipping_tax / $shipping_tax_total ) * 100 );
448 if ( fmod( $tax_percentage, 1 ) !== 0 ) {
449 $percentage = number_format( $tax_percentage, 2 );
450 $percent_decimal = $percentage * 100;
451 $decimal_place = $percent_decimal % 10;
452 if ( $decimal_place === 0 ) {
453 $percentage = number_format( $percentage, 1 );
454 }
455 } else {
456 $percentage = round( $tax_percentage );
457 }
458 }
459
460 if ( is_array( $pdt_items ) ) {
461 $impot = implode( ',', $pdt_items );
462 }
463
464 $pdt1 = '"customer_id": "' . $zi_customer_id . '","date": "' . $orders_date . '","line_items": [' . $impot . '],"is_discount_before_tax": "true","discount_type": "item_level","price_precision":"2","notes": "' . $notes . '","billing_address_id": "' . $billing_id . '","shipping_address_id": "' . $shipping_id . '","delivery_method": "' . $shipping_method . '"';
465
466 // if there is shipping tax
467 if ( ! empty( $shipping_tax ) ) {
468 $shipping_tax_id = $this->zi_get_tax_id( $percentage );
469 $pdt1 .= ',"shipping_charge_tax_id":"' . $shipping_tax_id . '"';
470 }
471
472 // Check if there are order fees total is more than 0
473 $order_fees = $order->get_fees();
474 // $transaction_fee = get_transaction_fees($order_id);
475 if ( ! empty( $order_fees ) ) {
476 foreach ( $order_fees as $order_fee ) {
477 $fee_name = $order_fee->get_name();
478 $fee_total = $order_fee->get_total();
479 }
480 if ( $fee_total > 0 ) {
481 $pdt1 .= ',"adjustment":' . $fee_total . '';
482 $pdt1 .= ',"adjustment_description":"' . $fee_name . '"';
483 }
484 }
485 // } elseif (!empty($transaction_fee)) {
486 // $pdt1 .= ',"adjustment":"' . -$transaction_fee . '"';
487 // $pdt1 .= ',"adjustment_description":"Stripe Fee"';
488 // }
489
490 $response_msg = '';
491
492 // Send orders as confirmed
493 $order_status = get_option( 'cmbird_zoho_enable_order_status_status' );
494 if ( $order_status ) {
495 $pdt1 .= ',"order_status": "draft"';
496 } else {
497 $pdt1 .= ',"order_status": "confirmed"';
498 }
499
500 // if items are incl. tax
501 $total_shipping1 = $total_shipping + $shipping_tax;
502 if ( $enable_incl_tax == 'yes' ) {
503 $pdt1 .= ',"is_inclusive_tax": true';
504 $pdt1 .= ',"shipping_charge":"' . round( $total_shipping1, 2 ) . '"';
505 } else {
506 $pdt1 .= ',"is_inclusive_tax": false';
507 $pdt1 .= ',"shipping_charge":"' . round( $total_shipping, 2 ) . '"';
508 }
509
510 // Custom Field mapping with zoho.
511 $getmappedfields = get_option( 'cmbird_wootozoho_custom_fields' );
512 $customfield = ',"custom_fields":[';
513
514 $data = json_decode( $getmappedfields, true );
515 if ( $data !== null ) {
516 $count = count( $data );
517 $i = 0;
518 foreach ( $data as $key => $label ) {
519 // Get the meta value which is the meta_key
520 $metavalue = $order->get_meta( $key );
521 // Add the custom field to the JSON string
522 $customfield .= '{"label": "' . $label . '","value":"' . $metavalue . '"}';
523 // Add comma if it's not the last iteration
524 if ( ++$i < $count ) {
525 $customfield .= ',';
526 }
527 }
528 }
529 $pdt1 .= $customfield . ']';
530
531 // If auto order number is enabled.
532 $enabled_auto_no = get_option( 'cmbird_zoho_enable_auto_number_status' );
533 $transaction_id = $order->get_transaction_id();
534 if ( empty( $transaction_id ) ) {
535 $transaction_id = $order->get_meta( '_order_number', true );
536 }
537 $order_prefix = get_option( 'cmbird_zoho_order_prefix_status' );
538 $reference_no = '';
539 if ( class_exists( 'WCJ_Order_Numbers' ) || class_exists( 'WC_Seq_Order_Number_Pro' ) ) {
540 $reference_no = $order_prefix . $transaction_id;
541 } elseif ( ! empty( $order_prefix ) ) {
542 $reference_no = $order_prefix . '-' . $order_id;
543 } else {
544 $reference_no = $order_id;
545 }
546 // if auto-generated sales order number is enabled.
547 if ( $enabled_auto_no ) {
548 $pdt1 .= ',"reference_number": "' . $reference_no . '"';
549 } else {
550 $pdt1 .= ',"salesorder_number": "' . $order_id . '"';
551 }
552
553 // add gst_no and gst_treatment to the order
554 $gst_no = get_user_meta( $userid, 'gst_no', true );
555 $gst_treatment = get_user_meta( $userid, 'gst_treatment', true );
556 if ( ! empty( $gst_no ) ) {
557 $pdt1 .= ',"gst_no": "' . $gst_no . '"';
558 $pdt1 .= ',"gst_treatment": "' . $gst_treatment . '"';
559 }
560
561 // fwrite($fd, PHP_EOL . '$pdt1 : {' . $pdt1 . '}');
562
563 if ( $zi_sales_order_id != '' ) {
564 $response_msg = $this->single_saleorder_zoho_inventory_update( $order_id, $zi_sales_order_id, $pdt1 );
565 // fwrite($fd,PHP_EOL.'Update response : '.$response_msg);
566 } else {
567 $response_msg = $this->single_saleorder_zoho_inventory( $pdt1 );
568 }
569 // fwrite($fd,PHP_EOL.'Update response : '. print_r($response_msg, true));
570
571 $order->update_meta_data( 'zi_body_request', $pdt1 );
572
573 $notes = 'Zoho Order Sync: ' . $response_msg['message'];
574
575 // end logging.
576 // fclose( $fd );
577
578 $order->add_order_note( $notes );
579 $order->update_meta_data( 'zi_salesorder_id', $response_msg['zi_salesorder_id'] );
580 $order->update_meta_data( 'zi_last_order_sync_time', $current_time );
581 $order->save();
582 }
583 return;
584 }
585 }
586
587 /**
588 * Void the sales order if cancelled in WooCommerce.
589 *
590 * @param int $order_id Order ID.
591 */
592 public function salesorder_void( $order_id ) {
593 if ( ! $order_id ) {
594 return;
595 }
596 $zoho_inventory_access_token = get_option( 'cmbird_zoho_inventory_access_token' );
597 if ( empty( $zoho_inventory_access_token ) ) {
598 return;
599 }
600
601 $order = wc_get_order( $order_id );
602 // return if order is already voided
603 if ( $order->get_meta( 'zi_salesorder_void', true ) ) {
604 return;
605 }
606 $order_status = $order->get_status();
607
608 if ( $order_status == 'cancelled' || $order_status == 'wc-merged' ) {
609 $zi_sales_order_id = $order->get_meta( 'zi_salesorder_id', true );
610 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
611 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
612
613 $url = $zoho_inventory_url . 'inventory/v1/salesorders/' . $zi_sales_order_id . '/status/void?organization_id=' .
614 $zoho_inventory_oid;
615 $data = '';
616 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
617 $json = $execute_curl_call_handle->execute_curl_call_post( $url, $data );
618
619 $errmsg = $json->message;
620 $code = $json->code;
621 if ( $code == '0' || $code == 0 ) {
622 // Add order meta key "zi_salesorder_void" to true
623 $order->update_meta_data( 'zi_salesorder_void', true );
624 $order->add_order_note( 'Zoho Order Void: ' . $errmsg );
625 $order->save();
626 return;
627 }
628 } else {
629 return;
630 }
631 }
632
633 /**
634 * Sync order from Woo to Zoho.
635 *
636 * @param string $pdt1 JSON string
637 * @return string Error message
638 */
639 public function single_saleorder_zoho_inventory( $pdt1 ) {
640 //start logging
641 // $fd = fopen( __DIR__ . '/order-sync-backend.txt', 'w+' );
642
643 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
644 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
645
646 $data = array(
647 'JSONString' => '{' . $pdt1 . '}',
648 'organization_id' => $zoho_inventory_oid,
649 );
650
651 //logging
652 // fwrite($fd, PHP_EOL . 'Data log : ' . print_r($data, true));
653
654 $enabled_auto_no = get_option( 'cmbird_zoho_enable_auto_number_status' );
655 $ignore_auto_no = ( $enabled_auto_no ) ? 'false' : 'true';
656 $url = $zoho_inventory_url . 'inventory/v1/salesorders?ignore_auto_number_generation=' . $ignore_auto_no;
657
658 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
659 $json = $execute_curl_call_handle->execute_curl_call_post( $url, $data );
660
661 // fwrite( $fd, PHP_EOL . 'Data log : ' . print_r( $json, true ) );
662 $response = array();
663 $code = $json->code;
664 // fwrite($fd, PHP_EOL . 'Code : ' . $code);
665
666 if ( '0' === $code || 0 === $code ) {
667 foreach ( $json->salesorder as $key => $value ) {
668
669 if ( 'salesorder_id' === $key ) {
670 $response['zi_salesorder_id'] = $value;
671 // $order->add_meta_data('zi_salesorder_id', $value, true);
672 }
673 }
674 }
675 $errmsg = $json->message;
676 $response['message'] = $errmsg;
677 // fclose( $fd );
678
679 return $response;
680 }
681
682 /**
683 * Function for updating single sales order.
684 *
685 * @param int $order_id Order ID.
686 * @param string $zi_sales_order_id
687 * @param string $pdt1 JSON string
688 * @return string Error message
689 */
690 public function single_saleorder_zoho_inventory_update( $order_id, $zi_sales_order_id, $pdt1 ) {
691 // $fd = fopen( __DIR__. '/single_saleorder_update.txt', 'w+' );
692
693 $response = array();
694 $zoho_inventory_oid = get_option( 'cmbird_zoho_inventory_oid' );
695 $zoho_inventory_url = get_option( 'cmbird_zoho_inventory_url' );
696
697 $url = $zoho_inventory_url . 'inventory/v1/salesorders/' . $zi_sales_order_id;
698 $data = array(
699 'JSONString' => '{' . $pdt1 . '}',
700 'organization_id' => $zoho_inventory_oid,
701 );
702
703 $order = wc_get_order( $order_id );
704 // fwrite($fd, PHP_EOL. print_r($data, true)); //logging response
705 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
706 $json = $execute_curl_call_handle->execute_curl_call_put( $url, $data );
707
708 // $code = $json->code;
709 $errmsg = $json->message;
710 $response['message'] = $errmsg;
711 $response['zi_salesorder_id'] = $zi_sales_order_id;
712
713 // echo '<pre>'; print_r($errmsg);
714
715 $package_id = $order->get_meta( 'zi_package_id', true );
716
717 if ( ! empty( $package_id ) ) {
718 // fwrite($fd, PHP_EOL. 'inside package exists'); //logging response
719 foreach ( $json->salesorder as $key => $value ) {
720 if ( $key == 'date' ) {
721 $ship_date = $value;
722 }
723
724 if ( $key == 'line_items' ) {
725 foreach ( $value as $kk => $vv ) {
726 $line_items[] = '{"so_line_item_id": "' . $vv->line_item_id . '","quantity": "' . $vv->quantity . '"}';
727 }
728 $impot = implode( ',', $line_items );
729
730 $json_package = '"date": "' . $ship_date . '","line_items": [' . $impot . ']';
731
732 $url_package = $zoho_inventory_url . 'inventory/v1/packages/' . $package_id;
733 $data3 = array(
734 'JSONString' => '{' . $json_package . '}',
735 'organization_id' => $zoho_inventory_oid,
736 );
737
738 $res_package = $execute_curl_call_handle->execute_curl_call_put( $url_package, $data3 );
739 }
740 }
741 }
742 // fclose( $fd ); //end of logging
743 return $response;
744 }
745
746 /**
747 * Function to get all Zoho Taxes.
748 *
749 * @param int $percentage Tax percentage.
750 * @return string Tax ID.
751 */
752 protected function zi_get_tax_id( $percentage ) {
753 // $fd = fopen( __DIR__ . '/zi_get_tax_id.txt', 'a+' );
754 // get all options that contain zoho_inventory_tax_rate_ in the name using global $wpdb.
755 global $wpdb;
756 $zoho_tax_rates = $wpdb->get_results( "SELECT option_name, option_value FROM $wpdb->options WHERE option_name LIKE 'cmbird_zoho_inventory_tax_rate_%'" );
757 $input_tax_percentage = floor( $percentage * 10 ) / 10;
758 // fwrite( $fd, PHP_EOL . 'Input Tax Percentage: ' . $input_tax_percentage );
759 $tax_id = '';
760 // for each zoho_tax_rate, check if the tax percentage matches the input percentage. The percentage at the end of the value e.g. 69497000002395146##BTW@@Hoog Exclusief##tax##21
761 foreach ( $zoho_tax_rates as $zoho_tax_rate ) {
762 $tax_rate = explode( '##', $zoho_tax_rate->option_value );
763 $tax_percentage = $tax_rate[3];
764 // Round the stored tax percentage to one decimal place for comparison
765 $stored_tax_percentage = round( $tax_percentage, 1 );
766 // Compare the rounded tax percentages with a tolerance for floating-point precision errors
767 if ( abs( $stored_tax_percentage - $input_tax_percentage ) < 0.01 ) {
768 $tax_id = $tax_rate[0];
769 break;
770 }
771 }
772 return $tax_id;
773 }
774
775 /**
776 * TODO: Get Order Transaction Fees
777 *
778 * @param int $order_id Order ID.
779 * @return float Transaction fees
780 */
781 protected function get_transaction_fees( $order_id ) {
782 $order = wc_get_order( $order_id );
783 switch ( true ) {
784 // get fees from Stripe, if exists
785 case $fees = $order->get_meta( '_stripe_fee' );
786 break;
787 // get fees from Paypal, if exists
788 case $fees = $order->get_meta( '_paypal_transaction_fee' ):
789 break;
790 // otherwise fee is 0
791 default:
792 $fees = 0;
793 break;
794 }
795 return $fees;
796 }
797 }
798 $CMBIRD_Order_Sync_ZI = new CMBIRD_Order_Sync_ZI();
799