Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

In this Discussion

osTicket v1.10 (stable) and Maintenance Release v1.9.15 are now available! Go get it now

[MOD] Simple time spent on ticket

edited November 2013 in Mods and Customizations
This is a rewrite of fidel's v1.6 mod, tested and working with v1.7.0. Note that the following patches should be applied at the TLD of your osTicket installation (using patch -p0 < ). Several files are affected:
  • include/ajax.tickets.php
  • include/class.pdf.php
  • include/class.ticket.php
  • include/staff/ticket-view.inc.php
  • scp/tickets.php
Note that my line numbers might differ from yours, and the order in which I apply this mod with others will most likely differ form the order in which you do.

NB - Before using this patch, you must add time_spent columns to your ticket and ticket_thread tables:

ALTER TABLE `ost_ticket`  ADD `time_spent` FLOAT(4,2) NULL DEFAULT '0.00';
ALTER TABLE `ost_ticket_thread` ADD `time_spent` FLOAT(4,2) NULL DEFAULT '0.00';


The patch containing all changes:

--- include/ajax.tickets.php	2013-04-01 23:40:05.000000000 -0600
+++ include/ajax.tickets.php 2013-05-02 10:50:37.000000000 -0600
@@ -319,6 +319,13 @@
</tr>',
Format::db_datetime($ticket->getEstDueDate()));
}
+ echo sprintf('
+ <tr>
+ <th width=\"100\">Time Spent:</th>
+ <td>%s</td>
+ </tr>',
+ Format::htmlchars($ticket->formatTime($ticket->getTimeSpent()))
+ );
echo '</table>';


--- include/class.pdf.php 2013-04-01 23:40:05.000000000 -0600
+++ include/class.pdf.php 2013-05-03 14:53:42.000000000 -0600
@@ -195,12 +195,16 @@
$this->SetFont('');
$this->Cell($c, 7, Format::db_datetime($ticket->getCloseDate()), 1, 0, 'L', true);
}
-
$this->SetFont('Arial', 'B', 11);
$this->Cell($l, 7, 'Last Message', 1, 0, 'L', true);
$this->SetFont('');
$this->Cell($c, 7, Format::db_datetime($ticket->getLastMsgDate()), 1, 1, 'L', true);
- $this->Ln(5);
+
+ $this->SetFont('Arial', 'B', 11);
+ $this->Cell($l, 7, 'Time Spent', 1, 0, 'L', true);
+ $this->SetFont('');
+ $this->Cell($c, 7, Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())), 1, 0, 'L', true);
+ $this->Ln(10);

$this->SetFont('Arial', 'B', 11);
$this->cMargin = 0;
--- include/class.ticket.php 2013-04-01 23:40:05.000000000 -0600
+++ include/class.ticket.php 2013-05-04 17:18:07.000000000 -0600
@@ -234,6 +234,10 @@
return $this->ht['closed'];
}

+ function getTimeSpent() {
+ return $this->ht['time_spent'];
+ }
+
function getStatus() {
return $this->ht['status'];
}
@@ -316,6 +320,24 @@
return $this->tlock;
}

+ function formatTime($time) {
+
+ $hours = floor($time);
+ $minutes = round(($time-$hours) * 60);
+
+ if ($hours > 0) {
+ $formatted_time .= $hours.($hours == 1 ? ' hour' : ' hours');
+ if ($minutes > 0) {
+ $formatted_time .= ' '.$minutes.($minutes == 1 ? ' minute' : ' minutes');
+ }
+ }
+ else {
+ $formatted_time .= $minutes.($minutes == 1 ? ' minute' : ' minutes');
+ }
+
+ return $formatted_time;
+ }
+
function acquireLock($staffId, $lockTime) {

if(!$staffId or !$lockTime) //Lockig disabled?
@@ -713,6 +735,57 @@
return (db_query($sql) && db_affected_rows());
}

+ function timeSpent($time) {
+ if (empty($time) || !is_numeric($time)) {
+ $time = 0.00;
+ } else {
+ $time = round($time, 2);
+ }
+
+ $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent+'.db_input($time)
+ .' WHERE ticket_id='.db_input($this->getId());
+
+ return (db_query($sql) && db_affected_rows());
+ }
+
+ function timeSpentDel($time) {
+ if (empty($time) || !is_numeric($time)) {
+ $time = 0.00;
+ } else {
+ $time = round($time, 2);
+ }
+
+ $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent-'.db_input($time)
+ .' WHERE ticket_id='.db_input($this->getId());
+
+ return (db_query($sql) && db_affected_rows());
+ }
+
+ function timeSpentEntry($id, $time) {
+ if (empty($time) || !is_numeric($time)) {
+ $time = 0.00;
+ } else {
+ $time = round($time, 2);
+ }
+
+ $sql='UPDATE '.TICKET_THREAD_TABLE.' SET time_spent='.db_input($time)
+ .' WHERE id='.db_input($id);
+
+ $this->timeSpent($time);
+
+ return (db_query($sql) && db_affected_rows());
+ }
+
+ function timeSpentEntryDel($id) {
+ $sql='SELECT time_spent FROM '.TICKET_THREAD_TABLE
+ .' WHERE id='.db_input($id);
+
+ $result = db_query($sql);
+ $row = db_fetch_array($result);
+ $time = $row['time_spent'];
+ $this->timeSpentDel($time);
+ }
+
function onNewTicket($message, $autorespond=true, $alertstaff=true) {
global $cfg;

--- include/staff/ticket-view.inc.php 2013-04-01 23:40:05.000000000 -0600
+++ include/staff/ticket-view.inc.php 2013-05-03 16:22:53.000000000 -0600
@@ -245,6 +245,10 @@
<?php
}
?>
+ <tr>
+ <th>Time Spent:</th>
+ <td><?php echo Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())); ?></td>
+ </tr>
</table>
</td>
<td width=\"50%\">
@@ -314,6 +318,11 @@
</tr>
<?php
}?>
+ <tr>
+ <td class=\"info\" colspan=\"2\">
+ <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($note['time_spent'])); ?>
+ </td>
+ </tr>
</table>
<?php
}
@@ -349,6 +358,11 @@
</tr>
<?php
}?>
+ <tr>
+ <td class=\"info\" colspan=\"3\">
+ <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($entry['time_spent'])); ?>
+ </td>
+ </tr>
</table>
<?php
if($entry['thread_type']=='M')
@@ -482,6 +496,18 @@
</td>
</tr>
<?php
+ if($ticket->isOpen()) { ?>
+ <tr>
+ <td width=\"160\">
+ <label for=\"reply_time_spent\" class=\"left\">Time Spent:</label>
+ </td>
+ <td width=\"765\">
+ <input type=\"text\" name=\"reply_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['reply_time_spent'])) echo $_POST['reply_time_spent']; ?>\"/> (0.75 = 45 minutes)
+ </td>
+ </tr>
+ <?php
+ } ?>
+ <?php
if($ticket->isClosed() || $thisstaff->canCloseTickets()) { ?>
<tr>
<td width=\"160\">
@@ -558,7 +584,19 @@
<?php
}
?>
- <tr><td colspan=\"2\">&nbsp;</td></tr>
+ <?php
+ if($ticket->isOpen()) { ?>
+ <tr>
+ <td width=\"160\">
+ <label for=\"note_time_spent\" class=\"left\">Time Spent:</label>
+ </td>
+ <td width=\"765\">
+ <input type=\"text\" name=\"note_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['note_time_spent'])) echo $_POST['note_time_spent']; ?>\"/> (0.75 = 45 minutes)
+ </td>
+ </tr>
+ <?php
+ }
+ ?>
<tr>
<td width=\"160\">
<label>Ticket Status:</label>
--- scp/tickets.php 2013-04-01 23:40:05.000000000 -0600
+++ scp/tickets.php 2013-05-03 16:25:08.000000000 -0600
@@ -66,6 +66,7 @@

if(!$errors && ($response=$ticket->postReply($vars, $errors, isset($_POST['emailreply'])))) {
$msg='Reply posted successfully';
+ $ticket->timeSpentEntry($response->getId(),$_POST['reply_time_spent']);
$ticket->reload();
if($ticket->isClosed() && $wasOpen)
$ticket=null;
@@ -168,6 +169,7 @@
if(($note=$ticket->postNote($vars, $errors, $thisstaff))) {

$msg='Internal note posted successfully';
+ $ticket->timeSpentEntry($note->getId(),$_POST['note_time_spent']);
if($wasOpen && $ticket->isClosed())
$ticket = null; //Going back to main listing.
«1

Comments

  • so, we need to insert the timespent manually? can we just set it by system (datetime now - last response) ? so there's no manipulation in the ticket

    for the staff and client..

    thank you
  • @wrustuch: while I can see the appeal to that approach, I think the premise that a staff member is devoting 100% of the time between the last response on a ticket that they've been assigned and the time of their reply is problematic for several reasons:
    • the staff member may be working on (an)other ticket(s) simultaneously
    • the staff member may be performing other work that is not ticket-related, or not at work at all
    • the ticket owner may reply to the ticket (e.g. to supply additional information) while the staff member is working on the issue
    • two or more staff members may be working on the same ticket
    These are just a few real-life examples of why manual entry of time spent is required where I work (I'll admit that there are some workarounds to address the most of the points, but the result ends up being both an estimation and an approximation of time spent, anyway).

    The statistical overview of response and services times provided by the dashboard seems to be a step in the direction you're looking at - maybe Peter would be including these metrics at the individual ticket level. You could also look at masino_sinaga's Auto Staff Time Sheet mod for v1.6.
  • Great Mod!

    With the Two mods I applied today (This one and Database driven "Second Status") I feel like osTicket is actually a replacement for Autotask and other PSA softwares I have previously used.

    Thanks for creating it. My techs really appreciate it, as now they can track time easier.
  • Looks awesome

    I'm realativly new to osTicket and PHP (running it on a Windows box)
    I manually made the changes in the files, and I'm now getting the following error:

    Fatal error: Call to a member function getId() on a non-object in \helpdesk\scp\tickets.php on line 67


                if(!$errors && ($respId=$ticket->postReply($_POST, $errorsi, isset($_POST['emailreply'])))) {
    $msg='Reply posted successfully';
    $ticket->timeSpentEntry($response->getId(),$_POST['reply_time_spent']);
    $ticket->reload();
    if($ticket->isClosed() && $wasOpen)
    $ticket=null;


    Which is a little different from what you had posted in the change file
  • @utopiasedge: thanks for the positive feedback. I'm sure that Peter will eventually incorporate some form of time tracking into osTicket - especially as it's such a common feature in other issue tracking software applications.
  • @hanspnilsson: it looks to me like you might be running an older version of osTicket, or you may have applied some mod to these lines already; when I download v1.7.0 from the Download page, I see the following lines in scp/tickets.php:

                if(!$errors && ($response=$ticket->postReply($vars, $errors, isset($_POST['emailreply'])))) {
    $msg='Reply posted successfully';
    $ticket->reload();
    if($ticket->isClosed() && $wasOpen)
    $ticket=null;


    If memory serves, this change appeared in v1.7.0, though it's not immediately obvious why the postReply function has been modified to return a Response object instead of its integer ID...

    I'd recommend starting from a fresh copy of v1.7.0, if you can. If that's not practical, you could try changing the line:

    $ticket->timeSpentEntry($response->getId(),$_POST['reply_time_spent']);


    to:

    $ticket->timeSpentEntry($respId,$_POST['reply_time_spent']);


    but (begin caveat) I can't honestly guarantee that will work, and that it won't ruin your installation of osTicket in some other way.(end caveat)
  • Refreshing scp\tickets.php and adding in manual updates again did it. Thanks!
  • @hanspnilsson: That's good news!
  • Simple and Effective

    Very simple MOD that adds just the functionality we were looking for.

    Easily 5 stars. Don't forget to vote at the top of the page folks.

    Thanks for your work on this MOD Tpope. :cool:
  • Thanks, lmpc!
  • Install Patch

    I have installed only a few mods before (still learning). So far each mod has had me manually editing the files. I have never done this as a 'Patch'.
    Sorry for the newbie question but how or where do I run this patch?
  • jdsmith;41060 said:
    I have installed only a few mods before (still learning). So far each mod has had me manually editing the files. I have never done this as a 'Patch'.
    Sorry for the newbie question but how or where do I run this patch?
    Its a linux command: http://en.wikipedia.org/wiki/Patch_(Unix)

    You can also manually edit the files, use this article to explain what the patchfile does:http://www.markusbe.com/2009/12/how-to-read-a-patch-or-diff-and-understand-its-structure-to-apply-it-manually/
  • Working

    Thanks for the details.
    I have enabled SSH, and created a session to the server using a telnet like program (zoc). The patch has been run and appears to be working correctly. However when I ran it, the last few lines make me think there was a problem

    patching file scp/tickets.php
    patch unexpectedly ends in middle of line
    Hunk #2 succeeded at 169 with fuzz 2.


    doesn't sound good, but the program appears to be working fine. Is this normal?
  • tpope;39755 said:
    This is a rewrite of fidel's v1.6 mod, tested and working with v1.7.0. Note that the following patches should be applied at the TLD of your osTicket installation (using patch -p0 < ). Several files are affected:
    • include/ajax.tickets.php
    • include/class.pdf.php
    • include/class.ticket.php
    • include/staff/ticket-view.inc.php
    • scp/tickets.php
    Note that my line numbers might differ from yours, and the order in which I apply this mod with others will most likely differ form the order in which you do.

    NB - Before using this patch, you must add time_spent columns to your ticket and ticket_thread tables:

    ALTER TABLE `ost_ticket`  ADD `time_spent` FLOAT(4,2) NULL DEFAULT '0.00';
    ALTER TABLE `ost_ticket_thread` ADD `time_spent` FLOAT(4,2) NULL DEFAULT '0.00';


    The patch containing all changes:

    --- include/ajax.tickets.php	2013-04-01 23:40:05.000000000 -0600
    +++ include/ajax.tickets.php 2013-05-02 10:50:37.000000000 -0600
    @@ -319,6 +319,13 @@
    </tr>',
    Format::db_datetime($ticket->getEstDueDate()));
    }
    + echo sprintf('
    + <tr>
    + <th width=\"100\">Time Spent:</th>
    + <td>%s</td>
    + </tr>',
    + Format::htmlchars($ticket->formatTime($ticket->getTimeSpent()))
    + );
    echo '</table>';


    --- include/class.pdf.php 2013-04-01 23:40:05.000000000 -0600
    +++ include/class.pdf.php 2013-05-03 14:53:42.000000000 -0600
    @@ -195,12 +195,16 @@
    $this->SetFont('');
    $this->Cell($c, 7, Format::db_datetime($ticket->getCloseDate()), 1, 0, 'L', true);
    }
    -
    $this->SetFont('Arial', 'B', 11);
    $this->Cell($l, 7, 'Last Message', 1, 0, 'L', true);
    $this->SetFont('');
    $this->Cell($c, 7, Format::db_datetime($ticket->getLastMsgDate()), 1, 1, 'L', true);
    - $this->Ln(5);
    +
    + $this->SetFont('Arial', 'B', 11);
    + $this->Cell($l, 7, 'Time Spent', 1, 0, 'L', true);
    + $this->SetFont('');
    + $this->Cell($c, 7, Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())), 1, 0, 'L', true);
    + $this->Ln(10);

    $this->SetFont('Arial', 'B', 11);
    $this->cMargin = 0;
    --- include/class.ticket.php 2013-04-01 23:40:05.000000000 -0600
    +++ include/class.ticket.php 2013-05-04 17:18:07.000000000 -0600
    @@ -234,6 +234,10 @@
    return $this->ht['closed'];
    }

    + function getTimeSpent() {
    + return $this->ht['time_spent'];
    + }
    +
    function getStatus() {
    return $this->ht['status'];
    }
    @@ -316,6 +320,24 @@
    return $this->tlock;
    }

    + function formatTime($time) {
    +
    + $hours = floor($time);
    + $minutes = round(($time-$hours) * 60);
    +
    + if ($hours > 0) {
    + $formatted_time .= $hours.($hours == 1 ? ' hour' : ' hours');
    + if ($minutes > 0) {
    + $formatted_time .= ' '.$minutes.($minutes == 1 ? ' minute' : ' minutes');
    + }
    + }
    + else {
    + $formatted_time .= $minutes.($minutes == 1 ? ' minute' : ' minutes');
    + }
    +
    + return $formatted_time;
    + }
    +
    function acquireLock($staffId, $lockTime) {

    if(!$staffId or !$lockTime) //Lockig disabled?
    @@ -713,6 +735,57 @@
    return (db_query($sql) && db_affected_rows());
    }

    + function timeSpent($time) {
    + if (empty($time) || !is_numeric($time)) {
    + $time = 0.00;
    + } else {
    + $time = round($time, 2);
    + }
    +
    + $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent+'.db_input($time)
    + .' WHERE ticket_id='.db_input($this->getId());
    +
    + return (db_query($sql) && db_affected_rows());
    + }
    +
    + function timeSpentDel($time) {
    + if (empty($time) || !is_numeric($time)) {
    + $time = 0.00;
    + } else {
    + $time = round($time, 2);
    + }
    +
    + $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent-'.db_input($time)
    + .' WHERE ticket_id='.db_input($this->getId());
    +
    + return (db_query($sql) && db_affected_rows());
    + }
    +
    + function timeSpentEntry($id, $time) {
    + if (empty($time) || !is_numeric($time)) {
    + $time = 0.00;
    + } else {
    + $time = round($time, 2);
    + }
    +
    + $sql='UPDATE '.TICKET_THREAD_TABLE.' SET time_spent='.db_input($time)
    + .' WHERE id='.db_input($id);
    +
    + $this->timeSpent($time);
    +
    + return (db_query($sql) && db_affected_rows());
    + }
    +
    + function timeSpentEntryDel($id) {
    + $sql='SELECT time_spent FROM '.TICKET_THREAD_TABLE
    + .' WHERE id='.db_input($id);
    +
    + $result = db_query($sql);
    + $row = db_fetch_array($result);
    + $time = $row['time_spent'];
    + $this->timeSpentDel($time);
    + }
    +
    function onNewTicket($message, $autorespond=true, $alertstaff=true) {
    global $cfg;

    --- include/staff/ticket-view.inc.php 2013-04-01 23:40:05.000000000 -0600
    +++ include/staff/ticket-view.inc.php 2013-05-03 16:22:53.000000000 -0600
    @@ -245,6 +245,10 @@
    <?php
    }
    ?>
    + <tr>
    + <th>Time Spent:</th>
    + <td><?php echo Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())); ?></td>
    + </tr>
    </table>
    </td>
    <td width=\"50%\">
    @@ -314,6 +318,11 @@
    </tr>
    <?php
    }?>
    + <tr>
    + <td class=\"info\" colspan=\"2\">
    + <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($note['time_spent'])); ?>
    + </td>
    + </tr>
    </table>
    <?php
    }
    @@ -349,6 +358,11 @@
    </tr>
    <?php
    }?>
    + <tr>
    + <td class=\"info\" colspan=\"3\">
    + <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($entry['time_spent'])); ?>
    + </td>
    + </tr>
    </table>
    <?php
    if($entry['thread_type']=='M')
    @@ -482,6 +496,18 @@
    </td>
    </tr>
    <?php
    + if($ticket->isOpen()) { ?>
    + <tr>
    + <td width=\"160\">
    + <label for=\"reply_time_spent\" class=\"left\">Time Spent:</label>
    + </td>
    + <td width=\"765\">
    + <input type=\"text\" name=\"reply_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['reply_time_spent'])) echo $_POST['reply_time_spent']; ?>\"/> (0.75 = 45 minutes)
    + </td>
    + </tr>
    + <?php
    + } ?>
    + <?php
    if($ticket->isClosed() || $thisstaff->canCloseTickets()) { ?>
    <tr>
    <td width=\"160\">
    @@ -558,7 +584,19 @@
    <?php
    }
    ?>
    - <tr><td colspan=\"2\">&nbsp;</td></tr>
    + <?php
    + if($ticket->isOpen()) { ?>
    + <tr>
    + <td width=\"160\">
    + <label for=\"note_time_spent\" class=\"left\">Time Spent:</label>
    + </td>
    + <td width=\"765\">
    + <input type=\"text\" name=\"note_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['note_time_spent'])) echo $_POST['note_time_spent']; ?>\"/> (0.75 = 45 minutes)
    + </td>
    + </tr>
    + <?php
    + }
    + ?>
    <tr>
    <td width=\"160\">
    <label>Ticket Status:</label>
    --- scp/tickets.php 2013-04-01 23:40:05.000000000 -0600
    +++ scp/tickets.php 2013-05-03 16:25:08.000000000 -0600
    @@ -66,6 +66,7 @@

    if(!$errors && ($response=$ticket->postReply($vars, $errors, isset($_POST['emailreply'])))) {
    $msg='Reply posted successfully';
    + $ticket->timeSpentEntry($response->getId(),$_POST['reply_time_spent']);
    $ticket->reload();
    if($ticket->isClosed() && $wasOpen)
    $ticket=null;
    @@ -168,6 +169,7 @@
    if(($note=$ticket->postNote($vars, $errors, $thisstaff))) {

    $msg='Internal note posted successfully';
    + $ticket->timeSpentEntry($note->getId(),$_POST['note_time_spent']);
    if($wasOpen && $ticket->isClosed())
    $ticket = null; //Going back to main listing.

    I am new to this, how would i implement this MOD on a windows box?
  • Could you give me a tutorial manual edit for files? :o I don't have an access on my server to running a patch (installed my os Ticket on web hosting).
  • @jdsmith - The message "patch unexpectedly ends in middle of line" probably indicates that the last line of the patch was expected to be just an end-of-line character, but contained other text (either "$ticket = null; //Going back to main listing." or some white space). I'll modify the original post to include the empty line at the end of the patch - otherwise, I'd say that the patch would appear to have been applied successfully.
  • @jdsmith - Also, "fuzz 2" simply means that the patch executable found the matching text either 2 lines above or 2 lines below where it was expecting to find them.
  • @evcarr - Depending on how you manage your mySQL database, the first step would be to add a column called "time_spent" to both the ost_ticket and ost_ticket_thread tables. This column should be of type float, have a default value of 0.00, and accept null values.

    Next, you can manually make the changes prescribed in the patch file; e.g.:

    --- include/ajax.tickets.php	2013-04-01 23:40:05.000000000 -0600
    +++ include/ajax.tickets.php 2013-05-02 10:50:37.000000000 -0600
    @@ -319,6 +319,13 @@
    </tr>',
    Format::db_datetime($ticket->getEstDueDate()));
    }
    + echo sprintf('
    + <tr>
    + <th width=\"100\">Time Spent:</th>
    + <td>%s</td>
    + </tr>',
    + Format::htmlchars($ticket->formatTime($ticket->getTimeSpent()))
    + );
    echo '</table>';


    means that in the file include/ajax.tickets.php (in the osticket directory), at line 319 (approximately - it might vary by a few lines) / below the curly bracket (}) under the line "Format::db_datetime($ticket->getEstDueDate()));" you would add the lines in the fragment above that have a plus sign (+) next to them.

    Before:

    include/ajax.tickets.php:
    [...]
    </tr>',
    Format::db_datetime($ticket->getEstDueDate()));
    }
    echo '</table>';
    [...]


    After:

    include/ajax.tickets.php:
    [...]
    </tr>',
    Format::db_datetime($ticket->getEstDueDate()));
    }
    echo sprintf('
    <tr>
    <th width=\"100\">Time Spent:</th>
    <td>%s</td>
    </tr>',
    Format::htmlchars($ticket->formatTime($ticket->getTimeSpent()))
    );
    echo '</table>';
    [...]


    Likewise, wherever you come across lines with a (-) next to them, you would remove these from the file.

    Naturally, I recommend making a copy (i.e. backup) of any files that you edit, before you start making changes :)

    You could also try a program like WinMerge - I haven't tried it myself, but it could make the whole process a lot easier.
  • Thank you so much!
  • I was able to use rhe patch using tortoise svn it took some time figuring it out but I got it! Thanks for this mod! Is there a way to have the the total time show up in a report?
  • @evcarr - No problem, glad it worked out for you :) as for reporting, it's something that we wrote a quick and dirty mod for when we were running 1.6rc5. I've been thinking about porting it to 1.7 - and integrating it with the new reporting tools on the dashboard - but haven't come up with anything tangible yet. If I do, I'll certainly post it on the forums!
  • Thanks for this mod! It is almost exactly what I was looking for.
    Can you explain me how to make the time spent field mandatory before closing ticket plz? (ie : when staff decide to close a ticket, this field must have been fulfilled)
  • Thanks for the [MOD], works great, very useful!

    I added a couple lines to hide the "0 minutes", when a time wasn't added, just to clean up the page a little.


    --- include/staff/ticket-view.inc.php

    @@ -245,6 +245,10 @@
    <?php
    }
    ?>
    [COLOR=\"GREEN\"]+ <?php
    + if($ticket->getTimeSpent() != 0) {?>[/COLOR]
    + <tr>
    + <th>Time Spent:</th>
    + <td><?php echo Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())); ?></td>
    + </tr>
    [COLOR=\"GREEN\"]+ <?php
    + }?>[/COLOR]
    </table>
    </td>
    <td width=\"50%\">
    @@ -314,6 +318,11 @@
    </tr>
    <?php
    }?>
    [COLOR=\"GREEN\"]+ <?php
    + if($note['time_spent'] != 0) {?>[/COLOR]
    + <tr>
    + <td class=\"info\" colspan=\"2\">
    + <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($note['time_spent'])); ?>
    + </td>
    + </tr>
    [COLOR=\"GREEN\"]+ <?php
    + }?>[/COLOR]
    </table>
    <?php
    }
    @@ -349,6 +358,11 @@
    </tr>
    <?php
    }?>
    [COLOR=\"GREEN\"]+ <?php
    + if($entry['time_spent'] != 0) {?>[/COLOR]
    + <tr>
    + <td class=\"info\" colspan=\"3\">
    + <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($entry['time_spent'])); ?>
    + </td>
    + </tr>
    [COLOR=\"GREEN\"]+ <?php
    + }?>[/COLOR]
    </table>
    <?php
    if($entry['thread_type']=='M')


    I use this [MOD] on 1.7RC5 here are the changes I made: (if anyone else uses 1.7RC5)

    	
    Changes:
    scp/tickets.php around line 68
    [COLOR=\"GREEN\"]$response->getId()[/COLOR] --TO-- [COLOR=\"GREEN\"]$respId[/COLOR]
    scp/tickets.php around line 178
    [COLOR=\"GREEN\"]$note->getId()[/COLOR] --TO-- [COLOR=\"GREEN\"]$noteId[/COLOR]


    Thanks Again
  • Screen Shot

    Also thought this [MOD] could use some screenshots.
    time_show.jpg
    620 x 158 - 18K
    time_test.jpg
    620 x 167 - 27K
  • PDF items

    Just added some code so it also prints the Time Spent to PDF.

    In File: include/class.pdf.php

    After


    $text.=\"\nFiles Attached: [\".implode(', ',$files).\"]\n\";
    }
    $this->WriteText($w*2, $text, 1);


    Add


    if($entry['time_spent'] != 0){
    $this->SetFillColor(221,221,221);
    $this->SetFont('Arial', '', 9);
    $this->Cell($w, 5, \"Time Spent: \" . $ticket->formatTime($entry['time_spent']), 'LBR', 1, 'L', true);
    }
    test_time_pdf.jpg
    620 x 222 - 31K
  • Not trying to over post.... Here is support for negative numbers. (In the case you would need to correct a previous input time)

    In File: include/class.ticket.php

    Add items in GREEN


    function formatTime($time) {

    [COLOR=\"Green\"] if ($time < 0){
    $negative_convert = 1;
    $time = $time * -1;
    }[/COLOR]
    $hours = floor($time);
    $minutes = round(($time-$hours) * 60);

    if ($hours > 0) {
    $formatted_time .= $hours.($hours == 1 ? ' hour' : ' hours');
    if ($minutes > 0) {
    $formatted_time .= ' '.$minutes.($minutes == 1 ? ' minute' : ' minutes');
    }
    }
    else {
    $formatted_time .= $minutes.($minutes == 1 ? ' minute' : ' minutes');
    }

    [COLOR=\"Green\"] if ($negative_convert == 1){
    $formatted_time = \"- \" . $formatted_time;
    }[/COLOR]

    return $formatted_time;
    }


    It seems the math that updates the times supports negative numbers it just needed a couple changes to display them.

    To use it just use a negative number as in the second screenshot [-1.5]
    test_subtract_time.jpg
    620 x 116 - 17K
    input_negative_time.jpg
    431 x 223 - 23K
  • I copied the patch code and double checked it after i received the error shoew below. I am new to the Patch command. I read the man but it didn;t help me much. Can someone help?

    ------------ Error output ----------------------------------------------------------------

    can't find file to patch at input line 3
    Perhaps you should have used the -p or --strip option?
    The text leading up to this was:
    --------------------------
    |--- include/ajax.tickets.php 2013-04-01 23:40:05.000000000 -0600
    |+++ include/ajax.tickets.php 2013-05-02 10:50:37.000000000 -0600
    --------------------------
    File to patch:
  • Please please help

    I have tried to use the patch file. Is anyone out there who could please translate the patch file into a add this and remove that tutorial? I would gladly put some money into a paypal account for this.

    And please add all the updates and further modifications.

    THANKS
  • promptcs;43801 said:
    I have tried to use the patch file. Is anyone out there who could please translate the patch file into a add this and remove that tutorial? I would gladly put some money into a paypal account for this.

    And please add all the updates and further modifications.

    THANKS
    Here is the tutorial, with the updates I added.

    In File: ajax.tickets.php

    After:

    } elseif($ticket->getEstDueDate()) {
    echo sprintf('
    <tr>
    <th>Due Date:</th>
    <td>%s</td>
    </tr>',
    Format::db_datetime($ticket->getEstDueDate()));
    }


    Add:

    echo sprintf('
    <tr>
    <th width=\"100\">Time Spent:</th>
    <td>%s</td>
    </tr>',
    Format::htmlchars($ticket->formatTime($ticket->getTimeSpent()))
    );



    In File: class.pdf.php

    After:

    $this->SetFont('Arial', 'B', 11);
    $this->Cell($l, 7, 'Last Message', 1, 0, 'L', true);
    $this->SetFont('');
    $this->Cell($c, 7, Format::db_datetime($ticket->getLastMsgDate()), 1, 1, 'L', true);


    Remove:

    $this->Ln(5);


    Add:

    if ($ticket->getTimeSpent() != 0){
    $this->SetFont('Arial', 'B', 11);
    $this->Cell($l, 7, 'Time Spent', 1, 0, 'L', true);
    $this->SetFont('');
    $this->Cell($c, 7, Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())), 1, 0, 'L', true);
    $this->Ln(10);
    } else {
    $this->Ln(5);
    }



    After:

    $text.=\"\nFiles Attached: [\".implode(', ',$files).\"]\n\";
    }
    $this->WriteText($w*2, $text, 1);


    Add:

    if($entry['time_spent'] != 0){
    $this->SetFillColor(221,221,221);
    $this->SetFont('Arial', '', 9);
    $this->Cell($w, 5, \"Time Spent: \" . $ticket->formatTime($entry['time_spent']), 'LBR', 1, 'L', true);
    }



    In File: class.ticket.php

    After:
             
    return $this->ht['closed'];
    }


    Add:

    function getTimeSpent() {
    return $this->ht['time_spent'];
    }



    After:

    function getLock(){

    if(!$this->tlock && $this->getLockId())
    $this->tlock= TicketLock::lookup($this->getLockId(),$this->getId());

    return $this->tlock;
    }


    Add:

    function formatTime($time) {

    if ($time < 0){
    $negative_convert = 1;
    $time = $time * -1;
    }
    $hours = floor($time);
    $minutes = round(($time-$hours) * 60);

    if ($hours > 0) {
    $formatted_time .= $hours.($hours == 1 ? ' hour' : ' hours');
    if ($minutes > 0) {
    $formatted_time .= ' '.$minutes.($minutes == 1 ? ' minute' : ' minutes');
    }
    }
    else {
    $formatted_time .= $minutes.($minutes == 1 ? ' minute' : ' minutes');
    }

    if ($negative_convert == 1){
    $formatted_time = \"- \" . $formatted_time;
    }

    return $formatted_time;
    }


    After:

    $this->logEvent('reopened', 'closed');
    return (db_query($sql) && db_affected_rows());
    }


    Add:

    function timeSpent($time) {
    if (empty($time) || !is_numeric($time)) {
    $time = 0.00;
    } else {
    $time = round($time, 2);
    }

    $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent+'.db_input($time)
    .' WHERE ticket_id='.db_input($this->getId());

    return (db_query($sql) && db_affected_rows());
    }

    function timeSpentDel($time) {
    if (empty($time) || !is_numeric($time)) {
    $time = 0.00;
    } else {
    $time = round($time, 2);
    }

    $sql='UPDATE '.TICKET_TABLE.' SET time_spent=time_spent-'.db_input($time)
    .' WHERE ticket_id='.db_input($this->getId());

    return (db_query($sql) && db_affected_rows());
    }

    function timeSpentEntry($id, $time) {
    if (empty($time) || !is_numeric($time)) {
    $time = 0.00;
    } else {
    $time = round($time, 2);
    }

    $sql='UPDATE '.TICKET_THREAD_TABLE.' SET time_spent='.db_input($time)
    .' WHERE id='.db_input($id);

    $this->timeSpent($time);

    return (db_query($sql) && db_affected_rows());
    }

    function timeSpentEntryDel($id) {
    $sql='SELECT time_spent FROM '.TICKET_THREAD_TABLE
    .' WHERE id='.db_input($id);

    $result = db_query($sql);
    $row = db_fetch_array($result);
    $time = $row['time_spent'];
    $this->timeSpentDel($time);
    }



    !!More in the next post!!
  • In File: staff/ticket-view.inc.php

    After:

    <th>Close Date:</th>
    <td><?php echo Format::db_datetime($ticket->getCloseDate()); ?></td>
    </tr>
    <?php
    }
    ?>


    Add:

    <?php
    if($ticket->getTimeSpent() != 0) {?>
    <tr>
    <th>Time Spent:</th>
    <td><?php echo Format::htmlchars($ticket->formatTime($ticket->getTimeSpent())); ?></td>
    </tr>
    <?php
    }?>


    After: (might be a little different for some users)(its in the
    )

    <th class=\"date\" width=\"300\"><?php echo Format::db_datetime($note['created']); ?></th>
    </tr>
    <tr>
    <td colspan=\"2\">
    <?php echo Format::display($note['body']); ?>
    </td>
    </tr>
    <?php
    if($note['attachments'] && ($links=$ticket->getAttachmentsLinks($note['id'],'N'))) {?>
    <tr>
    <td class=\"info\" colspan=\"2\"><?php echo $links; ?></td>
    </tr>
    <?php
    }?>


    Add:

    <?php
    if($note['time_spent'] != 0) {?>
    <tr>
    <td class=\"info\" colspan=\"2\">
    <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($note['time_spent'])); ?>
    </td>
    </tr>
    <?php
    }?>


    After: (might be different for some users)

    <div id=\"ticket_thread\">
    <?php
    $threadTypes=array('M'=>'message','R'=>'response', 'N'=>'note');
    /* -------- Messages & Responses & Notes (if inline)-------------*/
    if(($thread=$ticket->getThread($cfg->showNotesInline()))) {
    foreach($thread as $entry) {
    ?>
    <table class=\"<?php echo $threadTypes[$entry['thread_type']]; ?>\" cellspacing=\"0\" cellpadding=\"1\" width=\"940\" border=\"0\">
    <tr>
    <th width=\"200\"><?php echo Format::db_datetime($entry['created']);?></th>
    <th width=\"440\"><span><?php echo Format::htmlchars($entry['title']); ?></span></th>
    <th width=\"300\" class=\"tmeta\"><?php echo Format::htmlchars($entry['poster']); ?></th>
    </tr>
    <tr><td colspan=3><?php echo Format::display($entry['body']); ?></td></tr>
    <?php
    if($entry['attachments'] && ($links=$ticket->getAttachmentsLinks($entry['id'], $entry['thread_type']))) {?>
    <tr>
    <td class=\"info\" colspan=3><?php echo $links; ?></td>
    </tr>
    <?php
    }?>


    Add:

    <?php
    if($entry['time_spent'] != 0) {?>
    <tr>
    <td class=\"info\" colspan=\"3\">
    <b>Time Spent:</b> <?php echo Format::htmlchars($ticket->formatTime($entry['time_spent'])); ?>
    </td>
    </tr>
    <?php
    }?>


    After:

    Dept. Signature (<?php echo Format::htmlchars($dept->getName()); ?>)</label>
    <?php
    } ?>
    </td>
    </tr>
    <?php


    Add:

    if($ticket->isOpen()) { ?>
    <tr>
    <td width=\"160\">
    <label for=\"reply_time_spent\" class=\"left\">Time Spent:</label>
    </td>
    <td width=\"765\">
    <input type=\"text\" name=\"reply_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['reply_time_spent'])) echo $_POST['reply_time_spent']; ?>\"/> (0.75 = 45 minutes)
    </td>
    </tr>
    <?php
    } ?>
    <?php


    After:

    if($cfg->allowAttachments()) { ?>
    <tr>
    <td width=\"160\">
    <label for=\"attachment\">Attachments:</label>
    </td>
    <td width=\"765\" class=\"attachments\">
    <div class=\"uploads\">
    </div>
    <div class=\"file_input\">
    <input type=\"file\" class=\"multifile\" name=\"attachments[]\" size=\"30\" value=\"\" />
    </div>
    </td>
    </tr>
    <?php
    }
    ?>


    Remove:

    <tr><td colspan=\"2\">&nbsp;</td></tr>


    Add:

    <?php
    if($ticket->isOpen()) { ?>
    <tr>
    <td width=\"160\">
    <label for=\"note_time_spent\" class=\"left\">Time Spent:</label>
    </td>
    <td width=\"765\">
    <input type=\"text\" name=\"note_time_spent\" size=\"5\" value=\"<?php if (isset($_POST['note_time_spent'])) echo $_POST['note_time_spent']; ?>\"/> (0.75 = 45 minutes)
    </td>
    </tr>
    <?php
    }
    ?>



    In File: scp/tickets.php

    After:

    $wasOpen =($ticket->isOpen());
    //If no error...do the do.
    if(!$errors && ($respId=$ticket->postReply($_POST, $errorsi, isset($_POST['emailreply'])))) {
    $msg='Reply posted successfully';


    Add:

    + $ticket->timeSpentEntry($response->getId(),$_POST['reply_time_spent']);


    After:

    $wasOpen = ($ticket->isOpen());
    if(($noteId=$ticket->postNote($_POST, $errors, $thisstaff))) {
    $msg='Internal note posted successfully';


    Add:

    $ticket->timeSpentEntry($note->getId(),$_POST['note_time_spent']);


    !! Please note: I am using a heavily modified version 1.7RC5, this tutorial will work on 1.7 Stable, but note that my "After:" codes may differ slightly then what you see in your files.
Sign In or Register to comment.