PageRenderTime 49ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/incident.inc.php

https://github.com/paulheaney/sitracker
PHP | 697 lines | 452 code | 82 blank | 163 comment | 94 complexity | d5041b4f13018e995906160df6f84425 MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0, BSD-3-Clause, GPL-2.0
  1. <?php
  2. // incident.inc.php - functions relating to incidents
  3. //
  4. // SiT (Support Incident Tracker) - Support call tracking system
  5. // Copyright (C) 2000-2009 Salford Software Ltd. and Contributors
  6. //
  7. // This software may be used and distributed according to the terms
  8. // of the GNU General Public License, incorporated herein by reference.
  9. // Prevent script from being run directly (ie. it must always be included
  10. if (realpath(__FILE__) == realpath($_SERVER['SCRIPT_FILENAME']))
  11. {
  12. exit;
  13. }
  14. require_once (APPLICATION_LIBPATH . 'base.inc.php');
  15. require_once (APPLICATION_LIBPATH . 'contract.inc.php');
  16. /**
  17. * Gets incident details
  18. *
  19. * This function emulates a SQL query to the incident table while abstracting
  20. * SQL details
  21. * @param int $incident ID of the incident
  22. * @return object an object containing all parameters contained in the table
  23. * @author Kieran Hogg
  24. */
  25. function incident($incident)
  26. {
  27. global $dbIncidents;
  28. $incident = intval($incident);
  29. $sql = "SELECT * FROM `{$dbIncidents}` WHERE id = '$incident'";
  30. $result = mysql_query($sql);
  31. if (mysql_error()) trigger_error("MySQL Query Error ".mysql_error(), E_USER_ERROR);
  32. $row = mysql_fetch_object($result);
  33. return $row;
  34. }
  35. /**
  36. * Creates a new incident
  37. * @param string $title The title of the incident
  38. * @param int $contact The ID of the incident contact
  39. * @param int $servicelevel The ID of the servicelevel to log the incident under
  40. * @param int $contract The ID of the contract to log the incident under
  41. * @param int $product The ID of the product the incident refers to
  42. * @param int $skill The ID of the skill the incident refers to
  43. * @param int $priority (Optional) Priority of the incident (Default: 1 = Low)
  44. * @param int $owner (Optional) Owner of the incident (Default: 0 = SiT)
  45. * @param int $status (Optional) Incident status (Default: 1 = Active)
  46. * @param string $productversion (Optional) Product version field
  47. * @param string $productservicepacks (Optional) Product service packs field
  48. * @param int $opened (Optional) Timestamp when incident was opened (Default: now)
  49. * @param int $lastupdated (Optional) Timestamp when incident was updated (Default: now)
  50. * @return int|bool Returns FALSE on failure, an incident ID on success
  51. * @author Kieran Hogg
  52. */
  53. function create_incident($title, $contact, $servicelevel, $contract, $product,
  54. $software, $priority = 1, $owner = 0, $status = 1,
  55. $productversion = '', $productservicepacks = '',
  56. $opened = '', $lastupdated = '')
  57. {
  58. global $now, $dbIncidents;
  59. if (empty($opened))
  60. {
  61. $opened = $now;
  62. }
  63. if (empty($lastupdated))
  64. {
  65. $lastupdated = $now;
  66. }
  67. $sql = "INSERT INTO `{$dbIncidents}` (title, owner, contact, priority, ";
  68. $sql .= "servicelevel, status, maintenanceid, product, softwareid, ";
  69. $sql .= "productversion, productservicepacks, opened, lastupdated) ";
  70. $sql .= "VALUES ('{$title}', '{$owner}', '{$contact}', '{$priority}', ";
  71. $sql .= "'{$servicelevel}', '{$status}', '{$contract}', ";
  72. $sql .= "'{$product}', '{$software}', '{$productversion}', ";
  73. $sql .= "'{$productservicepacks}', '{$opened}', '{$lastupdated}')";
  74. $result = mysql_query($sql);
  75. if (mysql_error())
  76. {
  77. trigger_error("MySQL Query Error ".mysql_error(), E_USER_ERROR);
  78. return FALSE;
  79. }
  80. else
  81. {
  82. $incident = mysql_insert_id();
  83. return $incident;
  84. }
  85. }
  86. /**
  87. * Creates an incident based on an 'tempincoming' table entry
  88. * @author Kieran Hogg
  89. * @param int $incomingid the ID of the tempincoming entry
  90. * @return int|bool returns either the ID of the contract or FALSE if none
  91. */
  92. function create_incident_from_incoming($incomingid)
  93. {
  94. global $dbTempIncoming, $dbMaintenance, $dbServiceLevels,
  95. $dbSoftwareProducts, $CONFIG;
  96. $rtn = TRUE;
  97. $incomingid = intval($incomingid);
  98. $sql = "SELECT * FROM `{$dbTempIncoming}` ";
  99. $sql .= "WHERE id = '{$incomingid}'";
  100. $result = mysql_query($sql);
  101. if (mysql_error()) trigger_error(mysql_error(),E_USER_ERROR);
  102. $row = mysql_fetch_object($result);
  103. $contact = $row->contactid;
  104. $contract = guess_contract_id($contact);
  105. if (!$contract)
  106. {
  107. // we have no contract to log against, update stays in incoming
  108. return TRUE;
  109. }
  110. $subject = $row->subject;
  111. $update = $row->updateid;
  112. $sql = "SELECT servicelevelid, tag, product, softwareid ";
  113. $sql .= "FROM `{$dbMaintenance}` AS m, `{$dbServiceLevels}` AS s, ";
  114. $sql .= "`{$dbSoftwareProducts}` AS sp ";
  115. $sql .= "WHERE m.id = '{$contract}' ";
  116. $sql .= "AND m.servicelevelid = s.id ";
  117. $sql .= "AND m.product = sp.productid LIMIT 1";
  118. $result = mysql_query($sql);
  119. if (mysql_error())
  120. {
  121. trigger_error(mysql_error(),E_USER_ERROR);
  122. $rtn = FALSE;
  123. }
  124. $row = mysql_fetch_object($result);
  125. $sla = $row->tag;
  126. $product = $row->product;
  127. $software = $row->softwareid;
  128. $incident = create_incident($subject, $contact, $row->tag, $contract,
  129. $product, $software);
  130. if (!move_update_to_incident($update, $incident))
  131. {
  132. $rtn = FALSE;
  133. }
  134. if ($CONFIG['auto_assign_incidents'])
  135. {
  136. $user = suggest_reassign_userid($incident);
  137. if (!reassign_incident($incident, $user))
  138. {
  139. $rtn = FALSE;
  140. }
  141. }
  142. return $rtn;
  143. }
  144. /**
  145. * Move an update to an incident
  146. * @author Kieran Hogg
  147. * @param int $update the ID of the update
  148. * @param int $incident the ID of the incident
  149. * @return bool returns TRUE on success, FALSE on failure
  150. */
  151. function move_update_to_incident($update, $incident)
  152. {
  153. global $dbUpdates;
  154. $update = intval($update);
  155. $incident = intval($incident);
  156. $sql = "UPDATE `{$dbUpdates}` SET incidentid = '{$incident}' ";
  157. $sql .= "WHERE id = '{$update}'";
  158. mysql_query($sql);
  159. if (mysql_error())
  160. {
  161. trigger_error(mysql_error(),E_USER_ERROR);
  162. return FALSE;
  163. }
  164. else
  165. {
  166. return TRUE;
  167. }
  168. }
  169. /**
  170. * Gets update details
  171. *
  172. * This function emulates a SQL query to the update table while abstracting
  173. * SQL details
  174. * @param int $update ID of the update
  175. * @return object an object containing all parameters contained in the table
  176. * @author Kieran Hogg
  177. */
  178. function update($update)
  179. {
  180. global $dbUpdates;
  181. $update = intval($update);
  182. $sql = "SELECT * FROM `{$dbUpdates}` WHERE id = '{$update}'";
  183. $result = mysql_query($sql);
  184. if (mysql_error()) trigger_error("MySQL Query Error ".mysql_error(), E_USER_ERROR);
  185. $row = mysql_fetch_object($result);
  186. return $row;
  187. }
  188. /**
  189. * Suggest the userid of a suitable person to handle the given incident
  190. * @author Ivan Lucas
  191. * @param int $incidentid. An incident ID to suggest a new owner for
  192. * @param int $exceptuserid. This user ID will not be suggested (e.g. the existing owner)
  193. * @returns A user ID of the suggested new owner
  194. * @retval bool FALSE failure.
  195. * @retval int The user ID of the suggested new owner
  196. * @note Users are chosen randomly in a weighted lottery depending on their
  197. * avilability and queue status
  198. */
  199. function suggest_reassign_userid($incidentid, $exceptuserid = 0)
  200. {
  201. global $now, $dbUsers, $dbIncidents, $dbUserSoftware, $startofsession;
  202. $sql = "SELECT product, softwareid, priority, contact, owner FROM `{$dbIncidents}` WHERE id={$incidentid} LIMIT 1";
  203. $result = mysql_query($sql);
  204. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  205. if (!$result)
  206. {
  207. $userid = FALSE;
  208. }
  209. else
  210. {
  211. $incident = mysql_fetch_object($result);
  212. // If this is a critical incident the user we're assigning to must be online
  213. if ($incident->priority >= 4) $req_online = TRUE;
  214. else $req_online = FALSE;
  215. // Find the users with this skill (or all users)
  216. if (!empty($incident->softwareid))
  217. {
  218. $sql = "SELECT us.userid, u.status, u.lastseen FROM `{$dbUserSoftware}` AS us, `{$dbUsers}` AS u ";
  219. $sql .= "WHERE u.id = us.userid AND u.status > 0 AND u.accepting='Yes' ";
  220. if ($exceptuserid > 0) $sql .= "AND u.id != '$exceptuserid' ";
  221. $sql .= "AND softwareid = {$incident->softwareid}";
  222. }
  223. else
  224. {
  225. $sql = "SELECT id AS userid, status, lastseen FROM `{$dbUsers}` AS u WHERE status > 0 AND u.accepting='Yes' ";
  226. if ($exceptuserid > 0) $sql .= "AND id != '$exceptuserid' ";
  227. }
  228. $result = mysql_query($sql);
  229. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  230. // Fallback to all users if we have no results from above
  231. if (mysql_num_rows($result) < 1)
  232. {
  233. $sql = "SELECT id AS userid, status, lastseen FROM `{$dbUsers}` AS u WHERE status > 0 AND u.accepting='Yes' ";
  234. if ($exceptuserid > 0) $sql .= "AND id != '$exceptuserid' ";
  235. $result = mysql_query($sql);
  236. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  237. }
  238. while ($user = mysql_fetch_object($result))
  239. {
  240. // Get a ticket for being skilled
  241. // Or in the case we don't know the skill, just get a ticket for accepting
  242. $ticket[] = $user->userid;
  243. // Get a ticket for being seen within the current session time
  244. if (mysql2date($user->lastseen) > $startofsession) $ticket[] = $user->userid;
  245. // Get two tickets for being marked in-office or working at home
  246. if ($user->status == 1 OR $user->status == 6)
  247. {
  248. $ticket[] = $user->userid;
  249. $ticket[] = $user->userid;
  250. }
  251. // Get one ticket for being marked at lunch or in meeting
  252. // BUT ONLY if the incident isn't critical
  253. if ($incident->priority < 4 AND ($user->status == 3 OR $user->status == 4))
  254. {
  255. $ticket[] = $user->userid;
  256. }
  257. // Have a look at the users incident queue (owned)
  258. $qsql = "SELECT id, priority, lastupdated, status, softwareid FROM `{$dbIncidents}` WHERE owner={$user->userid}";
  259. $qresult = mysql_query($qsql);
  260. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  261. $queue_size = mysql_num_rows($qresult);
  262. if ($queue_size > 0)
  263. {
  264. $queued_critical = 0;
  265. $queued_high = 0;
  266. $queue_lastupdated = 0;
  267. $queue_samecontact = FALSE;
  268. while ($queue = mysql_fetch_object($qresult))
  269. {
  270. if ($queue->priority == 3) $queued_high++;
  271. if ($queue->priority >= 4) $queued_critical++;
  272. if ($queue->lastupdated > $queue_lastupdated) $queue_lastupdated = $queue->lastupdated;
  273. if ($queue->contact == $incident->contact) $queue_samecontact = TRUE;
  274. }
  275. // Get one ticket for your queue being updated in the past 4 hours
  276. if ($queue_lastupdated > ($now - 14400)) $user->userid;
  277. // Get two tickets for dealing with the same contact in your queue
  278. if ($queue_samecontact == TRUE)
  279. {
  280. $ticket[] = $user->userid;
  281. $ticket[] = $user->userid;
  282. }
  283. // Get one ticket for having five or less incidents
  284. if ($queue_size <=5) $ticket[] = $user->userid;
  285. // Get up to three tickets, one less ticket for each critical incident in queue
  286. for ($c = 1; $c < (3 - $queued_critical); $c++)
  287. {
  288. $ticket[] = $user->userid;
  289. }
  290. // Get up to three tickets, one less ticket for each high priority incident in queue
  291. for ($c = 1; $c < (3 - $queued_high); $c++)
  292. {
  293. $ticket[] = $user->userid;
  294. }
  295. }
  296. else
  297. {
  298. // Get one ticket for having an empty queue
  299. $ticket[] = $user->userid;
  300. }
  301. }
  302. // Do the lottery - "Release the balls"
  303. $numtickets = count($ticket)-1;
  304. $rand = mt_rand(0, $numtickets);
  305. $userid = $ticket[$rand];
  306. }
  307. if (empty($userid)) $userid = FALSE;
  308. return $userid;
  309. }
  310. /**
  311. * Reassigns an incident
  312. * @param int $incident incident ID to reassign
  313. * @param int $user user to reassign the incident to
  314. * @param string $type 'full' to do a full reassign, 'temp' for a temp
  315. * @return bool TRUE on success, FALSE on failure
  316. * @author Kieran Hogg
  317. */
  318. function reassign_incident($incident, $user, $tuser = '', $nextaction = '', $type = 'full')
  319. {
  320. global $dbIncidents, $dbUpdates, $now, $sit;
  321. $rtn = TRUE;
  322. if ($nextaction != '') {
  323. $incident->nextaction = $nextaction;
  324. }
  325. if ($type == 'temp')
  326. {
  327. $sql = "UPDATE `{$dbIncidents} SET towner = '{$tuser}'";
  328. }
  329. else
  330. {
  331. $sql = "UPDATE `{$dbIncidents}` SET owner = '{$user}'";
  332. }
  333. $sql .= "WHERE id = '{$incident}'";
  334. mysql_query($sql);
  335. if (mysql_error())
  336. {
  337. trigger_error(mysql_error(),E_USER_WARNING);
  338. $rtn = FALSE;
  339. }
  340. $sql = "INSERT INTO `{$dbUpdates}` (incidentid, userid, type, timestamp, currentowner, currentstatus, nextaction) ";
  341. $sql .= "VALUES ('{$incidentid}', '{$sit[2]}', 'reassigning', '{$now}', '{$user}', '1', '{$incident->nextaction}')";
  342. $result = mysql_query($sql);
  343. mysql_query($sql);
  344. if (mysql_error())
  345. {
  346. trigger_error(mysql_error(),E_USER_WARNING);
  347. $rtn = FALSE;
  348. }
  349. return $rtn;
  350. }
  351. /**
  352. * Reopens an incident
  353. * @param int $incident incident ID to reopen
  354. * @param int $newstatus (optional) status to set the incident to, defaults to active
  355. * @param string $message (optional) message to insert when reopening
  356. * @return bool TRUE on success, FALSE on failure$dbIncidents
  357. * @author Kieran Hogg
  358. */
  359. function reopen_incident($incident, $newstatus = STATUS_ACTIVE, $message = '')
  360. {
  361. global $dbIncidents, $dbUpdates, $now, $sit, $bodytext;
  362. $rtn = TRUE;
  363. $time = time();
  364. $sql = "UPDATE `{$dbIncidents}` SET status='{$newstatus}', ";
  365. $sql .= "lastupdated='{$time}', closed='0' WHERE id='{$incident}' LIMIT 1";
  366. mysql_query($sql);
  367. if (mysql_error()) trigger_error(mysql_error(),E_USER_ERROR);
  368. $owner = incident_owner($incident);
  369. // add update
  370. $sql = "INSERT INTO `{$dbUpdates}` (incidentid, userid, type, ";
  371. $sql .= "bodytext, timestamp, currentowner, currentstatus) ";
  372. $sql .= "VALUES ({$incident}, '{$sit[2]}', 'reopening', '{$bodytext}', '{$time}', ";
  373. $sql .= "'{$owner}', '{$newstatus}')";
  374. $result = mysql_query($sql);
  375. if (mysql_error())
  376. {
  377. trigger_error(mysql_error(),E_USER_ERROR);
  378. $rtn = FALSE;
  379. }
  380. // Insert the first SLA update for the reopened incident, this indicates
  381. // the start of an sla period
  382. // This insert could possibly be merged with another of the 'updates'
  383. // records, but for now we keep it seperate for clarity
  384. $sql = "INSERT INTO `{$dbUpdates}` (incidentid, userid, type, ";
  385. $sql .= "timestamp, currentowner, currentstatus, customervisibility, ";
  386. $sql .= "sla, bodytext) ";
  387. $sql .= "VALUES ('{$incident}', '{$sit[2]}', 'slamet', '{$now}', '{$owner}', ";
  388. $sql .= STATUS_ACTIVE.", 'show', 'opened','{$GLOBALS['strIncidentIsOpen']}')";
  389. mysql_query($sql);
  390. if (mysql_error())
  391. {
  392. trigger_error(mysql_error(),E_USER_ERROR);
  393. $rtn = FALSE;
  394. }
  395. // Insert the first Review update, this indicates the review period of an incident has restarted
  396. // This insert could possibly be merged with another of the 'updates' records, but for now we keep it seperate for clarity
  397. $sql = "INSERT INTO `{$dbUpdates}` (incidentid, userid, type, timestamp, currentowner, currentstatus, customervisibility, sla, bodytext) ";
  398. $sql .= "VALUES ('{$incident}', '0', 'reviewmet', '{$now}', '{$owner}', ".STATUS_ACTIVE.", 'hide', 'opened','')";
  399. mysql_query($sql);
  400. if (mysql_error())
  401. {
  402. trigger_error(mysql_error(),E_USER_ERROR);
  403. $rtn = FALSE;
  404. }
  405. return $rtn;
  406. }
  407. /**
  408. Send a template email without using a trigger
  409. @author Ivan Lucas
  410. @param int $templateid: The ID number of the template to use
  411. @param array $paramarray. An associative array of template parameters
  412. This should at the very least be
  413. array('incidentid' => $id, 'triggeruserid' => $sit[2])
  414. @param string $attach. Path and filename of file to attach
  415. @param string $attachtype. Type of file to attach (Default 'OCTET')
  416. @param string $attachdesc. Description of the attachment, (Default, same as filename)
  417. @retval bool TRUE: The email was sent successfully
  418. @retval bool FALSE: There was an error sending the mail
  419. @note This is v2 of this function, it has different paramters than v1
  420. **/
  421. function send_email_template($templateid, $paramarray, $attach='', $attachtype='', $attachdesc='')
  422. {
  423. global $CONFIG, $application_version_string, $sit;
  424. if (!is_array($paramarray))
  425. {
  426. trigger_error("Invalid Parameter Array", E_USER_NOTICE);
  427. $paramarray = array('triggeruserid' => $sit[2]);
  428. }
  429. if (!is_numeric($templateid))
  430. {
  431. trigger_error("Invalid Template ID '{$templateid}'", E_USER_NOTICE);
  432. }
  433. // Grab the template
  434. $tsql = "SELECT * FROM `{$dbEmailTemplates}` WHERE id=$templateid LIMIT 1";
  435. $tresult = mysql_query($tsql);
  436. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  437. if (mysql_num_rows($tresult) > 0) $template = mysql_fetch_object($tresult);
  438. $paramarray = array('incidentid' => $paramarray['incidentid'], 'triggeruserid' => $sit[2]);
  439. $from = replace_specials($template->fromfield, $paramarray);
  440. $replyto = replace_specials($template->replytofield, $paramarray);
  441. $ccemail = replace_specials($template->ccfield, $paramarray);
  442. $bccemail = replace_specials($template->bccfield, $paramarray);
  443. $toemail = replace_specials($template->tofield, $paramarray);
  444. $subject = replace_specials($template->subjectfield, $paramarray);
  445. $body = replace_specials($template->body, $paramarray);
  446. $extra_headers = "Reply-To: {$replyto}\nErrors-To: ".user_email($sit[2])."\n";
  447. $extra_headers .= "X-Mailer: {$CONFIG['application_shortname']} {$application_version_string}/PHP " . phpversion() . "\n";
  448. $extra_headers .= "X-Originating-IP: {$_SERVER['REMOTE_ADDR']}\n";
  449. if ($ccemail != '') $extra_headers .= "CC: $ccemail\n";
  450. if ($bccemail != '') $extra_headers .= "BCC: $bccemail\n";
  451. $extra_headers .= "\n"; // add an extra crlf to create a null line to separate headers from body
  452. // this appears to be required by some email clients - INL
  453. // Removed $mailerror as MIME_mail expects 5 args and not 6 of which is it not expect errors
  454. $mime = new MIME_mail($from, $toemail, html_entity_decode($subject), '', $extra_headers);
  455. $mime -> attach($body, '', "text-plain; charset={$GLOBALS['i18ncharset']}", 'quoted-printable');
  456. if (!empty($attach))
  457. {
  458. if (empty($attachdesc)) $attachdesc = "Attachment named {$attach}";
  459. $disp = "attachment; filename=\"{$attach}\"; name=\"{$attach}\";";
  460. $mime -> fattach($attach, $attachdesc, $attachtype, 'base64', $disp);
  461. }
  462. // actually send the email
  463. $rtnvalue = $mime -> send_mail();
  464. return $rtnvalue;
  465. }
  466. /**
  467. * Identified if there are drafts waiting to be sent/updated on an incident
  468. * @author Paul Heaney
  469. * @param int $incidentid - The incidentID to check for
  470. * @param string $type - The type of draft either all/email/update
  471. * @return bool TRUE of there are drafts waiting false otherwise
  472. */
  473. function drafts_waiting_on_incident($incidentid, $type='all')
  474. {
  475. $rtn = FALSE;
  476. $sql = "SELECT count(id) AS count FROM `{$GLOBALS['dbDrafts']}` WHERE incidentid = {$incidentid} ";
  477. if ($type == "update") $sql .= "AND type = 'update'";
  478. elseif ($type == "email") $sql .= "AND type = 'email'";
  479. $result = mysql_query($sql);
  480. if (mysql_error())
  481. {
  482. trigger_error(mysql_error(),E_USER_ERROR);
  483. $rtn = FALSE;
  484. }
  485. list($count) = mysql_fetch_array($result);
  486. if ($count > 0) $rtn = TRUE;
  487. return $rtn;
  488. }
  489. /**
  490. * Gets the incident ID for an email based on its subject
  491. * @author Kierna Hogg
  492. * @param string $subject The email subject
  493. * @param string $from The email address it was sent from
  494. * @return int ID of the incident, 0 if none
  495. */
  496. function incident_id_from_subject($subject, $from)
  497. {
  498. $incident_id = 0;
  499. $from_parts = explode($from, "@");
  500. $domain = $from_parts[2];
  501. if (preg_match('/\[(\d{1,5})\]/', $subject, $m))
  502. {
  503. $incident_id = $m[1];
  504. }
  505. else
  506. {
  507. preg_match('/\d{1,12}/', $subjectm, $external_id);
  508. $external_id = $external_id[0];
  509. $sql = "SELECT name, email_domain FROM `{$dbEscalationPaths}`";
  510. $result = mysql_query($sql);
  511. if ($result)
  512. {
  513. while ($row = mysql_fetch_object($result))
  514. {
  515. if ($row->email_domain == $domain)
  516. {
  517. $sql = "SELECT id FROM `{$dbIncidents}` ";
  518. $sql .= "WHERE externalid";
  519. }
  520. }
  521. }
  522. }
  523. }
  524. /**
  525. * @author Ivan Lucas
  526. */
  527. function count_incident_stats($incidentid)
  528. {
  529. global $dbUpdates;
  530. $sql = "SELECT count(DISTINCT currentowner),count(id) FROM `{$dbUpdates}` WHERE incidentid='$incidentid' AND userid!=0 GROUP BY userid";
  531. $result = mysql_query($sql);
  532. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  533. list($unique_users,$num_updates) = mysql_fetch_row($result);
  534. return array($unique_users,$num_updates);;
  535. }
  536. /**
  537. * Returns number of closed incidents that were opened within the period giving
  538. * the average duration in minutes and the average worked time in minutes
  539. * @author Ivan Lucas
  540. */
  541. function average_incident_duration($start,$end,$states)
  542. {
  543. global $dbIncidents;
  544. $sql = "SELECT opened, closed, (closed - opened) AS duration_closed, i.id AS incidentid ";
  545. $sql .= "FROM `{$dbIncidents}` AS i ";
  546. $sql .= "WHERE status='2' ";
  547. if ($start > 0) $sql .= "AND opened >= $start ";
  548. if ($end > 0) $sql .= "AND opened <= $end ";
  549. $result = mysql_query($sql);
  550. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  551. $totalduration = 0;
  552. $totalworkingduration = 0;
  553. $countclosed = 0;
  554. $total_unique_owners= 0;
  555. while ($row = mysql_fetch_object($result))
  556. {
  557. $working_time = calculate_incident_working_time($row->incidentid, $row->opened, $row->closed, $states);
  558. if ($row->duration_closed > 0)
  559. {
  560. $totalduration = $totalduration+$row->duration_closed;
  561. $totalworkingduration += $working_time;
  562. $cio = count_incident_stats($row->incidentid);
  563. $total_unique_owners += $cio[0];
  564. $total_updates += $cio[1];
  565. $countclosed++;
  566. }
  567. }
  568. $total_number_updates = number_format(($countclosed == 0) ? 0 : ($total_updates / $countclosed),1);
  569. $average_owners = number_format(($countclosed == 0) ? 0 : ($total_unique_owners / $countclosed),1);
  570. $average_incident_duration = ($countclosed == 0) ? 0 : ($totalduration / $countclosed) / 60;
  571. $average_worked_minutes = ($countclosed == 0) ? 0 : $totalworkingduration / $countclosed;
  572. return array($countclosed, $average_incident_duration, $average_worked_minutes,$average_owners, $total_updates, $total_number_updates);
  573. }
  574. /**
  575. * Returns the contents of an SLA target update, mostly for problem definition and action plan to pre-fill the close form
  576. * @author Kieran Hogg
  577. * @param $incidentid int The incident to get the update of
  578. * @param $target string The SLA target, initialresponse, probdef etc
  579. * @return string The updates of the message, stripped of line breaks
  580. */
  581. function sla_target_content($incidentid, $target)
  582. {
  583. $rtn = '';
  584. global $dbUpdates;
  585. $incidentid = cleanvar($incidentid);
  586. $target = cleanvar($target);
  587. $sql = "SELECT bodytext FROM `{$dbUpdates}` ";
  588. $sql .= "WHERE incidentid = '{$incidentid}' ";
  589. $sql .= "AND sla = '{$target}' ";
  590. $sql .= "ORDER BY timestamp DESC";
  591. $result = mysql_query($sql);
  592. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  593. list($bodytext) = mysql_fetch_array($result);
  594. $bodytext = str_replace("<hr>", "", $bodytext);
  595. $rtn .= $bodytext;
  596. return $rtn;
  597. }
  598. /**
  599. * Retreive the service level tag of the incident
  600. * @author Paul Heaney
  601. * @param $incidentid int The incident ID to retreive
  602. * @return String The service level tag
  603. * @todo Remove as of 4.0 in favour of incidents class
  604. */
  605. function incident_service_level($incidentid)
  606. {
  607. global $dbIncidents;
  608. $servicelevel = '';
  609. $sql = "SELECT servicelevel FROM `{$dbIncidents}` WHERE id = {$incidentid}";
  610. $result = mysql_query($sql);
  611. if (mysql_error()) trigger_error(mysql_error(),E_USER_WARNING);
  612. list($servicelevel) = mysql_fetch_array($result);
  613. return $servicelevel;
  614. }
  615. ?>