= (int) $body['meta']['last_page']) { break; } if ($page === 3) { return self::attention('נמצאו יותר מדי תוצאות לאימות איש הקשר. הפנייה לא נשלחה לאיש קשר משוער.'); } } if (count($matches) !== 1) { return self::attention('הליד קיים, אך לא נמצא איש קשר יחיד עם אותו טלפון. יש לבדוק את קישור הליד לאיש קשר ב-Wizup.'); } $content = self::content($payload, $meta); $chunks = []; for ($offset = 0; $offset < mb_strlen($content); $offset += 4400) { $chunks[] = mb_substr($content, $offset, 4400); } $workflow = ['kind' => 'repeat_note', 'contact' => array_key_first($matches), 'chunks' => $chunks, 'next' => 0]; // Persist the destination, body and progress before the first note POST. // Retries cannot change the recipient or generate a new action key. $checkpoint($workflow); return self::deliver($workflow, $key, $checkpoint); } private static function content(array $payload, array $meta): string { $lines = ['פנייה חוזרת מהטופס באתר', 'מועד הפנייה (UTC): ' . (string) ($meta['created_at'] ?? ''), 'טופס: ' . (string) ($meta['source'] ?? '') . ' / ' . (string) ($meta['form_id'] ?? '')]; foreach (['name' => 'שם שנשלח', 'phone' => 'טלפון', 'email' => 'אימייל שנשלח', 'stage_id' => 'שלב שנבחר בטופס'] as $field => $label) { if (isset($payload[$field]) && is_scalar($payload[$field])) { $lines[] = $label . ': ' . (string) $payload[$field]; } } foreach ((array) ($payload['custom_fields'] ?? []) as $field => $value) { if (is_scalar($value) || $value === null) { $lines[] = 'שדה ' . $field . ': ' . (is_bool($value) ? ($value ? 'כן' : 'לא') : (string) $value); } } return implode("\n", $lines); } public static function deliver(array $workflow, string $key, ?callable $checkpoint): array { if (!$checkpoint || !is_string($workflow['contact'] ?? null) || !wp_is_uuid($workflow['contact']) || !is_array($workflow['chunks'] ?? null) || !$workflow['chunks'] || !is_int($workflow['next'] ?? null) || $workflow['next'] < 0 || $workflow['next'] > count($workflow['chunks'])) { return self::attention('נתוני המשך השליחה אינם תקינים. נדרשת בדיקה.'); } $index = $workflow['next']; $count = count($workflow['chunks']); if ($index === $count) { return self::success(); } if (!is_string($workflow['chunks'][$index] ?? null) || mb_strlen($workflow['chunks'][$index]) > 4400) { return self::attention('תוכן הפנייה החוזרת אינו תקין.'); } $content = 'פנייה חוזרת ' . $key . ($count > 1 ? ' - חלק ' . ($index + 1) . '/' . $count : '') . "\n\n" . $workflow['chunks'][$index]; $response = Client::request('POST', '/contacts/' . $workflow['contact'] . '/notes', ['content' => $content], $key . '-note-' . ($index + 1)); $failure = self::failure($response, 'notes:write'); if ($failure) { return $failure; } $body = json_decode(wp_remote_retrieve_body($response), true); if (!is_string($body['data']['uuid'] ?? null) || !wp_is_uuid($body['data']['uuid'])) { return self::attention('Wizup החזירה תשובה לא מוכרת לשמירת ההערה. יש לבדוק במערכת לפני ניסיון נוסף.'); } $workflow['next']++; $checkpoint($workflow); if ($workflow['next'] === $count) { return self::success(); } return ['state' => 'pending', 'code' => 201, 'note' => 'נשמרו ' . $workflow['next'] . ' מתוך ' . $count . ' חלקי הפנייה החוזרת. יתר החלקים ממתינים לשליחה.', 'reset_attempts' => true, 'delay' => 1]; } private static function success(): array { return ['state' => 'noted', 'code' => 201, 'note' => 'הפנייה החוזרת נשמרה כהערה אצל איש הקשר. ב-Wizup היא מופיעה גם בליד המקושר אליו. פרטי הליד הקיימים נשמרו.']; } private static function attention(string $note): array { return ['state' => 'attention', 'code' => 422, 'note' => $note]; } private static function failure($response, string $scope): ?array { if (is_wp_error($response)) { return ['state' => 'retry', 'code' => 0, 'note' => 'תקלה בתקשורת בעת טיפול בפנייה חוזרת. יבוצע ניסיון חוזר.', 'delay' => 60]; } $code = wp_remote_retrieve_response_code($response); if ($code >= 200 && $code < 300) { return null; } if ($code === 429 || $code >= 500) { $retry = wp_remote_retrieve_header($response, 'retry-after'); $delay = is_scalar($retry) && ctype_digit((string) $retry) ? (int) $retry : (is_string($retry) ? max(0, (int) strtotime($retry) - time()) : 60); return ['state' => 'retry', 'code' => $code, 'note' => 'שמירת הפנייה החוזרת ממתינה עקב מגבלת API או תקלה בשרת. יבוצע ניסיון חוזר.', 'delay' => min(86400, max(60, $delay))]; } $note = $code === 403 ? 'מספר הטלפון כבר קיים. כדי לשמור פנייה חוזרת נדרשת הרשאת ' . $scope . ' ב-Token וגישה מתאימה ל-API. הפנייה עדיין לא נשמרה כהערה.' : ($code === 401 ? 'ה-Token נדחה בעת טיפול בפנייה חוזרת. יש לבדוק את החיבור.' : 'Wizup דחתה את שמירת הפנייה החוזרת (HTTP ' . $code . '). הפנייה נשמרה בתור לבדיקה.'); return ['state' => $code === 409 ? 'attention' : 'failed', 'code' => $code, 'note' => $note]; } }