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

This commit is contained in:
Laurent Destailleur 2021-06-30 17:27:40 +02:00
commit aec4d6016c
10 changed files with 147 additions and 16 deletions

View File

@ -65,6 +65,7 @@ $search_filter = GETPOST("search_filter", 'alpha');
$search_status = GETPOST("search_status", 'intcomma'); $search_status = GETPOST("search_status", 'intcomma');
$catid = GETPOST("catid", 'int'); $catid = GETPOST("catid", 'int');
$optioncss = GETPOST('optioncss', 'alpha'); $optioncss = GETPOST('optioncss', 'alpha');
$socid = GETPOST('socid', 'int');
$filter = GETPOST("filter", 'alpha'); $filter = GETPOST("filter", 'alpha');
if ($filter) { if ($filter) {

View File

@ -57,10 +57,11 @@ class FormIntervention
* @param int $selected Id intervention preselected * @param int $selected Id intervention preselected
* @param string $htmlname Nom de la zone html * @param string $htmlname Nom de la zone html
* @param int $maxlength Maximum length of label * @param int $maxlength Maximum length of label
* @param int $showempty Show empty line * @param int $showempty Show empty line ('1' or string to show for empty line)
* @param int $draftonly Show only drafts intervention
* @return int Nbre of project if OK, <0 if KO * @return int Nbre of project if OK, <0 if KO
*/ */
public function select_interventions($socid = -1, $selected = '', $htmlname = 'interventionid', $maxlength = 16, $showempty = 1) public function select_interventions($socid = -1, $selected = '', $htmlname = 'interventionid', $maxlength = 16, $showempty = 1, $draftonly = false)
{ {
// phpcs:enable // phpcs:enable
global $db, $user, $conf, $langs; global $db, $user, $conf, $langs;
@ -80,13 +81,17 @@ class FormIntervention
$sql .= " AND f.fk_soc = ".((int) $socid); $sql .= " AND f.fk_soc = ".((int) $socid);
} }
} }
if ($draftonly) $sql .= " AND f.fk_statut = 0";
dol_syslog(get_class($this)."::select_intervention", LOG_DEBUG); dol_syslog(get_class($this)."::select_intervention", LOG_DEBUG);
$resql = $this->db->query($sql); $resql = $this->db->query($sql);
if ($resql) { if ($resql) {
$out .= '<select id="interventionid" class="flat" name="'.dol_escape_htmltag($htmlname).'">'; $out .= '<select id="interventionid" class="flat" name="'.dol_escape_htmltag($htmlname).'">';
if ($showempty) { if ($showempty) {
$out .= '<option value="0">&nbsp;</option>'; $out .= '<option value="0">';
if (!is_numeric($showempty)) $out .= $showempty;
else $out .= '&nbsp;';
$out .= '</option>';
} }
$num = $this->db->num_rows($resql); $num = $this->db->num_rows($resql);
$i = 0; $i = 0;
@ -102,7 +107,7 @@ class FormIntervention
$out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>'; $out .= '<option value="'.$obj->rowid.'" selected>'.$labeltoshow.'</option>';
} else { } else {
$disabled = 0; $disabled = 0;
if (!$obj->fk_statut > 0) { if (!$obj->fk_statut > 0 && ! $draftonly) {
$disabled = 1; $disabled = 1;
$labeltoshow .= ' ('.$langs->trans("Draft").')'; $labeltoshow .= ' ('.$langs->trans("Draft").')';
} }

View File

@ -202,7 +202,7 @@ $now = dol_now();
//$help_url="EN:Module_KnowledgeRecord|FR:Module_KnowledgeRecord_FR|ES:Módulo_KnowledgeRecord"; //$help_url="EN:Module_KnowledgeRecord|FR:Module_KnowledgeRecord_FR|ES:Módulo_KnowledgeRecord";
$help_url = ''; $help_url = '';
$title = $langs->trans('ListOfArticles'); $title = $langs->trans('ListKnowledgeRecord');
$morejs = array(); $morejs = array();
$morecss = array(); $morecss = array();

View File

@ -66,3 +66,4 @@ RepeatableIntervention=Template of intervention
ToCreateAPredefinedIntervention=To create a predefined or recurring intervention, create a common intervention and convert it into intervention template ToCreateAPredefinedIntervention=To create a predefined or recurring intervention, create a common intervention and convert it into intervention template
Reopen=Reopen Reopen=Reopen
ConfirmReopenIntervention=Are you sure you want to open back the intervention <b>%s</b>? ConfirmReopenIntervention=Are you sure you want to open back the intervention <b>%s</b>?
GenerateInter=Generate intervention

View File

@ -242,6 +242,7 @@ LatestModifiedProjects=Latest %s modified projects
OtherFilteredTasks=Other filtered tasks OtherFilteredTasks=Other filtered tasks
NoAssignedTasks=No assigned tasks found (assign project/tasks to the current user from the top select box to enter time on it) NoAssignedTasks=No assigned tasks found (assign project/tasks to the current user from the top select box to enter time on it)
ThirdPartyRequiredToGenerateInvoice=A third party must be defined on project to be able to invoice it. ThirdPartyRequiredToGenerateInvoice=A third party must be defined on project to be able to invoice it.
ThirdPartyRequiredToGenerateInvoice=A third party must be defined on project to be able to create intervention.
ChooseANotYetAssignedTask=Choose a task not yet assigned to you ChooseANotYetAssignedTask=Choose a task not yet assigned to you
# Comments trans # Comments trans
AllowCommentOnTask=Allow user comments on tasks AllowCommentOnTask=Allow user comments on tasks
@ -253,10 +254,12 @@ SendProjectRef=Information project %s
ModuleSalaryToDefineHourlyRateMustBeEnabled=Module 'Salaries' must be enabled to define employee hourly rate to have time spent valorized ModuleSalaryToDefineHourlyRateMustBeEnabled=Module 'Salaries' must be enabled to define employee hourly rate to have time spent valorized
NewTaskRefSuggested=Task ref already used, a new task ref is required NewTaskRefSuggested=Task ref already used, a new task ref is required
TimeSpentInvoiced=Time spent billed TimeSpentInvoiced=Time spent billed
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
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
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.
ProjectFollowOpportunity=Follow opportunity ProjectFollowOpportunity=Follow opportunity
ProjectFollowTasks=Follow tasks or time spent ProjectFollowTasks=Follow tasks or time spent
@ -265,7 +268,9 @@ UsageOpportunity=Usage: Opportunity
UsageTasks=Usage: Tasks UsageTasks=Usage: Tasks
UsageBillTimeShort=Usage: Bill time UsageBillTimeShort=Usage: Bill time
InvoiceToUse=Draft invoice to use InvoiceToUse=Draft invoice to use
InterToUse=Draft intervention to use
NewInvoice=New invoice NewInvoice=New invoice
NewInter=New intervention
OneLinePerTask=One line per task OneLinePerTask=One line per task
OneLinePerPeriod=One line per period OneLinePerPeriod=One line per period
OneLinePerTimeSpentLine=One line for each time spent declaration OneLinePerTimeSpentLine=One line for each time spent declaration

View File

@ -64,3 +64,4 @@ InterLineDuration=Durée ligne intervention
InterLineDesc=Description ligne intervention InterLineDesc=Description ligne intervention
RepeatableIntervention=Modèle d'intervention RepeatableIntervention=Modèle d'intervention
ToCreateAPredefinedIntervention=Pour créer une intervention prédéfinie ou récurrente, créez une intervention standard et convertissez-la en modèle d'intervention ToCreateAPredefinedIntervention=Pour créer une intervention prédéfinie ou récurrente, créez une intervention standard et convertissez-la en modèle d'intervention
GenerateInter=Générer une fiche d'intervention

View File

@ -241,6 +241,7 @@ LatestModifiedProjects=Les %s derniers projets modifiés
OtherFilteredTasks=Autres tâches filtrées OtherFilteredTasks=Autres tâches filtrées
NoAssignedTasks=Aucune tâche assignée (assignez un projet/tâche à l'utilisateur depuis la liste déroulante utilisateur en haut pour pouvoir saisir du temps dessus) NoAssignedTasks=Aucune tâche assignée (assignez un projet/tâche à l'utilisateur depuis la liste déroulante utilisateur en haut pour pouvoir saisir du temps dessus)
ThirdPartyRequiredToGenerateInvoice=Un tiers doit être défini sur le projet pour pouvoir le facturer. ThirdPartyRequiredToGenerateInvoice=Un tiers doit être défini sur le projet pour pouvoir le facturer.
ThirdPartyRequiredToGenerateIntervention=Un tiers doit être défini sur le projet pour pouvoir créer une intervention.
ChooseANotYetAssignedTask=Choisissez une tâche qui ne vous est pas encore assignée ChooseANotYetAssignedTask=Choisissez une tâche qui ne vous est pas encore assignée
# Comments trans # Comments trans
AllowCommentOnTask=Autoriser les utilisateurs à ajouter des commentaires sur les tâches AllowCommentOnTask=Autoriser les utilisateurs à ajouter des commentaires sur les tâches
@ -253,9 +254,11 @@ ModuleSalaryToDefineHourlyRateMustBeEnabled=Le module 'Paiement des salaires des
NewTaskRefSuggested=Réf de tâche déjà utilisée, une nouvelle référence de tâche est requise NewTaskRefSuggested=Réf de tâche déjà utilisée, une nouvelle référence de tâche est requise
TimeSpentInvoiced=Temps passé facturé TimeSpentInvoiced=Temps passé facturé
TimeSpentForInvoice=Temps consommés TimeSpentForInvoice=Temps consommés
TimeSpentForIntervention=Temps consommés
OneLinePerUser=Une ligne par utilisateur OneLinePerUser=Une ligne par utilisateur
ServiceToUseOnLines=Service à utiliser sur les lignes ServiceToUseOnLines=Service à utiliser sur les lignes
InvoiceGeneratedFromTimeSpent=La facture %s a été générée à partir du temps passé sur le projet InvoiceGeneratedFromTimeSpent=La facture %s a été générée à partir du temps passé sur le projet
InterventionGeneratedFromTimeSpent=L'intervention %s a été générée à partir du temps passé sur le projet
ProjectBillTimeDescription=Cochez si vous saisissez du temps sur les tâches du projet ET prévoyez de générer des factures à partir des temps pour facturer le client du projet (ne cochez pas si vous comptez créer une facture qui n'est pas basée sur la saisie des temps). Note: Pour générer une facture, aller sur l'onglet 'Temps consommé' du project et sélectionnez les lignes à inclure. ProjectBillTimeDescription=Cochez si vous saisissez du temps sur les tâches du projet ET prévoyez de générer des factures à partir des temps pour facturer le client du projet (ne cochez pas si vous comptez créer une facture qui n'est pas basée sur la saisie des temps). Note: Pour générer une facture, aller sur l'onglet 'Temps consommé' du project et sélectionnez les lignes à inclure.
ProjectFollowOpportunity=Suivre une opportunité ProjectFollowOpportunity=Suivre une opportunité
ProjectFollowTasks=Suivre des tâches ou du temps passé ProjectFollowTasks=Suivre des tâches ou du temps passé
@ -264,7 +267,9 @@ UsageOpportunity=Utilisation: Opportunité
UsageTasks=Utilisation: Tâches UsageTasks=Utilisation: Tâches
UsageBillTimeShort=Utilisation: Facturation du temps UsageBillTimeShort=Utilisation: Facturation du temps
InvoiceToUse=Facture brouillon à utiliser InvoiceToUse=Facture brouillon à utiliser
InterToUse=Intervention brouillon à utiliser
NewInvoice=Nouvelle facture NewInvoice=Nouvelle facture
NewInter=Nouvelle intervention
OneLinePerTask=Une ligne par tâche OneLinePerTask=Une ligne par tâche
OneLinePerPeriod=Une ligne par période OneLinePerPeriod=Une ligne par période
OneLinePerTimeSpentLine=One line for each time spent declaration OneLinePerTimeSpentLine=One line for each time spent declaration

View File

@ -354,10 +354,10 @@ if ((!empty($conf->product->enabled) || !empty($conf->service->enabled)) && ($us
print '<tr class="oddeven">'; print '<tr class="oddeven">';
print '<td class="nowrap">'; print '<td class="nowraponall tdoverflowmax100">';
print $product_static->getNomUrl(1, '', 16); print $product_static->getNomUrl(1, '', 16);
print "</td>\n"; print "</td>\n";
print '<td>'.dol_trunc($objp->label, 32).'</td>'; print '<td class="tdoverflowmax200" title="'.dol_escape_htmltag($objp->label).'">'.dol_escape_htmltag($objp->label).'</td>';
print "<td>"; print "<td>";
print dol_print_date($db->jdate($objp->datem), 'day'); print dol_print_date($db->jdate($objp->datem), 'day');
print "</td>"; print "</td>";

View File

@ -5,7 +5,7 @@
* Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es> * Copyright (C) 2011 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es> * Copyright (C) 2018 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr> * Copyright (C) 2018 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2019 Christophe Battarel <christophe@altairis.fr> * Copyright (C) 2019-2021 Christophe Battarel <christophe@altairis.fr>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by * it under the terms of the GNU General Public License as published by
@ -35,6 +35,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.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/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
require_once DOL_DOCUMENT_ROOT.'/core/class/html.formintervention.class.php';
// Load translation files required by the page // Load translation files required by the page
$langsLoad=array('projects', 'bills', 'orders'); $langsLoad=array('projects', 'bills', 'orders');
@ -115,7 +116,7 @@ $extrafields->fetch_name_optionals_label($object->table_element);
if (GETPOST('cancel', 'alpha')) { if (GETPOST('cancel', 'alpha')) {
$action = ''; $action = '';
} }
if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend' && $massaction != 'confirm_generateinvoice') { if (!GETPOST('confirmmassaction', 'alpha') && $massaction != 'presend' && $massaction != 'confirm_presend' && $massaction != 'confirm_generateinvoice' && $massaction != 'confirm_generateinter') {
$massaction = ''; $massaction = '';
} }
@ -536,6 +537,81 @@ if ($action == 'confirm_generateinvoice') {
} }
} }
if ($action == 'confirm_generateinter') {
$langs->load('interventions');
if (!empty($projectstatic->socid)) $projectstatic->fetch_thirdparty();
if (!($projectstatic->thirdparty->id > 0)) {
setEventMessages($langs->trans("ThirdPartyRequiredToGenerateIntervention"), null, 'errors');
} else {
include_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
include_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
include_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php';
require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
$tmpinter = new Fichinter($db);
$tmptimespent = new Task($db);
$fuser = new User($db);
$db->begin();
$interToUse = GETPOST('interid', 'int');
$tmpinter->socid = $projectstatic->thirdparty->id;
$tmpinter->date = dol_mktime(GETPOST('rehour', 'int'), GETPOST('remin', 'int'), GETPOST('resec', 'int'), GETPOST('remonth', 'int'), GETPOST('reday', 'int'), GETPOST('reyear', 'int'));
$tmpinter->fk_project = $projectstatic->id;
$tmpinter->description = $projectstatic->title . ( ! empty($projectstatic->description) ? '-' . $projectstatic->label : '' );
if ($interToUse) {
$tmpinter->fetch($interToUse);
} else {
$result = $tmpinter->create($user);
if ($result <= 0) {
$error++;
setEventMessages($tmpinter->error, $tmpinter->errors, 'errors');
}
}
if (!$error) {
$arrayoftasks = array();
foreach ($toselect as $key => $value) {
// Get userid, timepent
$object->fetchTimeSpent($value);
// $object->id is the task id
$arrayoftasks[$object->timespent_id]['timespent'] = $object->timespent_duration;
$arrayoftasks[$object->timespent_id]['totalvaluetodivideby3600'] = $object->timespent_duration * $object->timespent_thm;
$arrayoftasks[$object->timespent_id]['note'] = $object->timespent_note;
$arrayoftasks[$object->timespent_id]['date'] = date('Y-m-d H:i:s', $object->timespent_datehour);
}
foreach ($arrayoftasks as $timespent_id => $value) {
$ftask = new Task($db);
$ftask->fetch($object->id);
// Define qty per hour
$qtyhour = $value['timespent'] / 3600;
$qtyhourtext = convertSecondToTime($value['timespent'], 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
// Add lines
$lineid = $tmpinter->addline($user, $tmpinter->id, $ftask->label . ( ! empty($value['note']) ? ' - ' . $value['note'] : '' ), $value['date'], $value['timespent']);
}
}
if (!$error) {
$urltointer = $tmpinter->getNomUrl(0);
$mesg = $langs->trans("InterventionGeneratedFromTimeSpent", '{s1}');
$mesg = str_replace('{s1}', $urltointer, $mesg);
setEventMessages($mesg, null, 'mesgs');
//var_dump($tmpinvoice);
$db->commit();
} else {
$db->rollback();
}
}
}
/* /*
* View * View
@ -749,12 +825,16 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
'generateinvoice'=>$langs->trans("GenerateBill"), 'generateinvoice'=>$langs->trans("GenerateBill"),
//'builddoc'=>$langs->trans("PDFMerge"), //'builddoc'=>$langs->trans("PDFMerge"),
); );
}
if ( ! empty($conf->ficheinter->enabled) && $user->rights->ficheinter->creer) {
$langs->load("interventions");
$arrayofmassactions['generateinter'] = $langs->trans("GenerateInter");
}
//if ($user->rights->projet->creer) $arrayofmassactions['predelete']='<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete"); //if ($user->rights->projet->creer) $arrayofmassactions['predelete']='<span class="fa fa-trash paddingrightonly"></span>'.$langs->trans("Delete");
if (in_array($massaction, array('presend', 'predelete', 'generateinvoice'))) { if (in_array($massaction, array('presend', 'predelete', 'generateinvoice', 'generateinter'))) {
$arrayofmassactions = array(); $arrayofmassactions = array();
} }
$massactionbutton = $form->selectMassAction('', $arrayofmassactions); $massactionbutton = $form->selectMassAction('', $arrayofmassactions);
}
// Show section with information of task. If id of task is not defined and project id defined, then $projectidforalltimes is not empty. // Show section with information of task. If id of task is not defined and project id defined, then $projectidforalltimes is not empty.
if (empty($projectidforalltimes)) { if (empty($projectidforalltimes)) {
@ -944,6 +1024,8 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
print '<input type="hidden" name="action" value="addtimespent">'; print '<input type="hidden" name="action" value="addtimespent">';
} elseif ($massaction == 'generateinvoice' && $user->rights->facture->lire) { } elseif ($massaction == 'generateinvoice' && $user->rights->facture->lire) {
print '<input type="hidden" name="action" value="confirm_generateinvoice">'; print '<input type="hidden" name="action" value="confirm_generateinvoice">';
} elseif ($massaction == 'generateinter' && $user->rights->ficheinter->lire) {
print '<input type="hidden" name="action" value="confirm_generateinter">';
} else { } else {
print '<input type="hidden" name="action" value="list">'; print '<input type="hidden" name="action" value="list">';
} }
@ -1026,6 +1108,36 @@ if (($id > 0 || !empty($ref)) || $projectidforalltimes > 0) {
print '</div>'; print '</div>';
$massaction = ''; $massaction = '';
} }
} elseif ($massaction == 'generateinter') {
// Form to convert time spent into invoice
print '<input type="hidden" name="massaction" value="confirm_createinter">';
if ($projectstatic->thirdparty->id > 0) {
print '<table class="noborder" width="100%" >';
print '<tr>';
print '<td class="titlefield">';
print $langs->trans('InterToUse');
print '</td>';
print '<td>';
$forminter = new FormIntervention($db);
print $forminter->select_interventions($projectstatic->thirdparty->id, '', 'interid', 24, $langs->trans('NewInter'), true);
print '</td>';
print '</tr>';
print '</table>';
print '<br>';
print '<div class="center">';
print '<input type="submit" class="button" id="createinter" name="createinter" value="'.$langs->trans('GenerateInter').'"> ';
print '<input type="submit" class="button" id="cancel" name="cancel" value="'.$langs->trans('Cancel').'">';
print '</div>';
print '<br>';
} else {
print '<div class="warning">'.$langs->trans("ThirdPartyRequiredToGenerateIntervention").'</div>';
print '<div class="center">';
print '<input type="submit" class="button" id="cancel" name="cancel" value="'.$langs->trans('Cancel').'">';
print '</div>';
$massaction = '';
}
} }
/* /*

View File

@ -185,6 +185,7 @@ $thirdpartygraph .= '</td></tr>';
$thirdpartygraph .= '</table>'; $thirdpartygraph .= '</table>';
$thirdpartygraph .= '</div>'; $thirdpartygraph .= '</div>';
$thirdpartycateggraph = '';
if (!empty($conf->categorie->enabled) && !empty($conf->global->CATEGORY_GRAPHSTATS_ON_THIRDPARTIES)) { if (!empty($conf->categorie->enabled) && !empty($conf->global->CATEGORY_GRAPHSTATS_ON_THIRDPARTIES)) {
require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
$elementtype = 'societe'; $elementtype = 'societe';