auth = new HVAC_Zoho_CRM_Auth(); // Determine if we're in staging mode $site_url = get_site_url(); $this->is_staging = strpos($site_url, 'upskillhvac.com') === false; } /** * Check if sync is allowed * * @return bool */ private function is_sync_allowed() { // Only allow sync on production (upskillhvac.com) $site_url = get_site_url(); return strpos($site_url, 'upskillhvac.com') !== false; } /** * Sync events to Zoho Campaigns * * @return array Sync results */ public function sync_events() { $results = array( 'total' => 0, 'synced' => 0, 'failed' => 0, 'errors' => array(), 'staging_mode' => $this->is_staging ); // Get all published events $events = tribe_get_events(array( 'posts_per_page' => -1, 'eventDisplay' => 'list', 'meta_query' => array( array( 'key' => '_hvac_event_type', 'value' => 'trainer', 'compare' => '=' ) ) )); $results['total'] = count($events); // If staging mode, simulate the sync if ($this->is_staging) { $results['message'] = 'STAGING MODE: Sync simulation only. No data sent to Zoho.'; $results['synced'] = $results['total']; $results['test_data'] = array(); foreach ($events as $event) { $campaign_data = $this->prepare_campaign_data($event); $results['test_data'][] = array( 'event_id' => $event->ID, 'event_title' => get_the_title($event), 'zoho_data' => $campaign_data ); } return $results; } // Production sync if (!$this->is_sync_allowed()) { $results['errors'][] = 'Sync not allowed on this domain. Only upskillhvac.com can sync to production.'; return $results; } foreach ($events as $event) { try { $campaign_data = $this->prepare_campaign_data($event); // Check if campaign already exists in Zoho $search_response = $this->auth->make_api_request('GET', '/crm/v2/Campaigns/search', array( 'criteria' => "(Campaign_Name:equals:{$campaign_data['Campaign_Name']})" )); if (!empty($search_response['data'])) { // Update existing campaign $campaign_id = $search_response['data'][0]['id']; $update_response = $this->auth->make_api_request('PUT', "/crm/v2/Campaigns/{$campaign_id}", array( 'data' => array($campaign_data) )); } else { // Create new campaign $create_response = $this->auth->make_api_request('POST', '/crm/v2/Campaigns', array( 'data' => array($campaign_data) )); } $results['synced']++; // Update event meta with Zoho ID if (isset($campaign_id)) { update_post_meta($event->ID, '_zoho_campaign_id', $campaign_id); } } catch (Exception $e) { $results['failed']++; $results['errors'][] = sprintf('Event %s: %s', $event->ID, $e->getMessage()); } } return $results; } /** * Sync users to Zoho Contacts * * @return array Sync results */ public function sync_users() { $results = array( 'total' => 0, 'synced' => 0, 'failed' => 0, 'errors' => array(), 'staging_mode' => $this->is_staging ); // Get trainers and attendees $users = get_users(array( 'role__in' => array('trainer', 'trainee'), 'meta_query' => array( 'relation' => 'OR', array( 'key' => '_sync_to_zoho', 'value' => '1', 'compare' => '=' ), array( 'key' => '_sync_to_zoho', 'compare' => 'NOT EXISTS' ) ) )); $results['total'] = count($users); // If staging mode, simulate the sync if ($this->is_staging) { $results['message'] = 'STAGING MODE: Sync simulation only. No data sent to Zoho.'; $results['synced'] = $results['total']; $results['test_data'] = array(); foreach ($users as $user) { $contact_data = $this->prepare_contact_data($user); $results['test_data'][] = array( 'user_id' => $user->ID, 'user_email' => $user->user_email, 'user_role' => implode(', ', $user->roles), 'zoho_data' => $contact_data ); } return $results; } // Production sync if (!$this->is_sync_allowed()) { $results['errors'][] = 'Sync not allowed on this domain. Only upskillhvac.com can sync to production.'; return $results; } foreach ($users as $user) { try { $contact_data = $this->prepare_contact_data($user); // Check if contact already exists in Zoho $search_response = $this->auth->make_api_request('GET', '/crm/v2/Contacts/search', array( 'criteria' => "(Email:equals:{$contact_data['Email']})" )); if (!empty($search_response['data'])) { // Update existing contact $contact_id = $search_response['data'][0]['id']; $update_response = $this->auth->make_api_request('PUT', "/crm/v2/Contacts/{$contact_id}", array( 'data' => array($contact_data) )); } else { // Create new contact $create_response = $this->auth->make_api_request('POST', '/crm/v2/Contacts', array( 'data' => array($contact_data) )); if (!empty($create_response['data'][0]['details']['id'])) { $contact_id = $create_response['data'][0]['details']['id']; } } $results['synced']++; // Update user meta with Zoho ID if (isset($contact_id)) { update_user_meta($user->ID, '_zoho_contact_id', $contact_id); } } catch (Exception $e) { $results['failed']++; $results['errors'][] = sprintf('User %s: %s', $user->ID, $e->getMessage()); } } return $results; } /** * Sync ticket purchases to Zoho Invoices * * @return array Sync results */ public function sync_purchases() { $results = array( 'total' => 0, 'synced' => 0, 'failed' => 0, 'errors' => array(), 'staging_mode' => $this->is_staging ); // Get all completed orders $orders = wc_get_orders(array( 'status' => 'completed', 'limit' => -1, 'meta_key' => '_tribe_tickets_event_id', 'meta_compare' => 'EXISTS' )); $results['total'] = count($orders); // If staging mode, simulate the sync if ($this->is_staging) { $results['message'] = 'STAGING MODE: Sync simulation only. No data sent to Zoho.'; $results['synced'] = $results['total']; $results['test_data'] = array(); foreach ($orders as $order) { $invoice_data = $this->prepare_invoice_data($order); $results['test_data'][] = array( 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'order_total' => $order->get_total(), 'zoho_data' => $invoice_data ); } return $results; } // Production sync if (!$this->is_sync_allowed()) { $results['errors'][] = 'Sync not allowed on this domain. Only upskillhvac.com can sync to production.'; return $results; } foreach ($orders as $order) { try { $invoice_data = $this->prepare_invoice_data($order); // Check if invoice already exists in Zoho $order_number = $order->get_order_number(); $search_response = $this->auth->make_api_request('GET', '/crm/v2/Invoices/search', array( 'criteria' => "(Invoice_Number:equals:{$order_number})" )); if (!empty($search_response['data'])) { // Update existing invoice $invoice_id = $search_response['data'][0]['id']; $update_response = $this->auth->make_api_request('PUT', "/crm/v2/Invoices/{$invoice_id}", array( 'data' => array($invoice_data) )); } else { // Create new invoice $create_response = $this->auth->make_api_request('POST', '/crm/v2/Invoices', array( 'data' => array($invoice_data) )); } $results['synced']++; // Update order meta with Zoho ID if (isset($invoice_id)) { $order->update_meta_data('_zoho_invoice_id', $invoice_id); $order->save(); } } catch (Exception $e) { $results['failed']++; $results['errors'][] = sprintf('Order %s: %s', $order->get_id(), $e->getMessage()); } } return $results; } /** * Prepare campaign data for Zoho * * @param WP_Post $event Event post object * @return array Campaign data */ private function prepare_campaign_data($event) { $trainer_id = get_post_meta($event->ID, '_trainer_id', true); $trainer = get_user_by('id', $trainer_id); $venue = tribe_get_venue($event->ID); return array( 'Campaign_Name' => get_the_title($event->ID), 'Start_Date' => tribe_get_start_date($event->ID, false, 'Y-m-d'), 'End_Date' => tribe_get_end_date($event->ID, false, 'Y-m-d'), 'Status' => (tribe_get_end_date($event->ID, false, 'U') < time()) ? 'Completed' : 'Active', 'Description' => get_the_content(null, false, $event), 'Type' => 'Training Event', 'Expected_Revenue' => floatval(get_post_meta($event->ID, '_price', true)), 'Total_Capacity' => intval(get_post_meta($event->ID, '_stock', true)), 'Venue' => $venue ? get_the_title($venue) : '', 'Trainer_Name' => $trainer ? $trainer->display_name : '', 'Trainer_Email' => $trainer ? $trainer->user_email : '', 'WordPress_Event_ID' => $event->ID ); } /** * Prepare contact data for Zoho * * @param WP_User $user User object * @return array Contact data */ private function prepare_contact_data($user) { $role = in_array('trainer', $user->roles) ? 'Trainer' : 'Trainee'; return array( 'First_Name' => get_user_meta($user->ID, 'first_name', true), 'Last_Name' => get_user_meta($user->ID, 'last_name', true), 'Email' => $user->user_email, 'Phone' => get_user_meta($user->ID, 'phone_number', true), 'Title' => get_user_meta($user->ID, 'hvac_professional_title', true), 'Company' => get_user_meta($user->ID, 'hvac_company_name', true), 'Lead_Source' => 'HVAC Community Events', 'Contact_Type' => $role, 'WordPress_User_ID' => $user->ID, 'License_Number' => get_user_meta($user->ID, 'hvac_license_number', true), 'Years_Experience' => get_user_meta($user->ID, 'hvac_years_experience', true), 'Certification' => get_user_meta($user->ID, 'hvac_certifications', true) ); } /** * Prepare invoice data for Zoho * * @param WC_Order $order Order object * @return array Invoice data */ private function prepare_invoice_data($order) { $event_id = $order->get_meta('_tribe_tickets_event_id'); $event_title = get_the_title($event_id); $customer = $order->get_user(); // Get contact ID from Zoho $contact_id = null; if ($customer) { $contact_id = get_user_meta($customer->ID, '_zoho_contact_id', true); } $items = array(); foreach ($order->get_items() as $item) { $items[] = array( 'Product_Name' => $item->get_name(), 'Quantity' => $item->get_quantity(), 'Rate' => $item->get_subtotal() / $item->get_quantity(), 'Total' => $item->get_total() ); } return array( 'Invoice_Number' => $order->get_order_number(), 'Invoice_Date' => $order->get_date_created()->format('Y-m-d'), 'Status' => 'Paid', 'Contact_Name' => $contact_id, 'Subject' => "Ticket Purchase - {$event_title}", 'Sub_Total' => $order->get_subtotal(), 'Tax' => $order->get_total_tax(), 'Total' => $order->get_total(), 'Balance' => 0, 'WordPress_Order_ID' => $order->get_id(), 'Product_Details' => $items ); } } ?>