<?/*
Copyright (C) 2003 Media Net Link, Inc. Danville, CA 94526 USA

This file is part of AthenaRMS.

AthenaRMS is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

AthenaRMS is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/?>
<?php

require_once 'base_object.php';
require_once 'search_result.php';
require_once 'crm.php';
require_once 'config.php';
require_once 'person.php';
require_once 'email.php';
require_once 'company_crm.php';

##
## - deletes need to be on ticket_customer_map
## - object needs set_customer method? all operations are on that customer_id then?
## 

class Ticket extends Base_Object {
  function Ticket () {
    global $dbi;
    $this->db = &$dbi;

    ## stuff updated by Update_Base and Update_Map
    $this->state_fields = array(
      'additional_info',
      'crm_id',
      'escalated_to_person_id',
      'info1',
      'info2',
      'mass_queue',
      'problem_id',
      'source_id',
      'status',
      'subject',
      'support_person_id',
      'tcrm_map_id',
      'ticket_id',
      'updated_by',
      'use_help',
    );

    $this->config = new Config();
  }

  function Info_by_Ticket_ID ($tid, $crm_id='') {
    $record = new Ticket_Record ();

    $record->Select_by_Ticket_ID ($tid, $crm_id);

    return $record;
  }

  function Delete($ticket_id='', $crm_id='') {
    return($this->Delete_Map($ticket_id, $crm_id) &&
	   $this->Delete_Base($ticket_id, $crm_id));
  }

  function Delete_Map($tid='', $crm_id='') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();
    if (!$tid) {
	$this->error = "Ticket::Delete_Map(): No ticket ID specified";
	return 0;
    }

    if (!$crm_id) {
	$this->error = "Ticket::Delete_Map(): Could not get CRM ID";
	return 0;
    }

    $h = $this->db->prepare ('
      delete from ticket_crm_map
            where ticket_id = ?
              and crm_id = ?
    ');
    $ok = $this->db->execute ($h, array($tid, $crm_id));
    if (DB::isError($ok)) {
	$this->error = "Ticket::Delete_Map(): ".$ok->getMessage();
	return 0;
    }
    return 1;
  }

  function Delete_Base($tid = '', $crm_id = '') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();
    if (!$tid) {
	$this->error = "Ticket::Delete_Base(): No ticket ID specified";
	return 0;
    }

    if (!$crm_id) {
	$this->error = "Ticket::Delete_Base(): Could not get CRM ID";
	return 0;
    }

    $h = $this->db->prepare ('
      delete from ticket
            where ticket_id = ?
              and crm_id = ?
    ');
    $ok = $this->db->execute ($h, array($tid, $crm_id));
    if (DB::isError($ok)) {
	$this->error = "Ticket::Delete_Base(): ".$ok->getMessage();
	return 0;
    }
    return 1;
  }

  function DeleteMapByMapID($tcrm_map_id) {
    if (!$tcrm_map_id) {
      $this->error = "Ticket::DeleteMapByMapID(): no tcrm_map_id supplied";
      return 0;
    }

    $sql = "
      delete from ticket_crm_map
      where tcrm_map_id = ?
    ";
    $res = $this->db->query($sql, array($tcrm_map_id));
    if (DB::isError($sql)) {
      $this->error = "Ticket::DeleteMapByMapID(): ".$res->getMessage();
      return 0;
    }

    return 1;
  }

  function Add_Both ($in_ary) {
    list ($rval, $add) = $this->Validate_Add_Fields($in_ary);
    if (!$rval) {
	$this->error = 'Ticket::Add_Both(): ' . $this->error;
	return array (NULL, NULL, NULL);
    }

    list ($rval, $tid) = $this->Add_Base ($add);
    if (!$rval) {
	$this->error = 'Ticket::Add_Both(): ' . $this->error;
	return array ($rval, $tid, NULL);
    }

    list ($rval, $tmid) = $this->Add_Map ($add);
    if (!$rval) {
	$this->error = 'Ticket::Add_Both(): ' . $this->error;
	return array ($rval, NULL, $tmid);
    }

    return array (1, $tid, $tmid);
  }

  function Add_Map ($in_ary) {
    list ($rval, $add) = $this->Validate_Add_Fields ($in_ary);

    if (!$rval) {
	$this->error = 'Ticket::Add_Map(): ' . $this->error;
	return array (0, 0);
    }

    if (!array_key_exists('TCRM_MAP_ID', $add))
    	$add['TCRM_MAP_ID'] = $this->db->nextId('ticket_crm_map_id');

    if (!$add['TCRM_MAP_ID']) {
	$this->error = 
	    'Ticket::Add_Map(): nextId(): did not return a tcrm_map_id';
	return array (0, 0);
    }

    if (!array_key_exists('STATUS', $add)) $add['STATUS'] = 'Open';

    $crm = new CRM ();
    $c = $crm->Select_by_CRM_ID ($add['CRM_ID']);
    if (!$c) {
      $this->error = 'Ticket::Add_Map(): ' . $crm->error;
      return array(0, 0);
    }

##
## need to validate that these belong to the CRM or just leave them?
##

    if (!array_key_exists('SOURCE_ID', $add) || !$add['SOURCE_ID'])
      $add['SOURCE_ID'] = $c->Get ('default_source_id');

    if (!array_key_exists('PROBLEM_ID', $add) || !$add['PROBLEM_ID'])
      $add['PROBLEM_ID'] = $c->Get ('default_problem_id');

    if (!array_key_exists('SUPPORT_PERSON_ID', $add))
      $add['SUPPORT_PERSON_ID'] = null;

    $add['SUPPORT_PERSON_ID'] = 
      $this->Check_Person_ID ($add['SUPPORT_PERSON_ID'], 
	$add['CRM_ID'], 'support');

    if (!array_key_exists('ESCALATED_TO_PERSON_ID', $add))
      $add['ESCALATED_TO_PERSON_ID'] = null;

    $add['ESCALATED_TO_PERSON_ID'] = 
      $this->Check_Person_ID ($add['ESCALATED_TO_PERSON_ID'], 
	$add['CRM_ID'], 'escalated');

    notices_off();
    $all_ok = ($add['SOURCE_ID'] and $add['PROBLEM_ID'] and 
	  $add['SUPPORT_PERSON_ID'] and $add['ESCALATED_TO_PERSON_ID']);
    notices_on();

    if (!$all_ok) {
	$this->error = 'Ticket::Add_Map(): no source, problem, support_person, or escalated_to_person id found';
	if (version_compare(phpversion(), '4.3.0', 'ge'))
	  $this->error .= "\n" . print_r($add, true);
	return array (0, 0);
    }

    $to_date = to_date();
    $h = $this->db->prepare ("
      insert into ticket_crm_map (
        ticket_id,
        tcrm_map_id,
        crm_id,
        support_person_id,
        escalated_to_person_id,
        info1,
        info2,
        problem_id,
        source_id,
        status,
        updated_by,
        subject,
        created_by,
        created_date,
        updated_date
      ) values (
        ?, ?, ?, ?, ?, ?,
        ?, ?, ?, ?, ?, ?, ?,
	$to_date,
	$to_date
      )
    ");
    notices_off();
    $rval = $this->db->execute ($h, array(
      $add['TICKET_ID'],
      $add['TCRM_MAP_ID'],
      $add['CRM_ID'],
      $add['SUPPORT_PERSON_ID'],
      $add['ESCALATED_TO_PERSON_ID'],
      $add['INFO1'],
      $add['INFO2'],
      $add['PROBLEM_ID'],
      $add['SOURCE_ID'],
      $add['STATUS'],
      $add['UPDATED_BY'],
      substr($add['SUBJECT'], 0, 25),
      $add['CREATED_BY'],
      $add['CREATED_DATE'],
      $add['UPDATED_DATE']
    ));
    notices_on();
    if (DB::isError($rval)) {
       $this->error = 'Ticket::Add_Map(): ' . $rval->getMessage()
	    . "\n" . $rval->getUserInfo();
       return;
    }

    if ($this->config->Get('new_ticket_notify', $add['CRM_ID']) == 'Y') {

      if (!$this->person) $this->person = new Person ();
      if (!$this->email_obj) $this->email_obj = new Email ();

      $prec = $this->person->Info_By_Person_ID ($add['SUPPORT_PERSON_ID']);

      $url = $this->config->CRM_URL($add[CRM_ID])
	   . "support/ticket/edit_ticket?ticket_id=$add[TICKET_ID]";

      $msg = "
Hi,

A new ticket has been entered into your AthenaRMS support system:

$url


Don't reply to this message, it won't do anything.


Sincerely,

The auto notification process

";

      if ($em = $prec->Get('email')) {
        $email_sig = $this->config->Get ('Email Sig', $add[CRM_ID]);
        $from = "\"$email_sig\" <autoresponse@".$this->config->Get('email_domain', $add[CRM_ID]).'>';
        $this->email_obj->Send_Msg ($em, "new ticket $add[TICKET_ID]", $msg, $from);
      }
    }

    return array (1, $add['TCRM_MAP_ID']);
  }

  function Check_Person_ID ($id, $crm_id, $type) {
    if ($type == 'support') {
      $method = 'GetDefaultSupportPersonId';
    } else {
      $method = 'GetDefaultEscalatedToId';
    }

    $company_crm = new Company_CRM();
    return $company_crm->$method( $crm_id, $id );
  }

  function Validate_Add_Fields ($in_ary) {
    $add = array();
    foreach ($in_ary as $k => $v) {
      $add[strtoupper($k)] = $v;
    }

    if (!array_key_exists('TICKET_ID', $add)) 
      $add['TICKET_ID'] = $this->db->nextId ('ticket_ticket_id');

    if (!array_key_exists('CRM_ID', $add))
      $add['CRM_ID'] = $this->Current_CRM ();

    if (!$add['TICKET_ID'] or !$add['CRM_ID']) {
	$this->error = 'Ticket::Validate_Add_Fields(): no ticket_id or crm_id';
	return array (0, $add);
    }

    $this->Set_Audit_Info ($add);

    return array (1, $add);
  }

  function Add_Base ($in_ary) {
    list ($rval, $add) = $this->Validate_Add_Fields ($in_ary);

    if (!$rval) {
	$this->error = 'Ticket::Add_Base(): ' . $this->error;
	return array (0, 0);
    }

    foreach (array ('WELL_PRESENTED', 'FIND_INFO', 
		    'USE_HELP', 'HELP_USEFUL') as $s) {
      if (!array_key_exists($s, $add)) $add[$s] = 'N';
    }

    $to_date = to_date();
    $h = $this->db->prepare ("
      insert into ticket (
        ticket_id,
        crm_id,
        user_person_id,
        well_presented,
        find_info,
        remote_host,
        browser,
        referring_url,
        account_id,
        additional_info,
        updated_by,
        created_by,
        created_date,
        updated_date
      ) values (
        ?, ?, ?, ?, ?, ?,
        ?, ?, ?, ?, ?, ?,
        $to_date,
        $to_date
      )
    ");
    notices_off();
    $rval = $this->db->execute ($h, array(
      $add['TICKET_ID'],
      $add['CRM_ID'],
      $add['USER_PERSON_ID'],
      $add['WELL_PRESENTED'],
      $add['FIND_INFO'],
      $add['REMOTE_HOST'],
      $add['BROWSER'],
      $add['REFERRING_URL'],
      $add['ACCOUNT_ID'],
      $add['ADDITIONAL_INFO'],
      $add['UPDATED_BY'],
      $add['CREATED_BY'],
      $add['CREATED_DATE'],
      $add['UPDATED_DATE']
    ));
    notices_on();

    if (DB::isError($rval)) {
       $this->error = "Ticket::Add_Base(): " . $rval->getMessage()
	. "\n" . $rval->getUserInfo();
       return array(0, 0);
    }

    if (!$rval) {
	$this->error = 'Ticket::Add_Base(): ' . $h->error();
	return array (0, $h->error ());
    }

    return array (1, $add['TICKET_ID']);
  }

  function Move_To ($tid, $to_crm_id, $from_crm_id, $updater_pid) {
    if (!$this->Owner_Change ($tid, $to_crm_id, $from_crm_id, $updater_pid)) return 0;

    $results = $this->Exists ($tid, $to_crm_id);
    $exists = $results[0];

    ## if it already existed in the other system just reopen it
    if (!$exists) {
      $r = $this->Info_by_Ticket_ID ($tid, $from_crm_id);
      $tm_id = $this->Copy_To ($tid, $to_crm_id, $updater_pid, $r->Get ('support_person_id'),
                               $r->Get('escalated_to_person_id'), $r->Get('subject'));
      if (!$tm_id) {
	$this->Undo_Owner_Change();
	return 0;
      }
      $r = $this->Info_by_Ticket_ID ($tid, $to_crm_id);
    } else {
      $r = $results[1];
      $r->Set ('status', 'ReOpen');
      $r->SaveState();
      $ok = $r->Update_Map ();
      if (!$ok) {
	$this->Undo_Owner_Change();
	$r->RestoreState();
	$r->Update_Map();
	return 0;
      }
    }

    if (!$tid or ($tid != $r->Get ('ticket_id'))) {
      $this->error = "Missing ticket ID, exists is $exists";
      $this->Undo_Owner_Change();
      if ($exists) {
	$r->RestoreState();
	$r->Update_Map();
      } else {
	$this->DeleteMapByMapId($tm_id);
      }

      return 0;
    }

    ## close the old one
    $old = $this->Info_by_Ticket_ID ($tid, $from_crm_id);
    $old->SaveState();
    $old->Set ('status', 'Closed');
    $ok = $old->Update_Map ();
    if (!$ok) {
      $this->Undo_Owner_Change();
      if ($exists) {
	$r->RestoreState();
	$r->Update_Map();
      } else {
	$this->DeleteMapByMapId($tm_id);
      }

      return 0;
    }

    ## point to the new ticket as the active one, don't carry over mass_queue
    $r->Set ('crm_id', $to_crm_id);
    $old->Set ('mass_queue', 'N');
    $ok = $r->Update_Base ();

    if (!$ok) {
      $this->Undo_Owner_Change();
      if ($exists) {
	$r->RestoreState();
	$r->Update_Map();
      } else {
	$this->DeleteMapByMapId($tm_id);
      }

      return 0;
    }

    return 1;
  }

  function Copy_To ($tid, $to_crm, $updater_pid, $spid='', $epid='', $subject='') {
    $add = array (
      'CRM_ID' => $to_crm,
      'TICKET_ID' => $tid,
      'UPDATED_BY' => $updater_pid,
      'SUPPORT_PERSON_ID' => $spid,
      'ESCALATED_TO_PERSON_ID' => $epid,
      'SUBJECT' => $subject
    );
    list ($ok, $tm_id) = $this->Add_Map ($add);

    if ($ok) return $tm_id;

    return $ok;
  }

  function Exists ($tid, $to_crm) {
    $r = $this->Info_by_Ticket_ID ($tid, $to_crm);

    if ($tid and ($tid == $r->Get ('ticket_id'))) return array (1, $r);
    
    return array (0);
  }

  function Owner_Change ($tid, $to_crm, $from_crm, $pid) {
    $add = array( 'UPDATED_BY' => $pid );
    $this->Set_Audit_Info ($add);

    $xfer_id = $this->db->nextId('ticket_owner_transfer_id');

    $to_date = to_date();
    $h = $this->db->prepare ("
      insert into ticket_owner_transfer (
	ticket_owner_transfer_id,
        ticket_id,
        from_crm_id,
        to_crm_id,
        updated_by,
        created_by,
        created_on,
        updated_on
      ) values (
	?,
        ?, ?, ?, ?, ?,
        $to_date,
        $to_date
      )
    ");
    $ok = $this->db->execute ($h, array(
      $xfer_id,
      $tid,
      $from_crm,
      $to_crm,
      $add['UPDATED_BY'],
      $add['CREATED_BY'],
      $add['CREATED_DATE'],
      $add['UPDATED_DATE']
    ));
    if (DB::isError($ok)) {
      $this->error = "Ticket::Owner_Change() ".$ok->getMessage();
      $this->owner_transfer_id = 0;
      return 0;
    } else {
      ## Save what we inserted in case we need to find it for deletion
      $this->owner_transfer_id = $xfer_id;
      return 1;
    }
  }

  function Undo_Owner_Change() {
    if (!$this->owner_transfer_id) {
      $this->error = "Ticket::Undo_Owner_Change(): Nothing to undo";
      return 0;
    }

    $sql = "
      delete from ticket_owner_transfer
      where ticket_owner_transfer_id = ?
    ";
    $res = $this->db->query($sql, array($this->owner_transfer_id));
    if (DB::isError($res)) {
      $this->error = "Ticket::Undo_Owner_Change(): ".$res->getMessage();
      return 0;
    }

    return 1;
  }

  function Owner_History ($tid) {
    $df = date_format('tot.created_on', '%Y/%m/%d');
    $sql = "
    select tot.ticket_id,
           tot.from_crm_id,
           cc1.crm_name as from_crm_name,
           tot.to_crm_id,
           cc2.crm_name as to_crm_name,
           $df as created_on,
           tot.created_by
      from ticket_owner_transfer tot,
           company_crm cc1,
           company_crm cc2
     where tot.from_crm_id = cc1.crm_id
       and tot.to_crm_id = cc2.crm_id
       and tot.ticket_id = ?
  order by tot.created_on
    ";

    $res = $this->db->getAll( $sql, array($tid), DB_FETCHMODE_ASSOC );

    if (DB::isError($res)) {
      return array();
    } else {
      return $res;
    }
  }

  function SaveState() {
    foreach ($this->state_fields as $k) {
      $this->state[$k] = $this->$k;
    }
  }

  function RestoreState() {
    foreach($this->state as $k => $v) {
      $this->$k = $v;
    }
  }

  function Update () {
    $this->Set_Audit_Info ($this);
    if (!$this->Update_Base(1) || !$this->Update_Map(1)) {
      $this->error = 'Ticket::Update(): ' . $this->error;
      return;
    }

    return true;
  }

  function Update_Base ($no_audit=0) {
    if (!$no_audit) $this->Set_Audit_Info ($this);

    $to_date = to_date();
    $sql = "
      update ticket
         set additional_info = ?,
             crm_id = ?,
             mass_queue = ?,
             updated_by = ?,
             use_help = ?,
             updated_date = $to_date
       where ticket_id = ?
    ";

    $h = $this->db->prepare( $sql );

    $ok = $this->db->execute ($h, array(
      $this->additional_info,
      $this->crm_id,
      $this->mass_queue,
      $this->updated_by,
      $this->use_help,
      $this->updated_date,
      $this->ticket_id
    ));

    if (DB::isError($ok)) {
      $this->error = 'Ticket::Update_Base(): ' . $ok->getMessage() . "\n" .
	$ok->getUserInfo();
      return;
    }

    return true;
  }

  function Update_Map ($no_audit=0) {
    if (!$no_audit) $this->Set_Audit_Info ($this);

    $binds = array(
      $this->support_person_id,
      $this->escalated_to_person_id,
      $this->problem_id,
      $this->source_id,
      $this->updated_by,
      $this->status,
      $this->info1,
      $this->info2,
      substr($this->subject, 0, 25),
      $this->updated_date
    );

    $close = '';
    $to_date = to_date();

    if ($this->status == 'Closed') {
      $oldstat = $this->db->getOne(
	'SELECT status FROM ticket_crm_map WHERE tcrm_map_id = ?', 
	array($this->tcrm_map_id));
      if (DB::isError($oldstat)) {
	$this->error = 'Ticket::Update_Map(): ' . $oldstat->getMessage()
	  . "\n" . $oldstat->getUserInfo();
	return;
      }
      if ($oldstat != 'Closed') {
	$close = ", close_date = $to_date ";
        array_push( $binds, $this->updated_date );
      }
    }

    array_push( $binds, $this->tcrm_map_id );

    $h = $this->db->prepare ("
      update ticket_crm_map
         set support_person_id = ?,
             escalated_to_person_id = ?,
             problem_id = ?,
             source_id = ?,
             updated_by = ?,
             status = ?,
             info1 = ?,
             info2 = ?,
             subject = ?,
             updated_date = $to_date
	     $close
       where tcrm_map_id = ?
    ");

    $ok = $this->db->execute( $h, $binds );

    if (DB::isError($ok)) {
      $this->error = 'Ticket::Update_Map(): ' . $ok->getMessage() . "\n"
	. $ok->getUserInfo();
      return;
    }

    return true;
  }

  ## REPORTING FUNCTIONS

  ## This actually returns the DBResult object.
  function Counts_by ($start, $end, $select_group, $crm_id='') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();
    if (!$crm_id) return 0;

    $to_date = to_date();
    $h = $this->db->prepare ("
      SELECT COUNT(*), $select_group
        FROM ticket_crm_map tm INNER JOIN 
	     ticket t ON (t.ticket_id = tm.ticket_id)
       WHERE tm.created_date BETWEEN $to_date AND $to_date
	 AND t.crm_id = tm.crm_id
         AND tm.crm_id = ?
    GROUP BY $select_group
    ");

    $res = $this->db->execute ($h, array($start, $end, $crm_id));

    if (DB::isError($res)) {
      $this->error = 'Ticket::Counts_by(): ' . $res->getMessage() . "\n" .
	$res->getUserInfo();
      return;
    }

    return $res;
  }

  ## Also returns DBResult object.
  function Counts_by_Closed ($start, $end, $select_group, $crm_id='') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();
    if (!$crm_id) return 0;

    $to_date = to_date();
    $h = $this->db->prepare ("
      SELECT COUNT(*), $select_group
        FROM ticket_crm_map tm INNER JOIN 
	     ticket t ON (t.ticket_id = tm.ticket_id and
                          t.crm_id = tm.crm_id)
       WHERE tm.close_date BETWEEN $to_date AND $to_date
         AND tm.crm_id = ?
    GROUP BY $select_group
    ");
    $res = $this->db->execute ($h, array($start, $end, $crm_id));

    if (DB::isError($res)) {
      $this->error = 'Counts_by_Closed(): ' . $res->getMessage() . "\n"
	. $res->getUserInfo();
      return;
    }

    return $res;
  }

  ## And this
  function Counts_by_Person ($start, $end, $status='', $crm_id='') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();
    if (!$crm_id) return 0;

    if ($status == 'Closed') {
      $status = "AND tm.status = 'Closed'";
      $date_column = 'close_date';
    } else {
      $status = '';
      $date_column = 'created_date';
    }

    $to_date = to_date();
    $last_first = sql_concat('p.last_name', "', '", 'p.first_name');

    $h = $this->db->prepare ("
      SELECT COUNT(*),
             $last_first AS name,
	     p.person_id
        FROM ticket_crm_map tm INNER JOIN
	     ticket t ON (t.ticket_id = tm.ticket_id and
                          t.crm_id = tm.crm_id) INNER JOIN 
             person p ON tm.support_person_id = p.person_id
       WHERE tm.$date_column BETWEEN $to_date AND $to_date
	 AND tm.crm_id = ?
             $status
    GROUP BY p.person_id, $last_first
    ORDER BY 1 DESC
    ");
    if (DB::isError($h)) {
      $this->error = 'Ticket::Counts_by_Person(): ' . $h->getMessage()
	. "\n" . $h->getUserInfo();
      return;
    }

    $res = $this->db->execute ($h, array($start, $end, $crm_id));
    if (DB::isError($res)) {
      $this->error = 'Ticket::Counts_by_Person(): ' . $res->getMessage()
	. "\n" . $res->getUserInfo();
      return;
    }

    return $res;
  }

  function All_My_Open ($pid) {
    $sql = '
      SELECT COUNT(*) AS total, 
	     pcm.crm_id
        FROM ticket_crm_map tcm INNER JOIN 
	     person_crm_map pcm ON (tcm.crm_id = pcm.crm_id AND
	       tcm.support_person_id = pcm.person_id) INNER JOIN 
	     ticket t ON (tcm.ticket_id = t.ticket_id and
	       tcm.crm_id = t.crm_id)
       WHERE tcm.support_person_id = ? AND NOT (tcm.status = ?)
    GROUP BY pcm.crm_id
    ';
    $res = $this->db->getAll($sql, array($pid,'Closed'), DB_FETCHMODE_ASSOC);

    if (DB::isError($res)) {
      $this->error = 'Ticket::All_My_Open(): ' . $res->getMessage() . "\n"
	. $res->getUserInfo();
      return;
    }

    return $res;
  }

  function My_RMS_Open ($pid) {
    $sql = '
       select count(*) as total, pcm.crm_id
         from ticket_crm_map tcm
                inner join ticket t on (tcm.ticket_id = t.ticket_id and
                                        tcm.crm_id = t.crm_id)
                inner join person_crm_map pcm on (tcm.crm_id = pcm.crm_id)
       where pcm.person_id = ?
         and not (tcm.status = ?)
    group by pcm.crm_id
    ';

    $res = $this->db->getAll($sql, array($pid,'Closed'), DB_FETCHMODE_ASSOC);
    if (DB::isError($res)) {
      $this->error = "Ticket::My_RMS_Open(): " . $res->getMessage()
	. "\n" . $res->getUserInfo();
      return;
    }

    if (count($res)) return $res;
    return array();
  }

  function Open_by_Person_RMS ($pid,$crm_id) {
    if (!$crm_id or !$pid) return 0;

    $h = $this->db->prepare ("
      select count(*)
        from ticket_crm_map
       where support_person_id = ?
         and crm_id = ?
         and not status = ?
    ");

    $res = $this->db->execute($h, array($pid,$crm_id,'Closed') );

    if (DB::isError($res)) {
      print "error in Open_by_person_RMS pid=$pid crm=$crm_id: ";
      print $res->getMessage();
      $this->error = "Ticket::Open_by_Person_RMS(): ".$res->getMessage();
      return;
    }

    $r = $res->fetchRow();

    return $r[0];
  }
}

class Ticket_Record extends Ticket {
  function Ticket_Record () {
    Ticket::Ticket();
  }

  function Select_by_Ticket_ID ($tid, $crm_id='') {
    return $this->Select_by ($tid, $crm_id);
  }

  function Select_by ($tid, $crm_id='') {
    if (!$crm_id) $crm_id = $this->Current_CRM ();

    $binds = array ($tid);
    $where = '';

    if ($crm_id) {
      $binds[] = $crm_id;
      $where = ' and tcm.crm_id = ? ';
    } else {
      $where = ' and t.crm_id = tcm.crm_id ';
    }

    $dfclosed = date_format('tcm.close_date');
    $dfupdated = date_format('tcm.updated_date');
    $dfcreated = date_format('tcm.created_date');

    $sql = "
      select tcm.support_person_id,
             tcm.escalated_to_person_id,
             t.user_person_id,
             t.well_presented,
             t.find_info,
             t.use_help,
             t.help_useful,
             t.remote_host,
             t.browser,
             t.referring_url,
             t.account_id,
             $dfclosed as close_date,
             t.mass_queue,
             tcm.status,
             tcm.info1,
             tcm.info2,
             $dfupdated as updated_date,
             tcm.updated_by,
             $dfcreated as created_date,
             tcm.created_by,
	     t.ticket_id,
             t.additional_info,
             tcrm_map_id,
             tcm.crm_id,
             tcm.source_id,
             tcm.problem_id,
             t.crm_id as owner_crm_id,
             tcm.subject
        from ticket_crm_map tcm,
             ticket t
       where tcm.ticket_id = t.ticket_id
         and t.ticket_id = ?
             $where
    ";
    $h = $this->db->prepare( $sql );
    $res = $this->db->execute ($h,$binds);
    if (DB::isError($res)) {
       $this->error = "Ticket::Select_by(): "
	. $res->getMessage() . $res->getUserInfo();
       return;
    }
    $r = $res->fetchRow (DB_FETCHMODE_ASSOC);

    if (!count($r)) {
      $this->error = "Ticket::Select_by(): No rows returned";
      return;
    }

    foreach ($r as $k => $v) {
      $k = strtolower ($k);
      $this->$k = $v;
    }

    return $r;
  }
}
?>
