/** * generate the final result * * @return array: * 'is_error': set if there is a fatal error * 'log': array with keys: 'type', 'level', 'timestamp', 'message' * 'download_url: URL to download the result * 'download_name: suggested file name for the download */ public function wrapUp($chunk, $is_test, $is_bulk) { $reply = array(); CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'Dummy process ended.', CRM_Donrec_Logic_Exporter::LOG_TYPE_INFO); return $reply; }
/** * Returns an array all exporters used to process the snapshot * @return array */ public function getExporters() { // get snapshot id $id = $this->getId(); // get ids of items which are already processed $query = "\n SELECT `id`\n FROM `donrec_snapshot`\n WHERE snapshot_id = {$id}\n AND status = 'DONE'\n "; $result = CRM_Core_DAO::executeQuery($query); // merge process-data of all items into array $merged_process_data = array(); $count = 0; while ($result->fetch()) { $process_data = $this->getProcessInformation($result->id); $merged_process_data = array_merge($merged_process_data, $process_data); $count += 1; } // exclude values that aren't exporters $list_keys = array_keys($merged_process_data); $exporters = array_intersect($list_keys, CRM_Donrec_Logic_Exporter::listExporters()); // if we have processed lines but no exporter, we use the Dummy if (!empty($count) && empty($exporters)) { $exporters = array('Dummy'); } return $exporters; }
function run() { CRM_Utils_System::setTitle(ts('Issue Donation Receipts', array('domain' => 'de.systopia.donrec'))); // Since 4.6 the css-class crm-summary-row lives in contactSummary.css // instead of civicrm.css if (version_compare(CRM_Utils_System::version(), '4.6', '>=')) { CRM_Core_Resources::singleton()->addStyleFile('civicrm', 'css/contactSummary.css'); } $id = empty($_REQUEST['sid']) ? NULL : $_REQUEST['sid']; $ccount = empty($_REQUEST['ccount']) ? NULL : $_REQUEST['ccount']; $selected_exporter = empty($_REQUEST['exporters']) ? NULL : $_REQUEST['exporters']; $origin = empty($_REQUEST['origin']) ? NULL : $_REQUEST['origin']; // working on a test-snapshot $from_test = empty($_REQUEST['from_test']) ? NULL : $_REQUEST['from_test']; $this->assign('from_test', $from_test); // add statistic if (!empty($id)) { $statistic = CRM_Donrec_Logic_Snapshot::getStatistic($id); $statistic['requested_contacts'] = $ccount; $this->assign('statistic', $statistic); } if (!empty($selected_exporter)) { $this->assign('selected_exporter', $selected_exporter); } // check which button was clicked // called when the 'abort' button was selected if (!empty($_REQUEST['donrec_abort']) || !empty($_REQUEST['donrec_abort_by_admin'])) { $by_admin = !empty($_REQUEST['donrec_abort_by_admin']); // we need a (valid) snapshot id here if (empty($id)) { $this->assign('error', ts('No snapshot id has been provided!', array('domain' => 'de.systopia.donrec'))); $this->assign('url_back', CRM_Utils_System::url('civicrm/donrec/task')); } else { $snapshot = CRM_Donrec_Logic_Snapshot::get($id); if (empty($snapshot)) { $this->assign('error', ts('Invalid snapshot id!', array('domain' => 'de.systopia.donrec'))); $this->assign('url_back', CRM_Utils_System::url('civicrm/donrec/task')); } else { // delete the snapshot and redirect to search form $snapshot->delete(); if ($by_admin) { $return_id = $_REQUEST['return_to']; CRM_Core_Session::setStatus(ts('The older snapshot has been deleted. You can now proceed.', array('domain' => 'de.systopia.donrec')), ts('Warning', array('domain' => 'de.systopia.donrec')), 'warning'); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/donrec/task', "sid={$return_id}&ccount={$ccount}")); } else { CRM_Core_Session::setStatus(ts('The previously created snapshot has been deleted.', array('domain' => 'de.systopia.donrec')), ts('Warning', array('domain' => 'de.systopia.donrec')), 'warning'); if (!empty($_REQUEST['origin'])) { CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/view', "reset=1&cid={$origin}&selectedChild=donation_receipts")); } else { CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/contact/search')); } } } } } elseif (!empty($_REQUEST['donrec_testrun'])) { // called when the 'test run' button was selected $bulk = (int) ($_REQUEST['donrec_type'] == "2"); $exporters = $_REQUEST['result_type']; // at least one exporter has to be selected if (empty($exporters)) { $this->assign('error', ts('Missing exporter!', array('domain' => 'de.systopia.donrec'))); $this->assign('url_back', CRM_Utils_System::url('civicrm/donrec/task')); } else { //on testrun we want to return to the stats-page instead of the contact-search-page //but we must not overwrite the url_back-var $session = CRM_Core_Session::singleton(); $session->set('url_back_test', CRM_Utils_System::url('civicrm/donrec/task', "sid={$id}&ccount={$ccount}&from_test=1&origin={$origin}")); CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/donrec/runner', "sid={$id}&bulk={$bulk}&exporters={$exporters}")); } } elseif (!empty($_REQUEST['donrec_run'])) { // issue donation receipts case $bulk = (int) ($_REQUEST['donrec_type'] == "2"); $exporters = $_REQUEST['result_type']; // at least one exporter has to be selected if (empty($exporters)) { $this->assign('error', ts('Missing exporter!', array('domain' => 'de.systopia.donrec'))); $this->assign('url_back', CRM_Utils_System::url('civicrm/donrec/task')); } else { CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/donrec/runner', "sid={$id}&bulk={$bulk}&final=1&exporters={$exporters}")); } } elseif (!empty($_REQUEST['conflict'])) { // called when a snapshot conflict has been detected $conflict = CRM_Donrec_Logic_Snapshot::hasIntersections(); if (!$conflict) { CRM_Utils_System::redirect(CRM_Utils_System::url('civicrm/donrec/task', "sid={$id}&ccount={$ccount}")); } $this->assign('conflict_error', $conflict[1]); $this->assign('url_back', CRM_Utils_System::url('civicrm/contact/search')); if (CRM_Core_Permission::check('delete receipts')) { $this->assign('is_admin', 1); $this->assign('return_to', $conflict[2][0]); $this->assign('formAction', CRM_Utils_System::url('civicrm/donrec/task', "sid=" . $conflict[1][0] . "&ccount={$ccount}", false, null, false, true)); } } else { if (empty($id)) { $this->assign('error', ts('No snapshot id has been provided!', array('domain' => 'de.systopia.donrec'))); $this->assign('url_back', CRM_Utils_System::url('civicrm/contact/search', '')); } else { // get supported exporters $exp_array = array(); $exporters = CRM_Donrec_Logic_Exporter::listExporters(); foreach ($exporters as $exporter) { $classname = CRM_Donrec_Logic_Exporter::getClassForExporter($exporter); // check requirements $instance = new $classname(); $result = $instance->checkRequirements(); $is_usable = TRUE; $error_msg = ""; $info_msg = ""; if ($result['is_error']) { $is_usable = FALSE; $error_msg = $result['message']; } else { if (!empty($result['message'])) { $info_msg = $result['message']; } } $exp_array[] = array($exporter, $classname::name(), $classname::htmlOptions(), $is_usable, $error_msg, $info_msg); } $this->assign('exporters', $exp_array); $this->assign('formAction', CRM_Utils_System::url('civicrm/donrec/task', "sid={$id}&ccount={$ccount}&origin={$origin}", false, null, false, true)); } } parent::run(); }
/** * generate the final result * * @return array: * 'is_error': set if there is a fatal error * 'log': array with keys: 'type', 'level', 'timestamp', 'message' * 'download_url: URL to download the result * 'download_name: suggested file name for the download */ public function wrapUp($snapshot_id, $is_test, $is_bulk) { $reply = array(); // create the zip file $config = CRM_Core_Config::singleton(); $preferredFileName = ts("donation_receipts", array('domain' => 'de.systopia.donrec')); $preferredSuffix = ts('.zip', array('domain' => 'de.systopia.donrec')); $archiveFileName = CRM_Donrec_Logic_File::makeFileName($preferredFileName, $preferredSuffix); $fileURL = $archiveFileName; $outerArchive = new ZipArchive(); $snapshot = CRM_Donrec_Logic_Snapshot::get($snapshot_id); $ids = $snapshot->getIds(); $toRemove = array(); // Sort array by page count $pageCountArr = array(); foreach ($ids as $id) { $proc_info = $snapshot->getProcessInformation($id); if (!empty($proc_info)) { $pageCount = isset($proc_info['PDF']['pdf_pagecount']) ? $proc_info['PDF']['pdf_pagecount'] : FALSE; $filename = isset($proc_info['PDF']['pdf_file']) ? $proc_info['PDF']['pdf_file'] : FALSE; if ($pageCount) { $pageCountArr[$pageCount][] = array($pageCount, $id, $filename); } } } // add files to sub-archives // open main archive and add sub-archives if ($outerArchive->open($fileURL, ZIPARCHIVE::CREATE) === TRUE) { foreach ($pageCountArr as $entry) { foreach ($entry as $item) { if ($item[0] && $item[2]) { // if page count and file name exists $folder = sprintf(ts('%d-page', array('domain' => 'de.systopia.donrec')), $item[0]) . DIRECTORY_SEPARATOR; $opResult = $outerArchive->addFile($item[2], $folder . basename($item[2])); CRM_Donrec_Logic_Exporter::addLogEntry($reply, "adding <span title='{$item[2]}'>created {$item[0]}-page PDF file</span> ({$opResult})", CRM_Donrec_Logic_Exporter::LOG_TYPE_DEBUG); } } } if (!$outerArchive->close()) { CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'zip->close() returned false!', CRM_Donrec_Logic_Exporter::LOG_TYPE_ERROR); } } else { CRM_Donrec_Logic_Exporter::addLogEntry($reply, sprintf('PDF processing failed: Could not open zip file '), CRM_Donrec_Logic_Exporter::FATAL); return $reply; } $file = CRM_Donrec_Logic_File::createTemporaryFile($fileURL, $preferredFileName . $preferredSuffix); CRM_Core_Error::debug_log_message("de.systopia.donrec: resulting ZIP file URL is '{$file}'."); if (!empty($file)) { $reply['download_name'] = $preferredFileName . $preferredSuffix; $reply['download_url'] = $file; } // remove loose pdf files or store them CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'Removing temporary files.', CRM_Donrec_Logic_Exporter::LOG_TYPE_DEBUG); foreach ($toRemove as $file) { unlink($file); } CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'PDF generation process ended.', CRM_Donrec_Logic_Exporter::LOG_TYPE_INFO); return $reply; }
/** * generate the final result * * @return array: * 'is_error': set if there is a fatal error * 'log': array with keys: 'type', 'level', 'timestamp', 'message' * 'download_url: URL to download the result * 'download_name: suggested file name for the download */ public function wrapUp($snapshot_id, $is_test, $is_bulk) { $snapshot = CRM_Donrec_Logic_Snapshot::get($snapshot_id); $reply = array(); // open file $preferredFileName = ts('donation_receipts'); $preferredFileSuffix = ts('.csv', array('domain' => 'de.systopia.donrec')); $temp_file = CRM_Donrec_Logic_File::makeFileName($preferredFileName, $preferredFileSuffix); $handle = fopen($temp_file, 'w'); // get headers $headers = CRM_Donrec_Logic_ReceiptTokens::getFullTokenList(); $headers = $this->flattenTokenData($headers); $headers = array_keys($headers); $header_written = false; // write them all into the file $ids = $snapshot->getIds(); foreach ($ids as $id) { $proc_info = $snapshot->getProcessInformation($id); $csv_data = $proc_info['CSV']['csv_data']; if (!empty($csv_data)) { if (!$header_written) { // extend header by extra fields $headers = array_merge($headers, array_keys($csv_data)); $headers = array_unique($headers); // write header fputcsv($handle, $headers, ';', '"'); $header_written = true; } // create and write a line $line = array(); foreach ($headers as $field) { if (isset($csv_data[$field])) { $line[$field] = $csv_data[$field]; } else { $line[$field] = ''; } } fputcsv($handle, $line, ';', '"'); } } // get process info iterator fclose($handle); // create the file $file = CRM_Donrec_Logic_File::createTemporaryFile($temp_file, $preferredFileName . $preferredFileSuffix); CRM_Core_Error::debug_log_message("de.systopia.donrec: resulting CSV file URL is '{$file}'."); if (!empty($file)) { $reply['download_name'] = $preferredFileName; $reply['download_url'] = $file; } CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'CSV process ended.', CRM_Donrec_Logic_Exporter::LOG_TYPE_INFO); return $reply; }
/** * generate the final result * * @return array: * 'is_error': set if there is a fatal error * 'log': array with keys: 'type', 'level', 'timestamp', 'message' * 'download_url: URL to download the result * 'download_name: suggested file name for the download */ public function wrapUp($snapshot_id, $is_test, $is_bulk) { $reply = array(); // create the zip file $config = CRM_Core_Config::singleton(); $preferredFileName = ts("donation_receipts.zip", array('domain' => 'de.systopia.donrec')); $archiveFileName = CRM_Donrec_Logic_File::makeFileName(ts("donation_receipts", array('domain' => 'de.systopia.donrec')), ".zip"); $zip = new ZipArchive(); $snapshot = CRM_Donrec_Logic_Snapshot::get($snapshot_id); $ids = $snapshot->getIds(); $toRemove = array(); if ($zip->open($archiveFileName, ZIPARCHIVE::CREATE) === TRUE) { foreach ($ids as $id) { $proc_info = $snapshot->getProcessInformation($id); if (!empty($proc_info)) { $filename = isset($proc_info['PDF']['pdf_file']) ? $proc_info['PDF']['pdf_file'] : FALSE; if ($filename) { $toRemove[$id] = $filename; $opResult = $zip->addFile($filename, basename($filename)); CRM_Donrec_Logic_Exporter::addLogEntry($reply, "adding <span title='{$filename}'>created PDF file</span> to <span title='{$archiveFileName}'>ZIP archive</span> ({$opResult})", CRM_Donrec_Logic_Exporter::LOG_TYPE_DEBUG); } } } if (!$zip->close()) { CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'zip->close() returned false!', CRM_Donrec_Logic_Exporter::LOG_TYPE_ERROR); } } else { CRM_Donrec_Logic_Exporter::addLogEntry($reply, sprintf('PDF processing failed: Could not open zip file '), CRM_Donrec_Logic_Exporter::LOG_TYPE_FATAL); return $reply; } $file = CRM_Donrec_Logic_File::createTemporaryFile($archiveFileName, $preferredFileName); CRM_Core_Error::debug_log_message("de.systopia.donrec: resulting ZIP file URL is '{$file}'."); if (!empty($file)) { $reply['download_name'] = $preferredFileName; $reply['download_url'] = $file; } // remove loose pdf files or store them CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'Removing temporary PDF files.', CRM_Donrec_Logic_Exporter::LOG_TYPE_DEBUG); foreach ($toRemove as $file) { unlink($file); } CRM_Donrec_Logic_Exporter::addLogEntry($reply, 'PDF generation process ended.', CRM_Donrec_Logic_Exporter::LOG_TYPE_INFO); return $reply; }
/** * execute the next step of a donation receipt run * * @return array of stats: */ public function nextStep() { // some containers $exporter_results = array(); $files = array(); $profile = $this->snapshot->getProfile(); // Synchronize this step $lock = CRM_Utils_DonrecHelper::getLock('CRM_Donrec_Logic_Engine', 'nextStep'); if (!$lock->isAcquired()) { // lock timed out CRM_Core_Error::debug_log_message("de.systopia.donrec - couldn't acquire lock. Timeout is " . $lock->_timeout); // compile and return "state of affairs" report $stats = $this->createStats(); $stats['log'] = array(); $stats['files'] = $files; $stats['chunk_size'] = 0; CRM_Donrec_Logic_Exporter::addLogEntry($stats, "Couldn't acquire lock. Parallel processing denied. Lock timeout is {$lock->_timeout}s."); return $stats; } // check status $is_bulk = !empty($this->parameters['bulk']); $is_test = !empty($this->parameters['test']); // initialize stuff $chunk = $this->snapshot->getNextChunk($is_bulk, $is_test); $exporters = $this->getExporters(); // loop over receipts foreach ($chunk as $chunk_id => $chunk_items) { // Setup some parameters //********************************** // Prepare chunk_items: // #FIXME: It is more convenient to have a simalar array-structure for bulk- // and single-processing. In future the getNextChunk-method might be // refactored and build up the arrays correspondingly. $chunk_items = $is_bulk ? $chunk_items : array($chunk_items); $contact_id = $chunk_items[0]['contact_id']; $line_ids = array(); foreach ($chunk_items as $chunk_item) { $line_ids[] = $chunk_item['id']; } // create a SnapshotReceipt $snapshot_receipt = $this->snapshot->getSnapshotReceipt($line_ids, $is_test); // call exporters //********************************** foreach ($exporters as $exporter) { $exporter_id = $exporter->getID(); if ($is_bulk) { $result = $exporter->exportBulk($snapshot_receipt, $is_test); } else { $result = $exporter->exportSingle($snapshot_receipt, $is_test); } if (!isset($exporter_results[$exporter_id])) { $exporter_results[$exporter_id] = array(); $exporter_results[$exporter_id]['success'] = 0; $exporter_results[$exporter_id]['failure'] = 0; } if ($result) { $exporter_results[$exporter_id]['success']++; } else { $exporter_results[$exporter_id]['failure']++; } } // save original pdfs and create receipt for non-test-runs //********************************** if (!$is_test) { $receipt_params = array(); $receipt_params['type'] = $is_bulk ? 'BULK' : 'SINGLE'; if ($profile->saveOriginalPDF()) { $pdf_file = $this->getPDF($line_ids); $file = CRM_Donrec_Logic_File::createPermanentFile($pdf_file, basename($pdf_file), $contact_id); if (!empty($file)) { $receipt_params['original_file'] = $file['id']; } } CRM_Donrec_Logic_Receipt::createFromSnapshotReceipt($snapshot_receipt, $receipt_params); } } // The last chunk is empty. // If it is the last do some wrap-up. // Otherwise mark the chunk as processed. //********************************** if (!$chunk) { foreach ($exporters as $exporter) { $result = $exporter->wrapUp($this->snapshot->getId(), $is_test, $is_bulk); if (!empty($result['download_name']) && !empty($result['download_url'])) { $files[$exporter->getID()] = array($result['download_name'], $result['download_url']); } } } else { $this->snapshot->markChunkProcessed($chunk, $is_test, $is_bulk); } // compile stats //********************************** $stats = $this->createStats(); // create log-messages foreach ($exporter_results as $exporter_id => $result) { $msg = sprintf('%s processed %d items - %d succeeded, %d failed', $exporter_id, count($chunk), $result['success'], $result['failure']); $type = $result['failure'] ? 'ERROR' : 'INFO'; CRM_Donrec_Logic_Exporter::addLogEntry($stats, $msg, $type); } $stats['files'] = $files; if ($chunk == NULL) { $stats['progress'] = 100.0; } else { $stats['chunk_size'] = count($chunk); } // release our lock $lock->release(); return $stats; }