PluginProbe ʕ •ᴥ•ʔ
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). / 2.6.0
CommerceBird – AI Command Center, ERP Integrations & B2B for WooCommerce (Zoho, Exact Online). v2.6.0
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 / Sync / ZohoCRMSync.php
commercebird / admin / includes / Actions / Sync Last commit date
ExactOnlineSync.php 9 months ago ZohoCRMSync.php 7 months ago index.php 1 year ago
ZohoCRMSync.php
273 lines
1 <?php
2
3 namespace CommerceBird\Admin\Actions\Sync;
4
5 if ( ! defined( 'ABSPATH' ) ) {
6 exit;
7 }
8
9 use CMBIRD_API_Handler_Zoho;
10 use CMBIRD_Auth_Zoho;
11 use WP_Error;
12
13 /**
14 * Handles synchronization actions with Zoho CRM, including fetching fields and refreshing tokens.
15 */
16 class ZohoCRMSync {
17
18 /*
19 create API Get call to Zoho CRM to get all custom fields
20 *
21 * @param module $module - module name
22 * @return array | \WP_Error
23 */
24 public static function get_custom_fields( $module ) {
25 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
26 $url = $zoho_crm_url . 'crm/v7/settings/fields?module=' . $module;
27 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
28 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
29 if ( is_wp_error( $json ) ) {
30 return $json;
31 } else {
32 // Parse the response.
33 $parsed_fields = array();
34
35 foreach ( $json->fields as $field ) {
36 if (
37 ! empty( $field->custom_field ) &&
38 ( empty( $field->read_only ) || $field->read_only === false )
39 ) {
40 $parsed_fields[] = array(
41 'id' => $field->id,
42 'apiName' => $field->api_name,
43 'visible' => (bool) $field->visible,
44 'fieldLabel' => $field->field_label,
45 'displayLabel' => $field->display_label,
46 'customField' => true,
47 'dataType' => $field->data_type,
48 );
49 }
50 }
51
52 return $parsed_fields;
53 }
54 }
55
56 /*
57 create API Get call to Zoho CRM to get ALL fields (standard + custom)
58 *
59 * @param module $module - module name
60 * @return array | \WP_Error
61 */
62 public static function get_all_fields( $module ) {
63 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
64 $url = $zoho_crm_url . 'crm/v7/settings/fields?module=' . $module;
65 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
66 $json = $execute_curl_call_handle->execute_curl_call_get( $url );
67 if ( is_wp_error( $json ) ) {
68 return $json;
69 } else {
70 // Parse the response to get ALL fields (both standard and custom).
71 $parsed_fields = array();
72
73 // Fields to exclude for Deals module.
74 $excluded_fields = array( 'Account_Name', 'Contact_Name', 'Stage' );
75
76 foreach ( $json->fields as $field ) {
77 // Include all fields that are not read-only and are visible.
78 // For Deals module, also exclude Account Name, Contact Name and Stage.
79 if ( ( empty( $field->read_only ) || $field->read_only === false ) && $field->visible ) {
80 // Skip excluded fields for Deals module.
81 if ( 'Deals' === $module && in_array( $field->api_name, $excluded_fields ) ) {
82 continue;
83 }
84 $parsed_fields[ $field->api_name ] = $field->field_label;
85 }
86 }
87
88 return $parsed_fields;
89 }
90 }
91
92 /**
93 * Refresh the access token of Zoho CRM.
94 *
95 * @since 1.0.0
96 * @return void | \WP_Error
97 */
98 public static function refresh_token() {
99 // return if there is no access token.
100 if ( empty( get_option( 'cmbird_zoho_crm_access_token' ) ) ) {
101 return;
102 }
103 $zoho_refresh_token = get_option( 'cmbird_zoho_crm_refresh_token' );
104 $zoho_timestamp = get_option( 'cmbird_zoho_crm_timestamp' );
105 $current_time = strtotime( gmdate( 'Y-m-d H:i:s' ) );
106 if ( $zoho_timestamp < $current_time ) {
107 $handlefunction = new CMBIRD_Auth_Zoho();
108 $respo_at_js = $handlefunction->get_zoho_refresh_token( $zoho_refresh_token, 'zoho_crm' );
109 if ( ! array_key_exists( 'access_token', $respo_at_js ) ) {
110 return new WP_Error( 403, 'Access denied!' );
111 } else {
112 update_option( 'cmbird_zoho_crm_access_token', $respo_at_js['access_token'] );
113 update_option( 'cmbird_zoho_crm_timestamp', strtotime( gmdate( 'Y-m-d H:i:s' ) ) + $respo_at_js['expires_in'] );
114 }
115 }
116 }
117
118 /**
119 * Sync a WooCommerce customer to Zoho CRM as a contact.
120 *
121 * Called via Action Scheduler.
122 *
123 * @param int $customer_id The customer ID to sync.
124 *
125 * @return void
126 */
127 public static function cmbird_zcrm_contact_sync( $customer_id ) {
128 // Refresh token before making API calls.
129 $token_refresh_result = self::refresh_token();
130 if ( is_wp_error( $token_refresh_result ) ) {
131 error_log( 'Zoho CRM Contact Sync: Token refresh failed for customer ID ' . $customer_id . ': ' . $token_refresh_result->get_error_message() );
132 return;
133 }
134
135 $customer = get_user_by( 'id', $customer_id );
136 if ( ! $customer ) {
137 error_log( 'Zoho CRM Contact Sync: Customer not found with ID ' . $customer_id );
138 return;
139 }
140
141 // Get billing address data.
142 $billing_address_1 = get_user_meta( $customer_id, 'billing_address_1', true );
143 $billing_address_2 = get_user_meta( $customer_id, 'billing_address_2', true );
144 $mailing_street = trim( $billing_address_1 . ' ' . $billing_address_2 );
145
146 // Format customer data to match Zoho CRM contact fields.
147 $contact_data = array(
148 'First_Name' => ! empty( $customer->first_name ) ? $customer->first_name : '',
149 'Last_Name' => ! empty( $customer->last_name ) ? $customer->last_name : ( ! empty( $customer->display_name ) ? $customer->display_name : 'Customer' ),
150 'Email' => $customer->user_email,
151 );
152
153 // Add optional fields only if they have values.
154 $optional_fields = array(
155 'Phone' => get_user_meta( $customer_id, 'billing_phone', true ),
156 'Mobile' => get_user_meta( $customer_id, 'billing_phone', true ),
157 'Mailing_Street' => $mailing_street,
158 'Mailing_City' => get_user_meta( $customer_id, 'billing_city', true ),
159 'Mailing_State' => get_user_meta( $customer_id, 'billing_state', true ),
160 'Mailing_Zip' => get_user_meta( $customer_id, 'billing_postcode', true ),
161 'Mailing_Country' => get_user_meta( $customer_id, 'billing_country', true ),
162 );
163
164 foreach ( $optional_fields as $field => $value ) {
165 if ( ! empty( $value ) ) {
166 $contact_data[ $field ] = $value;
167 }
168 }
169
170 // Add description with customer ID.
171 $contact_data['Description'] = 'WooCommerce Customer ID: ' . $customer_id;
172
173 // Apply selected contact layout if available.
174 $selected_layout = get_option( 'zcrm_contact_layout', '' );
175 if ( ! empty( $selected_layout ) ) {
176 $contact_data['Layout'] = array( 'id' => $selected_layout );
177 }
178
179 $zoho_crm_url = get_option( 'cmbird_zoho_crm_url' );
180 if ( empty( $zoho_crm_url ) ) {
181 error_log( 'Zoho CRM Contact Sync: Zoho CRM URL not configured for customer ID ' . $customer_id );
182 return;
183 }
184
185 $execute_curl_call_handle = new CMBIRD_API_Handler_Zoho();
186
187 // Check if customer already has a Zoho CRM contact ID stored.
188 $existing_contact_id = get_user_meta( $customer_id, 'zcrm_contact_id', true );
189
190 // Prepare data in Zoho CRM format.
191 $zoho_data = array( 'data' => array( $contact_data ) );
192
193 if ( ! empty( $existing_contact_id ) ) {
194 // Customer already has a Zoho CRM contact ID, update the existing contact.
195 $contact_id = $existing_contact_id;
196
197 $update_url = $zoho_crm_url . 'crm/v7/Contacts/' . $contact_id;
198 $update_result = $execute_curl_call_handle->execute_curl_call_put( $update_url, $zoho_data );
199
200 if ( is_wp_error( $update_result ) ) {
201 error_log( 'Zoho CRM Contact Sync: Failed to update existing contact - Customer ID ' . $customer_id . ', Contact ID ' . $contact_id . ': ' . $update_result->get_error_message() );
202 return;
203 }
204
205 error_log( 'Zoho CRM Contact Sync: Successfully updated contact - Customer ID ' . $customer_id . ', Contact ID ' . $contact_id );
206 } else {
207 // No existing contact ID, need to check if contact exists by email.
208 $email = $customer->user_email;
209 if ( empty( $email ) ) {
210 error_log( 'Zoho CRM Contact Sync: Customer has no email address - ID ' . $customer_id );
211 return;
212 }
213
214 $search_url = $zoho_crm_url . 'crm/v7/Contacts/search?criteria=(Email:equals:' . urlencode( $email ) . ')';
215 $search_result = $execute_curl_call_handle->execute_curl_call_get( $search_url );
216
217 if ( is_wp_error( $search_result ) ) {
218 error_log( 'Zoho CRM Contact Sync: Failed to search for existing contact - Customer ID ' . $customer_id . ': ' . $search_result->get_error_message() );
219 return;
220 }
221
222 // Check if contact exists by email - at this point $search_result is not a WP_Error.
223 /** @var object $search_result */
224 if ( isset( $search_result->data ) && ! empty( $search_result->data ) ) {
225 // Contact found by email, update it and store the contact ID.
226 $existing_contact = $search_result->data[0];
227 $contact_id = $existing_contact->id;
228
229 // Store the contact ID for future syncs.
230 update_user_meta( $customer_id, 'zcrm_contact_id', $contact_id );
231
232 $update_url = $zoho_crm_url . 'crm/v7/Contacts/' . $contact_id;
233 $update_result = $execute_curl_call_handle->execute_curl_call_put( $update_url, $zoho_data );
234
235 if ( is_wp_error( $update_result ) ) {
236 error_log( 'Zoho CRM Contact Sync: Failed to update existing contact found by email - Customer ID ' . $customer_id . ', Contact ID ' . $contact_id . ': ' . $update_result->get_error_message() );
237 return;
238 }
239
240 error_log( 'Zoho CRM Contact Sync: Successfully updated contact found by email - Customer ID ' . $customer_id . ', Contact ID ' . $contact_id );
241 } else {
242 // Contact does not exist, create a new one.
243 $create_url = $zoho_crm_url . 'crm/v7/Contacts';
244 $create_result = $execute_curl_call_handle->execute_curl_call_post( $create_url, $zoho_data );
245
246 if ( is_wp_error( $create_result ) ) {
247 error_log( 'Zoho CRM Contact Sync: Failed to create new contact - Customer ID ' . $customer_id . ': ' . $create_result->get_error_message() );
248 return;
249 }
250
251 if (
252 isset( $create_result->data )
253 && is_array( $create_result->data )
254 && isset( $create_result->data[0] )
255 && is_object( $create_result->data[0] )
256 && isset( $create_result->data[0]->details )
257 && is_object( $create_result->data[0]->details )
258 && ! empty( $create_result->data[0]->details->id )
259 ) {
260 $new_contact_id = $create_result->data[0]->details->id;
261
262 // Store the new contact ID for future syncs.
263 update_user_meta( $customer_id, 'zcrm_contact_id', $new_contact_id );
264
265 error_log( 'Zoho CRM Contact Sync: Successfully created new contact - Customer ID ' . $customer_id . ', Contact ID ' . $new_contact_id );
266 } else {
267 error_log( 'Zoho CRM Contact Sync: Contact created but ID not returned - Customer ID ' . $customer_id );
268 }
269 }
270 }
271 }
272 }
273