From 33ac44ff97f44022f8921c0bf9554e79b62ab3c3 Mon Sep 17 00:00:00 2001 From: Nikola Jelic Date: Wed, 28 Jan 2026 15:11:48 +0100 Subject: [PATCH] Add async report generation features and related models - Implement async report generation request and response handling. - Introduce new models for job management and report page handling. - Enhance existing functionality for report exports and job runs. - Add support for multiple document formats in report generation. --- src/Client/CxReportsClient.php | 228 +++++++++++++++++-- src/Models/AsyncReportGenerationRequest.php | 27 +++ src/Models/AsyncReportGenerationResponse.php | 13 ++ src/Models/DocumentFIleFormat.php | 11 + src/Models/Job.php | 25 ++ src/Models/JobRun.php | 13 ++ src/Models/JobRunEntriesStatus.php | 19 ++ src/Models/JobRunRequest.php | 15 ++ src/Models/JobRunStatus.php | 17 ++ src/Models/ReportExportRequest.php | 23 ++ src/Models/ReportPage.php | 17 ++ src/Models/ReportPageType.php | 9 + src/Models/TemporaryFileStatusResponse.php | 27 +++ 13 files changed, 425 insertions(+), 19 deletions(-) create mode 100644 src/Models/AsyncReportGenerationRequest.php create mode 100644 src/Models/AsyncReportGenerationResponse.php create mode 100644 src/Models/DocumentFIleFormat.php create mode 100644 src/Models/Job.php create mode 100644 src/Models/JobRun.php create mode 100644 src/Models/JobRunEntriesStatus.php create mode 100644 src/Models/JobRunRequest.php create mode 100644 src/Models/JobRunStatus.php create mode 100644 src/Models/ReportExportRequest.php create mode 100644 src/Models/ReportPage.php create mode 100644 src/Models/ReportPageType.php create mode 100644 src/Models/TemporaryFileStatusResponse.php diff --git a/src/Client/CxReportsClient.php b/src/Client/CxReportsClient.php index c7e7479..4895e9a 100644 --- a/src/Client/CxReportsClient.php +++ b/src/Client/CxReportsClient.php @@ -10,7 +10,18 @@ use CxReports\Models\TemporaryData; use CxReports\Models\TemporaryDataCreate; use CxReports\Models\NonceToken; +use CxReports\Models\ReportExportRequest; +use CxReports\Models\ReportPage; use CxReports\Models\ReportPDF; +use CxReports\Models\AsyncReportGenerationRequest; +use CxReports\Models\AsyncReportGenerationResponse; +use CxReports\Models\DocumentFIleFormat; +use CxReports\Models\Job; +use CxReports\Models\JobRun; +use CxReports\Models\JobRunRequest; +use CxReports\Models\JobRunStatus; +use CxReports\Models\TemporaryFileStatusResponse; + class CxReportsClient { @@ -24,7 +35,7 @@ public function __construct($url, $workspace_id, $pat, Client $client = null) $this->url = $url; $this->pat = $pat; $this->default_workspace_id = $workspace_id; - if($client == null){ + if ($client == null) { $this->client = new Client([ 'base_uri' => $this->url, 'headers' => [ @@ -37,14 +48,114 @@ public function __construct($url, $workspace_id, $pat, Client $client = null) } } + public function getAsyncExportStatus($tempFileId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('exports/' . $tempFileId . '/status', $workspace_id); + try { + $response = $this->client->get($url); + $data = $this->processResponse($response); + return new TemporaryFileStatusResponse($data); + } catch (RequestException $e) { + return new \Exception('Error getting export status'); + } + } + + public function getAsyncExportContent($tempFileId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('exports/' . $tempFileId . '/content', $workspace_id); + try { + $response = $this->client->get($url); + $reportName = $response->getHeader('Content-Disposition')[0]; + //filename="Sample report.pdf"; filename*=UTF-8''Sample%20report.pdf....... + // extract the filename from the header + $reportName = explode('filename*=UTF-8\'\'', $reportName)[1]; + $reportName = str_replace('"', '', $reportName); + $reportName = str_replace(' ', '_', $reportName); + $reportName = urldecode($reportName); + $pdf = $response->getBody()->getContents(); + return new ReportPDF([ + 'filename' => $reportName, + 'pdf' => $pdf, + ]); + } catch (RequestException $e) { + return new \Exception('Error fetching report pages'); + } + } + + public function listJobs($workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('jobs', $workspace_id); + + try { + $response = $this->client->get($url); + $data = $this->processResponse($response); + + $jobs = array_map(function ($jobData) { + return new Job($jobData); + }, $data); + return $jobs; + } catch (RequestException $e) { + return new \Exception('Error fetching jobs'); + } + } + + public function startNewJobRun($jobid, JobRunRequest $requestBody, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('jobs/' . $jobid . '/runs', $workspace_id); + try { + $response = $this->client->post($url, [ + 'json' => $requestBody + ]); + $data = $this->processResponse($response); + return new JobRun($data); + } catch (RequestException $e) { + return new \Exception('Error starting new Job Run'); + } + } + + public function getJobRunStatus($jobid, $runId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('jobs/' . $jobid . '/runs/' . $runId . '/status', $workspace_id); + try { + $response = $this->client->get($url); + $data = $this->processResponse($response); + return new JobRunStatus($data); + } catch (RequestException $e) { + return new \Exception('Error fetching JobRun status'); + } + } + + public function generateJobRunReviewDocument($jobid, $runId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('jobs/' . $jobid . '/runs/' . $runId . '/generate-review-document', $workspace_id); + try { + $response = $this->client->post($url); + $data = $this->processResponse($response); + return new AsyncReportGenerationResponse($data); + } catch (RequestException $e) { + return new \Exception('Error generating Job Run review document'); + } + } + + public function deliverAllJobRunEntries($jobid, $runId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('jobs/' . $jobid . '/runs/' . $runId . '/deliver', $workspace_id); + try { + $response = $this->client->post($url); + return true; + } catch (RequestException $e) { + return new \Exception('Error generating Job Run review document'); + } + } + public function listReports($type, $workspace_id = null) { - $url = $this->buildUrlWithWorkspace('reports?type=' . $type, $workspace_id ); + $url = $this->buildUrlWithWorkspace('reports?type=' . $type, $workspace_id); try { $response = $this->client->get($url); $data = $this->processResponse($response); - + $reports = array_map(function ($reportData) { return new Report($reportData); }, $data); @@ -54,6 +165,23 @@ public function listReports($type, $workspace_id = null) } } + public function listReportPages($reportId, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('reports/' . $reportId . '/pages', $workspace_id); + try { + $response = $this->client->get($url); + $data = $this->processResponse($response); + + $reportPages = array_map(function ($pageData) { + return new ReportPage($pageData); + }, $data); + return $reportPages; + } catch (RequestException $e) { + return new \Exception('Error fetching report pages'); + } + } + + public function downloadPdf($reportId, $params = [], $workspace_id = null) { $url = $this->buildUrlWithWorkspace('reports/' . $reportId . '/pdf', $workspace_id); @@ -80,6 +208,51 @@ public function downloadPdf($reportId, $params = [], $workspace_id = null) } } + + public function downloadPdfWithData($reportId, ReportExportRequest $requestBody, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('reports/' . $reportId . '/pdf', $workspace_id); + + try { + $response = $this->client->post($url, [ + 'json' => $requestBody, + ]); + + $reportName = $response->getHeader('Content-Disposition')[0]; + // filename="Sample report.pdf"; filename*=UTF-8''Sample%20report.pdf....... + // extract the filename from the header + $reportName = explode('filename*=UTF-8\'\'', $reportName)[1]; + $reportName = str_replace('"', '', $reportName); + $reportName = str_replace(' ', '_', $reportName); + $reportName = urldecode($reportName); + + $pdf = $response->getBody()->getContents(); + + return new ReportPDF([ + 'filename' => $reportName, + 'pdf' => $pdf, + ]); + } catch (RequestException $e) { + throw new \Exception('Error downloading document: ' . $e->getMessage()); + } + } + + public function startExport($reportId, AsyncReportGenerationRequest $requestBody, $workspace_id = null) + { + $url = $this->buildUrlWithWorkspace('reports/' . $reportId . '/export', $workspace_id); + try { + $response = $this->client->post($url, [ + 'json' => $requestBody, + ]); + $exportResponse = $this->processResponse($response); + return new AsyncReportGenerationResponse($exportResponse); + } catch (RequestException $th) { + throw new \Exception('Failed to start async export: ' . $th->getMessage()); + } + } + + + public function getReportTypes($workspace_id = null) { $url = $this->buildUrlWithWorkspace('report-types', $workspace_id); @@ -127,7 +300,7 @@ public function getReportPreviewURL($reportId, $params = [], $workspace_id = nul $prepared_params = $this->encodeReportPreviewParams($params); $tempDataId = null; - if(!empty($data)){ + if (!empty($data)) { $prepared_data = json_encode($data); $tmpData = $this->postTempData($prepared_data); $tmpDataId = $tmpData->id; @@ -139,13 +312,13 @@ public function getReportPreviewURL($reportId, $params = [], $workspace_id = nul $nonce = $this->createNonceAuthToken()->nonce; $queryParams = []; - if($prepared_params != null){ + if ($prepared_params != null) { $queryParams['params'] = $prepared_params; } - if($prepared_data != null){ + if ($prepared_data != null) { $queryParams['data'] = $prepared_data; } - if($nonce != null){ + if ($nonce != null) { $queryParams['nonce'] = $nonce; } $url = $this->url . '/ws/' . $ws . '/reports/' . $reportId . '/preview?' . http_build_query($queryParams); @@ -168,47 +341,64 @@ public function postTempData($data, $workspace_id = null) return new \Exception('Error posting temporary data'); } } - - private function processResponse($response){ - if($response->getStatusCode() != 200){ + + private function processResponse($response) + { + if ($response->getStatusCode() != 200 && $response->getStatusCode() != 202) { throw new \Exception('Error While running the request'); } return json_decode($response->getBody(), true); } - private function buildUrlWithWorkspace($path, $workspace_id = null){ + private function buildUrlWithWorkspace($path, $workspace_id = null) + { $ws = $workspace_id == null ? $this->default_workspace_id : $workspace_id; return $this->url . '/api/v1/ws/' . $ws . '/' . $path; } - private function buildUrl($path){ + private function buildUrl($path) + { return $this->url . '/api/v1/' . $path; } - private function encodeReportPreviewParams($params){ + private function encodeReportPreviewParams($params) + { $prepared_params = []; - if(!empty($params['params'])){ + if (!empty($params['params'])) { $prepared_params['params'] = json_encode($params['params']); } else { $prepared_params['params'] = null; } - if(!empty($params['data'])){ + if (!empty($params['data'])) { $prepared_params['data'] = json_encode($params['data']); } else { $prepared_params['data'] = null; } - if(!empty($params['nonce'])){ + if (!empty($params['nonce'])) { $prepared_params['nonce'] = $params['nonce']; } - if(!empty($params['tempDataId'])){ + if (!empty($params['tempDataId'])) { $prepared_params['tempDataId'] = $params['tempDataId']; } - if(!empty($params['timezone'])){ + if (!empty($params['timezone'])) { $prepared_params['timezone'] = $params['timezone']; } else { $prepared_params['timezone'] = 'UTC'; } + if (!empty($params['format'])) { + $prepared_params['format'] = $params['format']; + } else { + $prepared_params['format'] = DocumentFIleFormat::pdf; + } + if (!empty($params['includeAttachments'])) { + $prepared_params['includeAttachments'] = $params['includeAttachments']; + } else { + $prepared_params['includeAttachments'] = false; + } + if (!empty($params['lang'])) { + $prepared_params['lang'] = $params['lang']; + } return $prepared_params; } -} \ No newline at end of file +} diff --git a/src/Models/AsyncReportGenerationRequest.php b/src/Models/AsyncReportGenerationRequest.php new file mode 100644 index 0000000..8920a44 --- /dev/null +++ b/src/Models/AsyncReportGenerationRequest.php @@ -0,0 +1,27 @@ +params = $data['params'] ?? null; + $this->data = $data['data'] ?? null; + $this->lang = $data['lang'] ?? null; + $this->timezone = $data['timezone'] ?? null; + $this->format = $data['format'] ?? null; + $this->includeAttachments = $data['includeAttachments'] ?? null; + $this->excludePages = $data['excludePages'] ?? null; + $this->tempDataId = $data['tempDataId'] ?? null; + } +} \ No newline at end of file diff --git a/src/Models/AsyncReportGenerationResponse.php b/src/Models/AsyncReportGenerationResponse.php new file mode 100644 index 0000000..215f4ec --- /dev/null +++ b/src/Models/AsyncReportGenerationResponse.php @@ -0,0 +1,13 @@ +temporaryFileId = $data['temporaryFileId']; + } +} \ No newline at end of file diff --git a/src/Models/DocumentFIleFormat.php b/src/Models/DocumentFIleFormat.php new file mode 100644 index 0000000..836774f --- /dev/null +++ b/src/Models/DocumentFIleFormat.php @@ -0,0 +1,11 @@ +id = $data['id']; + $this->name = $data['name']; + $this->description = $data['description'] ?? null; + $this->code = $data['code'] ?? null; + $this->reviewRequired = $data['reviewRequired'] ?? null; + $this->isActive = $data['isActive'] ?? null; + $this->lastRunTime = $data['lastRunTime'] ?? null; + } +} \ No newline at end of file diff --git a/src/Models/JobRun.php b/src/Models/JobRun.php new file mode 100644 index 0000000..d6f5784 --- /dev/null +++ b/src/Models/JobRun.php @@ -0,0 +1,13 @@ +jobRunId = $data['jobRunId']; + } +} \ No newline at end of file diff --git a/src/Models/JobRunEntriesStatus.php b/src/Models/JobRunEntriesStatus.php new file mode 100644 index 0000000..6a2b012 --- /dev/null +++ b/src/Models/JobRunEntriesStatus.php @@ -0,0 +1,19 @@ +queued = $data['queued'] ?? null; + $this->review = $data['review'] ?? null; + $this->completed = $data['completed'] ?? null; + $this->errors = $data['errors'] ?? null; + } +} \ No newline at end of file diff --git a/src/Models/JobRunRequest.php b/src/Models/JobRunRequest.php new file mode 100644 index 0000000..b4b7c22 --- /dev/null +++ b/src/Models/JobRunRequest.php @@ -0,0 +1,15 @@ +params = $data['params'] ?? null; + $this->data = $data['data'] ?? null; + } +} \ No newline at end of file diff --git a/src/Models/JobRunStatus.php b/src/Models/JobRunStatus.php new file mode 100644 index 0000000..30f3ea9 --- /dev/null +++ b/src/Models/JobRunStatus.php @@ -0,0 +1,17 @@ +finished = $data['finished']; + $this->entries = $data['entries']; + $this->status = new JobRunEntriesStatus($data['status']); + } +} \ No newline at end of file diff --git a/src/Models/ReportExportRequest.php b/src/Models/ReportExportRequest.php new file mode 100644 index 0000000..0a75ee1 --- /dev/null +++ b/src/Models/ReportExportRequest.php @@ -0,0 +1,23 @@ +params = $data['params'] ?? null; + $this->data = $data['data'] ?? null; + $this->lang = $data['lang'] ?? null; + $this->timezone = $data['timezone'] ?? null; + $this->format = $data['format'] ?? null; + $this->includeAttachments = $data['includeAttachments'] ?? null; + } +} \ No newline at end of file diff --git a/src/Models/ReportPage.php b/src/Models/ReportPage.php new file mode 100644 index 0000000..0219c89 --- /dev/null +++ b/src/Models/ReportPage.php @@ -0,0 +1,17 @@ +id = $data['id']; + $this->name = $data['name']; + $this->type = $data['type']; + } +} \ No newline at end of file diff --git a/src/Models/ReportPageType.php b/src/Models/ReportPageType.php new file mode 100644 index 0000000..19ee858 --- /dev/null +++ b/src/Models/ReportPageType.php @@ -0,0 +1,9 @@ +id = $data['id']; + $this->status = $data['status']; + $this->isReady = $data['isReady']; + $this->errorMessage = $data['errorMessage'] ?? null; + $this->expiryTime = $data['expiryTime']; + $this->name = $data['name'] ?? null; + $this->contentSize = $data['contentSize'] ?? null; + $this->contentType = $data['contentType'] ?? null; + } +} \ No newline at end of file