TUTOS PHP Cross Reference Groupware Applications

Source: /php/timetrack/timetrack.pinc - 1182 lines - 38484 bytes - Summary - Text - Print

Description: Copyright 1999 - 2013 by Gero Kohnert This program 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; version 2 of the License.

   1  <?php
   2  /**
   3   *  Copyright 1999 - 2013 by Gero Kohnert
   4   *
   5   *  This program is free software; you can redistribute it and/or modify it
   6   *  under the terms of the GNU General Public License as published by the
   7   *  Free Software Foundation; version 2 of the License.
   8   *
   9   *  SVN Info  $Id: timetrack.pinc 1062 2013-05-18 14:36:11Z gokohnert $
  10   *  $Author: gokohnert $
  11   *
  12   * @modulegroup timetrack
  13   * @package timetrack
  14   */
  15  $tutos['files'][__FILE__] = '$Rev: 1062 $';
  16  
  17  define ('TT_STATE_CHECKED',1);
  18  define ('TT_STATE_BILLED',2);
  19  define ('TT_STATE_PAYED',3);
  20  define ('TT_STATE_NOBILL',4);
  21  
  22  loadmodule('stc');
  23  /**
  24   * ask a timetrack state
  25   */
  26  function TimetrackAskState (array $default,$any) {
  27      global $lang,$tutos,$current_user;
  28  
  29      $stc = getObject($current_user->dbconn,$tutos['timetrack_state_stc']);
  30      if (!is_object($stc)) {
  31          $stc = new Stc(null);
  32          $stc->initByArray('TTStates',timetrack::$c_state);
  33      }
  34  
  35      $additional = array();
  36      if ( $any ) {
  37          $additional[-2] = $lang['any'];
  38      }
  39      $r = "<select id=\"state\" multiple=\"multiple\" name=\"state[]\">\n";
  40      foreach ($stc->states as $f) {
  41          $r .= '  <option value="'. $f->stc_state .'" style="background:'.$f->color.'"';
  42          if ( isset($default[$f->stc_state]) ) {
  43              $r .= ' selected="selected"';
  44          }
  45          $r .= '>'. myentities($f->getFullName()) ."</option>\n";
  46      }
  47      foreach ($additional as $i => $f) {
  48          $r .= '  <option value="'.$i.'"';
  49          if ( isset($default[$i]) ) {
  50              $r .= ' selected="selected"';
  51          }
  52          $r .= ">". myentities($f) ."</option>\n";
  53      }
  54  
  55      $r .= "</select>\n";
  56  
  57      return $r;
  58  }
  59  
  60  /**
  61   * Read a summary of times for given object
  62   */
  63  function readTimetrackSum (tutos_base $obj,array $objs = null, $topic = '') {
  64      global $table;
  65  
  66      #    echo $obj.'|'.(is_array($objs) ? count($objs):'null').'|'.$topic.'<br><pre>';
  67      #    echo TUTOS_backtrace();
  68      #    echo '</pre><br>';
  69  
  70      if (!isset($obj->timetracksum)) {
  71          $obj->timetracksum    = 0;
  72          $obj->distancesum     = 0;
  73          $obj->timetrack_w_sum = array();
  74          $obj->distance_w_sum  = array();
  75          $obj->tsum            = array();
  76          $obj->dsum            = array();
  77      }
  78      if ($topic != '' && !isset($obj->tsum[$topic])) {
  79          $obj->tsum[$topic]    = 0;
  80          $obj->dsum[$topic]    = 0;
  81      }
  82  
  83      $sub = false;
  84      $pn  = '';
  85      $q   = 'SELECT adr_id,SUM(volume) as XX, SUM(distance) as YY FROM '. $obj->dbconn->prefix .$table['timetrack'][name];
  86      $pre = ' WHERE';
  87      if (   ($obj->getType() == "address")
  88             ||($obj->getType() == "user" )
  89             ||($obj->getType() == "team" )
  90          ) {
  91          // per user or team
  92          if (is_array($objs)) {
  93              if (count($objs) == 0) return;
  94              $q .= $pre . ' adr_id ='. $obj->id ;
  95              $pre = ' AND';
  96              $o = '';
  97              $opre = '';
  98              foreach ($objs as $i => $j) {
  99                  if (is_object($j)) {
 100                      $o .= $opre.$j->id;
 101                  } else if (is_numeric($j)) {
 102                      $o .= $opre.$j;
 103                  } else {
 104                      $o .= $opre.$i;
 105                  }
 106                  $opre = ',';
 107              }
 108              $q .= $pre . ' link_id in ('. $o .')' ;
 109  
 110              // here we have to substract fromo totals as ist always included in the normal search
 111              $sub = true;
 112          } else {
 113              $pq = $q.$pre. ' adr_id =$1';
 114              $q .= $pre . ' adr_id ='. $obj->id ;
 115              $pn = 'TT1';
 116              $pre = ' AND';
 117          }
 118      } else {
 119          // per project or whatever
 120          if (is_array($objs)) {
 121              if (count($objs) == 0) return;
 122              $o = '';
 123              $opre = '';
 124              foreach ($objs as $i => $j) {
 125                  if (is_object($j)) {
 126                      $o .= $opre.$j->id;
 127                  } else if (is_numeric($j)) {
 128                      $o .= $opre.$j;
 129                  } else {
 130                      $o .= $opre.$i;
 131                  }
 132                  $opre = ',';
 133              }
 134              $q .= $pre . ' link_id in ('. $o .')' ;
 135              $pre = ' AND';
 136          } else {
 137              $pq = $q.$pre. ' link_id =$1';
 138              $q .= $pre . ' link_id ='. $obj->id ;
 139              $pre = ' AND';
 140              $pn = 'TT2';
 141          }
 142      }
 143  
 144      if ( ($pn != '') && $obj->dbconn->prep) {
 145          $pq .= ' GROUP BY adr_id';
 146          $ps = $obj->dbconn->addPStatement($pq,$pn);
 147          $r = $obj->dbconn->execPStatement($pn,0,$obj->id);
 148      } else {
 149          $q .= ' GROUP BY adr_id';
 150          $r = $obj->dbconn->Exec($q,0);
 151      }
 152      $n = $r->numrows();
 153      if ( $n == 0 ) {
 154          $r->free();
 155          return;
 156      }
 157  
 158      $a = 0;
 159      while ( $a < $n ) {
 160          $adr = $r->get($a,'adr_id');
 161          $xx = $r->get($a,'XX');
 162          $yy = $r->get($a,'YY');
 163          if ($topic != '') {
 164              $obj->tsum[$topic] += $xx;
 165              $obj->dsum[$topic] += $yy;
 166              if ($sub) {
 167                  $obj->timetracksum -= $xx;
 168                  $obj->distancesum  -= $yy;
 169              }
 170          } else {
 171              $obj->timetracksum += $xx;
 172              $obj->distancesum += $yy;
 173          }
 174          if (!isset($obj->timetrack_w_sum[$adr])) {
 175              $obj->timetrack_w_sum[$adr] = 0.0;
 176              $obj->distance_w_sum[$adr] = 0.0;
 177          }
 178          $obj->timetrack_w_sum[$adr] += $xx;
 179          $obj->distance_w_sum[$adr] += $yy;
 180          $a++;
 181      }
 182      $r->free();
 183      return;
 184  }
 185  
 186  /**
 187   * Compute the amount of work done by $address on $task
 188   *
 189   * FIXME : add some time schedule restriction
 190   */
 191  function computeWorkedHours(&$address, &$task) {
 192      global $table;
 193  
 194      $sum = 0;
 195  
 196      $q = 'SELECT SUM(volume) as XX FROM '. $task->dbconn->prefix .$table['timetrack'][name].
 197          ' WHERE adr_id = '. $address->id. ' AND link_id = '. $task->id;
 198  
 199      $r = $task->dbconn->Exec($q);
 200      $n = $r->numrows();
 201      if ( $n == 0 ) {
 202          return $sum;
 203      }
 204      $sum = $r->get(0,"XX");
 205      $r->free();
 206  
 207      return $sum == "" ? 0 : $sum;
 208  }
 209  
 210  /**
 211   * A fraction of a timetrack
 212   * @package timetrack
 213   */
 214  class Timetrack extends tutos_module {
 215      /**
 216       * URL to use for modify this object
 217       */
 218      protected $modurl  = 'timetrack/timetrack_new.php';
 219      /**
 220       * URL to use for display this object
 221       */
 222      protected $showurl = 'timetrack/timetrack_overview.php';
 223      /**
 224       * revision of file
 225       */
 226      static public $revision = '$Rev: 1062 $';
 227  
 228      static public $c_state = array(TT_STATE_CHECKED      => 'lightgreen',
 229                                     TT_STATE_BILLED       => 'orange',
 230                                     TT_STATE_PAYED        => 'green',
 231                                     TT_STATE_NOBILL       => 'red',
 232          );
 233  
 234      /**
 235       */
 236      function timetrack(tutos_db $dbconn) {
 237          global $tutos,$current_user,$table;
 238  
 239          $this->init($dbconn);
 240  
 241          $this->wid         = $current_user->id;
 242          $this->worker      = $current_user;
 243          $this->link_id     = -1;
 244          $this->ref         = -1;
 245          $this->desc        = '';
 246          $this->volume      = 0.0;
 247          $this->volume_todo = -1;
 248          $this->distance    = 0.0;
 249          $this->wday        = new TUTOS_Date_Time();
 250          $this->creation    = new TUTOS_Date_Time();
 251          $this->t_start     = new TUTOS_Date_Time(0);
 252          $this->t_end       = new TUTOS_Date_Time(0);
 253          $this->diff        = 0.0;
 254          // number of invoice
 255          $this->invoice     = -1;
 256          $this->currency    = $tutos[currencies][0];
 257          // Costs per hour ("" == default)
 258          $this->cph         = 0.0;
 259          $this->state       = -1;
 260          $this->inv_id      = -1;
 261  
 262          $this->setfinish   = false; // set ref to finished
 263          $this->tablename   = $this->dbconn->prefix .$table['timetrack'][name];
 264          $this->run_postinit_hook();
 265      }
 266  
 267      /**
 268       * read a resultset
 269       */
 270      function read_result (result $r, $pos ) {
 271          global $g_hash,$tutos;
 272  
 273          $this->id          = $r->get($pos, 'id');
 274          $this->wid         = $r->get($pos, 'adr_id');
 275          $this->worker      = getObject($this->dbconn,$this->wid);
 276          $this->link_id     = $r->get($pos, 'link_id');
 277          $this->ref         = getObject($this->dbconn,$this->link_id);
 278          $this->desc        = $r->get($pos, 'description');
 279          $this->volume      = $r->get($pos, 'volume');
 280          $this->distance    = $r->get($pos, 'distance');
 281          $this->volume_todo = $r->get($pos, 'volume_todo');
 282          $this->state       = (integer)$r->get($pos, 'state');
 283          $this->cph         = $r->get($pos, 'cph');
 284          $this->currency    = $r->get($pos, 'currency');
 285          $this->inv_id      = $r->get($pos, 'invoice');
 286          $this->creation    = $r->getDateTime($pos, 'creation');
 287          $this->wday        = $r->getDateTime($pos, 'vtime');
 288          $this->t_start     = $r->getDateTime($pos, 't_start');
 289          $this->t_end       = $r->getDateTime($pos, 't_end');
 290          if ( $this->inv_id == '' ) {
 291              $this->inv_id   = -1;
 292              $this->invoice  = -1;
 293          }
 294          if ( $this->cph == '' ) {
 295              $this->cph      = 0.00;
 296          }
 297  
 298          $this->creator     = $r->getObject($pos, 'creator');
 299  
 300          parent::read_result($r,$pos);
 301          return;
 302      }
 303  
 304      /**
 305       * get a list of possible new parents
 306       */
 307      function read_relations () {
 308          global $lang,$current_user,$table,$tutos;
 309  
 310          $this->plist = array();
 311          if (is_object($this->ref)) {
 312              // Read possible new parents
 313              $this->plist = $this->ref->getNeighbours();
 314          }
 315          // a timetrack object could be attached to all projects and tasks where we play a role
 316          if ( $current_user->feature_ok(useprojects,PERM_SEE) ) {
 317              require_once  'product.pinc';
 318              $q = 'SELECT p.* from '. $this->dbconn->prefix.$table['product'][name].' p,'. $this->dbconn->prefix .$table['product2'][name].' r ';
 319              $pre = ' WHERE ';
 320              if (is_object($this->worker) && ($this->worker->id > 0) ) {
 321                  $q .= $pre ." r.adr_id in(". $this->worker->id;
 322                  $q .= ' ) ';
 323                  $pre = ' AND ';
 324              }
 325              $q .= $pre .' r.pro_id = p.id';
 326              $x = preg_split('#,#',$tutos['prod_activ_states']);
 327              // only activ projects
 328              $s = '';
 329              $spre = '';
 330              foreach ($x as $i) {
 331                  if (is_numeric($i)) {
 332                      $s .= $spre.$i;
 333                      $spre = ',';
 334                  }
 335              }
 336              $q .= ' AND  p.state in ('.$s.')';
 337              $q .= ' order by p.name';
 338              $result = $this->dbconn->Exec($q);
 339              $n = $result->numrows();
 340              $a = 0;
 341              while ( $a < $n ) {
 342                  $p = new Product($this->dbconn);
 343                  $p->read_result($result,$a);
 344                  $a++;
 345                  if ( $p->use_ok()) {
 346                      $this->plist[$p->id] = &$p;
 347                  }
 348                  unset($p);
 349              }
 350              $result->free();
 351          }
 352          if ( $current_user->feature_ok(usetaskmanagement,PERM_SEE) ) {
 353              $q = 'SELECT t.* from '. $this->dbconn->prefix.$table['task'][name].' t,'. $this->dbconn->prefix .$table['taskworker'][name].' w ';
 354              $pre = ' WHERE ';
 355              if (is_object($this->worker) && ($this->worker->id > 0) ) {
 356                  $q .= $pre ." w.w_id in(". $this->worker->id;
 357                  $q .= " ) ";
 358                  $pre = ' AND ';
 359              }
 360              $q .= $pre .' w.t_id = t.id';
 361              $q .= ' AND  t.status != '.$tutos['task_finish_state'];
 362              $q .= ' order by t.name';
 363              $result = $this->dbconn->Exec($q);
 364              $n = $result->numrows();
 365              $a = 0;
 366              while ( $a < $n ) {
 367                  $p = new Task($this->dbconn);
 368                  $p->read_result($result,$a);
 369                  $a++;
 370                  if ( $p->use_ok()) {
 371                      $this->plist[$p->id] = &$p;
 372                  }
 373                  unset($p);
 374              }
 375              $result->free();
 376          }
 377      }
 378  
 379      /**
 380       * set the Description
 381       */
 382      function setDescription($value) {
 383          $this->setStrField('desc',$value,'Description');
 384          return;
 385      }
 386  
 387      /**
 388       * set the Worker
 389       */
 390      function setWorker($name) {
 391          $i = new Tutos_address($this->dbconn);
 392          $i = $i->read($name,$i);
 393  
 394          if ( ($this->worker->id != $name) && ($i->id != -1) ) {
 395              $this->modified[] = array ( 'field' => 'TimetrackWorker', 'old' => $this->worker->id , 'new' => $name );
 396              $this->worker = $i;
 397          }
 398          return;
 399      }
 400  
 401      /**
 402       * set the workday
 403       */
 404      function setWorkday(&$value) {
 405          return $this->setDateField('wday',$value,'Date');
 406      }
 407  
 408      /**
 409       * set the Start
 410       */
 411      function setStart(&$value) {
 412          return $this->setDateTimeField('t_start',$value,'AppStart');
 413      }
 414  
 415      /**
 416       * set the End
 417       */
 418      function setEnd(&$value) {
 419          return $this->setDateTimeField('t_end',$value,'AppEnd');
 420      }
 421  
 422      /**
 423       * set the Currency
 424       */
 425      function setCurrency($value) {
 426          return $this->setStrField('currency',$value,'Currency');
 427      }
 428  
 429      /**
 430       * set the costs per hour
 431       */
 432      function setCph($value) {
 433          return $this->setFloatField('cph',$value,'TTcph');
 434      }
 435  
 436      /**
 437       * set the volume
 438       */
 439      function setVolume($value) {
 440  
 441          if (is_float($value)) {
 442              $value = sprintf('%f',$value);
 443          }
 444          $this->diff = $value - $this->volume;
 445          return $this->setFloatField('volume',$value,'TaskVolumeDone');
 446      }
 447  
 448      /**
 449       * set the distance
 450       */
 451      function setDistance($value) {
 452          return $this->setFloatField('distance',$value,'Distance');
 453      }
 454  
 455      /**
 456       * set the volume todo
 457       */
 458      function setVolumeTodo($value) {
 459          return $this->setFloatField('volume_todo',$value,'TaskVolumeTodo');
 460      }
 461  
 462      /**
 463       * set the state
 464       */
 465      function setState($value) {
 466          if ($value < 0) return false; // no change
 467          return $this->setIntField('state',$value,'TTState');
 468      }
 469  
 470      /**
 471       * get current state of this timetrack as HTML
 472       */
 473      function getState ($s = '') {
 474          global $tutos,$lang;
 475  
 476          $r = '';
 477          if ( $s == '' ) {
 478              $s = $this->state;
 479          }
 480  
 481          $stc = getObject($this->dbconn,$tutos['timetrack_state_stc']);
 482          if (!is_object($stc)) {
 483              $stc = new Stc(null);
 484              $stc->initByArray('TTStates',self::$c_state);
 485          }
 486          $r .= $stc->getState($s);
 487  
 488          return $r;
 489      }
 490  
 491      /**
 492       * get current state color of this bug
 493       */
 494      function getStateColor ($s = '') {
 495          global $tutos,$lang;
 496  
 497          $r = '';
 498          if ( $s == '' ) {
 499              $s = $this->state;
 500          }
 501  
 502          $stc = getObject($this->dbconn,$tutos['timetrack_state_stc']);
 503          if (!is_object($stc)) {
 504              $stc = new stc(null);
 505              $stc->initByArray('TTStates',self::$c_state);
 506          }
 507          if (isset($stc->states[$s]))
 508              $r .= $stc->states[$s]->color;
 509          return $r;
 510      }
 511  
 512      /**
 513       * get a state color block
 514       */
 515      function getStateColorBlock($s = '') {
 516          return '<span style="font-size:0.8em;background:'.$this->getStateColor($s).';">&#160;&#160;</span>&#160;';
 517      }
 518  
 519      /**
 520       * create a select list with possible states
 521       */
 522      function askState () {
 523          global $tutos;
 524  
 525          $r = '';
 526          $stc = getObject($this->dbconn,$tutos['timetrack_state_stc']);
 527          if (!is_object($stc)) {
 528              $stc = new Stc(null);
 529              $stc->initByArray('TTStates',self::$c_state);
 530              if ($this->state == -1) {
 531                  $this->state = $tutos['timetrack_default_state'];
 532              }
 533          }
 534          $stc->stateowner = $this;
 535          $r .= $stc->getStateSelection($this->state,'state');
 536          return $r;
 537      }
 538  
 539      /**
 540       * set the Invoice
 541       */
 542      function setInvoice($value) {
 543          return $this->setIntField('inv_id',$value,'Invoice');
 544      }
 545  
 546      /**
 547       * set the Invoice
 548       */
 549      function setReference($value) {
 550          return $this->setIntField('link_id',$value,'TimetrackRef');
 551      }
 552  
 553      /**
 554       * Save Time Fraction to DB
 555       *
 556       * The norec parameter allows to create a timetrack from task.pink
 557       * without re entrance problems that may occur when timetrack tries
 558       * to save the ref task...
 559       */
 560      function save($norec=0) {
 561          global $table,$tutos, $lang, $current_user;
 562  
 563          $msg = $this->run_presave_hook();
 564  
 565          $this->isnew = true;
 566          // We may have to compute the volume todo of this timetrack entry
 567          // This is the same as the task volume todo
 568          if( $this->volume_todo == -1 ) {
 569              if (isset($this->ref->volume_todo) && ($this->ref->volume_todo != -1) ) {
 570                  $ref_todo = $this->ref->volume_todo;
 571              } elseif (isset($this->ref->volume) && ($this->ref->volume != -1) ) {
 572                  // If no volume_todo has been set for the task, we consider
 573                  // the planned volume as the volume_todo
 574                  $ref_todo = $this->ref->volume;
 575              } else {
 576                  // the diff will be zero
 577                  $ref_todo = $this->volume;
 578              }
 579              // And the calculated volume_todo is the volume todo before this
 580              // timetrack entry, minus this timetrack entry volume...
 581              $this->volume_todo = $ref_todo - $this->volume;
 582          } else {
 583              // If a volume has been entered, we then just take it
 584              $this->volume_todo = $this->volume_todo;
 585          }
 586  
 587          $q = new Query($this->dbconn);
 588          $q->setTable($this->tablename);
 589          $q->addFV('link_id',$this->link_id,'');
 590          $q->addFV('adr_id',(is_object($this->worker) ? $this->worker->id:-1),'');
 591          $q->addFV('volume',$this->volume,'FLOAT');
 592          $q->addFV('distance',$this->distance,'FLOAT');
 593          $q->addFV('volume_todo',$this->volume_todo,'FLOAT');
 594          $q->addFV('description',$this->desc,'STRING',$table['timetrack']['description'][size]);
 595          $q->addFV('vtime',$this->wday,'DATETIME');
 596          $q->addFV('state',$this->state,'');
 597          $q->addFV('invoice',$this->inv_id,'');
 598          $q->addFV('cph',$this->cph,'FLOAT');
 599          $q->addFV('currency',$this->currency,'STRING',4);
 600          $q->addFV('t_start',$this->t_start,'DATETIME');
 601          $q->addFV('t_end',$this->t_end,'DATETIME');
 602          $this->save_custom_fields($q);
 603  
 604          if ( $this->id < 0 ) {
 605              $this->isnew = true;
 606              $this->modified = array();
 607              if ( isset($this->newid) ) {
 608                  $this->id = $this->newid;
 609                  $q->addFV('id',$this->id,'');
 610              } else {
 611                  $this->id = $q->addFV('id',-1,'NEXTID');
 612                  $this->acl_default();
 613                  $this->acl_raise($this->worker->id,$tutos[useok]);
 614  
 615                  // the master (i.e. projectmanager or similar) of the parent
 616                  $this->acl_raise($this->getObjectGroupId(129),$tutos[delok]);
 617  
 618                  // Prepare the history
 619                  $this->modified[] = array ( 'field' => 'TimetrackCreate' ,
 620                                              'old' => '' ,
 621                                              'new' => $this->volume,
 622                                              'obj_id' => $this->link_id
 623                      );
 624                  $this->modified[] = array ( 'field' => 'created' ,
 625                                              'old' => $this->getType() ,
 626                                              'new' => $this->id,
 627                                              'obj_id' => $this->id
 628                      );
 629              }
 630              $q->addFV('creation',$this->creation,'DATETIME');
 631              $q->addFV('creator',$this->creator,'OBJ');
 632  
 633              $query = $q->getInsert();
 634          } else {
 635              $this->isnew = false;
 636              $q->addWC('id',$this->id,'');
 637              $query = $q->getUpdate();
 638          }
 639  
 640          $r = $this->dbconn->Exec($query);
 641          $r->free();
 642          if ( $norec == 0 &&
 643               is_object($this->ref) &&
 644               ( $this->ref->getType() == 'task') ) {
 645              if ( $this->ref->r_start->notime == 1 ) {
 646                  $this->ref->setRStart($this->wday);
 647              } else {
 648                  if ($this->wday->ts < $this->ref->r_start->ts) {
 649                      $this->ref->setRStart($this->wday);
 650                  }
 651              }
 652              if ( $this->ref->r_end->notime == 1 ) {
 653                  $this->ref->setREnd($this->wday);
 654              } else {
 655                  if ($this->wday->ts > $this->ref->r_end->ts) {
 656                      $this->ref->setREnd($this->wday);
 657                  }
 658              }
 659          }
 660          $msg = addLine($msg,parent::save());
 661  
 662          // notify others that time was booked objects
 663          if (is_object($this->ref) && method_exists($this->ref,'time_booked') ) {
 664              $this->ref->time_booked($this);
 665          }
 666  
 667          return $msg;
 668      }
 669  
 670      /**
 671       * Delete Timetrack fraction from DB
 672       */
 673      function delete() {
 674          $this->modified[] = array ( 'field' => 'TimetrackDel' ,
 675                                      'old' => $this->volume ,
 676                                      'new' => '0',
 677                                      'obj_id' => $this->link_id
 678              );
 679          return parent::delete();
 680      }
 681  
 682      /**
 683       * the url where we go after deleting this object
 684       */
 685      function get_after_del_url () {
 686          if (is_object($this->ref)) {
 687              return $this->ref->getUrl();
 688          }
 689          return 'mytutos.php';
 690      }
 691  
 692      /**
 693       * Return a url that displays this timetrack fraction
 694       */
 695      function getFullName() {
 696          // not yet finished (we calc the time)
 697          if (!$this->t_start->notime && $this->t_end->notime) {
 698              $tt = new TUTOS_Date_Time();
 699              $this->volume = ($tt->getTimeStamp() - $this->t_start->getTimeStamp()) / 3600.0;
 700          }
 701          return hour_format($this->volume) .'@' . $this->wday->getDate();
 702      }
 703  
 704      /**
 705       * Return a link to this timefragement
 706       */
 707      function getLink($text = '',$arg = '') {
 708          global $lang;
 709  
 710          if ( empty($text) ) {
 711              $text = $this->getFullName();
 712          }
 713          if ( $this->see_ok() ) {
 714              return makelink($this->getURL() , myentities($text) ,sprintf($lang['timetrack'] .' %s',$this->getFullName()));
 715          } else {
 716              return myentities($text);
 717          }
 718      }
 719  
 720      /**
 721       * Data of XML export
 722       */
 723      function exportXML_body () {
 724          $r = parent::exportXML_body();
 725          $r .=  '<worker>'. htmlspecialchars($this->worker->id) ."</worker>\n";
 726          if ( $this->worker->id != null ) {
 727              $r .=  "<workername>". htmlspecialchars($this->worker->getFullName()) ."</workername>\n";
 728          }
 729          $r .=  "<reference>". htmlspecialchars($this->ref->id) ."</reference>\n";
 730          if ( $this->ref->id != null ) {
 731              $r .=  "<referencename>". htmlspecialchars($this->ref->getFullName()) ."</referencename>\n";
 732          }
 733          $r .=  "<volume>". htmlspecialchars($this->volume) ."</volume>\n";
 734          $r .=  "<volume_todo>". htmlspecialchars($this->volume_todo) ."</volume_todo>\n";
 735          if ( $this->t_start->notime != 1 ) {
 736              $r .=  "<t_start>". $this->t_start->exportXML_body() ."</t_start>\n";
 737          }
 738          if ( $this->t_end->notime != 1 ) {
 739              $r .=  "<t_end>". $this->t_end->exportXML_body() ."</t_end>\n";
 740          }
 741          $r .=  "<description>". htmlspecialchars($this->desc) ."</description>\n";
 742          $r .=  "<invoice>". htmlspecialchars($this->invoice) ."</invoice>\n";
 743          $r .=  "<state>". htmlspecialchars($this->state) ."</state>\n";
 744          $r .=  "<cph>". htmlspecialchars($this->cph) ."</cph>\n";
 745          $r .=  "<cost>". htmlspecialchars($this->cph * $this->volume) ."</cost>\n";
 746          $r .=  "<currency>". htmlspecialchars($this->currency) ."</currency>\n";
 747          if ( $this->wday->notime != 1 ) {
 748              $r .=  "<vtime>". $this->wday->exportXML_body() ."</vtime>\n";
 749          }
 750          return $r;
 751      }
 752  
 753      /**
 754       * a headline for CSV Export
 755       */
 756      static function exportCSV_Header() {
 757          $r = '';
 758          $r .= txt2csv('ID');
 759          $r .= txt2csv('TimetrackWorker');
 760          $r .= txt2csv('TimetrackRef');
 761          $r .= txt2csv('Description');
 762          $r .= txt2csv('TaskVolumeDone');
 763          $r .= txt2csv('TTcph');
 764          $r .= txt2csv('Currency');
 765          $r .= txt2csv('TTState');
 766          $r .= txt2csv('TimetrackDate');
 767          $r .= "\r\n";
 768          return $r;
 769      }
 770  
 771      /**
 772       * Return a data  as comma seperated values string
 773       */
 774      function exportCSV() {
 775          global $lang;
 776  
 777          if ( $this->ref->id > 0 ) {
 778              $ref =  $this->ref->getFullName();
 779          } else {
 780              $ref = $lang['HistoryDeleted'];
 781          }
 782          if (is_object($this->worker)) {
 783              $w =  $this->worker->getFullName();
 784          } else {
 785              $w = $lang['HistoryDeleted'];
 786          }
 787          $r = '';
 788          $r .= txt2csv($this->id);
 789          $r .= txt2csv($w);
 790          $r .= txt2csv($ref);
 791          $r .= txt2csv($this->desc);
 792          $r .= txt2csv(my_number_format($this->volume,2));
 793          $r .= txt2csv(my_number_format($this->cph,2));
 794          $r .= txt2csv($this->currency);
 795          $r .= txt2csv($this->state);
 796          $r .= txt2csv($this->wday->getYYYYMMDD());
 797          $r .= "\r\n";
 798  
 799          return  $r;
 800      }
 801  
 802      /**
 803       * Transfer reference ids according to given table
 804       */
 805      function transfer_ids (&$trans) {
 806          if (isset($trans[$this->worker->id])) {
 807              $this->worker->id = $trans[$this->worker->id];
 808          }
 809          if (isset($trans[$this->inv_id])) {
 810              $this->inv_id = $trans[$this->inv_id];
 811          }
 812          if (isset($trans[$this->link_id])) {
 813              $this->link_id = $trans[$this->link_id];
 814          }
 815          return;
 816      }
 817  
 818      /**
 819       * resolve a history Tag (to be called from history_show)
 820       */
 821      function resolveHistoryTag ($f) {
 822          global $lang;
 823  
 824          $x = array();
 825          switch ($f['field']) {
 826          case 'Date':
 827              $x = resolve_history_datetime($f,$this->dbconn);
 828              return $x;
 829              break;
 830          case 'TTState':
 831              $x = resolve_history_lgarr ($f,'TTStates');
 832              return $x;
 833              break;
 834          case 'Invoice':
 835              $x = resolve_history_obj ($f,$this->dbconn);
 836              return $x;
 837              break;
 838          default:
 839              return null;
 840          }
 841      }
 842  
 843      /**
 844       * get the type of object
 845       */
 846      static function gettype () {
 847          return 'timetrack';
 848      }
 849  
 850      /**
 851       * get the type id of object
 852       */
 853      static function gettypeid () {
 854          return usetimetrack;
 855      }
 856  
 857      /**
 858       * get name of icons
 859       */
 860      static function getHtmlIcon () {
 861          return 'time';
 862      }
 863  
 864      /**
 865       * get a array with virtual groups used in STC for state changes
 866       */
 867      function getStateObjectGroups(array &$x,Stc_transition $stc) {
 868          global $lang,$tutos;
 869  
 870          $x[$stc->getTypeId()][1] =  $lang[$stc->getType()].':'.$lang['Timetrack'].':Creator';
 871  
 872          foreach ($lang['ProdRole'] as $role => $f) {
 873              if ( $tutos[rolecheck][$role] != "p") {
 874                  $x[$stc->getTypeId()][$role +128] = $lang[$stc->getType()].':'.$lang['Timetrack'].' - '.$lang['Project'].' '.$f;
 875              }
 876          }
 877      }
 878  
 879      /**
 880       * get a array with virtual groups
 881       */
 882      function getObjectGroups() {
 883          global $lang,$tutos;
 884  
 885          $x = parent::getObjectGroups();
 886  
 887          foreach ($lang['ProdRole'] as $role => $f) {
 888              if ( $tutos[rolecheck][$role] != "p") {
 889                  $x[$this->getTypeId()][$role +128] = $lang[$this->getType()].':'.$lang['Project'].' '.$f;
 890              }
 891          }
 892          return $x;
 893      }
 894  
 895      /**
 896       * get a array with virtual groups members
 897       */
 898      function getObjectGroupList($id) {
 899          global $lang;
 900  
 901          if ($id < 0) {
 902              $id2 = -($id - ($this->getTypeId() << ACLSHIFT));
 903          } else {
 904              $id2 = $id;
 905          }
 906  
 907          $x = parent::getObjectGroupList($id);
 908  
 909          if ( $id2 > 128 ) {
 910              if (!is_object($this->ref)) return $x;
 911              if ($this->ref->getTypeId()  != useprojects) return $x;
 912              $x = $this->ref->getObjectGroupList($id2);
 913          } else if ( $id2 > 1 ) {
 914              // manage old style
 915              if (!is_object($this->ref)) return $x;
 916              if ($this->ref->getTypeId()  != useprojects) return $x;
 917              $x = $this->ref->getObjectGroupList($id2+127);
 918          }
 919          return $x;
 920      }
 921  
 922      /* ---------------------------------------------------------------------------
 923       * The following methods are abstract factory functions for groups
 924       * which handle the membership list of an object
 925       * --------------------------------------------------------------------------- */
 926      /**
 927       * create a list of timetracks for the given object
 928       */
 929      static function infolist (tutos_user $user,tutos_base $obj,$cols,$format = "html") {
 930          global $lang;
 931  
 932          $r = '';
 933          $d = '';
 934          if (! is_object($obj) ) return $r;
 935          if ( $obj->id < 0 ) return $r;
 936  
 937          if ( $obj->getType() == 'team' ) return $r;
 938  
 939          if ( ! $user->feature_ok(usetimetrack,PERM_SEE) ) return $r;
 940          if ( ! $obj->obj_feature_ok($user,usetimetrack,PERM_SEE) ) return $r;
 941  
 942          if (method_exists($obj,'readTimetrackSum')) {
 943              $timesum = 0.0;
 944              $costsum = 0.0;
 945              $obj->readTimetrackSum();
 946          } else {
 947              timetrack::obj_read($obj);
 948              if (count($obj->ttlist) == 0) return $r;
 949          }
 950  
 951          $link = 'timetrack/timetrack_overview.php';
 952          if (   ($obj->getType() == "address")
 953                 ||($obj->getType() == "user" )
 954                 ||($obj->getType() == "team" )
 955              ) {
 956              $link = addUrlParameter($link,'worker='.$obj->id);
 957              $nolink = true;
 958          } else {
 959              $link = addUrlParameter($link,'link_id='.$obj->id);
 960              $nolink = false;
 961          }
 962          if (method_exists($obj,'readTimetrackSum')) {
 963              $cnt = 0;
 964              $timesum += $obj->timetracksum;
 965  
 966              $dx = '';
 967              if (isset($obj->tsum) && is_array($obj->tsum))
 968                  foreach ($obj->tsum as $i => $f) {
 969                      if ( $obj->tsum[$i] > 0 ) {
 970                          $dx .= '<br/><div align="right" style="width:10em;display:inline;float:left">';
 971                          if ($nolink) {
 972                              $dx .= hour_format($obj->tsum[$i]).'</div>';
 973                          } else {
 974                              $dx .= makelink(addUrlParameter($link,'show='.$i),hour_format($obj->tsum[$i]),$lang['TimetrackOverview']).'</div>';
 975                          }
 976                          $dx .= '&#160;'.$lang['hours'].' ('.$lang[$i].")\n";
 977                          $timesum += $obj->tsum[$i];
 978                          $cnt++;
 979                      }
 980                  }
 981  
 982              $d .= '<div align="right" style="width:10em;display:inline;float:left">';
 983              if ($cnt > 0 && $nolink) {
 984                  $d .= hour_format($obj->timetracksum).'</div>';
 985              } else {
 986                  $d .= makelink($link ,hour_format($obj->timetracksum),$lang['TimetrackOverview']).'</div>';
 987              }
 988              $d .= '&#160;'.$lang['hours'] ."\n";
 989  
 990              $d .= $dx;
 991  
 992              if ($cnt > 0) {
 993                  $d .= '<br/><div align="right" style="width:10em;display:inline;float:left">';
 994                  $d .= '== '.makelink(addUrlParameter($link,'show=all'),hour_format($timesum,2),$lang['TimetrackOverview']).'</div>';
 995                  $d .= '&#160;'.$lang['hours']."\n";
 996              }
 997              if ($timesum == 0) return $r;
 998          } else {
 999              $d .= '<div align="right" style="width:10em;display:inline;float:left">';
1000              $d .= makelink($link,hour_format($obj->ttsum),$lang['TimetrackOverview']).'</div>';
1001              $d .= '&#160;'.$lang['hours'] ."\n";
1002              if ($obj->ttsum == 0) return $r;
1003          }
1004  
1005          $r .= $user->layout->ContentRowStart();
1006          $r .= $user->layout->showfield($lang['Timetrack']);
1007          $r .= $user->layout->showdata($d,$cols-1);
1008          $r .= $user->layout->ContentRowEnd();
1009          return $r;
1010      }
1011  
1012      /**
1013       * Read a list of all timetrack elements
1014       */
1015      static function obj_read (tutos_base $obj) {
1016          global $table;
1017  
1018          if ( ! isset($obj->id) )  return;
1019  
1020          $obj->ttlist = array();
1021          $obj->ttsum = 0.0;
1022  
1023          $q = 'SELECT * from '. $obj->dbconn->prefix .$table['timetrack'][name].' where link_id = '. $obj->id .' order by vtime asc';
1024          $r = $obj->dbconn->Exec($q);
1025          $n = $r->numrows();
1026          $a = 0;
1027          while ($a < $n) {
1028              $tt = new Timetrack($obj->dbconn);
1029              $tt->read_result($r,$a);
1030              if ( $tt->see_ok() ) {
1031                  $obj->ttlist[$tt->id] = &$tt;
1032                  $obj->ttsum += $tt->volume;
1033              }
1034              $a++;
1035              unset($tt);
1036          }
1037          $r->free();
1038          return;
1039      }
1040  
1041      /**
1042       * delete timetrack entries for a object
1043       */
1044      static function obj_delete(tutos_user $user,tutos_base $obj) {
1045          global $table;
1046  
1047          $msg = '';
1048  
1049          // TODO FIXME (mybe we should rebook the efforts to the user himself) !!
1050          $q = 'DELETE FROM '. $obj->dbconn->prefix .$table['timetrack'][name].' WHERE link_id = '. $obj->id;
1051          $r = $obj->dbconn->Exec($q);
1052          $r->free();
1053          return $msg;
1054      }
1055  
1056      /**
1057       * create a link where a timetrack for work on the given object could be added
1058       */
1059      static function getaddlink (tutos_user $user,tutos_base $obj,$text = "") {
1060          global $lang,$tutos;
1061          if (! is_object($obj) ) return;
1062          if ( $obj->id == -1 ) return;
1063          if (! $user->feature_ok(usetimetrack,PERM_NEW) ) return;
1064          if (! $obj->obj_feature_ok($user,usetimetrack,PERM_NEW) ) return;
1065          if (! $obj->use_ok() ) return;
1066          if ($obj->gettype() == 'team') return;
1067          if ($obj->gettype() == 'address') return;
1068          if ($obj->getType() == 'stc') return '';
1069  
1070          if ($obj->gettype() == "product") {
1071              $x = preg_split('#,#',$tutos['prod_activ_states']);
1072              if (!in_array($obj->state,$x)) return;
1073          }
1074          if ($obj->gettype() == "task") {
1075              if ($obj->state == $tutos['task_finish_state']) return;
1076          }
1077  
1078          $x[] = array( url => 'timetrack/timetrack_new.php?mode=1&amp;lid='. $obj->id,
1079                        confirm => false,
1080                        text => ($text == "" ? $lang['TTRecord']:$text),
1081                        info => $lang['TTRecord'],
1082                        category => array('timetrack','support',usetimetrack)
1083              );
1084          if ($user->id != $obj->id ) {
1085              $x[] = array( url => 'timetrack/timetrack_new.php?lid='. $obj->id,
1086                            confirm => false,
1087                            text => ($text == "" ? $lang['TimetrackCreate']:$text),
1088                            info => sprintf($lang['TimetrackCreateI'], $obj->getFullName()),
1089                            category => array('timetrack','new','module',usetimetrack)
1090                  );
1091          }
1092          return $x;
1093      }
1094  
1095      /**
1096       * create a link to a select page
1097       */
1098      static function getSelectLink (tutos_user $user,$text = "") {
1099          global $lang,$tutos;
1100          if ( ! $user->feature_ok(usetimetrack,PERM_SEL) ) {
1101              return;
1102          }
1103          return array( url => 'timetrack/timetrack_select.php',
1104                        image => $user->layout->theme->getImage(timetrack::getHtmlIcon(),'menu'),
1105                        text => ($text == "" ?  $lang['TimetrackSearch']: $text),
1106                        info => $lang['SearchForTT'],
1107                        category => array('search','timetrack',usetimetrack)
1108              );
1109      }
1110  
1111      /**
1112       * show the mytutos info about timetracks
1113       */
1114      static function mytutos (tutos_user $user) {
1115          global $tutos,$lang,$current_user,$table;
1116  
1117          if ( ! $current_user->feature_ok(usetimetrack,PERM_SEE) ) {
1118              return '';
1119          }
1120          if ( ! $current_user->feature_ok(usetimetrack,PERM_MYTUTOS) ) {
1121              return '';
1122          }
1123  
1124          $q = 'SELECT * from '. $user->dbconn->prefix .$table['timetrack'][name].' where adr_id = '. $user->id .' order by vtime desc';
1125  
1126          $res = $user->dbconn->Exec($q);
1127          $n = $res->numrows();
1128  
1129          if ($n == 0) {
1130              $res->free();
1131              return '';
1132          }
1133  
1134          $a = 0;
1135  
1136          $r = info_table_start();
1137          $r .= " <tr>\n";
1138          $m = timetrack::getSelectLink($current_user,$lang['Timetracks']);
1139          if ($m) {
1140              $ml = menulink($m[url],$m[text],$m[info]);
1141          } else {
1142              $ml = $lang['Timetracks'];
1143          }
1144          $r .= ' <th colspan="3">'. $current_user->layout->theme->getImage(timetrack::getHtmlIcon(),'list') .' '.$ml."</th>\n";
1145          $r .= " </tr>\n";
1146          $r .= " <tr>\n";
1147          $r .= '  <th>'. $lang['TimetrackRef'] ."</th>\n";
1148          $r .= '  <th>'. $lang['TimetrackDate'] ."</th>\n";
1149          $r .= '  <th>'. $lang['TimetrackBooked'] ."</th>\n";
1150          $r .= " </tr>\n";
1151          while ( ($a < $n) and ($a < 2* $tutos['maxshort']) ) {
1152              $f = new Timetrack($user->dbconn);
1153              $f->read_result($res,$a);
1154              $r .= " <tr>\n";
1155              $r .= '  <td>' . (is_object($f->ref) ? $f->ref->getLink():$lang['HistoryDeleted']) ."</td>\n";
1156              $r .= '  <td>' . $f->wday->getDateTime() ."</td>\n";
1157              $r .= '  <td align="right">' . hour_format($f->volume) ."</td>\n";
1158              $r .= " </tr>\n";
1159              $a++;
1160              unset($f);
1161          }
1162          $r .= info_table_end();
1163          $res->free();
1164          return $r;
1165      }
1166  
1167      /**
1168       * get the help index
1169       */
1170      static function getHelpIndex () {
1171          global $lang;
1172  
1173          $r = '';
1174          $r .= '<h3>'. makelink('help.php?p=glossary#timetrack',$lang['Timetrack'],$lang['Timetrack']) ."</h3><ul>\n";
1175          $r .= ' <li>'. makelink('help.php?p=timetrack_new',$lang['NewEntry'].'/'. $lang['Modify'],$lang['NewEntry'].'/'. $lang['Modify']) ."</li>\n";
1176          $r .= ' <li>'. makelink('help.php?p=timetrack_overview',$lang['TimetrackOverview'],$lang['TimetrackOverview'])."</li>\n";
1177          $r .= "</ul>\n";
1178          return $r;
1179      }
1180  }
1181  $tutos['classes'][usetimetrack] = 'Timetrack';
1182  ?>

title

Description

title

Description

title

Description

title

title

Body