PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.5.1
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.5.1
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 / admin / includes / Actions / Ajax / ZohoCRMAjax.php
commercebird / admin / includes / Actions / Ajax Last commit date
AcfAjax.php 11 months ago ExactOnlineAjax.php 11 months ago SettingsAjax.php 11 months ago ZohoCRMAjax.php 11 months ago ZohoInventoryAjax.php 11 months ago index.php 1 year ago
ZohoCRMAjax.php
777 lines
1 <?php
2
3 namespace CommerceBird\Admin\Actions\Ajax;
4
5 use CMBIRD_Auth_Zoho;
6 use CMBIRD_API_Handler_Zoho;
7 use CommerceBird\Admin\Actions\Sync\ZohoCRMSync;
8 use CommerceBird\Admin\Template;
9 use CommerceBird\Admin\Traits\AjaxRequest;
10 use CommerceBird\Admin\Traits\OptionStatus;
11 use CommerceBird\Admin\Traits\Singleton;
12 use CommerceBird\Admin\Traits\LogWriter;
13 use WC_Tax;
14 use Throwable;
15
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit;
19 }
20 /**
21 * Initializes the Zoho CRM class.
22 *
23 * @since 1.0.0
24 * @return void
25 */
26 final class ZohoCRMAjax {
27
28 use Singleton;
29 use AjaxRequest;
30 use OptionStatus;
31 use LogWriter;
32
33
34
35 private const FORMS = array(
36 // 'connect' => array(.
37 // 'token',.
38 // ),.
39 'product' => array(
40 'importProducts',
41 ),
42 'order' => array( 'range' ),
43 'order_settings' => array(
44 'syncAsDeals',
45 ),
46 'order_field_mapping' => array(
47 'dealFields',
48 ),
49 'order_status_stage_mapping' => array(
50 'mapping',
51 ),
52 'customer' => array(
53 'importCustomers',
54 ),
55 'fields' => array(
56 'form',
57 'module',
58 ),
59 'tax' => array(
60 'selectedTaxRates',
61 ),
62 );
63 private const ACTIONS = array(
64 'get_zcrm_connect' => 'connection_get',
65 'save_zcrm_connect' => 'connection_set',
66 'reset_zcrm_connect' => 'connection_reset',
67 'is_zcrm_connected' => 'connection_done',
68 'import_zcrm_product' => 'product_import',
69 'map_zcrm_product' => 'product_map',
70 'map_zcrm_customer' => 'customer_map',
71 'map_zcrm_order' => 'order_map',
72 'export_zcrm_order' => 'order_export',
73 'get_zcrm_order_settings' => 'order_settings_get',
74 'save_zcrm_order_settings' => 'order_settings_save',
75 'get_zcrm_deal_fields' => 'deal_fields_get',
76 'get_zcrm_deal_field_mapping' => 'deal_field_mapping_get',
77 'save_zcrm_deal_field_mapping' => 'deal_field_mapping_save',
78 'get_wc_order_statuses' => 'wc_order_statuses_get',
79 'get_zcrm_deal_stages' => 'deal_stages_get',
80 'get_order_status_stage_mapping' => 'order_status_stage_mapping_get',
81 'save_order_status_stage_mapping' => 'order_status_stage_mapping_save',
82 'refresh_zcrm_fields' => 'refresh_zcrm_fields',
83 'zcrm_get_custom_fields' => 'zcrm_get_custom_fields',
84 'zcrm_save_custom_fields' => 'zcrm_save_custom_fields',
85 'zcrm_reset_custom_fields' => 'zcrm_reset_custom_fields',
86 'zcrm_fields' => 'get_zcrm_fields',
87 'zcrm_handle_code' => 'handle_code',
88 'get_zcrm_tax' => 'tax_get',
89 'save_zcrm_tax' => 'tax_set',
90 'reset_zcrm_tax' => 'tax_reset',
91 'get_wc_taxes' => 'wc_tax_collect',
92 'get_zcrm_taxes' => 'zoho_tax_rates_collect',
93 'get_zcrm_layouts' => 'layouts_get',
94 'save_zcrm_layout' => 'layout_save',
95 'get_zcrm_selected_layout' => 'layout_get_selected',
96 );
97 private const OPTIONS = array(
98 // 'connect' => array(.
99 // 'token' => 'commercebird-exact-online-token',.
100 // ),.
101 'zcrm_sales_orders_fields' => 'zcrm_sales_orders_fields',
102 'zcrm_contacts_fields' => 'zcrm_contacts_fields',
103 'zcrm_products_fields' => 'zcrm_products_fields',
104 'zcrm_sales_order_layout' => 'zcrm_sales_order_layout',
105 );
106
107 public function __construct() {
108 $this->load_actions();
109 }
110
111 /**
112 * Sets the connection for the Zoho crm API.
113 */
114 public function connection_set(): void {
115 $this->verify(
116 array(
117 'account_domain',
118 'client_id',
119 'client_secret',
120 'redirect_uri',
121 ),
122 );
123 try {
124 $crm_url = sprintf( 'https://www.zohoapis.%s/', $this->data['account_domain'] );
125 update_option( 'cmbird_zoho_crm_domain', $this->data['account_domain'] );
126 update_option( 'cmbird_zoho_crm_cid', $this->data['client_id'] );
127 update_option( 'cmbird_zoho_crm_cs', $this->data['client_secret'] );
128 update_option( 'cmbird_zoho_crm_url', $crm_url );
129 update_option( 'cmbird_authorization_redirect_uri', $this->data['redirect_uri'] );
130 $redirect = esc_url_raw(
131 'https://accounts.zoho.'
132 . $this->data['account_domain']
133 . '/oauth/v2/auth?response_type=code&client_id='
134 . $this->data['client_id'] . '&scope=ZohoCRM.users.ALL,ZohoCRM.bulk.ALL,ZohoCRM.modules.ALL,ZohoCRM.settings.ALL,ZohoCRM.org.ALL,profile.userphoto.READ,ZohoFiles.files.CREATE&redirect_uri='
135 . $this->data['redirect_uri'] . '&prompt=consent&access_type=offline&state='
136 . wp_create_nonce( Template::NAME )
137 );
138 $this->response = array(
139 'redirect' => $redirect,
140 'message' => 'We are redirecting you to zoho. please wait...',
141 );
142 } catch ( Throwable $throwable ) {
143 $this->errors = array( 'message' => $throwable->getMessage() );
144 }
145
146 $this->serve();
147 }
148
149 /**
150 * Retrieves the connection details.
151 *
152 * @return void
153 */
154 public function connection_get(): void {
155 $this->verify();
156 $this->response['account_domain'] = get_option( 'cmbird_zoho_crm_domain' );
157 $this->response['client_id'] = get_option( 'cmbird_zoho_crm_cid' );
158 $this->response['client_secret'] = get_option( 'cmbird_zoho_crm_cs' );
159 $this->response['crm_url'] = get_option( 'cmbird_zoho_crm_url' );
160 $this->response['redirect_uri'] = get_option( 'cmbird_authorization_redirect_uri' );
161 $this->serve();
162 }
163
164 /**
165 * Handles the oAuth code.
166 */
167 public function handle_code(): void {
168 $this->verify();
169 if ( array_key_exists( 'code', $this->request ) ) {
170 $class_functions = new CMBIRD_Auth_Zoho();
171 $code = $this->request['code'];
172 try {
173 $access_token = $class_functions->get_zoho_access_token( $code, 'zoho_crm' );
174 if ( array_key_exists( 'access_token', $access_token ) ) {
175 update_option( 'cmbird_zoho_crm_auth_code', $code );
176 update_option( 'cmbird_zoho_crm_access_token', $access_token['access_token'] );
177 update_option( 'cmbird_zoho_crm_refresh_token', $access_token['refresh_token'] );
178 update_option( 'cmbird_zoho_crm_timestamp', strtotime( gmdate( 'Y-m-d H:i:s' ) ) + $access_token['expires_in'] );
179 $this->response = (array) $access_token;
180 } else {
181 $this->errors = (array) $access_token;
182 }
183 } catch ( Throwable $throwable ) {
184 $this->errors = array( 'message' => $throwable->getMessage() );
185 }
186 }
187 $this->serve();
188 }
189
190 /**
191 * Resets the connection by deleting specific options from the database.
192 */
193 public function connection_reset(): void {
194 $this->verify();
195 try {
196 $options = array(
197 'cmbird_zoho_crm_domain',
198 'cmbird_zoho_crm_cid',
199 'cmbird_zoho_crm_cs',
200 'cmbird_zoho_crm_url',
201 'cmbird_zoho_crm_access_token',
202 );
203 foreach ( $options as $zi_option ) {
204 delete_option( $zi_option );
205 }
206 $this->response = array( 'message' => 'Reset successfully!' );
207 } catch ( Throwable $throwable ) {
208 $this->errors = array( 'message' => $throwable->getMessage() );
209 }
210
211 $this->serve();
212 }
213
214
215 public function connection_done() {
216 $this->verify();
217 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
218 $url = $zoho_crm_url . 'crm/v7/org';
219 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
220 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
221 if ( is_wp_error( $json ) ) {
222 $this->errors = array( 'message' => $json->get_error_message() );
223 } elseif ( empty( $json ) ) {
224 $this->errors = array( 'message' => 'We lost connection with zoho. please refresh page.' );
225 } else {
226 $this->response = ! empty( $json->org ) ? (array) $json->org[0] : array();
227 // schedule a wp cron to refresh the token after one hour from now.
228 if ( ! wp_next_scheduled( 'zcrm_refresh_token' ) ) {
229 wp_schedule_event( time() + 3600, 'hourly', 'zcrm_refresh_token' );
230 } else {
231 // unschedule first and reschedule.
232 wp_unschedule_event( wp_next_scheduled( 'zcrm_refresh_token' ), 'zcrm_refresh_token' );
233 wp_schedule_event( time() + 3600, 'hourly', 'zcrm_refresh_token' );
234 }
235 }
236 $this->serve();
237 }
238
239 /**
240 * Get Zoho CRM custom fields.
241 *
242 * @since 1.0.0
243 * @return void
244 */
245 public function refresh_zcrm_fields() {
246 $module = isset( $_GET['module'] ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended.
247 if ( empty( $module ) ) {
248 $this->errors['message'] = 'Module name is required.';
249 } else {
250 $fields = ( new ZohoCRMSync() )->get_custom_fields( $module );
251 if ( is_wp_error( $fields ) ) {
252 $this->errors['message'] = $fields->get_error_message();
253 } else {
254 $option_name = 'zcrm_' . strtolower( $module ) . '_fields';
255 update_option( self::OPTIONS[ $option_name ], $fields );
256 $this->response = array( 'message' => 'Refresh successfully!' );
257 $this->response['fields'] = $fields;
258 }
259 $this->serve();
260 }
261 }
262
263 /**
264 * Get Zoho CRM fields from WordPress database.
265 */
266 public function get_zcrm_fields() {
267 $module = isset( $_GET['module'] ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended.
268 if ( empty( $module ) ) {
269 $this->errors['message'] = 'Module name is required.';
270 } else {
271 $fields = get_option( 'zcrm_' . strtolower( $module ) . '_fields', array() );
272 $this->response['fields'] = $fields;
273 $this->serve();
274 }
275 }
276
277 /**
278 * Retrieves the fields and serves the response.
279 *
280 * @return object
281 */
282 public function zcrm_get_custom_fields(): void {
283
284 $module = isset( $_GET['module'] ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended.
285
286 if ( empty( $module ) ) {
287 $this->errors['message'] = 'Module name is required.';
288 } else {
289 $this->verify();
290 $option_name = 'zcrm_' . strtolower( $module ) . '_custom_fields';
291 $this->response['form'] = get_option( $option_name, array() );
292 $this->serve();
293 }
294 }
295
296 /**
297 * Sets the custom fields for the form.
298 *
299 * @return void
300 */
301 public function zcrm_save_custom_fields(): void {
302 $this->verify( self::FORMS['fields'] );
303 $module = isset( $this->data['module'] ) ? $this->data['module'] : '';
304 if ( empty( $module ) ) {
305 $this->errors['message'] = 'Module name is required.';
306 } else {
307 try {
308 $option_name = 'zcrm_' . strtolower( $module ) . '_custom_fields';
309 update_option( $option_name, $this->data['form'] );
310 $this->response = array( 'message' => 'saved' );
311 } catch ( Throwable $throwable ) {
312 $this->errors = array( 'message' => $throwable->getMessage() );
313 }
314 $this->serve();
315 }
316 }
317
318 /**
319 * Resets the fields.
320 *
321 * @return void
322 */
323 public function zcrm_reset_custom_fields(): void {
324 $module = isset( $_GET['module'] ) ? sanitize_text_field( wp_unslash( $_GET['module'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended.
325 if ( empty( $module ) ) {
326 $this->errors['message'] = 'Module name is required.';
327 } else {
328 $this->verify();
329 $option_name = 'zcrm_' . strtolower( $module ) . '_custom_fields';
330 delete_option( $option_name );
331 $this->response = array( 'message' => 'Reset successfully!' );
332 $this->serve();
333 }
334 }
335
336 /**
337 * Export Orders to Zoho CRM.
338 *
339 * @param int $start_date_raw The start date.
340 * @param int $end_date_raw The end date.
341 */
342 public function export_order( $start_date_raw, $end_date_raw ) {
343 // $fd = fopen( __DIR__ . '/export_order.log', 'a+' );
344
345 $start_date = gmdate( 'Y-m-d H:i:s', $start_date_raw );
346 $end_date = gmdate( 'Y-m-d H:i:s', $end_date_raw );
347 // Define the order statuses to exclude.
348 $exclude_statuses = array( 'wc-failed', 'wc-cancelled', 'wc-checkout-draft' );
349 $posts_per_page = 20;
350 $paged = 1;
351
352 do {
353 // Query to get orders.
354 $args = array(
355 'date_created' => $start_date . '...' . $end_date,
356 'status' => array_diff( array_keys( wc_get_order_statuses() ), $exclude_statuses ),
357 'limit' => $posts_per_page,
358 'paged' => $paged,
359 'orderby' => 'date',
360 'order' => 'ASC',
361 'return' => 'ids',
362 );
363 $orders = wc_get_orders( $args );
364 // Loop through orders and schedule them for Zoho CRM sync.
365 foreach ( $orders as $order_id ) {
366 // Use WC Action Scheduler to sync the order to Zoho CRM.
367 $existing_schedule = as_has_scheduled_action( 'sync_zcrm_order', array( $order_id ) );
368 if ( ! $existing_schedule ) {
369 as_schedule_single_action( time(), 'sync_zcrm_order', array( $order_id ) );
370 }
371 }
372 // Increment the offset for the next batch.
373 ++$paged;
374 } while ( ! empty( $orders ) );
375 // fclose( $fd );
376 }
377
378 public function order_export() {
379 $this->verify( self::FORMS['order'] );
380 if ( empty( $this->data ) || empty( $this->data['range'] ) ) {
381 $this->response['success'] = false;
382 $this->response['message'] = __( 'Select dates', 'commercebird' );
383 $this->serve();
384 }
385 // Set the date range to last 30 days.
386 $start_date = strtotime( $this->data['range'][0] );
387 $end_date = strtotime( $this->data['range'][1] );
388 $zoho_crm_access_token = get_option( 'cmbird_zoho_crm_access_token' );
389 if ( empty( $zoho_crm_access_token ) ) {
390 $this->response['success'] = false;
391 $this->response['message'] = __( 'Zoho CRM is not Connected.', 'commercebird' );
392 $this->serve();
393 }
394 $this->export_order( $start_date, $end_date );
395 $this->response['success'] = true;
396 $this->response['message'] = __( 'Exported', 'commercebird' );
397 $this->serve();
398 }
399
400 /**
401 * Retrieves an array of all tax rates from WooCommerce.
402 *
403 * @return array An array of all tax rates.
404 */
405 public function wc_taxes(): array {
406 $wc_tax_array = array();
407 $tax_classes = WC_Tax::get_tax_classes(); // Retrieve all tax classes.
408 if ( ! in_array( '', $tax_classes ) ) { // Make sure "Standard rate" (empty class name) is present.
409 array_unshift( $tax_classes, '' );
410 }
411
412 foreach ( $tax_classes as $tax_class ) { // For each tax class, get all rates.
413 $taxes = WC_Tax::get_rates_for_tax_class( $tax_class );
414
415 foreach ( $taxes as $key => $tax ) {
416 $taxarray = (array) $tax;
417 $taxarray['id'] = $key;
418 $wc_tax_array[] = $taxarray;
419 }
420 }
421
422 return $wc_tax_array;
423 }
424 /**
425 * Executes the wc_tax_collect function.
426 *
427 * This function verifies the current state, retrieves the taxes using the
428 * wc_taxes method, and serves the response.
429 */
430 public function wc_tax_collect(): void {
431 $this->verify();
432 $this->response = $this->wc_taxes();
433 $this->serve();
434 }
435
436 /**
437 * Retrieves the tax information.
438 *
439 * @return void
440 */
441 public function tax_get(): void {
442 $this->verify();
443 $this->response = array();
444 foreach ( $this->wc_taxes() as $tax ) {
445 $this->response['selectedTaxRates'][] = $tax['id'] . '^^' . get_option( 'cmbird_zoho_crm_tax_rate_' . $tax['id'] );
446 }
447 $this->serve();
448 }
449
450
451 /**
452 * Saves tax rates to the database.
453 */
454 public function tax_set(): void {
455 $this->verify( self::FORMS['tax'] );
456 $rates = array_filter( $this->data['selectedTaxRates'] );
457 try {
458 foreach ( $rates as $value ) {
459 $valarray = explode( '^^', $value );
460 update_option( 'cmbird_zoho_crm_tax_rate_' . $valarray[0], $valarray[1] );
461 }
462 $this->response = array( 'message' => 'Saved' );
463 } catch ( Throwable $throwable ) {
464 $this->errors = array( 'message' => $throwable->getMessage() );
465 }
466
467 $this->serve();
468 }
469
470 /**
471 * Resets the tax settings.
472 *
473 * This function verifies the tax settings and then deletes the options
474 * related to the tax rates
475 *
476 * @return void
477 */
478 public function tax_reset(): void {
479 $this->verify();
480 foreach ( $this->wc_taxes() as $tax ) {
481 delete_option( 'cmbird_zoho_crm_tax_rate_' . $tax['id'] );
482 }
483 $this->response = array( 'message' => 'Reset successfully!' );
484 $this->serve();
485 }
486
487 /**
488 * Retrieves the Zoho tax rates for the organization.
489 *
490 * This function verifies the request, retrieves the organization ID and URL
491 * from the options, constructs the URL for the API request, and executes
492 * the cURL call to fetch the tax rates. If the response contains the
493 * 'taxes' key, it sets the response to the tax rates. Otherwise, it sets
494 * the errors to a default message.
495 */
496 public function zoho_tax_rates_collect(): void {
497 $this->verify();
498 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
499 $url = $zoho_crm_url . 'crm/v7/org/taxes';
500 try {
501 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
502 $json = (array) $execute_curl_call_handle->execute_curl_call_get( $url );
503
504 // error_log('Data: ' . print_r($response, true));
505 if (
506 is_array( $json ) &&
507 isset( $json['org_taxes'] ) &&
508 isset( $json['org_taxes']->taxes )
509 ) {
510 $this->response = $json['org_taxes']->taxes;
511 } else {
512 $this->errors = array( 'message' => 'Something went wrong!' );
513 }
514 } catch ( Throwable $throwable ) {
515 $this->errors = array( 'message' => $throwable->getMessage() );
516 }
517 $this->serve();
518 }
519
520 /**
521 * Get Zoho CRM Sales Order layouts.
522 */
523 public function layouts_get(): void {
524 $this->verify();
525 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
526 $url = $zoho_crm_url . 'crm/v7/settings/layouts?module=Sales_Orders';
527 try {
528 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
529 $json = (array) $execute_curl_call_handle->execute_curl_call_get( $url );
530
531 if (
532 is_array( $json ) &&
533 isset( $json['layouts'] ) &&
534 is_array( $json['layouts'] )
535 ) {
536 // Format the layouts for frontend dropdown.
537 $formatted_layouts = array();
538 foreach ( $json['layouts'] as $layout ) {
539 if ( isset( $layout->id ) && isset( $layout->name ) ) {
540 $formatted_layouts[] = array(
541 'id' => $layout->id,
542 'name' => $layout->name,
543 'api_name' => $layout->api_name ?? '',
544 'status' => $layout->status ?? '',
545 );
546 }
547 }
548 $this->response = $formatted_layouts;
549 } else {
550 $this->errors = array( 'message' => 'Unable to fetch layouts!' );
551 }
552 } catch ( Throwable $throwable ) {
553 $this->errors = array( 'message' => $throwable->getMessage() );
554 }
555 $this->serve();
556 }
557
558 /**
559 * Save selected Zoho CRM Sales Order layout.
560 */
561 public function layout_save(): void {
562 $this->verify( array( 'layout_id' ) );
563 if ( empty( $this->data['layout_id'] ) ) {
564 $this->errors = array( 'message' => 'Layout ID is required!' );
565 $this->serve();
566 return;
567 }
568
569 $updated = update_option( self::OPTIONS['zcrm_sales_order_layout'], sanitize_text_field( $this->data['layout_id'] ) );
570
571 if ( $updated ) {
572 $this->response = array( 'message' => 'Layout saved successfully!' );
573 } else {
574 $this->errors = array( 'message' => 'Failed to save layout!' );
575 }
576 $this->serve();
577 }
578
579 /**
580 * Get selected Zoho CRM Sales Order layout.
581 */
582 public function layout_get_selected(): void {
583 $this->verify();
584 $saved_layout = get_option( self::OPTIONS['zcrm_sales_order_layout'], '' );
585 $this->response = array( 'selected_layout' => $saved_layout );
586 $this->serve();
587 }
588
589 /**
590 * Get order settings for Zoho CRM sync.
591 */
592 public function order_settings_get(): void {
593 $this->verify();
594 $sync_as_deals = get_option( 'cmbird_zcrm_sync_as_deals', false );
595 $this->response = array( 'syncAsDeals' => (bool) $sync_as_deals );
596 $this->serve();
597 }
598
599 /**
600 * Save order settings for Zoho CRM sync.
601 */
602 public function order_settings_save(): void {
603 $this->verify( self::FORMS['order_settings'] );
604 try {
605 $sync_as_deals = isset( $this->data['syncAsDeals'] ) ? (bool) $this->data['syncAsDeals'] : false;
606 update_option( 'cmbird_zcrm_sync_as_deals', $sync_as_deals );
607 $this->response = array(
608 'success' => true,
609 'message' => __( 'Order settings saved successfully!', 'commercebird' ),
610 );
611 } catch ( \Throwable $throwable ) {
612 $this->errors = array( 'message' => $throwable->getMessage() );
613 }
614 $this->serve();
615 }
616
617 /**
618 * Get Zoho CRM Deals fields.
619 */
620 public function deal_fields_get(): void {
621 $this->verify();
622 $refresh = isset( $this->data['refresh'] ) && $this->data['refresh'];
623
624 $fields = get_option( 'zcrm_deals_fields', array() );
625
626 // If refresh is requested or no fields exist, try to refresh them from Zoho.
627 if ( $refresh || empty( $fields ) ) {
628 $sync = new ZohoCRMSync();
629 $fresh_fields = $sync->get_all_fields( 'Deals' );
630 if ( ! is_wp_error( $fresh_fields ) ) {
631 // Convert to simple key-value format, excluding hardcoded fields.
632 $formatted_fields = array();
633 foreach ( $fresh_fields as $field_key => $field_label ) {
634 // Skip hardcoded fields (Deal_Name, Amount, Currency).
635 if ( in_array( $field_key, array( 'Deal_Name', 'Amount', 'Currency' ) ) ) {
636 continue;
637 }
638 $formatted_fields[ $field_key ] = $field_label;
639 }
640
641 // Add empty option at the beginning.
642 $formatted_fields = array_merge( array( '' => 'Select a field...' ), $formatted_fields );
643
644 update_option( 'zcrm_deals_fields', $formatted_fields );
645 $fields = $formatted_fields;
646 }
647 } else {
648 // Ensure empty option exists.
649 if ( ! isset( $fields[''] ) ) {
650 $fields = array_merge( array( '' => 'Select a field...' ), $fields );
651 }
652 }
653
654 $this->response = array( 'fields' => $fields );
655 $this->serve();
656 }
657
658 /**
659 * Get deal field mapping settings.
660 */
661 public function deal_field_mapping_get(): void {
662 $this->verify();
663 $mapping = get_option( 'cmbird_zcrm_deal_field_mapping', array() );
664 $this->response = array( 'dealFields' => $mapping );
665 $this->serve();
666 }
667
668 /**
669 * Save deal field mapping settings.
670 */
671 public function deal_field_mapping_save(): void {
672 $this->verify( self::FORMS['order_field_mapping'] );
673 try {
674 $deal_fields = isset( $this->data['dealFields'] ) ? $this->data['dealFields'] : array();
675 update_option( 'cmbird_zcrm_deal_field_mapping', $deal_fields );
676 $this->response = array(
677 'success' => true,
678 'message' => __( 'Deal field mapping saved successfully!', 'commercebird' ),
679 );
680 } catch ( \Throwable $throwable ) {
681 $this->errors = array( 'message' => $throwable->getMessage() );
682 }
683 $this->serve();
684 }
685
686 /**
687 * Get WooCommerce order statuses.
688 */
689 public function wc_order_statuses_get(): void {
690 $this->verify();
691 $order_statuses = wc_get_order_statuses();
692 $formatted_statuses = array();
693
694 // Add empty option.
695 $formatted_statuses[''] = 'Select order status...';
696
697 foreach ( $order_statuses as $status_key => $status_label ) {
698 $formatted_statuses[ $status_key ] = $status_label;
699 }
700
701 $this->response = array( 'statuses' => $formatted_statuses );
702 $this->serve();
703 }
704
705 /**
706 * Get Zoho Deal stages.
707 */
708 public function deal_stages_get(): void {
709 $this->verify();
710 $cached_stages = get_option( 'zcrm_deal_stages', array() );
711
712 // Check if we have cached stages and they're not empty.
713 if ( ! empty( $cached_stages ) && is_array( $cached_stages ) && count( $cached_stages ) > 1 ) {
714 $this->response = array( 'stages' => $cached_stages );
715 $this->serve();
716 return;
717 }
718
719 try {
720 // Directly get the Stage field pick list values without calling get_all_fields.
721 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
722 $url = $zoho_crm_url . 'crm/v7/settings/fields?module=Deals';
723 $execute_curl_call_handle = new \CMBIRD_API_Handler_Zoho();
724 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
725
726 $stage_options = array( '' => 'Select stage...' );
727
728 if ( ! is_wp_error( $json ) && ! empty( $json->fields ) ) {
729 foreach ( $json->fields as $field ) {
730 if ( $field->api_name === 'Stage' && ! empty( $field->pick_list_values ) ) {
731 foreach ( $field->pick_list_values as $option ) {
732 $stage_options[ $option->actual_value ] = $option->display_value;
733 }
734 break;
735 }
736 }
737 }
738
739 // Cache the stages.
740 update_option( 'zcrm_deal_stages', $stage_options );
741 $this->response = array( 'stages' => $stage_options );
742 } catch ( \Exception $e ) {
743 $this->response = array( 'stages' => array( '' => 'Select stage...' ) );
744 }
745
746 $this->serve();
747 }
748
749 /**
750 * Get order status to stage mapping settings.
751 */
752 public function order_status_stage_mapping_get(): void {
753 $this->verify();
754 $mapping = get_option( 'cmbird_zcrm_order_status_stage_mapping', array() );
755 $this->response = array( 'mapping' => $mapping );
756 $this->serve();
757 }
758
759 /**
760 * Save order status to stage mapping settings.
761 */
762 public function order_status_stage_mapping_save(): void {
763 $this->verify( self::FORMS['order_status_stage_mapping'] );
764 try {
765 $mapping = isset( $this->data['mapping'] ) ? $this->data['mapping'] : array();
766 update_option( 'cmbird_zcrm_order_status_stage_mapping', $mapping );
767 $this->response = array(
768 'success' => true,
769 'message' => __( 'Order status to stage mapping saved successfully!', 'commercebird' ),
770 );
771 } catch ( \Throwable $throwable ) {
772 $this->errors = array( 'message' => $throwable->getMessage() );
773 }
774 $this->serve();
775 }
776 }
777