. * --------------------------------------------------------------------- */ if (!defined('GLPI_ROOT')) { die("Sorry. You can't access this file directly"); } /** * CommonITILCost Class * * @since 0.85 **/ abstract class CommonITILCost extends CommonDBChild { public $dohistory = true; static function getTypeName($nb = 0) { return _n('Cost', 'Costs', $nb); } function getItilObjectItemType() { return str_replace('Cost', '', $this->getType()); } /** * @see CommonGLPI::getTabNameForItem() **/ function getTabNameForItem(CommonGLPI $item, $withtemplate = 0) { // can exists for template if (($item->getType() == static::$itemtype) && static::canView()) { $nb = 0; if ($_SESSION['glpishow_count_on_tabs']) { $nb = countElementsInTable($this->getTable(), [$item->getForeignKeyField() => $item->getID()]); } return self::createTabEntry(self::getTypeName(Session::getPluralNumber()), $nb); } return ''; } /** * @param $item CommonGLPI object * @param $tabnum (default 1) * @param $withtemplate (default 0) **/ static function displayTabContentForItem(CommonGLPI $item, $tabnum = 1, $withtemplate = 0) { self::showForObject($item, $withtemplate); return true; } function rawSearchOptions() { $tab = []; $tab[] = [ 'id' => 'common', 'name' => __('Characteristics') ]; $tab[] = [ 'id' => '1', 'table' => $this->getTable(), 'field' => 'name', 'name' => __('Title'), 'searchtype' => 'contains', 'datatype' => 'itemlink', 'massiveaction' => false, 'autocomplete' => true, ]; $tab[] = [ 'id' => '2', 'table' => $this->getTable(), 'field' => 'id', 'name' => __('ID'), 'massiveaction' => false, 'datatype' => 'number' ]; $tab[] = [ 'id' => '16', 'table' => $this->getTable(), 'field' => 'comment', 'name' => __('Comments'), 'datatype' => 'text' ]; $tab[] = [ 'id' => '12', 'table' => $this->getTable(), 'field' => 'begin_date', 'name' => __('Begin date'), 'datatype' => 'datetime' ]; $tab[] = [ 'id' => '10', 'table' => $this->getTable(), 'field' => 'end_date', 'name' => __('End date'), 'datatype' => 'datetime' ]; $tab[] = [ 'id' => '11', 'table' => $this->getTable(), 'field' => 'actiontime', 'name' => __('Duration'), 'datatype' => 'timestamp' ]; $tab[] = [ 'id' => '14', 'table' => $this->getTable(), 'field' => 'cost_time', 'name' => __('Time cost'), 'datatype' => 'decimal' ]; $tab[] = [ 'id' => '15', 'table' => $this->getTable(), 'field' => 'cost_fixed', 'name' => __('Fixed cost'), 'datatype' => 'decimal' ]; $tab[] = [ 'id' => '19', 'table' => $this->getTable(), 'field' => 'cost_material', 'name' => __('Material cost'), 'datatype' => 'decimal' ]; $tab[] = [ 'id' => '18', 'table' => 'glpi_budgets', 'field' => 'name', 'name' => Budget::getTypeName(1), 'datatype' => 'dropdown' ]; $tab[] = [ 'id' => '80', 'table' => 'glpi_entities', 'field' => 'completename', 'name' => Entity::getTypeName(1), 'massiveaction' => false, 'datatype' => 'dropdown' ]; return $tab; } static function rawSearchOptionsToAdd() { global $DB; $tab = []; $tab[] = [ 'id' => 'cost', 'name' => _n('Cost', 'Costs', 1) ]; $tab[] = [ 'id' => '48', 'table' => static::getTable(), 'field' => 'totalcost', 'name' => __('Total cost'), 'datatype' => 'decimal', 'forcegroupby' => true, 'usehaving' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child' ], 'computation' => '(SUM(' . $DB->quoteName('TABLE.actiontime') . ' * ' . $DB->quoteName('TABLE.cost_time') . '/' . HOUR_TIMESTAMP . ' + ' . $DB->quoteName('TABLE.cost_fixed') . ' + ' . $DB->quoteName('TABLE.cost_material') . ') / COUNT(' . $DB->quoteName('TABLE.id') . ')) * COUNT(DISTINCT ' . $DB->quoteName('TABLE.id') . ')' ]; $tab[] = [ 'id' => '42', 'table' => static::getTable(), 'field' => 'cost_time', 'name' => __('Time cost'), 'datatype' => 'decimal', 'forcegroupby' => true, 'usehaving' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child' ], 'computation' => '(SUM(' . $DB->quoteName('TABLE.actiontime') . ' * ' . $DB->quoteName('TABLE.cost_time') . '/' . HOUR_TIMESTAMP . ') / COUNT(' . $DB->quoteName('TABLE.id') . ')) * COUNT(DISTINCT ' . $DB->quoteName('TABLE.id') . ')' ]; $tab[] = [ 'id' => '49', 'table' => static::getTable(), 'field' => 'actiontime', 'name' => sprintf(__('%1$s - %2$s'), _n('Cost', 'Costs', 1), __('Duration')), 'datatype' => 'timestamp', 'forcegroupby' => true, 'usehaving' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child' ] ]; $tab[] = [ 'id' => '43', 'table' => static::getTable(), 'field' => 'cost_fixed', 'name' => __('Fixed cost'), 'datatype' => 'decimal', 'forcegroupby' => true, 'usehaving' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child' ], 'computation' => '(SUM(' . $DB->quoteName('TABLE.cost_fixed') . ') / COUNT(' . $DB->quoteName('TABLE.id') . ')) * COUNT(DISTINCT ' . $DB->quoteName('TABLE.id') . ')' ]; $tab[] = [ 'id' => '44', 'table' => static::getTable(), 'field' => 'cost_material', 'name' => __('Material cost'), 'datatype' => 'decimal', 'forcegroupby' => true, 'usehaving' => true, 'massiveaction' => false, 'joinparams' => [ 'jointype' => 'child' ], 'computation' => '(SUM(' . $DB->quoteName('TABLE.cost_material') . ') / COUNT(' . $DB->quoteName('TABLE.id') . ')) * COUNT(DISTINCT ' . $DB->quoteName('TABLE.id') . ')' ]; return $tab; } /** * Init cost for creation based on previous cost **/ function initBasedOnPrevious() { $item = new static::$itemtype(); if (!isset($this->fields[static::$items_id]) || !$item->getFromDB($this->fields[static::$items_id])) { return false; } // Set actiontime to $this->fields['actiontime'] = max(0, $item->fields['actiontime'] - $this->getTotalActionTimeForItem($this->fields[static::$items_id])); $lastdata = $this->getLastCostForItem($this->fields[static::$items_id]); if (isset($lastdata['end_date'])) { $this->fields['begin_date'] = $lastdata['end_date']; } if (isset($lastdata['cost_time'])) { $this->fields['cost_time'] = $lastdata['cost_time']; } if (isset($lastdata['cost_fixed'])) { $this->fields['cost_fixed'] = $lastdata['cost_fixed']; } if (isset($lastdata['budgets_id'])) { $this->fields['budgets_id'] = $lastdata['budgets_id']; } if (isset($lastdata['name'])) { $this->fields['name'] = $lastdata['name']; } } /** * Get total actiNULL 11400 0.0000 0.0000 0.0000 on time used on costs for an item * * @param $items_id integer ID of the item **/ function getTotalActionTimeForItem($items_id) { global $DB; $result = $DB->request([ 'SELECT' => ['SUM' => 'actiontime AS sumtime'], 'FROM' => $this->getTable(), 'WHERE' => [static::$items_id => $items_id] ])->next(); return $result['sumtime']; } /** * Get last datas for an item * * @param $items_id integer ID of the item **/ function getLastCostForItem($items_id) { global $DB; $result = $DB->request([ 'FROM' => $this->getTable(), 'WHERE' => [ static::$items_id => $items_id ], 'ORDER' => [ 'end_date DESC', 'id DESC' ] ])->next(); return $result; } /** * Print the item cost form * * @param $ID integer ID of the item * @param $options array options used **/ function showForm($ID, $options = []) { if (isset($options['parent']) && !empty($options['parent'])) { $item = $options['parent']; } if ($ID > 0) { $this->check($ID, READ); } else { // Create item $options[static::$items_id] = $item->getField('id'); $this->check(-1, CREATE, $options); $this->initBasedOnPrevious(); } if ($ID > 0) { $items_id = $this->fields[static::$items_id]; } else { $items_id = $options['parent']->fields["id"]; } $item = new static::$itemtype(); if (!$item->getFromDB($items_id)) { return false; } $this->showFormHeader($options); echo ""; echo "".__('Name').""; echo ""; echo ""; Html::autocompletionTextField($this, 'name'); echo ""; echo "".__('Begin date').""; echo ""; Html::showDateField("begin_date", ['value' => $this->fields['begin_date']]); echo ""; echo ""; echo ""; echo "".__('Duration').""; echo ""; Dropdown::showTimeStamp('actiontime', ['value' => $this->fields['actiontime'], 'addfirstminutes' => true]); echo ""; echo "".__('End date').""; echo ""; Html::showDateField("end_date", ['value' => $this->fields['end_date']]); echo ""; echo ""; echo ""; echo "".__('Time cost').""; echo ""; echo ""; $rowspan = 4; echo "".__('Comments').""; echo ""; echo ""; echo "\n"; echo ""; echo "".__('Fixed cost').""; echo ""; echo ""; echo ""; echo ""; echo "".__('Material cost').""; echo ""; echo ""; echo ""; echo "".Budget::getTypeName(1).""; echo ""; Budget::dropdown(['value' => $this->fields["budgets_id"], 'entity' => $this->fields["entities_id"]]); echo ""; $this->showFormButtons($options); return true; } /** * Print the item costs * * @param $item CommonITILObject object or Project * @param $withtemplate boolean Template or basic item (default 0) * * @return number total cost **/ static function showForObject($item, $withtemplate = 0) { global $DB, $CFG_GLPI; $forproject = false; if (is_a($item, 'Project', true)) { $forproject = true; } $ID = $item->fields['id']; if (!$item->getFromDB($ID) || !$item->canViewItem() || !static::canView()) { return false; } $canedit = false; if (!$forproject) { $canedit = $item->canAddItem(__CLASS__); } echo "
"; $items_ids = $ID; if ($forproject) { $alltickets = ProjectTask::getAllTicketsForProject($ID); $items_ids = (count($alltickets) ? $alltickets : 0); } $iterator = $DB->request([ 'FROM' => static::getTable(), 'WHERE' => [ static::$items_id => $items_ids ], 'ORDER' => 'begin_date' ]); $rand = mt_rand(); if ($canedit && !in_array($item->fields['status'], array_merge($item->getClosedStatusArray(), $item->getSolvedStatusArray()))) { echo "
\n"; echo "\n"; if (static::canCreate()) { echo "
". ""; echo __('Add a new cost')."
\n"; } } $total = 0; $total_time = 0; $total_costtime = 0; $total_fixed = 0; $total_material = 0; echo ""; echo ""; if ($forproject) { echo ""; } else { echo ""; echo ""; echo ""; } echo ""; if (count($iterator)) { echo ""; if ($forproject) { echo ""; $ticket = new Ticket(); } echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; echo ""; Session::initNavigateListItems(static::getType(), //TRANS : %1$s is the itemtype name, // %2$s is the name of the item (used for headings of a list) sprintf(__('%1$s = %2$s'), $item->getTypeName(1), $item->getName())); while ($data = $iterator->next()) { echo ""; $name = (empty($data['name'])? sprintf(__('%1$s (%2$s)'), $data['name'], $data['id']) : $data['name']); if ($forproject) { $ticket->getFromDB($data['tickets_id']); echo ""; } echo ""; echo ""; echo ""; echo ""; echo ""; $total_time += $data['actiontime']; echo ""; $total_costtime += ($data['actiontime']*$data['cost_time']/HOUR_TIMESTAMP); echo ""; $total_fixed += $data['cost_fixed']; echo ""; $total_material += $data['cost_material']; $cost = self::computeTotalCost($data['actiontime'], $data['cost_time'], $data['cost_fixed'], $data['cost_material']); echo ""; $total += $cost; echo ""; Session::addToNavigateListItems(static::getType(), $data['id']); } $colspan = 4; if ($forproject) { $colspan++; } echo "'; echo ""; echo ""; echo "'; echo "'; echo "'; } else { echo ""; } echo "
"._n('Ticket cost', 'Ticket costs', count($iterator))."".self::getTypeName(count($iterator))."".__('Item duration')."".CommonITILObject::getActionTime($item->fields['actiontime'])."
".Ticket::getTypeName(1)."".__('Name')."".__('Begin date')."".__('End date')."".Budget::getTypeName(1)."".__('Duration')."".__('Time cost')."".__('Fixed cost')."".__('Material cost')."".__('Total cost')."
".$ticket->getLink().""; printf(__('%1$s %2$s'), $name, Html::showToolTip($data['comment'], ['display' => false])); if ($canedit) { echo "\n\n"; } echo "".Html::convDate($data['begin_date'])."".Html::convDate($data['end_date'])."".Dropdown::getDropdownName('glpi_budgets', $data['budgets_id'])."".CommonITILObject::getActionTime($data['actiontime'])."".Html::formatNumber($data['cost_time'])."".Html::formatNumber($data['cost_fixed'])."".Html::formatNumber($data['cost_material'])."".Html::formatNumber($cost)."
".__('Total').'".CommonITILObject::getActionTime($total_time)."".Html::formatNumber($total_costtime)."".Html::formatNumber($total_fixed).'".Html::formatNumber($total_material).'".Html::formatNumber($total).'
".__('No item found')."
"; echo "

"; return $total; } /** * Get costs summary values * * @param $type string type * @param $ID integer ID of the ticket * * @return array of costs and actiontime **/ static function getCostsSummary($type, $ID) { global $DB; $result = $DB->request( [ 'FROM' => getTableForItemType($type), 'WHERE' => [ static::$items_id => $ID, ], 'ORDER' => [ 'begin_date' ], ] ); $tab = ['totalcost' => 0, 'actiontime' => 0, 'costfixed' => 0, 'costtime' => 0, 'costmaterial' => 0 ]; foreach ($result as $data) { $tab['actiontime'] += $data['actiontime']; $tab['costfixed'] += $data['cost_fixed']; $tab['costmaterial'] += $data['cost_material']; $tab['costtime'] += ($data['actiontime']*$data['cost_time']/HOUR_TIMESTAMP); $tab['totalcost'] += self::computeTotalCost($data['actiontime'], $data['cost_time'], $data['cost_fixed'], $data['cost_material']); } foreach ($tab as $key => $val) { $tab[$key] = Html::formatNumber($val); } return $tab; } /** * Computer total cost of a item * * @param $actiontime float actiontime * @param $cost_time float time cost * @param $cost_fixed float fixed cost * @param $cost_material float material cost * @param $edit boolean used for edit of computation ? (true by default) * * @return string total cost formatted string **/ static function computeTotalCost($actiontime, $cost_time, $cost_fixed, $cost_material, $edit = true) { return Html::formatNumber(($actiontime*$cost_time/HOUR_TIMESTAMP)+$cost_fixed+$cost_material, $edit); } }