Merge pull request #11679 from atm-john/develop_new_task_progress_bar
FIX/NEW task widget and add task progress bar
This commit is contained in:
commit
cc3fd0f1f6
109
ChangeLog
109
ChangeLog
@ -126,6 +126,115 @@ FIX: When saving an action it didn't save the label based on the type of event i
|
||||
FIX: when STOCK_CALCULATE_ON_SHIPMENT_NEW: is set, deleting a "closed" shipment now increases stock as expected
|
||||
FIX: wrong path sociales/index.php doesnt exist anymore
|
||||
|
||||
|
||||
***** ChangeLog for 10.0.1 compared to 10.0.0 *****
|
||||
FIX: #10930
|
||||
FIX: #10984
|
||||
FIX: reposition on "Build backup" button
|
||||
FIX: #11400
|
||||
FIX: #11412
|
||||
FIX: #11460
|
||||
FIX: #11463
|
||||
FIX: #11466
|
||||
FIX: #11492
|
||||
FIX: #11498
|
||||
FIX: #11505
|
||||
FIX: #11506
|
||||
FIX: #11507
|
||||
FIX: #11509
|
||||
FIX: #11537
|
||||
FIX: #11543
|
||||
FIX: #11553
|
||||
FIX: #11576
|
||||
FIX: #11584
|
||||
FIX: #11590
|
||||
FIX: accounting mode must be taken from global conf, because there's no way to choose a mode with interface
|
||||
FIX: Add message from public interface
|
||||
FIX: add missing hook calls
|
||||
FIX: Add warning when setup is strange
|
||||
FIX: ajax call for line positioning when CSRFCHECK_WITH_TOKEN is on
|
||||
FIX: API return 404 sometimes even if API exists
|
||||
FIX: Attachment was lost when we validate an expense report
|
||||
FIX: avoid conflict with "$classname" in card.php
|
||||
FIX: Bad sql request
|
||||
FIX: better compatibility with multicompany transverse mode
|
||||
FIX: Better PHP compatibility
|
||||
FIX: Block to link with tickets
|
||||
FIX: Can't submit a ticket from public interface
|
||||
FIX: categories import: prevent mismatch between category type and object type
|
||||
FIX: Closing ticket from public interface
|
||||
FIX: Column 'paid' missing in expense report
|
||||
FIX: compatibility mysql 8. rank is reserved
|
||||
FIX: Computed field were not calculated into lists.
|
||||
FIX: Content of email for subscription
|
||||
FIX: correct error in files with multiple spaces
|
||||
FIX: CVE-2019-11199
|
||||
FIX: delete of links between objects
|
||||
FIX: div not balanced
|
||||
FIX: do not return formatted prices in json string
|
||||
FIX: duplicate on the check (TODO field $onetrtd not used ?)
|
||||
FIX: element name in update_price
|
||||
FIX: empty product_use_units in product configuration
|
||||
FIX: expedition card: infinite loop for printObjectLine hook if return > 0
|
||||
FIX: extrafield loading bug due to assumption that an object is a third party while it may be a contact if MAIN_USE_COMPANY_NAME_OF_CONTACT is set.
|
||||
FIX: Fatal error on dol_htmloutput_mesg with corrupted array
|
||||
FIX: Fatal situation if payment removed on expense report. Action
|
||||
FIX: FEC Format - Missing date_creation in general ledger when you add a new transaction
|
||||
FIX: FEC Format - Save translation of the journal label in database & nowrap on amount
|
||||
FIX: floating point precision errors in the triggers of the workflow module
|
||||
FIX: for #11232
|
||||
FIX: format of field with type timestamp
|
||||
FIX: fournrprice log for insert
|
||||
FIX: help text
|
||||
FIX: import filter error
|
||||
FIX: __INFOS__ tag not exists
|
||||
FIX: issue #9300: install error with PostgreSQL when using custom table prefix
|
||||
FIX: Language key
|
||||
FIX: Limit of uploaded files (max_post_size was not used)
|
||||
FIX: list of balance of leaves
|
||||
FIX: minor spelling issues
|
||||
FIX: missing "dropdown-icon" replacement
|
||||
FIX: Missing field "Conciliated" into bank transaction export
|
||||
FIX: missing filter by current contact
|
||||
FIX: missing token
|
||||
FIX: Missing where on entity
|
||||
FIX: move sql request in INNER JOIN
|
||||
FIX: name was able to be in field but went back to new line
|
||||
FIX: Nowrap on amount
|
||||
FIX: Online payment
|
||||
FIX: on shipment delete confirm dialog, a new checkbox allows the user to choose if they want their stock re-incremented after the deletion.
|
||||
FIX: option EXPORT_LABEL_FOR_SELECT to restore compatibility in export
|
||||
FIX: Option THIRDPARTY_SUGGEST_ALSO_ADDRESS_CREATION
|
||||
FIX: outdated phpdoc
|
||||
FIX: Permission for BOM menu
|
||||
FIX: permission to delete a draft purchase order
|
||||
FIX: phpcs
|
||||
FIX: Position was lost when we edit the line of template invoice
|
||||
FIX: product_use_units was set to 0 each time a conf in block other was set
|
||||
FIX: propal createFrom hook: undefined parameter attached
|
||||
FIX: Responsive of public interface of ticket
|
||||
FIX: search by phone pro
|
||||
FIX: Setup of TakePos was not possible after a clean install
|
||||
FIX: Show list of events on tickets
|
||||
FIX: socpeople assigned list in action com list
|
||||
FIX: SQL problem on donation & nowrap on amount
|
||||
FIX: stock increase on shipment deletion if STOCK_CALCULATE_ON_SHIPMENT_NEW: is set
|
||||
FIX: stripe webhook ID constant set
|
||||
FIX: summary of time spent in preview tab of projects
|
||||
FIX: the feature to bill time spent was not enabled.
|
||||
FIX: The new feature to attach document on lines was not correclty
|
||||
FIX: The proposed new supplier code does not work
|
||||
FIX: this function can not be private
|
||||
FIX: tk9877 - PDF rouget requires product.lib.php (otherwise measuring_units_string() is not defined)
|
||||
FIX: Update the file index table when we validate/rename a ref.
|
||||
FIX: use rounding to compare the amounts
|
||||
FIX: We must save code instead of value in database for template invoice modelpdf
|
||||
FIX: we need to be able to add freeline with qty between 0 & 1 in supplierorder line
|
||||
FIX: We should remove property comments only for project and task api.
|
||||
FIX: When saving an action it didn't save the label based on the type of event if the label is empty and the type is customized
|
||||
FIX: when STOCK_CALCULATE_ON_SHIPMENT_NEW: is set, deleting a "closed" shipment now increases stock as expected
|
||||
FIX: wrong path sociales/index.php doesnt exist anymore
|
||||
|
||||
***** ChangeLog for 10.0.0 compared to 9.0.0 *****
|
||||
For Users:
|
||||
NEW: Module "Ticket" is available as a stable module.
|
||||
|
||||
@ -31,10 +31,10 @@ require_once DOL_DOCUMENT_ROOT."/core/lib/date.lib.php";
|
||||
*/
|
||||
class box_task extends ModeleBoxes
|
||||
{
|
||||
public $boxcode="projet";
|
||||
public $boxcode="projettask";
|
||||
public $boximg="object_projecttask";
|
||||
public $boxlabel;
|
||||
//public $depends = array("projet");
|
||||
public $depends = array("projet");
|
||||
|
||||
/**
|
||||
* @var DoliDB Database handler.
|
||||
@ -42,7 +42,7 @@ class box_task extends ModeleBoxes
|
||||
public $db;
|
||||
|
||||
public $param;
|
||||
public $enabled = 0; // Disabled because bugged.
|
||||
public $enabled = 1; // enable because fixed ;-).
|
||||
|
||||
public $info_box_head = array();
|
||||
public $info_box_contents = array();
|
||||
@ -78,54 +78,110 @@ class box_task extends ModeleBoxes
|
||||
global $conf, $user, $langs, $db;
|
||||
|
||||
$this->max=$max;
|
||||
|
||||
$totalMnt = 0;
|
||||
$totalnb = 0;
|
||||
$totalDuree=0;
|
||||
$totalplannedtot=0;
|
||||
$totaldurationtot=0;
|
||||
|
||||
include_once DOL_DOCUMENT_ROOT."/projet/class/task.class.php";
|
||||
include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
|
||||
require_once DOL_DOCUMENT_ROOT."/core/lib/project.lib.php";
|
||||
$projectstatic = new Project($this->db);
|
||||
$taskstatic=new Task($db);
|
||||
$form= new Form($db);
|
||||
$cookie_name='boxfilter_task';
|
||||
$boxcontent='';
|
||||
|
||||
$textHead = $langs->trans("CurentlyOpenedTasks");
|
||||
|
||||
$filterValue='all';
|
||||
if(in_array(GETPOST($cookie_name), array('all','im_project_contact','im_task_contact'))){
|
||||
$filterValue = GETPOST($cookie_name);
|
||||
}
|
||||
elseif(!empty($_COOKIE[$cookie_name])){
|
||||
$filterValue = $_COOKIE[$cookie_name];
|
||||
}
|
||||
|
||||
|
||||
$textHead = $langs->trans("Tasks")." ".date("Y");
|
||||
$this->info_box_head = array('text' => $textHead, 'limit'=> dol_strlen($textHead));
|
||||
if($filterValue == 'im_task_contact'){
|
||||
$textHead.= ' : '.$langs->trans("WhichIamLinkedTo");
|
||||
}
|
||||
elseif($filterValue == 'im_project_contact'){
|
||||
$textHead.= ' : '.$langs->trans("WhichIamLinkedToProject");
|
||||
}
|
||||
|
||||
|
||||
$this->info_box_head = array(
|
||||
'text' => $textHead,
|
||||
'limit'=> dol_strlen($textHead),
|
||||
'sublink'=>'',
|
||||
'subtext'=>$langs->trans("Filter"),
|
||||
'subpicto'=>'filter.png',
|
||||
'subclass'=>'linkobject boxfilter',
|
||||
'target'=>'none' // Set '' to get target="_blank"
|
||||
);
|
||||
|
||||
// list the summary of the orders
|
||||
if ($user->rights->projet->lire) {
|
||||
// FIXME fk_statut on a task is not be used. We use the percent. This means this box is useless.
|
||||
$sql = "SELECT pt.fk_statut, count(DISTINCT pt.rowid) as nb, sum(ptt.task_duration) as durationtot, sum(pt.planned_workload) as plannedtot";
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."projet_task as pt, ".MAIN_DB_PREFIX."projet_task_time as ptt";
|
||||
$sql.= " WHERE pt.datec BETWEEN '".$this->db->idate(dol_get_first_day(date("Y"), 1))."' AND '".$this->db->idate(dol_get_last_day(date("Y"), 12))."'";
|
||||
$sql.= " AND pt.rowid = ptt.fk_task";
|
||||
$sql.= " GROUP BY pt.fk_statut ";
|
||||
$sql.= " ORDER BY pt.fk_statut DESC";
|
||||
$boxcontent.= '<div id="ancor-idfilter'.$this->boxcode.'" style="display: block; position: absolute; margin-top: -100px"></div>'."\n";
|
||||
$boxcontent.= '<div id="idfilter'.$this->boxcode.'" class="hideobject center" >'."\n";
|
||||
$boxcontent.= '<form class="flat " method="POST" action="'.$_SERVER["PHP_SELF"].'#ancor-idfilter'.$this->boxcode.'">'."\n";
|
||||
$boxcontent.= '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">'."\n";
|
||||
$selectArray = array('all' => $langs->trans("NoFilter"), 'im_task_contact' => $langs->trans("WhichIamLinkedTo"), 'im_project_contact' => $langs->trans("WhichIamLinkedToProject"));
|
||||
$boxcontent.= $form->selectArray($cookie_name, $selectArray, $filterValue);
|
||||
$boxcontent.= '<button type="submit" >'.$langs->trans("Change").'</button>';
|
||||
$boxcontent.= '</form>'."\n";
|
||||
$boxcontent.= '</div>'."\n";
|
||||
$boxcontent.= '<script type="text/javascript" language="javascript">
|
||||
jQuery(document).ready(function() {
|
||||
jQuery("#idsubimg'.$this->boxcode.'").click(function() {
|
||||
jQuery("#idfilter'.$this->boxcode.'").toggle();
|
||||
});
|
||||
});
|
||||
</script>';
|
||||
|
||||
|
||||
|
||||
$sql = "SELECT pt.rowid, pt.ref, pt.fk_projet, pt.fk_task_parent, pt.datec, pt.dateo, pt.datee, pt.datev, pt.label, pt.description, pt.duration_effective, pt.planned_workload, pt.progress";
|
||||
$sql.= ", p.rowid project_id, p.ref project_ref, p.title project_title";
|
||||
|
||||
$sql.= " FROM ".MAIN_DB_PREFIX."projet_task as pt";
|
||||
$sql.= " JOIN ".MAIN_DB_PREFIX."projet as p ON (pt.fk_projet = p.rowid)";
|
||||
|
||||
if($filterValue === 'im_task_contact') {
|
||||
$sql .= " JOIN " . MAIN_DB_PREFIX . "element_contact as ec ON (ec.element_id = pt.rowid AND ec.fk_socpeople = '" . $user->id . "' )";
|
||||
$sql .= " JOIN " . MAIN_DB_PREFIX . "c_type_contact as tc ON (ec.fk_c_type_contact = tc.rowid AND tc.element = 'project_task' AND tc.source = 'internal' )";
|
||||
}
|
||||
elseif($filterValue === 'im_project_contact') {
|
||||
$sql .= " JOIN " . MAIN_DB_PREFIX . "element_contact as ec ON (ec.element_id = p.rowid AND ec.fk_socpeople = '" . $user->id . "' )";
|
||||
$sql .= " JOIN " . MAIN_DB_PREFIX . "c_type_contact as tc ON (ec.fk_c_type_contact = tc.rowid AND tc.element = 'project' AND tc.source = 'internal' )";
|
||||
}
|
||||
|
||||
$sql.= " WHERE ";
|
||||
$sql.= " pt.entity = ".$conf->entity;
|
||||
$sql.= " AND p.fk_statut = ".Project::STATUS_VALIDATED;
|
||||
$sql.= " AND (pt.progress < 100 OR pt.progress IS NULL ) "; // 100% is done and not displayed
|
||||
|
||||
$sql.= " ORDER BY pt.datee ASC, pt.dateo ASC";
|
||||
$sql.= $db->plimit($max, 0);
|
||||
|
||||
$result = $db->query($sql);
|
||||
$i = 0;
|
||||
if ($result) {
|
||||
$num = $db->num_rows($result);
|
||||
while ($i < $num) {
|
||||
$objp = $db->fetch_object($result);
|
||||
$this->info_box_contents[$i][] = array(
|
||||
'td' => '',
|
||||
'text' =>$langs->trans("Task")." ".$taskstatic->LibStatut($objp->fk_statut, 0),
|
||||
);
|
||||
while ($objp = $db->fetch_object($result)) {
|
||||
|
||||
$this->info_box_contents[$i][] = array(
|
||||
'td' => 'class="right"',
|
||||
'text' => $objp->nb." ".$langs->trans("Tasks"),
|
||||
'url' => DOL_URL_ROOT."/projet/tasks/list.php?leftmenu=projects&viewstatut=".$objp->fk_statut,
|
||||
);
|
||||
$totalnb += $objp->nb;
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right"', 'text' => ConvertSecondToTime($objp->plannedtot, 'all', 25200, 5));
|
||||
$totalplannedtot += $objp->plannedtot;
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right"', 'text' => ConvertSecondToTime($objp->durationtot, 'all', 25200, 5));
|
||||
$totaldurationtot += $objp->durationtot;
|
||||
$taskstatic->id=$objp->rowid;
|
||||
$taskstatic->ref=$objp->ref;
|
||||
$taskstatic->label=$objp->label;
|
||||
$taskstatic->progress = $objp->progress;
|
||||
$taskstatic->fk_statut = $objp->fk_statut;
|
||||
$taskstatic->date_end = $objp->datee;
|
||||
$taskstatic->planned_workload= $objp->planned_workload;
|
||||
$taskstatic->duration_effective= $objp->duration_effective;
|
||||
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right" width="18"', 'text' => $taskstatic->LibStatut($objp->fk_statut, 3));
|
||||
$projectstatic->id = $objp->project_id;
|
||||
$projectstatic->ref = $objp->project_ref;
|
||||
$projectstatic->title = $objp->project_title;
|
||||
|
||||
$label = $projectstatic->getNomUrl(1).' '.$taskstatic->getNomUrl(1).' '.dol_htmlentities($taskstatic->label);
|
||||
|
||||
$boxcontent.= getTaskProgressView($taskstatic, $label, true, false, true);
|
||||
|
||||
$i++;
|
||||
}
|
||||
@ -134,12 +190,15 @@ class box_task extends ModeleBoxes
|
||||
}
|
||||
}
|
||||
|
||||
// Add the sum at the bottom of the boxes
|
||||
$this->info_box_contents[$i][] = array('tr' => 'class="liste_total"', 'td' => '', 'text' => $langs->trans("Total")." ".$textHead);
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right" ', 'text' => number_format($totalnb, 0, ',', ' ')." ".$langs->trans("Tasks"));
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right" ', 'text' => ConvertSecondToTime($totalplannedtot, 'all', 25200, 5));
|
||||
$this->info_box_contents[$i][] = array('td' => 'class="right" ', 'text' => ConvertSecondToTime($totaldurationtot, 'all', 25200, 5));
|
||||
$this->info_box_contents[$i][] = array('td' => '', 'text' => "");
|
||||
// set cookie by js
|
||||
if(empty($i)){
|
||||
$boxcontent.='<script >date = new Date(); date.setTime(date.getTime()+(30*86400000)); document.cookie = "'.$cookie_name.'='.$filterValue.'; expires= " + date.toGMTString() + "; path=/ "; </script>';
|
||||
}
|
||||
|
||||
$this->info_box_contents[0][] = array(
|
||||
'td' => '',
|
||||
'text' => $boxcontent,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -457,6 +457,9 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t
|
||||
$taskstatic->progress = $lines[$i]->progress;
|
||||
$taskstatic->fk_statut = $lines[$i]->status;
|
||||
$taskstatic->datee = $lines[$i]->date_end;
|
||||
$taskstatic->planned_workload= $lines[$i]->planned_workload;
|
||||
$taskstatic->duration_effective= $lines[$i]->duration;
|
||||
|
||||
|
||||
if ($showproject)
|
||||
{
|
||||
@ -556,10 +559,15 @@ function projectLinesa(&$inc, $parent, &$lines, &$level, $var, $showproject, &$t
|
||||
print '<td class="right">';
|
||||
if ($lines[$i]->progress != '')
|
||||
{
|
||||
print $lines[$i]->progress.' %';
|
||||
print getTaskProgressBadge($taskstatic);
|
||||
}
|
||||
print '</td>';
|
||||
|
||||
// resume
|
||||
print '<td class="right">';
|
||||
print getTaskProgressView($taskstatic, false, false);
|
||||
print '</td>';
|
||||
|
||||
if ($showbilltime)
|
||||
{
|
||||
// Time not billed
|
||||
@ -1943,3 +1951,164 @@ function print_projecttasks_array($db, $form, $socid, $projectsListId, $mytasks
|
||||
print '</table></form>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param task $task Task the task object
|
||||
* @param label $label bool|string true = auto, false = dont display, string = replace output
|
||||
* @param progressNumber $progressNumber bool|string true = auto, false = dont display, string = replace output
|
||||
* @param hideOnProgressNull $hideOnProgressNull bool hide if progress is null
|
||||
* @param spaced $spaced bool used to add space at bottom (made by css)
|
||||
* @return string
|
||||
*/
|
||||
function getTaskProgressView($task, $label = true, $progressNumber = true, $hideOnProgressNull = false, $spaced = false)
|
||||
{
|
||||
global $langs, $conf;
|
||||
|
||||
$out = '';
|
||||
|
||||
$plannedworkloadoutputformat='allhourmin';
|
||||
$timespentoutputformat='allhourmin';
|
||||
if (! empty($conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT)) $plannedworkloadoutputformat=$conf->global->PROJECT_PLANNED_WORKLOAD_FORMAT;
|
||||
if (! empty($conf->global->PROJECT_TIMES_SPENT_FORMAT)) $timespentoutputformat=$conf->global->PROJECT_TIME_SPENT_FORMAT;
|
||||
|
||||
if(empty($task->progress) && !empty($hideOnProgressNull)){
|
||||
return '';
|
||||
}
|
||||
|
||||
$spaced = !empty($spaced)?'spaced':'';
|
||||
|
||||
$diff = '';
|
||||
|
||||
// define progress color according to time spend vs workload
|
||||
$progressBarClass = 'progress-bar-info';
|
||||
if ($task->planned_workload){
|
||||
$progressCalculated = round(100 * doubleval($task->duration_effective) / doubleval($task->planned_workload), 2);
|
||||
|
||||
// this conf is actually hidden, by default we use 1% for "be carefull or warning"
|
||||
$warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.01;
|
||||
|
||||
$diffTitle = '<br/>'.$langs->trans('ProgressDeclared').' : '.$task->progress.'%';
|
||||
$diffTitle.= '<br/>'.$langs->trans('ProgressCalculated').' : '.$progressCalculated.'%';
|
||||
|
||||
if($progressCalculated > doubleval($task->progress)){
|
||||
$progressBarClass = 'progress-bar-danger';
|
||||
$title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress-$progressCalculated).'%');
|
||||
$diff = '<span class="text-danger classfortooltip"" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-down"></i> '.($task->progress-$progressCalculated).'%</span>';
|
||||
}
|
||||
elseif($progressCalculated * $warningRatio >= doubleval($task->progress)){ // warning if close at 1%
|
||||
$progressBarClass = 'progress-bar-warning';
|
||||
$title = $langs->trans('TheReportedProgressIsLessThanTheCalculatedProgressionByX', abs($task->progress-$progressCalculated).'%');
|
||||
$diff = '<span class="text-warning classfortooltip" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-left"></i> '.($task->progress-$progressCalculated).'%</span>';
|
||||
}
|
||||
else{
|
||||
$progressBarClass = 'progress-bar-success';
|
||||
$title = $langs->trans('TheReportedProgressIsMoreThanTheCalculatedProgressionByX', ($task->progress-$progressCalculated).'%');
|
||||
$diff = '<span class="text-success classfortooltip" title="'.dol_htmlentities($title.$diffTitle).'" ><i class="fa fa-caret-up"></i> '.($task->progress-$progressCalculated).'%</span>';
|
||||
}
|
||||
}
|
||||
|
||||
$out.= '<div class="progress-group">';
|
||||
|
||||
if($label !== false)
|
||||
{
|
||||
$out.= ' <span class="progress-text">';
|
||||
|
||||
if($label!==true){
|
||||
$out.= $label; // replace label by param
|
||||
}
|
||||
else{
|
||||
$out.= $task->getNomUrl(1).' '.dol_htmlentities($task->label);
|
||||
}
|
||||
$out.= ' </span>';
|
||||
}
|
||||
|
||||
|
||||
if($progressNumber !== false)
|
||||
{
|
||||
$out.= ' <span class="progress-number">';
|
||||
if($progressNumber!==true){
|
||||
$out.= $progressNumber; // replace label by param
|
||||
}
|
||||
else{
|
||||
if ($task->hasDelay()) $out.= img_warning($langs->trans("Late")).' ';
|
||||
|
||||
$out.= !empty($diff) ? $diff.' ':'';
|
||||
|
||||
$out.= '<b title="'.$langs->trans('TimeSpent').'" >';
|
||||
if ($task->duration_effective) $out.= convertSecondToTime($task->duration_effective, $timespentoutputformat);
|
||||
else $out.= '--:--';
|
||||
$out.= '</b>';
|
||||
|
||||
$out.= '/';
|
||||
|
||||
$out.= '<span title="'.$langs->trans('PlannedWorkload').'" >';
|
||||
if ($task->planned_workload) $out.= convertSecondToTime($task->planned_workload, $plannedworkloadoutputformat);
|
||||
else $out.= '--:--';
|
||||
}
|
||||
$out.= ' </span>';
|
||||
}
|
||||
|
||||
|
||||
|
||||
$out.= '</span>';
|
||||
$out.= ' <div class="progress sm '.$spaced.'" title="'.doubleval($task->progress).'%" >';
|
||||
$out.= ' <div class="progress-bar '.$progressBarClass.'" style="width: '.doubleval($task->progress).'%"></div>';
|
||||
$out.= ' </div>';
|
||||
$out.= '</div>';
|
||||
|
||||
|
||||
|
||||
return $out;
|
||||
}
|
||||
/**
|
||||
* @param task $task Task the task object
|
||||
* @param label $label string empty = auto (progress), string = replace output
|
||||
* @param tooltip $tooltip string empty = auto , string = replace output
|
||||
* @return string
|
||||
*/
|
||||
function getTaskProgressBadge($task, $label = '', $tooltip = '')
|
||||
{
|
||||
global $conf;
|
||||
|
||||
$out = '';
|
||||
$badgeClass = '';
|
||||
if ($task->progress != '')
|
||||
{
|
||||
// TODO : manage 100%
|
||||
|
||||
// define color according to time spend vs workload
|
||||
$badgeClass = 'badge ';
|
||||
if ($task->planned_workload){
|
||||
$progressCalculated = round(100 * doubleval($task->duration_effective) / doubleval($task->planned_workload), 2);
|
||||
|
||||
// this conf is actually hidden, by default we use 1% for "be carefull or warning"
|
||||
$warningRatio = !empty($conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT) ? (1 + $conf->global->PROJECT_TIME_SPEND_WARNING_PERCENT / 100) : 1.01;
|
||||
|
||||
if($progressCalculated > doubleval($task->progress)){
|
||||
$badgeClass.= 'badge-danger';
|
||||
}
|
||||
elseif($progressCalculated * $warningRatio >= doubleval($task->progress)){ // warning if close at 1%
|
||||
$badgeClass.= 'badge-warning';
|
||||
}
|
||||
else{
|
||||
$badgeClass.= 'badge-success';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$title = '';
|
||||
if(!empty($tooltip)){
|
||||
$badgeClass.= ' classfortooltip';
|
||||
$title = 'title="'.dol_htmlentities($tooltip).'"';
|
||||
}
|
||||
|
||||
if(empty($label)){
|
||||
$label = $task->progress.' %';
|
||||
}
|
||||
|
||||
if(!empty($label)){
|
||||
$out = '<span class="'.$badgeClass.'" '.$title.' >'.$label.'</span>';
|
||||
}
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
@ -76,7 +76,13 @@ MyProjects=My projects
|
||||
MyProjectsArea=My projects Area
|
||||
DurationEffective=Effective duration
|
||||
ProgressDeclared=Declared progress
|
||||
TaskProgressSummary=Task progress
|
||||
CurentlyOpenedTasks=Curently opened tasks
|
||||
TheReportedProgressIsLessThanTheCalculatedProgressionByX=The declared progress is less %s than the calculated progression
|
||||
TheReportedProgressIsMoreThanTheCalculatedProgressionByX=The declared progress is more %s than the calculated progression
|
||||
ProgressCalculated=Calculated progress
|
||||
WhichIamLinkedTo=which I'm linked to
|
||||
WhichIamLinkedToProject=which I'm linked to project
|
||||
Time=Time
|
||||
ListOfTasks=List of tasks
|
||||
GoToListOfTimeConsumed=Go to list of time consumed
|
||||
|
||||
@ -746,9 +746,12 @@ elseif ($id > 0 || ! empty($ref))
|
||||
print '<input class="flat" type="text" size="4" name="search_progresscalc" value="'.$search_progresscalc.'">';
|
||||
print '</td>';
|
||||
|
||||
print '<td class="liste_titre right">';
|
||||
print '<input class="flat" type="text" size="4" name="search_progressdeclare" value="'.$search_progressdeclare.'">';
|
||||
print '</td>';
|
||||
print '<td class="liste_titre right">';
|
||||
print '<input class="flat" type="text" size="4" name="search_progressdeclare" value="'.$search_progressdeclare.'">';
|
||||
print '</td>';
|
||||
|
||||
// progress resume not searchable
|
||||
print '<td class="liste_titre right"></td>';
|
||||
|
||||
if ($object->bill_time)
|
||||
{
|
||||
@ -778,6 +781,7 @@ elseif ($id > 0 || ! empty($ref))
|
||||
print_liste_field_titre("TimeSpent", $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'right ');
|
||||
print_liste_field_titre("ProgressCalculated", $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'right ');
|
||||
print_liste_field_titre("ProgressDeclared", $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'right ');
|
||||
print_liste_field_titre("TaskProgressSummary", $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'right ');
|
||||
if ($object->bill_time)
|
||||
{
|
||||
print_liste_field_titre("TimeToBill", $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'right ');
|
||||
|
||||
@ -405,6 +405,16 @@ textarea.centpercent {
|
||||
.small, small {
|
||||
font-size: 85%;
|
||||
}
|
||||
|
||||
.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small {
|
||||
font-size: 65%;
|
||||
}
|
||||
.h1 .small, .h1 small, .h2 .small, .h2 small, .h3 .small, .h3 small, .h4 .small, .h4 small, .h5 .small, .h5 small, .h6 .small, .h6 small, h1 .small, h1 small, h2 .small, h2 small, h3 .small, h3 small, h4 .small, h4 small, h5 .small, h5 small, h6 .small, h6 small {
|
||||
font-weight: 400;
|
||||
line-height: 1;
|
||||
color: #777;
|
||||
}
|
||||
|
||||
.center {
|
||||
text-align: center;
|
||||
margin: 0px auto;
|
||||
@ -483,6 +493,24 @@ textarea.centpercent {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.text-warning{
|
||||
color : <?php print $textWarning ; ?>
|
||||
}
|
||||
body[class*="colorblind-"] .text-warning{
|
||||
color : <?php print $colorblind_deuteranopes_textWarning ; ?>
|
||||
}
|
||||
.text-success{
|
||||
color : <?php print $textSuccess ; ?>
|
||||
}
|
||||
body[class*="colorblind-"] .text-success{
|
||||
color : <?php print $colorblind_deuteranopes_textSuccess ; ?>
|
||||
}
|
||||
|
||||
.text-danger{
|
||||
color : <?php print $textDanger ; ?>
|
||||
}
|
||||
|
||||
|
||||
/* Themes for badges */
|
||||
<?php include dol_buildpath($path.'/theme/'.$theme.'/badges.inc.php', 0); ?>
|
||||
|
||||
@ -3209,10 +3237,6 @@ span.boxstatsindicator {
|
||||
flex-grow: 1;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
span.dashboardlineindicator, span.dashboardlineindicatorlate {
|
||||
font-size: 130%;
|
||||
font-weight: normal;
|
||||
@ -5773,4 +5797,4 @@ div.tabsElem a.tab {
|
||||
<?php
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/dropdown.inc.php', 0);
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/info-box.inc.php', 0);
|
||||
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/progress.inc.php', 0);
|
||||
|
||||
187
htdocs/theme/eldy/progress.inc.php
Normal file
187
htdocs/theme/eldy/progress.inc.php
Normal file
@ -0,0 +1,187 @@
|
||||
<?php
|
||||
if (! defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet'); ?>
|
||||
/* <style type="text/css" > */
|
||||
/*
|
||||
progress style is based on boostrap and admin lte framework
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Component: Progress Bar
|
||||
* -----------------------
|
||||
*/
|
||||
|
||||
.progress * {
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.progress {
|
||||
height: 20px;
|
||||
overflow: hidden;
|
||||
background-color: #f5f5f5;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
border-radius: 4px;
|
||||
-webkit-box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
box-shadow: inset 0 1px 2px rgba(0,0,0,.1);
|
||||
}
|
||||
|
||||
.progress.spaced{
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
float: left;
|
||||
width: 0;
|
||||
height: 100%;
|
||||
font-size: 12px;
|
||||
line-height: 20px;
|
||||
color: #fff;
|
||||
text-align: center;
|
||||
background-color: #337ab7;
|
||||
-webkit-box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
|
||||
box-shadow: inset 0 -1px 0 rgba(0,0,0,.15);
|
||||
-webkit-transition: width .6s ease;
|
||||
-o-transition: width .6s ease;
|
||||
transition: width .6s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
.progress-group > .progress{
|
||||
clear: both;
|
||||
}
|
||||
|
||||
.progress,
|
||||
.progress > .progress-bar {
|
||||
-webkit-box-shadow: none;
|
||||
box-shadow: none;
|
||||
}
|
||||
.progress,
|
||||
.progress > .progress-bar,
|
||||
.progress .progress-bar,
|
||||
.progress > .progress-bar .progress-bar {
|
||||
border-radius: 1px;
|
||||
}
|
||||
/* size variation */
|
||||
.progress.sm,
|
||||
.progress-sm {
|
||||
height: 10px;
|
||||
}
|
||||
.progress.sm,
|
||||
.progress-sm,
|
||||
.progress.sm .progress-bar,
|
||||
.progress-sm .progress-bar {
|
||||
border-radius: 1px;
|
||||
}
|
||||
.progress.xs,
|
||||
.progress-xs {
|
||||
height: 7px;
|
||||
}
|
||||
.progress.xs,
|
||||
.progress-xs,
|
||||
.progress.xs .progress-bar,
|
||||
.progress-xs .progress-bar {
|
||||
border-radius: 1px;
|
||||
}
|
||||
.progress.xxs,
|
||||
.progress-xxs {
|
||||
height: 3px;
|
||||
}
|
||||
.progress.xxs,
|
||||
.progress-xxs,
|
||||
.progress.xxs .progress-bar,
|
||||
.progress-xxs .progress-bar {
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
|
||||
/* Vertical bars */
|
||||
.progress.vertical {
|
||||
position: relative;
|
||||
width: 30px;
|
||||
height: 200px;
|
||||
display: inline-block;
|
||||
margin-right: 10px;
|
||||
}
|
||||
.progress.vertical > .progress-bar {
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
}
|
||||
.progress.vertical.sm,
|
||||
.progress.vertical.progress-sm {
|
||||
width: 20px;
|
||||
}
|
||||
.progress.vertical.xs,
|
||||
.progress.vertical.progress-xs {
|
||||
width: 10px;
|
||||
}
|
||||
.progress.vertical.xxs,
|
||||
.progress.vertical.progress-xxs {
|
||||
width: 3px;
|
||||
}
|
||||
.progress-group .progress-text {
|
||||
font-weight: 600;
|
||||
}
|
||||
.progress-group .progress-number {
|
||||
float: right;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Remove margins from progress bars when put in a table */
|
||||
.table tr > td .progress {
|
||||
margin: 0;
|
||||
}
|
||||
.progress-bar-light-blue,
|
||||
.progress-bar-primary {
|
||||
background-color: #3c8dbc;
|
||||
}
|
||||
.progress-striped .progress-bar-light-blue,
|
||||
.progress-striped .progress-bar-primary {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-bar-green,
|
||||
.progress-bar-success {
|
||||
background-color: #00a65a;
|
||||
}
|
||||
.progress-striped .progress-bar-green,
|
||||
.progress-striped .progress-bar-success {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-bar-aqua,
|
||||
.progress-bar-info {
|
||||
background-color: #00c0ef;
|
||||
}
|
||||
.progress-striped .progress-bar-aqua,
|
||||
.progress-striped .progress-bar-info {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-bar-yellow,
|
||||
.progress-bar-warning {
|
||||
background-color: #f39c12;
|
||||
}
|
||||
.progress-striped .progress-bar-yellow,
|
||||
.progress-striped .progress-bar-warning {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
.progress-bar-red,
|
||||
.progress-bar-danger {
|
||||
background-color: #dd4b39;
|
||||
}
|
||||
.progress-striped .progress-bar-red,
|
||||
.progress-striped .progress-bar-danger {
|
||||
background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
background-image: linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);
|
||||
}
|
||||
@ -77,6 +77,14 @@ $topMenuFontSize='1.2em';
|
||||
$toolTipBgColor='rgba(255, 255, 255, 0.96);';
|
||||
$toolTipFontColor='#333';
|
||||
|
||||
// text color
|
||||
$textSuccess ='#28a745';
|
||||
$colorblind_deuteranopes_textSuccess ='#37de5d';
|
||||
$textDanger ='#dc3545';
|
||||
$textWarning ='#f39c12';
|
||||
$colorblind_deuteranopes_textWarning = $textWarning; // currently not tested with a color blind people so use default color
|
||||
|
||||
|
||||
// Badges colors
|
||||
$badgePrimary ='#007bff';
|
||||
$badgeSecondary ='#999999';
|
||||
@ -94,7 +102,7 @@ $colorblind_deuteranopes_badgeWarning ='#e4e411';
|
||||
|
||||
/* default color for status : After a quick check, somme status can have oposite function according to objects
|
||||
* So this badges status uses default value according to theme eldy status img
|
||||
* TODO: use color definition vars above for define badges color status X -> expemple $badgeStatusValidate, $badgeStatusClosed, $badgeStatusActive ....
|
||||
* TODO: use color definition vars above for define badges color status X -> exemple $badgeStatusValidate, $badgeStatusClosed, $badgeStatusActive ....
|
||||
*/
|
||||
$badgeStatus0='#cbd3d3';
|
||||
$badgeStatus1='#bc9526';
|
||||
|
||||
7
htdocs/theme/md/progress.inc.php
Normal file
7
htdocs/theme/md/progress.inc.php
Normal file
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
if (! defined('ISLOADEDBYSTEELSHEET')) die('Must be call by steelsheet');
|
||||
|
||||
include dol_buildpath($path.'/theme/eldy/progress.inc.php', 0); // actually md use same style as eldy theme
|
||||
|
||||
?>
|
||||
/* <style type="text/css" > */
|
||||
@ -690,6 +690,23 @@ textarea.centpercent {
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.text-warning{
|
||||
color : <?php print $textWarning ; ?>
|
||||
}
|
||||
body[class*="colorblind-"] .text-warning{
|
||||
color : <?php print $colorblind_deuteranopes_textWarning ; ?>
|
||||
}
|
||||
.text-success{
|
||||
color : <?php print $textSuccess ; ?>
|
||||
}
|
||||
body[class*="colorblind-"] .text-success{
|
||||
color : <?php print $colorblind_deuteranopes_textSuccess ; ?>
|
||||
}
|
||||
|
||||
.text-danger{
|
||||
color : <?php print $textDanger ; ?>
|
||||
}
|
||||
|
||||
/* Themes for badges */
|
||||
<?php include dol_buildpath($path.'/theme/'.$theme.'/badges.inc.php', 0); ?>
|
||||
|
||||
@ -5717,7 +5734,9 @@ border-top-right-radius: 6px;
|
||||
<?php }
|
||||
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/dropdown.inc.php', 0);
|
||||
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/info-box.inc.php', 0);
|
||||
include dol_buildpath($path.'/theme/'.$theme.'/progress.inc.php', 0);
|
||||
|
||||
|
||||
|
||||
if (is_object($db)) $db->close();
|
||||
|
||||
@ -70,6 +70,13 @@ $colortextlink='0,0,120';
|
||||
$fontsize='14';
|
||||
$fontsizesmaller='11';
|
||||
|
||||
// text color
|
||||
$textSuccess ='#28a745';
|
||||
$colorblind_deuteranopes_textSuccess ='#37de5d';
|
||||
$textDanger ='#dc3545';
|
||||
$textWarning ='#f39c12';
|
||||
$colorblind_deuteranopes_textWarning = $textWarning; // currently not tested with a color blind people so use default color
|
||||
|
||||
// Badges colors
|
||||
$badgePrimary ='#007bff';
|
||||
$badgeSecondary ='#999999';
|
||||
|
||||
Loading…
Reference in New Issue
Block a user