From 0115c173211391ba1362491a2089ee56a314af24 Mon Sep 17 00:00:00 2001
From: Jared Hancock <jared@osticket.com>
Date: Mon, 8 Dec 2014 12:58:23 -0600
Subject: [PATCH] print: Add support for client printing

---
 include/class.pdf.php                         |   9 +-
 include/class.ticket.php                      |   2 +-
 .../client/templates/ticket-print.tmpl.php    | 234 ++++++++++++++++++
 include/client/view.inc.php                   |   4 +
 include/staff/templates/ticket-print.tmpl.php |  34 ++-
 tickets.php                                   |  13 +-
 6 files changed, 278 insertions(+), 18 deletions(-)
 create mode 100644 include/client/templates/ticket-print.tmpl.php

diff --git a/include/class.pdf.php b/include/class.pdf.php
index 9a7f0a700..32bc4b881 100644
--- a/include/class.pdf.php
+++ b/include/class.pdf.php
@@ -61,13 +61,18 @@ class Ticket2PDF extends mPDF
     }
 
     function _print() {
-        global $thisstaff, $cfg;
+        global $thisstaff, $thisclient, $cfg;
 
         if(!($ticket=$this->getTicket()))
             return;
 
         ob_start();
-        include STAFFINC_DIR.'templates/ticket-print.tmpl.php';
+        if ($thisstaff)
+            include STAFFINC_DIR.'templates/ticket-print.tmpl.php';
+        elseif ($thisclient)
+            include CLIENTINC_DIR.'templates/ticket-print.tmpl.php';
+        else
+            return;
         $html = ob_get_clean();
 
         $this->WriteHtml($html, 0, true, true);
diff --git a/include/class.ticket.php b/include/class.ticket.php
index 5bdec7646..7b95d9b82 100644
--- a/include/class.ticket.php
+++ b/include/class.ticket.php
@@ -2177,7 +2177,7 @@ class Ticket {
 
         $pdf = new Ticket2PDF($this, $psize, $notes);
         $name='Ticket-'.$this->getNumber().'.pdf';
-        $pdf->Output($name, 'I');
+        Http::download($name, 'application/pdf', $pdf->Output($name, 'S'));
         //Remember what the user selected - for autoselect on the next print.
         $_SESSION['PAPER_SIZE'] = $psize;
         exit;
diff --git a/include/client/templates/ticket-print.tmpl.php b/include/client/templates/ticket-print.tmpl.php
new file mode 100644
index 000000000..d30973911
--- /dev/null
+++ b/include/client/templates/ticket-print.tmpl.php
@@ -0,0 +1,234 @@
+<html>
+
+<head>
+    <style type="text/css">
+@page {
+    header: html_def;
+    footer: html_def;
+    margin: 15mm;
+    margin-top: 30mm;
+    margin-bottom: 22mm;
+}
+.logo {
+  max-width: 220px;
+  max-height: 71px;
+  width: auto;
+  height: auto;
+  margin: 0;
+}
+#ticket_thread .message,
+#ticket_thread .response,
+#ticket_thread .note {
+    margin-top:10px;
+    border:1px solid #aaa;
+    border-bottom:2px solid #aaa;
+}
+#ticket_thread .header {
+    text-align:left;
+    border-bottom:1px solid #aaa;
+    padding:3px;
+    width: 100%;
+    table-layout: fixed;
+}
+#ticket_thread .message .header {
+    background:#C3D9FF;
+}
+#ticket_thread .response .header {
+    background:#DDD;
+}
+#ticket_thread .note .header {
+    background:#FFE;
+}
+#ticket_thread .info {
+    padding:5px;
+    background: snow;
+    border-top: 0.3mm solid #ccc;
+}
+
+table.meta-data {
+    width: 100%;
+}
+table.custom-data {
+    margin-top: 10px;
+}
+table.custom-data th {
+    width: 25%;
+}
+table.custom-data th,
+table.meta-data th {
+    text-align: right;
+    background-color: #ddd;
+    padding: 3px 8px;
+}
+table.meta-data td {
+    padding: 3px 8px;
+}
+.faded {
+    color:#666;
+}
+.pull-left {
+    float: left;
+}
+.pull-right {
+    float: right;
+}
+.flush-right {
+    text-align: right;
+}
+.flush-left {
+    text-align: left;
+}
+.ltr {
+    direction: ltr;
+    unicode-bidi: embed;
+}
+.headline {
+    border-bottom: 2px solid black;
+    font-weight: bold;
+}
+div.hr {
+    border-top: 0.2mm solid #bbb;
+    margin: 0.5mm 0;
+    font-size: 0.0001em;
+}
+.thread-entry, .thread-body {
+    page-break-inside: avoid;
+}
+<?php include ROOT_DIR . 'css/thread.css'; ?>
+    </style>
+</head>
+<body>
+
+<htmlpageheader name="def" style="display:none">
+<?php if ($logo = $cfg->getClientLogo()) { ?>
+    <img src="cid:<?php echo $logo->getKey(); ?>" class="logo"/>
+<?php } else { ?>
+    <img src="<?php echo INCLUDE_DIR . 'fpdf/print-logo.png'; ?>" class="logo"/>
+<?php } ?>
+    <div class="hr">&nbsp;</div>
+    <table><tr>
+        <td class="flush-left"><?php echo (string) $ost->company; ?></td>
+        <td class="flush-right"><?php echo Format::db_daydatetime(Misc::gmtime()); ?></td>
+    </tr></table>
+</htmlpageheader>
+
+<htmlpagefooter name="def" style="display:none">
+    <div class="hr">&nbsp;</div>
+    <table width="100%"><tr><td class="flush-left">
+        Ticket #<?php echo $ticket->getNumber(); ?> printed by
+        <?php echo $thisclient->getName()->getFirst(); ?> on
+        <?php echo Format::db_daydatetime(Misc::gmtime()); ?>
+    </td>
+    <td class="flush-right">
+        Page {PAGENO}
+    </td>
+    </tr></table>
+</htmlpagefooter>
+
+<!-- Ticket metadata -->
+<h1>Ticket #<?php echo $ticket->getNumber(); ?></h1>
+<table class="meta-data" cellpadding="0" cellspacing="0">
+<tbody>
+<tr>
+    <th><?php echo __('Status'); ?></th>
+    <td><?php echo $ticket->getStatus(); ?></td>
+    <th><?php echo __('Name'); ?></th>
+    <td><?php echo $ticket->getOwner()->getName(); ?></td>
+</tr>
+<tr>
+    <th><?php echo __('Priority'); ?></th>
+    <td><?php echo $ticket->getPriority(); ?></td>
+    <th><?php echo __('Email'); ?></th>
+    <td><?php echo $ticket->getEmail(); ?></td>
+</tr>
+<tr>
+    <th><?php echo __('Department'); ?></th>
+    <td><?php echo $ticket->getDept(); ?></td>
+    <th><?php echo __('Phone'); ?></th>
+    <td><?php echo $ticket->getPhoneNumber(); ?></td>
+</tr>
+<tr>
+    <th><?php echo __('Create Date'); ?></th>
+    <td><?php echo Format::db_datetime($ticket->getCreateDate()); ?></td>
+    <th><?php echo __('Source'); ?></th>
+    <td><?php echo $ticket->getSource(); ?></td>
+</tr>
+</tbody>
+</table>
+
+<!-- Custom Data -->
+<?php
+foreach (DynamicFormEntry::forTicket($ticket->getId()) as $form) {
+    // Skip core fields shown earlier in the ticket view
+    // TODO: Rewrite getAnswers() so that one could write
+    //       ->getAnswers()->filter(not(array('field__name__in'=>
+    //           array('email', ...))));
+    $answers = array_filter($form->getAnswers(), function ($a) {
+        return !in_array($a->getField()->get('name'),
+                array('email','subject','name','priority'))
+            && !$a->getField()->get('private');
+        });
+    if (count($answers) == 0)
+        continue;
+    ?>
+        <table class="custom-data" cellspacing="0" cellpadding="4" width="100%" border="0">
+        <tr><td colspan="2" class="headline flush-left"><?php echo $form->getTitle(); ?></th></tr>
+        <?php foreach($answers as $a) {
+            if (!($v = $a->display())) continue; ?>
+            <tr>
+                <th><?php
+    echo $a->getField()->get('label');
+                ?>:</th>
+                <td><?php
+    echo $v;
+                ?></td>
+            </tr>
+            <?php } ?>
+        </table>
+    <?php
+    $idx++;
+} ?>
+
+<!-- Ticket Thread -->
+<h2><?php echo $ticket->getSubject(); ?></h2>
+<div id="ticket_thread">
+<?php
+$types = array('M', 'R');
+
+if ($thread = $ticket->getThreadEntries($types)) {
+    $threadTypes=array('M'=>'message','R'=>'response', 'N'=>'note');
+    foreach ($thread as $entry) { ?>
+        <div class="thread-entry <?php echo $threadTypes[$entry['thread_type']]; ?>">
+            <table class="header"><tr><td>
+                    <span><?php
+                        echo Format::db_datetime($entry['created']);?></span>
+                    <span style="padding:0 1em" class="faded title"><?php
+                        echo Format::truncate($entry['title'], 100); ?></span>
+                </td>
+                <td class="flush-right faded title" style="white-space:no-wrap">
+                    <?php
+                        echo Format::htmlchars($entry['name'] ?: $entry['poster']); ?></span>
+                </td>
+            </tr></table>
+            <div class="thread-body">
+                <div><?php echo $entry['body']->display('pdf'); ?></div>
+            </div>
+            <?php
+            if ($entry['attachments']
+                    && ($tentry = $ticket->getThreadEntry($entry['id']))
+                    && ($files = $tentry->getAttachments())) { ?>
+                <div class="info">
+<?php           foreach ($files as $F) { ?>
+                    <div>
+                        <span><?php echo $F['name']; ?></span>
+                        <span class="faded">(<?php echo Format::file_size($F['size']); ?>)</span>
+                    </div>
+<?php           } ?>
+                </div>
+<?php       } ?>
+        </div>
+<?php }
+} ?>
+</div>
+</body>
+</html>
diff --git a/include/client/view.inc.php b/include/client/view.inc.php
index 6fb76a9d9..59ddf6b0b 100644
--- a/include/client/view.inc.php
+++ b/include/client/view.inc.php
@@ -33,12 +33,16 @@ if ($thisclient && $thisclient->isGuest()
             <h1>
                 <?php echo sprintf(__('Ticket #%s'), $ticket->getNumber()); ?> &nbsp;
                 <a href="tickets.php?id=<?php echo $ticket->getId(); ?>" title="<?php echo __('Reload'); ?>"><span class="Icon refresh">&nbsp;</span></a>
+<div class="pull-right">
+    <a class="action-button" href="tickets.php?a=print&id=<?php
+        echo $ticket->getId(); ?>"><i class="icon-print"></i> <?php echo __('Print'); ?></a>
 <?php if ($ticket->hasClientEditableFields()
         // Only ticket owners can edit the ticket details (and other forms)
         && $thisclient->getId() == $ticket->getUserId()) { ?>
                 <a class="action-button pull-right" href="tickets.php?a=edit&id=<?php
                      echo $ticket->getId(); ?>"><i class="icon-edit"></i> <?php echo __('Edit'); ?></a>
 <?php } ?>
+</div>
             </h1>
         </td>
     </tr>
diff --git a/include/staff/templates/ticket-print.tmpl.php b/include/staff/templates/ticket-print.tmpl.php
index bd9ed2aa7..430c775d9 100644
--- a/include/staff/templates/ticket-print.tmpl.php
+++ b/include/staff/templates/ticket-print.tmpl.php
@@ -6,7 +6,8 @@
     header: html_def;
     footer: html_def;
     margin: 15mm;
-    margin-top: 35mm;
+    margin-top: 30mm;
+    margin-bottom: 22mm;
 }
 .logo {
   max-width: 220px;
@@ -26,7 +27,8 @@
     text-align:left;
     border-bottom:1px solid #aaa;
     padding:3px;
-    position: relative;
+    width: 100%;
+    table-layout: fixed;
 }
 #ticket_thread .message .header {
     background:#C3D9FF;
@@ -39,9 +41,8 @@
 }
 #ticket_thread .info {
     padding:5px;
-    background:#F4FAFF;
-    height:16px;
-    line-height:16px;
+    background: snow;
+    border-top: 0.3mm solid #ccc;
 }
 
 table.meta-data {
@@ -70,8 +71,6 @@ table.meta-data td {
 }
 .pull-right {
     float: right;
-    position: absolute;
-    right: 0;
 }
 .flush-right {
     text-align: right;
@@ -92,6 +91,9 @@ div.hr {
     margin: 0.5mm 0;
     font-size: 0.0001em;
 }
+.thread-entry, .thread-body {
+    page-break-inside: avoid;
+}
 <?php include ROOT_DIR . 'css/thread.css'; ?>
     </style>
 </head>
@@ -111,7 +113,7 @@ div.hr {
 </htmlpageheader>
 
 <htmlpagefooter name="def" style="display:none">
-    <hr class="tight faded"/>
+    <div class="hr">&nbsp;</div>
     <table width="100%"><tr><td class="flush-left">
         Ticket #<?php echo $ticket->getNumber(); ?> printed by
         <?php echo $thisstaff->getUserName(); ?> on
@@ -235,12 +237,18 @@ if ($thread = $ticket->getThreadEntries($types)) {
             <div class="thread-body">
                 <div><?php echo $entry['body']->display('pdf'); ?></div>
             <?php
-            if($entry['attachments']
+            if ($entry['attachments']
                     && ($tentry = $ticket->getThreadEntry($entry['id']))
-                    && ($links = $tentry->getAttachmentsLinks())) {?>
-            <div class="info"><?php echo $tentry->getAttachmentsLinks(); ?></div>
-            <?php
-            } ?>
+                    && ($files = $tentry->getAttachments())) { ?>
+                <div class="info">
+<?php           foreach ($files as $F) { ?>
+                    <div>
+                        <span><?php echo $F['name']; ?></span>
+                        <span class="faded">(<?php echo Format::file_size($F['size']); ?>)</span>
+                    </div>
+<?php           } ?>
+                </div>
+<?php       } ?>
             </div>
         </div>
 <?php }
diff --git a/tickets.php b/tickets.php
index 2161b67b2..052762488 100644
--- a/tickets.php
+++ b/tickets.php
@@ -40,7 +40,7 @@ $messageField = $tform->getField('message');
 $attachments = $messageField->getWidget()->getAttachments();
 
 //Process post...depends on $ticket object above.
-if($_POST && is_object($ticket) && $ticket->getId()):
+if ($_POST && is_object($ticket) && $ticket->getId()) {
     $errors=array();
     switch(strtolower($_POST['a'])){
     case 'edit':
@@ -101,7 +101,16 @@ if($_POST && is_object($ticket) && $ticket->getId()):
         $errors['err']=__('Unknown action');
     }
     $ticket->reload();
-endif;
+}
+elseif (is_object($ticket) && $ticket->getId()) {
+    switch(strtolower($_REQUEST['a'])) {
+    case 'print':
+        if (!$ticket || !$ticket->pdfExport($_REQUEST['psize']))
+            $errors['err'] = __('Internal error: Unable to export the ticket to PDF for print.');
+        break;
+    }
+}
+
 $nav->setActiveNav('tickets');
 if($ticket && $ticket->checkUserAccess($thisclient)) {
     if (isset($_REQUEST['a']) && $_REQUEST['a'] == 'edit'
-- 
GitLab