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