/** * 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; }
/** * Delete original-file if exists * @return TRUE for success, FALSE for failure */ public function deleteOriginalFile() { $file_id = self::getOriginalFileId(); if (!$file_id) { return FALSE; } $receipt_fields = self::$_custom_fields; $receipt_group_id = self::$_custom_group_id; $receipt_id = $this->Id; $query = "\n UPDATE `civicrm_value_donation_receipt_{$receipt_group_id}`\n SET `{$receipt_fields['original_file']}` = NULL\n WHERE id = {$receipt_id}\n "; $result = CRM_Core_DAO::executeQuery($query); $success = CRM_Donrec_Logic_File::deleteFile($file_id); return $success; }
/** * 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; }
/** * View Receipts */ function civicrm_api3_donation_receipt_view($params) { // check for missing receipt id parameter if (empty($params['rid'])) { return civicrm_api3_create_error(ts("No 'rid' parameter given.", array('domain' => 'de.systopia.donrec'))); } $receipt = CRM_Donrec_Logic_Receipt::get($params['rid']); if (empty($receipt)) { return civicrm_api3_create_error(sprintf(ts("Receipt with id %d does not exist.", array('domain' => 'de.systopia.donrec')), $params['rid'])); } if (empty($params['name'])) { $name = 'View.pdf'; } else { $name = $params['name']; } $values = $receipt->getAllProperties(); $profile = $receipt->getProfile(); // mark this as DRAFT id ORIGINAL if (empty($values['watermark'])) { $values['status'] = 'DRAFT'; $values['watermark'] = $profile->get('draft_text'); } $pdf = $profile->getTemplate()->generatePDF($values, $parameter); $url = CRM_Donrec_Logic_File::createTemporaryFile($pdf, $name); // and return the result return civicrm_api3_create_success($url); }
/** * 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; }
public static function addDynamicTokens(&$values) { if (!empty($values['issued_by'])) { // add created_by_display_name try { $creator = civicrm_api3('Contact', 'getsingle', array('id' => $values['issued_by'])); $values['issued_by_display_name'] = $creator['display_name']; } catch (Exception $e) { CRM_Core_Error::debug_log_message('de.systopia.donrec - ' . print_r($e, 1)); } } // add the legacy 'today' token if (!empty($values['issued_on'])) { $values['today'] = $values['issued_on']; } // add the monetary tokens: 'total', 'totaltext', 'totalmoney' if (isset($values['total_amount'])) { // format total_amount $values['total_amount'] = number_format((double) $values['total_amount'], 2, '.', ''); $values['total'] = $values['total_amount']; $values['totaltext'] = CRM_Utils_DonrecHelper::convert_number_to_words($values['total_amount']); $values['totalmoney'] = CRM_Utils_Money::format($values['total_amount'], ''); } // add financial type name $financialTypes = CRM_Contribute_PseudoConstant::financialType(); if (is_array($values['lines'])) { foreach ($values['lines'] as $key => $line) { if (!empty($line['financial_type_id'])) { $values['lines'][$key]['financial_type'] = $financialTypes[$line['financial_type_id']]; } } } // sort contribution lines by receive date (#1497) $receive_dates = array(); $sorted_lines = $values['lines']; foreach ($sorted_lines as $key => $line) { $sorted_lines[$key]['id'] = $key; $receive_dates[$key] = $line['receive_date']; } array_multisort($receive_dates, SORT_ASC, $sorted_lines); $values['lines'] = array(); foreach ($sorted_lines as $key => $line) { $values['lines'][$line['id']] = $line; } // add legacy 'items' if (count($values['lines']) > 1) { $values['items'] = $values['lines']; } // add organisation address if (empty($values['organisation'])) { $domain = CRM_Core_BAO_Domain::getDomain(); $values['organisation'] = self::lookupAddressTokens($domain->contact_id, 0, 0); } // ADD watermarks $profile = CRM_Donrec_Logic_Profile::getProfile($values['profile']); if ($values['status'] == 'ORIGINAL') { // nothing to to in this case.. } elseif ($values['status'] == 'COPY') { $values['watermark'] = $profile->get('copy_text'); } else { // in all other cases, it's INVALID/DRAFT: $values['watermark'] = $profile->get('draft_text'); } // copy contributor values to addressee, if not set separately if (!isset($values['addressee']['display_name'])) { $values['addressee']['display_name'] = $values['contributor']['display_name']; } if (!isset($values['addressee']['addressee_display'])) { $values['addressee']['addressee_display'] = $values['contributor']['addressee_display']; } // add URL to view original file, if it exists if (!empty($values['original_file'])) { $values['view_url'] = CRM_Donrec_Logic_File::getPermanentURL($values['original_file'], $values['contributor']['id']); } // TODO: call Token hooks? Currently done by PDF generator }
/** * Creates a PDF file from the specified values * * @param array associative array of values that will be * assigned to the template * @param array of configuration parameters * @return filename or False */ public function generatePDF($values, &$parameters) { $smarty = CRM_Core_Smarty::singleton(); $config = CRM_Core_Config::singleton(); // assign all values foreach ($values as $token => $value) { $smarty->assign($token, $value); } // callback for custom variables CRM_Utils_DonrecCustomisationHooks::pdf_unique_token($smarty, $values); // get template $html = $this->_template->msg_html; // --- watermark injection --- // identify pdf engine $pdf_engine = $config->wkhtmltopdfPath; if (!empty($pdf_engine)) { $wk_is_enabled = TRUE; $watermark_css = '<style> {literal} .watermark { position: fixed; z-index: 999; color: rgba(128, 128, 128, 0.20); -ms-transform: rotate(-45deg); /* IE 9 */ -webkit-transform: rotate(-45deg); /* Chrome, Safari, Opera */ transform: rotate(-45deg); font-size: 100pt!important; } .watermark-center { left: 10px; top: 400px; } {/literal} </style> '; } else { $wk_is_enabled = FALSE; $watermark_css = '<style> {literal} .watermark { position: fixed; z-index: 999; opacity: 0.10; -ms-transform: rotate(-45deg); /* IE 9 */ -webkit-transform: rotate(-45deg); /* Chrome, Safari, Opera */ transform: rotate(-45deg); font-size: 100pt!important; } .watermark-center { left: 30px; top: 650px; } {/literal} </style> '; } $smarty->assign('wk_enabled', $wk_is_enabled); // prepare watermark $watermark_site = '<div class="watermark watermark-center">{if $watermark}{$watermark}{/if}</div>'; // find </style> element $matches = array(); preg_match('/<\\/style>/', $html, $matches, PREG_OFFSET_CAPTURE); if (count($matches) == 1) { $head_offset = $matches[0][1]; $html = substr_replace($html, $watermark_css, $head_offset + strlen($matches[0][0]), 0); } else { if (count($matches) < 1) { CRM_Core_Error::debug_log_message('de.systopia.donrec: watermark css could not be created (</style> not found). falling back to <body>.'); $matches = array(); preg_match('/<body>/', $html, $matches, PREG_OFFSET_CAPTURE); if (count($matches) == 1) { $head_offset = $matches[0][1]; $html = substr_replace($html, $watermark_css, $head_offset, 0); } else { CRM_Core_Error::debug_log_message('de.systopia.donrec: watermark could not be created. pdf rendering cancelled.'); return FALSE; } } } // find <body> element $matches = array(); preg_match('/<body[^>]*>/', $html, $matches, PREG_OFFSET_CAPTURE); if (count($matches) == 1) { $body_offset = $matches[0][1]; $html = substr_replace($html, $watermark_site, $body_offset + strlen($matches[0][0]), 0); } else { if (count($matches) < 1) { CRM_Core_Error::debug_log_message('de.systopia.donrec: watermark could not be created for site one (<body> not found). pdf rendering cancelled.'); return FALSE; } } // --- watermark injection end --- // compile template $html = $smarty->fetch("string:{$html}"); // reset template variables $smarty->clearTemplateVars(); // set up file names $filename_export = CRM_Donrec_Logic_File::makeFileName(ts("donationreceipt-", array('domain' => 'de.systopia.donrec')) . "{$values['contributor']['id']}-" . date('YmdHis'), ".pdf"); // render PDF receipt $result = file_put_contents($filename_export, CRM_Utils_PDF_Utils::html2pdf($html, null, true, $this->_template->pdf_format_id)); if ($result) { return $filename_export; } else { $parameters['error'] = "Could not write file {$filename_export}"; return FALSE; } }
/** * 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; }