/* ====================================================== * Contact search helpers (robust) * ====================================================== */ if (!function_exists('mtbg_zb_contacts_search')) { function mtbg_zb_contacts_search(string $search_text): array { $search_text = trim($search_text); if ($search_text === '') return []; $res = mtbg_zb_api('GET', '/books/v3/contacts', ['search_text' => $search_text]); $body = mtbg_zb_body($res); if (!is_array($body) || empty($body['contacts']) || !is_array($body['contacts'])) return []; return $body['contacts']; } } if (!function_exists('mtbg_zb_find_contact_by_email_or_name')) { function mtbg_zb_find_contact_by_email_or_name(string $email, string $full_name): ?string { $email = sanitize_email($email); $full_name = trim(preg_replace('/\s+/', ' ', $full_name)); if ($email === '' && $full_name === '') return null; $email_lc = strtolower($email); // Search in a few ways $queries = []; if ($email !== '') $queries[] = $email; if ($full_name !== '') $queries[] = $full_name; if ($email !== '' && $full_name !== '') $queries[] = $full_name . ' (' . $email . ')'; $seen = []; $candidates = []; foreach ($queries as $q) { $list = mtbg_zb_contacts_search($q); foreach ($list as $c) { if (!is_array($c)) continue; $cid = (string)($c['contact_id'] ?? ''); if ($cid === '' || isset($seen[$cid])) continue; $seen[$cid] = true; $candidates[] = $c; } } // First pass: exact email match (contact.email or contact_persons) foreach ($candidates as $c) { $cid = (string)($c['contact_id'] ?? ''); if ($cid === '') continue; $c_email = strtolower(trim((string)($c['email'] ?? ''))); if ($email !== '' && $c_email !== '' && $c_email === $email_lc) return $cid; if (!empty($c['contact_persons']) && is_array($c['contact_persons'])) { foreach ($c['contact_persons'] as $p) { if (!is_array($p)) continue; $p_email = strtolower(trim((string)($p['email'] ?? ''))); if ($email !== '' && $p_email !== '' && $p_email === $email_lc) return $cid; } } } // Second pass: if Zoho hides email, match by contact_name containing the email foreach ($candidates as $c) { $cid = (string)($c['contact_id'] ?? ''); if ($cid === '') continue; $cn = strtolower((string)($c['contact_name'] ?? '')); if ($email !== '' && $cn !== '' && strpos($cn, strtolower($email)) !== false) { return $cid; } } return null; } } /* ====================================================== * Contact upsert (3062-proof) * ====================================================== */ if (!function_exists('mtbg_zb_upsert_contact')) { function mtbg_zb_upsert_contact(string $email, string $name, string $phone): string { $email = sanitize_email($email); if (!$email) throw new Exception('Invalid email'); $name = trim((string)$name); if ($name === '') $name = $email; // 1) Find existing by email/name/pattern $found = mtbg_zb_find_contact_by_email_or_name($email, $name); if ($found) return $found; // 2) Create contact [$first, $last] = mtbg_zb_split_name($name); $mobile = mtbg_zb_phone($phone); $base_contact_name = trim(($first . ' ' . $last)); if ($base_contact_name === '') $base_contact_name = $name; $payload_base = [ 'contact_type' => 'customer', 'email' => $email, 'contact_persons' => [[ 'email' => $email, 'first_name' => $first, 'last_name' => $last, 'mobile' => ($mobile !== '' ? $mobile : null), 'is_primary_contact' => true, ]], ]; // Try 1: original name $payload = $payload_base; $payload['contact_name'] = $base_contact_name; $created = mtbg_zb_api('POST', '/books/v3/contacts', [], $payload); $body = mtbg_zb_body($created); if (is_array($body) && !empty($body['contact']['contact_id'])) { return (string)$body['contact']['contact_id']; } // If already exists (3062), try to FIND AGAIN using Zoho's own display pattern if (mtbg_zb_code($created) === 3062) { $found = mtbg_zb_find_contact_by_email_or_name($email, $name); if ($found) return $found; // Try 2: force unique contact_name suffix to bypass "name exists" rules $suffix = ' #' . substr(sha1($email . '|' . microtime(true)), 0, 6); $payload2 = $payload_base; $payload2['contact_name'] = $base_contact_name . $suffix; $created2 = mtbg_zb_api('POST', '/books/v3/contacts', [], $payload2); $body2 = mtbg_zb_body($created2); if (is_array($body2) && !empty($body2['contact']['contact_id'])) { return (string)$body2['contact']['contact_id']; } // If it STILL says exists, last attempt: search by "Name (email)" exactly $found = mtbg_zb_find_contact_by_email_or_name($email, $name . ' (' . $email . ')'); if ($found) return $found; throw new Exception('Zoho contact create failed (3062, could not resolve existing contact): ' . mtbg_zb_err($created2)); } throw new Exception('Zoho contact create failed: ' . mtbg_zb_err($created)); } } 5.5 hrs Archives - MTB Guatemala Mountain Bike Tours
Your Cart

5.5 hrs

View: