Merge branch 'develop' of git@github.com:Dolibarr/dolibarr.git into develop

This commit is contained in:
Laurent Destailleur 2022-07-08 10:17:24 +02:00
commit 7dbff58da7
9 changed files with 394 additions and 97 deletions

View File

@ -3820,6 +3820,7 @@ class Facture extends CommonInvoice
return -2; return -2;
} }
} else { } else {
$this->errors[]='status of invoice must be Draft to allow use of ->addline()';
dol_syslog(get_class($this)."::addline status of invoice must be Draft to allow use of ->addline()", LOG_ERR); dol_syslog(get_class($this)."::addline status of invoice must be Draft to allow use of ->addline()", LOG_ERR);
return -3; return -3;
} }

View File

@ -1291,6 +1291,7 @@ class FormFile
$nboflines++; $nboflines++;
print '<!-- Line list_of_documents '.$key.' relativepath = '.$relativepath.' -->'."\n"; print '<!-- Line list_of_documents '.$key.' relativepath = '.$relativepath.' -->'."\n";
// Do we have entry into database ? // Do we have entry into database ?
print '<!-- In database: position='.(array_key_exists('position', $filearray[$key]) ? $filearray[$key]['position'] : 0).' -->'."\n"; print '<!-- In database: position='.(array_key_exists('position', $filearray[$key]) ? $filearray[$key]['position'] : 0).' -->'."\n";
print '<tr class="oddeven" id="row-'.((array_key_exists('rowid', $filearray[$key]) && $filearray[$key]['rowid'] > 0) ? $filearray[$key]['rowid'] : 'AFTER'.$lastrowid.'POS'.($i + 1)).'">'; print '<tr class="oddeven" id="row-'.((array_key_exists('rowid', $filearray[$key]) && $filearray[$key]['rowid'] > 0) ? $filearray[$key]['rowid'] : 'AFTER'.$lastrowid.'POS'.($i + 1)).'">';
@ -1436,7 +1437,7 @@ class FormFile
if ($permtoeditline) { if ($permtoeditline) {
// Link to resize // Link to resize
$moreparaminurl = ''; $moreparaminurl = '';
if ($object->id > 0) { if (!empty($object->id) && $object->id > 0) {
$moreparaminurl = '&id='.$object->id; $moreparaminurl = '&id='.$object->id;
} elseif (GETPOST('website', 'alpha')) { } elseif (GETPOST('website', 'alpha')) {
$moreparaminurl = '&website='.GETPOST('website', 'alpha'); $moreparaminurl = '&website='.GETPOST('website', 'alpha');

View File

@ -54,7 +54,9 @@ if ($module == 'medias') {
$showroot = 1; $showroot = 1;
} }
if (!isset($section)) {
$section = 0;
}
// Confirm remove file (for non javascript users) // Confirm remove file (for non javascript users)
if (($action == 'delete' || $action == 'file_manager_delete') && empty($conf->use_javascript_ajax)) { if (($action == 'delete' || $action == 'file_manager_delete') && empty($conf->use_javascript_ajax)) {
@ -106,12 +108,26 @@ $('#acreatedir').on('click', function() {
try{ try{
section_dir = $('.directory.expanded')[$('.directory.expanded').length-1].children[0].rel; section_dir = $('.directory.expanded')[$('.directory.expanded').length-1].children[0].rel;
section = $('.directory.expanded')[$('.directory.expanded').length-1].children[0].id.split('_')[2]; section = $('.directory.expanded')[$('.directory.expanded').length-1].children[0].id.split('_')[2];
catParent = ";
if ($module == 'ecm') {
print "section;";
} else {
print "section_dir.substring(0, section_dir.length - 1);";
}
print "
} catch{ } catch{
section_dir = '/'; section_dir = '/';
section = 0; section = 0;
catParent = ";
if ($module == 'ecm') {
print "section;";
} else {
print "section_dir;";
}
print "
} }
console.log('We click to create a new directory, we set current section_dir='+section_dir+' into href url of button acreatedir'); console.log('We click to create a new directory, we set current section_dir='+section_dir+' into href url of button acreatedir');
$('#acreatedir').attr('href', $('#acreatedir').attr('href')+'&section_dir='+encodeURI(section_dir)+'&section='+encodeURI(section)); $('#acreatedir').attr('href', $('#acreatedir').attr('href')+'%26section_dir%3D'+encodeURI(section_dir)+'%26section%3D'+encodeURI(section)+'&section_dir='+encodeURI(section_dir)+'&section='+encodeURI(section)+'&catParent='+encodeURI(catParent));
console.log($('#acreatedir').attr('href')); console.log($('#acreatedir').attr('href'));
}); });
$('#agenerateimgwebp').on('click', function() { $('#agenerateimgwebp').on('click', function() {

View File

@ -230,7 +230,7 @@ if ($action == 'create') {
print '<table class="border centpercent">'; print '<table class="border centpercent">';
// Label // Label
print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Label").'</td><td><input name="label" class="minwidth100" maxlength="32" value="'.$ecmdir->label.'" autofocus></td></tr>'."\n"; print '<tr><td class="titlefieldcreate fieldrequired">'.$langs->trans("Label").'</td><td><input name="label" class="minwidth100" maxlength="32" value="'.(GETPOST("label", 'alpha') ? GETPOST("label", 'alpha') : $ecmdir->label).'" autofocus></td></tr>'."\n";
print '<tr><td>'.$langs->trans("AddIn").'</td><td>'; print '<tr><td>'.$langs->trans("AddIn").'</td><td>';
print $formecm->selectAllSections((GETPOST("catParent", 'alpha') ? GETPOST("catParent", 'alpha') : $ecmdir->fk_parent), 'catParent', $module); print $formecm->selectAllSections((GETPOST("catParent", 'alpha') ? GETPOST("catParent", 'alpha') : $ecmdir->fk_parent), 'catParent', $module);

View File

@ -259,7 +259,7 @@ TimeSpentInvoiced=Time spent billed
TimeSpentForIntervention=Time spent TimeSpentForIntervention=Time spent
TimeSpentForInvoice=Time spent TimeSpentForInvoice=Time spent
OneLinePerUser=One line per user OneLinePerUser=One line per user
ServiceToUseOnLines=Service to use on lines ServiceToUseOnLines=Service to use on lines by default
InvoiceGeneratedFromTimeSpent=Invoice %s has been generated from time spent on project InvoiceGeneratedFromTimeSpent=Invoice %s has been generated from time spent on project
InterventionGeneratedFromTimeSpent=Intervention %s has been generated from time spent on project InterventionGeneratedFromTimeSpent=Intervention %s has been generated from time spent on project
ProjectBillTimeDescription=Check if you enter timesheet on tasks of project AND you plan to generate invoice(s) from the timesheet to bill the customer of the project (do not check if you plan to create invoice that is not based on entered timesheets). Note: To generate invoice, go on tab 'Time spent' of the project and select lines to include. ProjectBillTimeDescription=Check if you enter timesheet on tasks of project AND you plan to generate invoice(s) from the timesheet to bill the customer of the project (do not check if you plan to create invoice that is not based on entered timesheets). Note: To generate invoice, go on tab 'Time spent' of the project and select lines to include.

View File

@ -6159,6 +6159,43 @@ class Product extends CommonObject
dol_print_error($this->db); dol_print_error($this->db);
} }
} }
/**
* Return the duration in Hours of a service base on duration fields
* @return int -1 KO, >= 0 is the duration in hours
*/
public function getProductDurationHours()
{
global $langs;
if (empty($this->duration_value)) {
$this->errors[]='ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice';
return -1;
}
if ($this->duration_unit == 'i') {
$prodDurationHours = 1. / 60;
}
if ($this->duration_unit == 'h') {
$prodDurationHours = 1.;
}
if ($this->duration_unit == 'd') {
$prodDurationHours = 24.;
}
if ($this->duration_unit == 'w') {
$prodDurationHours = 24. * 7;
}
if ($this->duration_unit == 'm') {
$prodDurationHours = 24. * 30;
}
if ($this->duration_unit == 'y') {
$prodDurationHours = 24. * 365;
}
$prodDurationHours *= $this->duration_value;
return $prodDurationHours;
}
} }

View File

@ -27,6 +27,9 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/company.lib.php';
require_once DOL_DOCUMENT_ROOT.'/product/inventory/class/inventory.class.php'; require_once DOL_DOCUMENT_ROOT.'/product/inventory/class/inventory.class.php';
if (!empty($conf->categorie->enabled)) {
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
}
// Load translation files required by the page // Load translation files required by the page
$langs->loadLangs(array("stocks", "other")); $langs->loadLangs(array("stocks", "other"));
@ -88,6 +91,13 @@ foreach ($object->fields as $key => $val) {
$search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int')); $search[$key.'_dtend'] = dol_mktime(23, 59, 59, GETPOST('search_'.$key.'_dtendmonth', 'int'), GETPOST('search_'.$key.'_dtendday', 'int'), GETPOST('search_'.$key.'_dtendyear', 'int'));
} }
} }
$searchCategoryProductOperator = 0;
if (GETPOSTISSET('formfilteraction')) {
$searchCategoryProductOperator = GETPOST('search_category_product_operator', 'int');
} elseif (!empty($conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT)) {
$searchCategoryProductOperator = $conf->global->MAIN_SEARCH_CAT_OR_BY_DEFAULT;
}
$searchCategoryProductList = GETPOST('search_category_product_list', 'array');
// List of fields to search into when doing a "search in all" // List of fields to search into when doing a "search in all"
$fieldstosearchall = array(); $fieldstosearchall = array();
@ -166,6 +176,7 @@ if (empty($reshook)) {
$search[$key.'_dtend'] = ''; $search[$key.'_dtend'] = '';
} }
} }
$searchCategoryProductList = array();
$toselect = array(); $toselect = array();
$search_array_options = array(); $search_array_options = array();
} }
@ -259,6 +270,50 @@ foreach ($search as $key => $val) {
if ($search_all) { if ($search_all) {
$sql .= natural_search(array_keys($fieldstosearchall), $search_all); $sql .= natural_search(array_keys($fieldstosearchall), $search_all);
} }
$searchCategoryProductSqlList = array();
if ($searchCategoryProductOperator == 1) {
$existsCategoryProductList = array();
foreach ($searchCategoryProductList as $searchCategoryProduct) {
if (intval($searchCategoryProduct) == -2) {
$sqlCategoryProductNotExists = " NOT EXISTS (";
$sqlCategoryProductNotExists .= " SELECT cp.fk_product";
$sqlCategoryProductNotExists .= " FROM ".$db->prefix()."categorie_product AS cp";
$sqlCategoryProductNotExists .= " WHERE cp.fk_product = t.fk_product";
$sqlCategoryProductNotExists .= " )";
$searchCategoryProductSqlList[] = $sqlCategoryProductNotExists;
} elseif (intval($searchCategoryProduct) > 0) {
$existsCategoryProductList[] = $db->escape($searchCategoryProduct);
}
}
if (!empty($existsCategoryProductList)) {
$sqlCategoryProductExists = " EXISTS (";
$sqlCategoryProductExists .= " SELECT cp.fk_product";
$sqlCategoryProductExists .= " FROM ".$db->prefix()."categorie_product AS cp";
$sqlCategoryProductExists .= " WHERE cp.fk_product = t.fk_product";
$sqlCategoryProductExists .= " AND cp.fk_categorie IN (".$db->sanitize(implode(',', $existsCategoryProductList)).")";
$sqlCategoryProductExists .= " )";
$searchCategoryProductSqlList[] = $sqlCategoryProductExists;
}
if (!empty($searchCategoryProductSqlList)) {
$sql .= " AND (".implode(' OR ', $searchCategoryProductSqlList).")";
}
} else {
foreach ($searchCategoryProductList as $searchCategoryProduct) {
if (intval($searchCategoryProduct) == -2) {
$sqlCategoryProductNotExists = " NOT EXISTS (";
$sqlCategoryProductNotExists .= " SELECT cp.fk_product";
$sqlCategoryProductNotExists .= " FROM ".$db->prefix()."categorie_product AS cp";
$sqlCategoryProductNotExists .= " WHERE cp.fk_product = t.fk_product";
$sqlCategoryProductNotExists .= " )";
$searchCategoryProductSqlList[] = $sqlCategoryProductNotExists;
} elseif (intval($searchCategoryProduct) > 0) {
$searchCategoryProductSqlList[] = "t.fk_product IN (SELECT fk_product FROM ".$db->prefix()."categorie_product WHERE fk_categorie = ".((int) $searchCategoryProduct).")";
}
}
if (!empty($searchCategoryProductSqlList)) {
$sql .= " AND (".implode(' AND ', $searchCategoryProductSqlList).")";
}
}
//$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear); //$sql.= dolSqlDateFilter("t.field", $search_xxxday, $search_xxxmonth, $search_xxxyear);
// Add where from extra fields // Add where from extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_sql.tpl.php';
@ -348,6 +403,9 @@ foreach ($search as $key => $val) {
if ($optioncss != '') { if ($optioncss != '') {
$param .= '&optioncss='.urlencode($optioncss); $param .= '&optioncss='.urlencode($optioncss);
} }
foreach ($searchCategoryProductList as $searchCategoryProduct) {
$param .= "&search_category_product_list[]=".urlencode($searchCategoryProduct);
}
// Add $param from extra fields // Add $param from extra fields
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php'; include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_param.tpl.php';
// Add $param from hooks // Add $param from hooks
@ -405,6 +463,19 @@ $moreforfilter = '';
$moreforfilter.= $langs->trans('MyFilter') . ': <input type="text" name="search_myfield" value="'.dol_escape_htmltag($search_myfield).'">'; $moreforfilter.= $langs->trans('MyFilter') . ': <input type="text" name="search_myfield" value="'.dol_escape_htmltag($search_myfield).'">';
$moreforfilter.= '</div>';*/ $moreforfilter.= '</div>';*/
// Filter on categories
if (!empty($conf->global->MAIN_SEARCH_CATEGORY_PRODUCT_ON_LISTS) && !empty($conf->categorie->enabled) && $user->rights->categorie->lire) {
$moreforfilter .= '<div class="divsearchfield">';
$tmptitle = $langs->transnoentities('ProductsCategoriesShort');
$moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"');
$categoriesProductArr = $form->select_all_categories(Categorie::TYPE_PRODUCT, '', '', 64, 0, 1);
$categoriesProductArr[-2] = '- '.$langs->trans('NotCategorized').' -';
$moreforfilter .= Form::multiselectarray('search_category_product_list', $categoriesProductArr, $searchCategoryProductList, 0, 0, 'minwidth300', 0, 0, '', 'category', $tmptitle);
$moreforfilter .= ' <input type="checkbox" class="valignmiddle" id="search_category_product_operator" name="search_category_product_operator" value="1"'.($searchCategoryProductOperator == 1 ? ' checked="checked"' : '').'/>';
$moreforfilter .= $form->textwithpicto('', $langs->trans('UseOrOperatorForCategories') . ' : ' . $tmptitle, 1, 'help', '', 0, 2, 'tooltip_cat_pro'); // Tooltip on click
$moreforfilter .= '</div>';
}
$parameters = array(); $parameters = array();
$reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object); // Note that $action and $object may have been modified by hook
if (empty($reshook)) { if (empty($reshook)) {

View File

@ -127,6 +127,7 @@ class Task extends CommonObjectLine
public $timespent_fk_user; public $timespent_fk_user;
public $timespent_thm; public $timespent_thm;
public $timespent_note; public $timespent_note;
public $timespent_fk_product;
public $comments = array(); public $comments = array();
@ -1227,6 +1228,7 @@ class Task extends CommonObjectLine
$sql .= ", task_date_withhour"; $sql .= ", task_date_withhour";
$sql .= ", task_duration"; $sql .= ", task_duration";
$sql .= ", fk_user"; $sql .= ", fk_user";
$sql .= ", fk_product";
$sql .= ", note"; $sql .= ", note";
$sql .= ", datec"; $sql .= ", datec";
$sql .= ") VALUES ("; $sql .= ") VALUES (";
@ -1236,6 +1238,7 @@ class Task extends CommonObjectLine
$sql .= ", ".(empty($this->timespent_withhour) ? 0 : 1); $sql .= ", ".(empty($this->timespent_withhour) ? 0 : 1);
$sql .= ", ".((int) $this->timespent_duration); $sql .= ", ".((int) $this->timespent_duration);
$sql .= ", ".((int) $this->timespent_fk_user); $sql .= ", ".((int) $this->timespent_fk_user);
$sql .= ", ".((int) $this->timespent_fk_product);
$sql .= ", ".(isset($this->timespent_note) ? "'".$this->db->escape($this->timespent_note)."'" : "null"); $sql .= ", ".(isset($this->timespent_note) ? "'".$this->db->escape($this->timespent_note)."'" : "null");
$sql .= ", '".$this->db->idate($now)."'"; $sql .= ", '".$this->db->idate($now)."'";
$sql .= ")"; $sql .= ")";
@ -1523,6 +1526,7 @@ class Task extends CommonObjectLine
$sql .= " t.task_date_withhour,"; $sql .= " t.task_date_withhour,";
$sql .= " t.task_duration,"; $sql .= " t.task_duration,";
$sql .= " t.fk_user,"; $sql .= " t.fk_user,";
$sql .= " t.fk_product,";
$sql .= " t.thm,"; $sql .= " t.thm,";
$sql .= " t.note"; $sql .= " t.note";
$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t"; $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t";
@ -1541,6 +1545,7 @@ class Task extends CommonObjectLine
$this->timespent_withhour = $obj->task_date_withhour; $this->timespent_withhour = $obj->task_date_withhour;
$this->timespent_duration = $obj->task_duration; $this->timespent_duration = $obj->task_duration;
$this->timespent_fk_user = $obj->fk_user; $this->timespent_fk_user = $obj->fk_user;
$this->timespent_fk_product = $obj->fk_product;
$this->timespent_thm = $obj->thm; // hourly rate $this->timespent_thm = $obj->thm; // hourly rate
$this->timespent_note = $obj->note; $this->timespent_note = $obj->note;
} }
@ -1694,6 +1699,7 @@ class Task extends CommonObjectLine
$sql .= " task_date_withhour = ".(empty($this->timespent_withhour) ? 0 : 1).","; $sql .= " task_date_withhour = ".(empty($this->timespent_withhour) ? 0 : 1).",";
$sql .= " task_duration = ".((int) $this->timespent_duration).","; $sql .= " task_duration = ".((int) $this->timespent_duration).",";
$sql .= " fk_user = ".((int) $this->timespent_fk_user).","; $sql .= " fk_user = ".((int) $this->timespent_fk_user).",";
$sql .= " fk_product = ".((int) $this->timespent_fk_product).",";
$sql .= " note = ".(isset($this->timespent_note) ? "'".$this->db->escape($this->timespent_note)."'" : "null"); $sql .= " note = ".(isset($this->timespent_note) ? "'".$this->db->escape($this->timespent_note)."'" : "null");
$sql .= " WHERE rowid = ".((int) $this->timespent_id); $sql .= " WHERE rowid = ".((int) $this->timespent_id);

View File

@ -73,6 +73,7 @@ $search_task_ref = GETPOST('search_task_ref', 'alpha');
$search_task_label = GETPOST('search_task_label', 'alpha'); $search_task_label = GETPOST('search_task_label', 'alpha');
$search_user = GETPOST('search_user', 'int'); $search_user = GETPOST('search_user', 'int');
$search_valuebilled = GETPOST('search_valuebilled', 'int'); $search_valuebilled = GETPOST('search_valuebilled', 'int');
$search_product_ref = GETPOST('search_product_ref', 'alpha');
$search_company = GETPOST('$search_company', 'alpha'); $search_company = GETPOST('$search_company', 'alpha');
$limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit; $limit = GETPOST('limit', 'int') ?GETPOST('limit', 'int') : $conf->liste_limit;
@ -166,6 +167,7 @@ if (GETPOST('button_removefilter_x', 'alpha') || GETPOST('button_removefilter.x'
$search_task_label = ''; $search_task_label = '';
$search_user = 0; $search_user = 0;
$search_valuebilled = ''; $search_valuebilled = '';
$search_product_ref = '';
$toselect = array(); $toselect = array();
$search_array_options = array(); $search_array_options = array();
$action = ''; $action = '';
@ -220,6 +222,7 @@ if ($action == 'addtimespent' && $user->rights->projet->time) {
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timemonth", 'int'), GETPOST("timeday", 'int'), GETPOST("timeyear", 'int')); $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timemonth", 'int'), GETPOST("timeday", 'int'), GETPOST("timeyear", 'int'));
} }
$object->timespent_fk_user = GETPOST("userid", 'int'); $object->timespent_fk_user = GETPOST("userid", 'int');
$object->timespent_fk_product = GETPOST("fk_product", 'int');
$result = $object->addTimeSpent($user); $result = $object->addTimeSpent($user);
if ($result >= 0) { if ($result >= 0) {
setEventMessages($langs->trans("RecordSaved"), null, 'mesgs'); setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
@ -271,17 +274,17 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear")); $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth"), GETPOST("timelineday"), GETPOST("timelineyear"));
} }
$object->timespent_fk_user = GETPOST("userid_line", 'int'); $object->timespent_fk_user = GETPOST("userid_line", 'int');
$object->timespent_fk_product = GETPOST("fk_product", 'int');
$result = 0; $result = 0;
if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) { if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
$result = $object->addTimeSpent($user); $result = $object->addTimeSpent($user);
} if ($result >= 0) {
setEventMessages($langs->trans("RecordSaved"), null, 'mesgs');
if ($result >= 0) { } else {
setEventMessages($langs->trans("RecordSaved"), null, 'mesgs'); setEventMessages($langs->trans($object->error), null, 'errors');
} else { $error++;
setEventMessages($langs->trans($object->error), null, 'errors'); }
$error++;
} }
} else { } else {
$object->fetch($id, $ref); $object->fetch($id, $ref);
@ -298,6 +301,7 @@ if (($action == 'updateline' || $action == 'updatesplitline') && !$cancel && $us
$object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int')); $object->timespent_date = dol_mktime(12, 0, 0, GETPOST("timelinemonth", 'int'), GETPOST("timelineday", 'int'), GETPOST("timelineyear", 'int'));
} }
$object->timespent_fk_user = GETPOST("userid_line", 'int'); $object->timespent_fk_user = GETPOST("userid_line", 'int');
$object->timespent_fk_product = GETPOST("fk_product", 'int');
$result = 0; $result = 0;
if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) { if (in_array($object->timespent_fk_user, $childids) || $user->rights->projet->all->creer) {
@ -391,36 +395,22 @@ if ($action == 'confirm_generateinvoice') {
$generateinvoicemode = GETPOST('generateinvoicemode', 'string'); $generateinvoicemode = GETPOST('generateinvoicemode', 'string');
$invoiceToUse = GETPOST('invoiceid', 'int'); $invoiceToUse = GETPOST('invoiceid', 'int');
$prodDurationHours = 1.0; $prodDurationHoursBase = 1.0;
$product_data_cache = array();
if ($idprod > 0) { if ($idprod > 0) {
$tmpproduct->fetch($idprod); $tmpproduct->fetch($idprod);
if ($result<0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
if (empty($tmpproduct->duration_value)) { $prodDurationHoursBase=$tmpproduct->getProductDurationHours();
if ($prodDurationHoursBase<0) {
$error++; $error++;
$langs->load("errors"); $langs->load("errors");
setEventMessages($langs->trans("ErrorDurationForServiceNotDefinedCantCalculateHourlyPrice"), null, 'errors'); setEventMessages(null, $tmpproduct->errors, 'errors');
} }
if ($tmpproduct->duration_unit == 'i') {
$prodDurationHours = 1. / 60;
}
if ($tmpproduct->duration_unit == 'h') {
$prodDurationHours = 1.;
}
if ($tmpproduct->duration_unit == 'd') {
$prodDurationHours = 24.;
}
if ($tmpproduct->duration_unit == 'w') {
$prodDurationHours = 24. * 7;
}
if ($tmpproduct->duration_unit == 'm') {
$prodDurationHours = 24. * 30;
}
if ($tmpproduct->duration_unit == 'y') {
$prodDurationHours = 24. * 365;
}
$prodDurationHours *= $tmpproduct->duration_value;
$dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0); $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht']; $pu_ht = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
@ -428,7 +418,7 @@ if ($action == 'confirm_generateinvoice') {
$localtax1 = $dataforprice['localtax1']; $localtax1 = $dataforprice['localtax1'];
$localtax2 = $dataforprice['localtax2']; $localtax2 = $dataforprice['localtax2'];
} else { } else {
$prodDurationHours = 1; $prodDurationHoursBase = 1;
$pu_ht = 0; $pu_ht = 0;
$txtva = get_default_tva($mysoc, $projectstatic->thirdparty); $txtva = get_default_tva($mysoc, $projectstatic->thirdparty);
@ -456,39 +446,85 @@ if ($action == 'confirm_generateinvoice') {
foreach ($toselect as $key => $value) { foreach ($toselect as $key => $value) {
// Get userid, timepent // Get userid, timepent
$object->fetchTimeSpent($value); $object->fetchTimeSpent($value);
$arrayoftasks[$object->timespent_fk_user]['timespent'] += $object->timespent_duration; $arrayoftasks[$object->timespent_fk_user][(int) $object->timespent_fk_product]['timespent'] += $object->timespent_duration;
$arrayoftasks[$object->timespent_fk_user]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm); $arrayoftasks[$object->timespent_fk_user][(int) $object->timespent_fk_product]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
} }
foreach ($arrayoftasks as $userid => $value) { foreach ($arrayoftasks as $userid => $data) {
$fuser->fetch($userid); $fuser->fetch($userid);
//$pu_ht = $value['timespent'] * $fuser->thm; //$pu_ht = $value['timespent'] * $fuser->thm;
$username = $fuser->getFullName($langs); $username = $fuser->getFullName($langs);
foreach ($data as $fk_product=>$timespent_data) {
// Define qty per hour
$qtyhour = $timespent_data['timespent'] / 3600;
$qtyhourtext = convertSecondToTime($timespent_data['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
// Define qty per hour // If no unit price known
$qtyhour = $value['timespent'] / 3600; if (empty($pu_ht)) {
$qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY); $pu_ht = price2num($timespent_data['totalvaluetodivideby3600'] / 3600, 'MU');
}
// If no unit price known // Add lines
if (empty($pu_ht)) { $prodDurationHours = $prodDurationHoursBase;
$pu_ht = price2num($value['totalvaluetodivideby3600'] / 3600, 'MU'); $idprodline=$idprod;
} $pu_htline = $pu_ht;
$txtvaline = $txtva;
$localtax1line = $localtax1;
$localtax2line = $localtax2;
// Add lines if (!empty($fk_product) && $fk_product!==$idprod) {
$lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice", $username).' : '.$qtyhourtext, $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0)); if (!array_key_exists($fk_product, $product_data_cache)) {
$result = $tmpproduct->fetch($fk_product);
if ($result < 0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
$prodDurationHours = $tmpproduct->getProductDurationHours();
if ($prodDurationHours < 0) {
$error++;
$langs->load("errors");
setEventMessages(null, $tmpproduct->errors, 'errors');
}
// Update lineid into line of timespent $dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).') AND fk_user = '.((int) $userid); $pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
$result = $db->query($sql); $txtvaline = $dataforprice['tva_tx'];
if (!$result) { $localtax1line = $dataforprice['localtax1'];
$error++; $localtax2line = $dataforprice['localtax2'];
setEventMessages($db->lasterror(), null, 'errors');
break; $product_data_cache[$fk_product] = array('duration'=>$prodDurationHours,'dataforprice'=>$dataforprice);
} else {
$prodDurationHours = $product_data_cache[$fk_product]['duration'];
$pu_htline = empty($product_data_cache[$fk_product]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$fk_product]['dataforprice']['pu_ht'];
$txtvaline = $product_data_cache[$fk_product]['dataforprice']['tva_tx'];
$localtax1line = $product_data_cache[$fk_product]['dataforprice']['localtax1'];
$localtax2line = $product_data_cache[$fk_product]['dataforprice']['localtax2'];
}
$idprodline=$fk_product;
}
// Add lines
$lineid = $tmpinvoice->addline($langs->trans("TimeSpentForInvoice", $username).' : '.$qtyhourtext, $pu_htline, round($qtyhour / $prodDurationHours, 2), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0));
if ($lineid<0) {
$error++;
setEventMessages(null, $tmpinvoice->errors, 'errors');
}
// Update lineid into line of timespent
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).') AND fk_user = '.((int) $userid);
$result = $db->query($sql);
if (!$result) {
$error++;
setEventMessages($db->lasterror(), null, 'errors');
break;
}
} }
} }
} elseif ($generateinvoicemode == 'onelineperperiod') { // One line for each time spent line } elseif ($generateinvoicemode == 'onelineperperiod') { // One line for each time spent line
$arrayoftasks = array(); $arrayoftasks = array();
$withdetail=GETPOST('detail_time_duration', 'alpha'); $withdetail=GETPOST('detail_time_duration', 'alpha');
foreach ($toselect as $key => $value) { foreach ($toselect as $key => $value) {
// Get userid, timepent // Get userid, timepent
@ -518,6 +554,7 @@ if ($action == 'confirm_generateinvoice') {
$arrayoftasks[$object->timespent_id]['note'] .= ' - '.$langs->trans("Duration").': '.convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY); $arrayoftasks[$object->timespent_id]['note'] .= ' - '.$langs->trans("Duration").': '.convertSecondToTime($object->timespent_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
} }
$arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user; $arrayoftasks[$object->timespent_id]['user'] = $object->timespent_fk_user;
$arrayoftasks[$object->timespent_id]['fk_product'] = $object->timespent_fk_product;
} }
foreach ($arrayoftasks as $timespent_id => $value) { foreach ($arrayoftasks as $timespent_id => $value) {
@ -533,7 +570,49 @@ if ($action == 'confirm_generateinvoice') {
} }
// Add lines // Add lines
$lineid = $tmpinvoice->addline($value['note'], $pu_ht, round($qtyhour / $prodDurationHours, 2), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0)); $prodDurationHours = $prodDurationHoursBase;
$idprodline=$idprod;
$pu_htline = $pu_ht;
$txtvaline = $txtva;
$localtax1line = $localtax1;
$localtax2line = $localtax2;
if (!empty($value['fk_product']) && $value['fk_product']!==$idprod) {
if (!array_key_exists($value['fk_product'], $product_data_cache)) {
$result = $tmpproduct->fetch($value['fk_product']);
if ($result < 0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
$prodDurationHours = $tmpproduct->getProductDurationHours();
if ($prodDurationHours < 0) {
$error++;
$langs->load("errors");
setEventMessages(null, $tmpproduct->errors, 'errors');
}
$dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
$txtvaline = $dataforprice['tva_tx'];
$localtax1line = $dataforprice['localtax1'];
$localtax2line = $dataforprice['localtax2'];
$product_data_cache[$value['fk_product']] = array('duration'=>$prodDurationHours,'dataforprice'=>$dataforprice);
} else {
$prodDurationHours = $product_data_cache[$value['fk_product']]['duration'];
$pu_htline = empty($product_data_cache[$value['fk_product']]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$value['fk_product']]['dataforprice']['pu_ht'];
$txtvaline = $product_data_cache[$value['fk_product']]['dataforprice']['tva_tx'];
$localtax1line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax1'];
$localtax2line = $product_data_cache[$value['fk_product']]['dataforprice']['localtax2'];
}
$idprodline=$value['fk_product'];
}
$lineid = $tmpinvoice->addline($value['note'], $pu_htline, round($qtyhour / $prodDurationHours, 2), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0));
if ($lineid<0) {
$error++;
setEventMessages(null, $tmpinvoice->errors, 'errors');
}
//var_dump($lineid);exit; //var_dump($lineid);exit;
// Update lineid into line of timespent // Update lineid into line of timespent
@ -552,56 +631,99 @@ if ($action == 'confirm_generateinvoice') {
// Get userid, timepent // Get userid, timepent
$object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object) $object->fetchTimeSpent($value); // Call method to get list of timespent for a timespent line id (We use the utiliy method found into Task object)
// $object->id is now the task id // $object->id is now the task id
$arrayoftasks[$object->id]['timespent'] += $object->timespent_duration; $arrayoftasks[$object->id][(int) $object->timespent_fk_product]['timespent'] += $object->timespent_duration;
$arrayoftasks[$object->id]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm); $arrayoftasks[$object->id][(int) $object->timespent_fk_product]['totalvaluetodivideby3600'] += ($object->timespent_duration * $object->timespent_thm);
} }
foreach ($arrayoftasks as $task_id => $value) { foreach ($arrayoftasks as $task_id => $data) {
$ftask = new Task($db); $ftask = new Task($db);
$ftask->fetch($task_id); $ftask->fetch($task_id);
// Define qty per hour
$qtyhour = $value['timespent'] / 3600;
$qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
if ($idprod > 0) { foreach ($data as $fk_product=>$timespent_data) {
// If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously). $qtyhour = $timespent_data['timespent'] / 3600;
$pu_ht_for_task = $pu_ht; $qtyhourtext = convertSecondToTime($timespent_data['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
// If we want to reuse the value of timespent (so use same price than cost price)
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) { // Add lines
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours; $prodDurationHours = $prodDurationHoursBase;
$idprodline=$idprod;
$pu_htline = $pu_ht;
$txtvaline = $txtva;
$localtax1line = $localtax1;
$localtax2line = $localtax2;
if (!empty($fk_product) && $fk_product!==$idprod) {
if (!array_key_exists($fk_product, $product_data_cache)) {
$result = $tmpproduct->fetch($fk_product);
if ($result < 0) {
$error++;
setEventMessages($tmpproduct->error, $tmpproduct->errors, 'errors');
}
$prodDurationHours = $tmpproduct->getProductDurationHours();
if ($prodDurationHours < 0) {
$error++;
$langs->load("errors");
setEventMessages(null, $tmpproduct->errors, 'errors');
}
$dataforprice = $tmpproduct->getSellPrice($mysoc, $projectstatic->thirdparty, 0);
$pu_htline = empty($dataforprice['pu_ht']) ? 0 : $dataforprice['pu_ht'];
$txtvaline = $dataforprice['tva_tx'];
$localtax1line = $dataforprice['localtax1'];
$localtax2line = $dataforprice['localtax2'];
$product_data_cache[$fk_product] = array('duration'=>$prodDurationHours,'dataforprice'=>$dataforprice);
} else {
$prodDurationHours = $product_data_cache[$fk_product]['duration'];
$pu_htline = empty($product_data_cache[$fk_product]['dataforprice']['pu_ht']) ? 0 : $product_data_cache[$fk_product]['dataforprice']['pu_ht'];
$txtvaline = $product_data_cache[$fk_product]['dataforprice']['tva_tx'];
$localtax1line = $product_data_cache[$fk_product]['dataforprice']['localtax1'];
$localtax2line = $product_data_cache[$fk_product]['dataforprice']['localtax2'];
}
$idprodline=$fk_product;
} }
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU') * $prodDurationHours;
} else {
// If not product used, we use the hour unit for duration and unit price. if ($idprodline > 0) {
$pu_ht_for_task = 0; // If a product is defined, we msut use the $prodDurationHours and $pu_ht of product (already set previously).
// If we want to reuse the value of timespent (so use same price than cost price) $pu_ht_for_task = $pu_htline;
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) { // If we want to reuse the value of timespent (so use same price than cost price)
$pu_ht_for_task = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU'); if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
$pu_ht_for_task = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU') * $prodDurationHours;
}
$pa_ht = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU') * $prodDurationHours;
} else {
// If not product used, we use the hour unit for duration and unit price.
$pu_ht_for_task = 0;
// If we want to reuse the value of timespent (so use same price than cost price)
if (!empty($conf->global->PROJECT_TIME_SPENT_INTO_INVOICE_USE_VALUE)) {
$pu_ht_for_task = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU');
}
$pa_ht = price2num($timespent_data['totalvaluetodivideby3600'] / $timespent_data['timespent'], 'MU');
} }
$pa_ht = price2num($value['totalvaluetodivideby3600'] / $value['timespent'], 'MU');
}
// Add lines // Add lines
$date_start = ''; $date_start = '';
$date_end = ''; $date_end = '';
$lineName = $ftask->ref.' - '.$ftask->label; $lineName = $ftask->ref . ' - ' . $ftask->label;
$lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtva, $localtax1, $localtax2, ($idprod > 0 ? $idprod : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht); $lineid = $tmpinvoice->addline($lineName, $pu_ht_for_task, price2num($qtyhour / $prodDurationHours, 'MS'), $txtvaline, $localtax1line, $localtax2line, ($idprodline > 0 ? $idprodline : 0), 0, $date_start, $date_end, 0, 0, '', 'HT', 0, 1, -1, 0, '', 0, 0, null, $pa_ht);
if ($lineid < 0) { if ($lineid < 0) {
$error++;
setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
break;
}
if (!$error) {
// Update lineid into line of timespent
$sql = 'UPDATE '.MAIN_DB_PREFIX.'projet_task_time SET invoice_line_id = '.((int) $lineid).', invoice_id = '.((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN ('.$db->sanitize(join(',', $toselect)).')';
$result = $db->query($sql);
if (!$result) {
$error++; $error++;
setEventMessages($db->lasterror(), null, 'errors'); setEventMessages($tmpinvoice->error, $tmpinvoice->errors, 'errors');
break; break;
} }
if (!$error) {
// Update lineid into line of timespent
$sql = 'UPDATE ' . MAIN_DB_PREFIX . 'projet_task_time SET invoice_line_id = ' . ((int) $lineid) . ', invoice_id = ' . ((int) $tmpinvoice->id);
$sql .= ' WHERE rowid IN (' . $db->sanitize(join(',', $toselect)) . ')';
$result = $db->query($sql);
if (!$result) {
$error++;
setEventMessages($db->lasterror(), null, 'errors');
break;
}
}
} }
} }
} }
@ -1085,6 +1207,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
} }
$arrayfields['author'] = array('label'=>$langs->trans("By"), 'checked'=>1); $arrayfields['author'] = array('label'=>$langs->trans("By"), 'checked'=>1);
$arrayfields['t.note'] = array('label'=>$langs->trans("Note"), 'checked'=>1); $arrayfields['t.note'] = array('label'=>$langs->trans("Note"), 'checked'=>1);
if ($conf->service->enabled && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
$arrayfields['t.fk_product'] = array('label' => $langs->trans("Product"), 'checked' => 1);
}
$arrayfields['t.task_duration'] = array('label'=>$langs->trans("Duration"), 'checked'=>1); $arrayfields['t.task_duration'] = array('label'=>$langs->trans("Duration"), 'checked'=>1);
$arrayfields['value'] = array('label'=>$langs->trans("Value"), 'checked'=>1, 'enabled'=>(empty($conf->salaries->enabled) ? 0 : 1)); $arrayfields['value'] = array('label'=>$langs->trans("Value"), 'checked'=>1, 'enabled'=>(empty($conf->salaries->enabled) ? 0 : 1));
$arrayfields['valuebilled'] = array('label'=>$langs->trans("Billed"), 'checked'=>1, 'enabled'=>(((!empty($conf->global->PROJECT_HIDE_TASKS) || empty($conf->global->PROJECT_BILL_TIME_SPENT)) ? 0 : 1) && $projectstatic->usage_bill_time)); $arrayfields['valuebilled'] = array('label'=>$langs->trans("Billed"), 'checked'=>1, 'enabled'=>(((!empty($conf->global->PROJECT_HIDE_TASKS) || empty($conf->global->PROJECT_BILL_TIME_SPENT)) ? 0 : 1) && $projectstatic->usage_bill_time));
@ -1312,6 +1437,7 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
$tasks = array(); $tasks = array();
$sql = "SELECT t.rowid, t.fk_task, t.task_date, t.task_datehour, t.task_date_withhour, t.task_duration, t.fk_user, t.note, t.thm,"; $sql = "SELECT t.rowid, t.fk_task, t.task_date, t.task_datehour, t.task_date_withhour, t.task_duration, t.fk_user, t.note, t.thm,";
$sql .= " t.fk_product,";
$sql .= " pt.ref, pt.label, pt.fk_projet,"; $sql .= " pt.ref, pt.label, pt.fk_projet,";
$sql .= " u.lastname, u.firstname, u.login, u.photo, u.statut as user_status,"; $sql .= " u.lastname, u.firstname, u.login, u.photo, u.statut as user_status,";
$sql .= " il.fk_facture as invoice_id, inv.fk_statut,"; $sql .= " il.fk_facture as invoice_id, inv.fk_statut,";
@ -1324,9 +1450,10 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
$sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t"; $sql .= " FROM ".MAIN_DB_PREFIX."projet_task_time as t";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet as il ON il.rowid = t.invoice_line_id"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facturedet as il ON il.rowid = t.invoice_line_id";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as inv ON inv.rowid = il.fk_facture"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."facture as inv ON inv.rowid = il.fk_facture";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."product as prod ON prod.rowid = t.fk_product";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet_task as pt ON pt.rowid = t.fk_task"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet_task as pt ON pt.rowid = t.fk_task";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON t.fk_user = u.rowid";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet as p ON p.rowid = pt.fk_projet"; $sql .= " INNER JOIN ".MAIN_DB_PREFIX."projet as p ON p.rowid = pt.fk_projet";
$sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON t.fk_user = u.rowid";
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s ON s.rowid = p.fk_soc";
// Add table from hooks // Add table from hooks
@ -1363,6 +1490,9 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
if ($search_user > 0) { if ($search_user > 0) {
$sql .= natural_search('t.fk_user', $search_user, 2); $sql .= natural_search('t.fk_user', $search_user, 2);
} }
if (!empty($search_product_ref)) {
$sql .= natural_search('prod.ref', $search_product_ref);
}
if ($search_valuebilled == '1') { if ($search_valuebilled == '1') {
$sql .= ' AND t.invoice_id > 0'; $sql .= ' AND t.invoice_id > 0';
} }
@ -1461,6 +1591,10 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
print '<td>'.$langs->trans("ProgressDeclared").'</td>'; print '<td>'.$langs->trans("ProgressDeclared").'</td>';
if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) { if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
print '<td></td>'; print '<td></td>';
if ($conf->service->enabled && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
print '<td>'.$langs->trans("Product").'</td>';
}
} }
// Hook fields // Hook fields
$parameters = array('mode' => 'create'); $parameters = array('mode' => 'create');
@ -1536,6 +1670,12 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) { if (empty($conf->global->PROJECT_HIDE_TASKS) && !empty($conf->global->PROJECT_BILL_TIME_SPENT)) {
print '<td>'; print '<td>';
print '</td>'; print '</td>';
if ($conf->service->enabled && $projectstatic->thirdparty->id > 0 && $projectstatic->usage_bill_time) {
print '<td class="nowrap">';
print $form->select_produits('', 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
print '</td>';
}
} }
// Fields from hook // Fields from hook
@ -1619,6 +1759,10 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
if (!empty($arrayfields['t.task_duration']['checked'])) { if (!empty($arrayfields['t.task_duration']['checked'])) {
print '<td class="liste_titre right"></td>'; print '<td class="liste_titre right"></td>';
} }
// Product
if (!empty($arrayfields['t.fk_product']['checked'])) {
print '<td class="liste_titre right"></td>';
}
// Value in main currency // Value in main currency
if (!empty($arrayfields['value']['checked'])) { if (!empty($arrayfields['value']['checked'])) {
print '<td class="liste_titre"></td>'; print '<td class="liste_titre"></td>';
@ -1670,6 +1814,10 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
if (!empty($arrayfields['t.task_duration']['checked'])) { if (!empty($arrayfields['t.task_duration']['checked'])) {
print_liste_field_titre($arrayfields['t.task_duration']['label'], $_SERVER['PHP_SELF'], 't.task_duration', '', $param, '', $sortfield, $sortorder, 'right '); print_liste_field_titre($arrayfields['t.task_duration']['label'], $_SERVER['PHP_SELF'], 't.task_duration', '', $param, '', $sortfield, $sortorder, 'right ');
} }
if (!empty($arrayfields['t.fk_product']['checked'])) {
print_liste_field_titre($arrayfields['t.fk_product']['label'], $_SERVER['PHP_SELF'], 't.fk_product', '', $param, '', $sortfield, $sortorder);
}
if (!empty($arrayfields['value']['checked'])) { if (!empty($arrayfields['value']['checked'])) {
print_liste_field_titre($arrayfields['value']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right '); print_liste_field_titre($arrayfields['value']['label'], $_SERVER['PHP_SELF'], '', '', $param, '', $sortfield, $sortorder, 'right ');
} }
@ -1860,6 +2008,23 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0 || $allprojectforuser
$totalarray['totalduration'] += $task_time->task_duration; $totalarray['totalduration'] += $task_time->task_duration;
} }
//Product
if (!empty($arrayfields['t.fk_product']['checked'])) {
print '<td class="nowraponall">';
if ($action == 'editline' && $_GET['lineid'] == $task_time->rowid) {
$form->select_produits($task_time->fk_product, 'fk_product', '1', 0, $projectstatic->thirdparty->price_level, 1, 2, '', 0, array(), $projectstatic->thirdparty->id, 'None', 0, 'maxwidth500');
} elseif (!empty($task_time->fk_product)) {
$product = new Product($db);
$resultFetch = $product->fetch($task_time->fk_product);
if ($resultFetch < 0) {
setEventMessages($product->error, $product->errors, 'errors');
} else {
print $product->getNomUrl(1);
}
}
print '</td>';
}
// Value spent // Value spent
if (!empty($arrayfields['value']['checked'])) { if (!empty($arrayfields['value']['checked'])) {
$langs->load("salaries"); $langs->load("salaries");