commerce_billy_pdf.module in Commerce Billy 7
Commerce Billy module file.
File
modules/commerce_billy_pdf/commerce_billy_pdf.moduleView source
<?php
/**
* @file
* Commerce Billy module file.
*/
/**
* Implements hook_menu().
*/
function commerce_billy_pdf_menu() {
$items['invoice-pdf/%commerce_order'] = array(
'title' => 'Invoice',
'page callback' => 'commerce_billy_pdf',
'page arguments' => array(
1,
),
'access callback' => 'commerce_billy_pdf_view_access',
'access arguments' => array(
1,
),
'type' => MENU_CALLBACK,
);
// Add a HTML version of the invoice for easier debugging for themers and
// printing.
$items['invoice-pdf/%commerce_order/print'] = array(
'title' => 'HTML Invoice',
'page callback' => 'commerce_billy_pdf_html_page',
'page arguments' => array(
1,
),
'access callback' => 'commerce_billy_pdf_view_access',
'access arguments' => array(
1,
),
'type' => MENU_CALLBACK,
);
$items['admin/commerce/config/billy-invoice/pdf'] = array(
'title' => 'PDF',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'commerce_billy_pdf_admin_form',
),
'access arguments' => array(
'configure order settings',
),
'type' => MENU_LOCAL_TASK,
'file' => 'commerce_billy_pdf.admin.inc',
);
$items['admin/commerce/orders/%commerce_order/pdf-invoice'] = array(
'title' => 'Invoice (PDF)',
'page callback' => 'commerce_billy_pdf',
'page arguments' => array(
3,
),
'access callback' => 'commerce_billy_pdf_view_access',
'access arguments' => array(
3,
),
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'weight' => 10,
);
return $items;
}
/**
* Implements hook_admin_paths_alter().
*
* Render PDF using default theme.
*/
function commerce_billy_pdf_admin_paths_alter(&$paths) {
$paths['admin/commerce/orders/*/pdf-invoice'] = FALSE;
}
/**
* Access callback for the PDF invoice.
*
* Deny access if order is not in status 'invoiced' or the current user does not
* have view access to the order itself.
* Furthermore admins can access 'canceled' orders (credit memo).
*/
function commerce_billy_pdf_view_access($order) {
if ($order->status == 'canceled' && $order->order_id != $order->order_number && user_access('administer commerce_order entities')) {
return TRUE;
}
elseif (!in_array($order->status, variable_get('commerce_billy_pdf_order_statuses', array(
'invoiced',
)))) {
return FALSE;
}
return commerce_order_customer_order_view_access($order);
}
/**
* Implements hook_views_api().
*/
function commerce_billy_pdf_views_api() {
return array(
'api' => 3,
'path' => drupal_get_path('module', 'commerce_billy_pdf') . '/includes/views',
);
}
/**
* Implements hook_entity_info_alter().
*/
function commerce_billy_pdf_entity_info_alter(&$info) {
$info['commerce_order']['view modes']['pdf'] = array(
'label' => t('PDF'),
'custom settings' => FALSE,
);
$info['commerce_order']['view modes']['canceled'] = array(
'label' => t('Credit memo'),
'custom settings' => FALSE,
);
}
/**
* Implements hook_theme().
*/
function commerce_billy_pdf_theme() {
// Register the template specific for the commerce pdf order.
$items['commerce_order__commerce_order__pdf'] = array(
'render element' => 'elements',
'template' => 'commerce_order--commerce_order--pdf',
'path' => drupal_get_path('module', 'commerce_billy_pdf') . '/templates',
);
$items['commerce_order__commerce_order__canceled'] = array(
'render element' => 'elements',
'template' => 'commerce_order--commerce_order--canceled',
'path' => drupal_get_path('module', 'commerce_billy_pdf') . '/templates',
);
$items['commerce_billy_pdf_page'] = array(
'variables' => array(
'viewed_orders' => array(),
'inline_css' => '',
),
'template' => 'commerce_billy_pdf_page',
'path' => drupal_get_path('module', 'commerce_billy_pdf') . '/templates',
);
return $items;
}
/**
* Implements hook_preprocess_entity().
*
* Adds theme hook suggestions for the pdf and canceled view modes, allowing the
* commerce_billy_pdf templates to be used for orders of all bundles.
*/
function commerce_billy_pdf_preprocess_entity(&$variables) {
$entity_type = $variables['entity_type'];
$view_mode = $variables['view_mode'];
$pdf_view_modes = array(
'pdf',
'canceled',
);
if ($entity_type == 'commerce_order' && in_array($view_mode, $pdf_view_modes)) {
$variables['theme_hook_suggestions'][] = $entity_type . '__commerce_order__' . $view_mode;
}
}
/**
* Page callback for invoice PDF.
*/
function commerce_billy_pdf($order) {
$html = commerce_billy_pdf_html($order);
$filename = preg_replace('/[^a-z0-9]/', '_', drupal_strtolower('invoice_' . $order->order_number));
commerce_billy_pdf_output($html, $filename);
// print $html;
drupal_exit();
}
/**
* Page callback for the HTML version of the invoice.
*/
function commerce_billy_pdf_html_page($order) {
$html = commerce_billy_pdf_html($order);
print $html;
drupal_exit();
}
/**
* Helper function that returns the generated HTML for the invoice PDFs.
*
* @param object[] $orders
* Array of order objects.
*/
function commerce_billy_pdf_html($orders) {
// Backwards compatibilty: also accept a single order object.
if (is_object($orders)) {
$orders = array(
$orders,
);
}
foreach ($orders as $order) {
$vars['viewed_orders'][] = entity_view('commerce_order', array(
$order->order_id => $order,
), 'pdf', NULL, TRUE);
// Add a credit memo.
if ($order->status == 'canceled') {
$vars['viewed_orders'][] = entity_view('commerce_order', array(
$order->order_id => $order,
), 'canceled', NULL, TRUE);
}
}
$css_files = variable_get('commerce_billy_pdf_css_files', array(
drupal_get_path('module', 'commerce_billy_pdf') . '/css/pdf.css',
));
if (variable_get('commerce_billy_pdf_converter', 'dompdf') == 'wkhtmltopdf') {
$css_files[] = drupal_get_path('module', 'commerce_billy_pdf') . '/css/pdf_wkhtmltopdf.css';
}
$vars['inline_css'] = "";
foreach ($css_files as $file) {
$vars['inline_css'] .= file_get_contents($file);
}
return theme('commerce_billy_pdf_page', $vars);
}
/**
* Implements hook_commerce_order_view().
*/
function commerce_billy_pdf_commerce_order_view($order, $view_mode) {
// Add content variables for the PDF generation.
$settings = variable_get('commerce_billy_pdf_text_settings', array());
$custom_date_format = !empty($settings['invoice_date_format']) ? $settings['invoice_date_format'] : 'Y-m-d';
if ($view_mode == "pdf" || $view_mode == 'canceled') {
$order->content['invoice_footer'] = array(
'#markup' => isset($settings['invoice_footer']) ? $settings['invoice_footer'] : '',
);
$order->content['invoice_header'] = array(
'#markup' => isset($settings['invoice_header']) ? $settings['invoice_header'] : '',
);
$order->content['invoice_text'] = array(
'#markup' => isset($settings['invoice_text']) ? $settings['invoice_text'] : '',
);
$date_field_name = $view_mode == 'pdf' ? 'field_commerce_billy_i_date' : 'field_commerce_billy_cancel_date';
$date_formatted = format_date($order->{$date_field_name}[LANGUAGE_NONE][0]['value'], 'custom', $custom_date_format);
if (!empty($settings['invoice_location'])) {
$invoice_header_date_text = t('@location, @date', array(
'@location' => $settings['invoice_location'],
'@date' => $date_formatted,
));
}
else {
$invoice_header_date_text = $date_formatted;
}
$order->content['invoice_header_date'] = array(
'#markup' => $invoice_header_date_text,
);
$order->content['order_number'] = array(
'#markup' => t('Invoice No.: @id', array(
'@id' => $order->order_number,
)),
);
$order->content['order_id'] = array(
'#markup' => t('Order No.: @id', array(
'@id' => $order->order_id,
)),
);
$logo_path = variable_get('commerce_billy_pdf_logo', 'misc/druplicon.png');
if (variable_get('commerce_billy_pdf_converter', 'dompdf') == 'wkhtmltopdf') {
$logo_path = DRUPAL_ROOT . '/' . $logo_path;
}
$order->content['invoice_logo'] = array(
'#value' => $logo_path,
);
}
}
/**
* Transforms HTML to PDF and outputs it to the browser.
*
* @param $html
* The HTML to render as PDF
*
* @param $filename
* The filename to be used for the PDF.
*
* @param $as_file
* TRUE if a filecontent should be returned (e.g. for mails), else as stream
* for downloads.
*/
function commerce_billy_pdf_output($html, $filename, $as_file = FALSE) {
$pdf_converter = variable_get('commerce_billy_pdf_converter', 'dompdf');
if ($pdf_converter == 'dompdf') {
return commerce_billy_pdf_dompdf($html, $filename, $as_file);
}
elseif ($pdf_converter == 'wkhtmltopdf') {
return commerce_billy_pdf_wkhtmltopdf($html, $filename, $as_file);
}
}
/**
* DOMPDF converter
*/
function commerce_billy_pdf_dompdf($html, $filename, $as_file = FALSE) {
$dompdf = commerce_billy_pdf_prepare_dompdf($html, $filename);
if ($dompdf) {
try {
if ($as_file) {
$filecontent = $dompdf
->output();
return $filecontent;
}
else {
return $dompdf
->stream($filename, array(
'Attachment' => TRUE,
));
}
} catch (\Dompdf\Exception $e) {
drupal_set_message(t('Error generating PDF invoice. Please contact the website administrator.'), 'error');
watchdog('commerce_billy_pdf', 'DOMPDF exception while generating pdf invoice: %message', array(
'%message' => $e
->getMessage(),
), WATCHDOG_ERROR);
return '';
}
}
}
/**
* WKHTMLTOPDF converter
*/
function commerce_billy_pdf_wkhtmltopdf($html, $filename, $as_file = FALSE) {
$path = libraries_get_path('phpwkhtmltopdf');
if (!empty($path)) {
$wkhtmltopdf_path = variable_get('wkhtmltopdf_path', '/usr/bin/wkhtmltopdf');
require_once DRUPAL_ROOT . '/' . $path . '/WkHtmlToPdf.php';
$filename .= '.pdf';
$tmp = file_directory_temp();
$pdf = new WkHtmlToPdf(array(
'binPath' => $wkhtmltopdf_path,
'tmp' => $tmp,
'no-outline',
'margin-top' => 0,
'margin-right' => 0,
'margin-bottom' => 0,
'margin-left' => 0,
// Default page options
'disable-smart-shrinking',
));
$pdf
->addPage($html);
if ($as_file) {
$pdf
->saveAs($tmp . '/' . $filename);
$file_content = file_get_contents($tmp . '/' . $filename);
return $file_content;
}
else {
$output = $pdf
->send($filename);
$error = $pdf
->getError();
// Log any errors.
if (!empty($error)) {
watchdog('commerce_billy_pdf', 'WkHtmlToPdf exception while generating pdf resume: %message', array(
'%message' => $error,
), WATCHDOG_ERROR);
return t('Error generating PDF resume. Please contact the website administrator.');
}
else {
return $output;
}
}
}
return t('WkHtmlToPdf not found');
}
/**
* Helper function that instantiates new DOMPDF class and renders the HTML.
*
* The returned dompdf object can then be used to either directly stream the
* output or to create a file.
*/
function commerce_billy_pdf_prepare_dompdf($html, $filename) {
// dompdf needs write access to its font directory.
// Copy "libraries/dompdf/lib/fonts" to your public files directory in order
// for this to work. Older versions of Dompdf use these constants.
if (!defined('DOMPDF_FONT_DIR')) {
$dir = drupal_realpath('public://');
define('DOMPDF_FONT_DIR', $dir . '/fonts/');
}
if (!defined('DOMPDF_TEMP_DIR')) {
define('DOMPDF_TEMP_DIR', file_directory_temp());
}
// First check if dompdf is already auto-loaded with composer, if not try to
// load it with Libraries API.
if (class_exists('\\Dompdf\\Dompdf')) {
$dompdf = new \Dompdf\Dompdf();
$font_dir = drupal_realpath('public://fonts');
// Dompdf writes out font files for caching, make sure they are in a
// writeable directory in the files folder.
$dompdf
->set_option('fontDir', $font_dir);
$dompdf
->set_option('fontCache', $font_dir);
}
else {
$path = libraries_get_path('dompdf');
if (empty($path)) {
return FALSE;
}
// Support for Dompdf 0.7.0 and newer, using PHP 5.3 namespaces.
if (file_exists(DRUPAL_ROOT . '/' . $path . '/autoload.inc.php')) {
require_once DRUPAL_ROOT . '/' . $path . '/autoload.inc.php';
$dompdf = new \Dompdf\Dompdf();
}
else {
require_once DRUPAL_ROOT . '/' . $path . '/dompdf_config.inc.php';
spl_autoload_register('DOMPDF_autoload');
$dompdf = new DOMPDF();
}
}
$dompdf
->set_paper('a4', 'portrait');
$html = htmlspecialchars_decode(htmlentities($html, ENT_NOQUOTES, 'UTF-8'), ENT_NOQUOTES);
$dompdf
->load_html($html);
$dompdf
->render();
return $dompdf;
}
/**
* Implements hook_action_info().
*/
function commerce_billy_pdf_action_info() {
return array(
'commerce_billy_pdf_print_invoices' => array(
'label' => t('Print invoice'),
'type' => 'commerce_order',
'aggregate' => TRUE,
'configurable' => FALSE,
'triggers' => array(
'any',
),
),
);
}
/**
* Callback to generate a PDF.
*/
function commerce_billy_pdf_print_invoices($orders) {
$html = commerce_billy_pdf_html($orders);
// The .pdf file extension is added by DOMPDF.
$filename = 'invoices';
commerce_billy_pdf_output($html, $filename);
drupal_exit();
}