dolibarr 25.0.0-alpha
element.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2001-2004 Rodolphe Quiedeville <rodolphe@quiedeville.org>
3 * Copyright (C) 2004-2020 Laurent Destailleur <eldy@users.sourceforge.net>
4 * Copyright (C) 2005-2010 Regis Houssin <regis.houssin@inodbox.com>
5 * Copyright (C) 2012-2016 Juanjo Menent <jmenent@2byte.es>
6 * Copyright (C) 2015-2021 Alexandre Spangaro <aspangaro@open-dsi.fr>
7 * Copyright (C) 2015 Marcos García <marcosgdf@gmail.com>
8 * Copyright (C) 2016 Josep Lluís Amador <joseplluis@lliuretic.cat>
9 * Copyright (C) 2021-2023 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
10 * Copyright (C) 2021 Noé Cendrier <noe.cendrier@altairis.fr>
11 * Copyright (C) 2023-2025 Frédéric France <frederic.france@free.fr>
12 * Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
13 * Copyright (C) 2025 Günter Lukas <github@gl.co.at>
14 * Copyright (C) 2026 Joachim Kueter <git-jk@bloxera.com>
15 * Copyright (C) 2026 Ferran Marcet <fmarcet@2byte.es>
16 *
17 * This program is free software; you can redistribute it and/or modify
18 * it under the terms of the GNU General Public License as published by
19 * the Free Software Foundation; either version 3 of the License, or
20 * (at your option) any later version.
21 *
22 * This program is distributed in the hope that it will be useful,
23 * but WITHOUT ANY WARRANTY; without even the implied warranty of
24 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 * GNU General Public License for more details.
26 *
27 * You should have received a copy of the GNU General Public License
28 * along with this program. If not, see <https://www.gnu.org/licenses/>.
29 */
30
37// Load Dolibarr environment
38require '../main.inc.php';
48require_once DOL_DOCUMENT_ROOT.'/projet/class/project.class.php';
49require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php';
50require_once DOL_DOCUMENT_ROOT.'/core/class/html.formprojet.class.php';
51require_once DOL_DOCUMENT_ROOT.'/core/lib/project.lib.php';
52require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php';
53require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php';
54require_once DOL_DOCUMENT_ROOT.'/core/class/timespent.class.php';
55
56if (isModEnabled('agenda')) {
57 require_once DOL_DOCUMENT_ROOT.'/comm/action/class/actioncomm.class.php';
58}
59if (isModEnabled('bank')) {
60 require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/paymentvarious.class.php';
61}
62if (isModEnabled('category')) {
63 require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php';
64}
65if (isModEnabled('order')) {
66 require_once DOL_DOCUMENT_ROOT.'/commande/class/commande.class.php';
67}
68if (isModEnabled('contract')) {
69 require_once DOL_DOCUMENT_ROOT.'/contrat/class/contrat.class.php';
70}
71if (isModEnabled('don')) {
72 require_once DOL_DOCUMENT_ROOT.'/don/class/don.class.php';
73}
74if (isModEnabled('shipping')) {
75 require_once DOL_DOCUMENT_ROOT.'/expedition/class/expedition.class.php';
76}
77if (isModEnabled('expensereport')) {
78 require_once DOL_DOCUMENT_ROOT.'/expensereport/class/expensereport.class.php';
79}
80if (isModEnabled('invoice')) {
81 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php';
82 require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php';
83}
84if (isModEnabled('intervention')) {
85 require_once DOL_DOCUMENT_ROOT.'/fichinter/class/fichinter.class.php';
86}
87if (isModEnabled('loan')) {
88 require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php';
89 require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php';
90}
91if (isModEnabled('mrp')) {
92 require_once DOL_DOCUMENT_ROOT.'/mrp/class/mo.class.php';
93}
94if (isModEnabled('propal')) {
95 require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php';
96}
97if (isModEnabled('salaries')) {
98 require_once DOL_DOCUMENT_ROOT.'/salaries/class/salary.class.php';
99}
100if (isModEnabled('stock')) {
101 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/entrepot.class.php';
102 require_once DOL_DOCUMENT_ROOT.'/product/stock/class/mouvementstock.class.php';
103}
104if (isModEnabled('supplier_invoice')) {
105 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php';
106}
107if (isModEnabled('supplier_order')) {
108 require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.commande.class.php';
109}
110if (isModEnabled('supplier_proposal')) {
111 require_once DOL_DOCUMENT_ROOT.'/supplier_proposal/class/supplier_proposal.class.php';
112}
113if (isModEnabled('tax')) {
114 require_once DOL_DOCUMENT_ROOT.'/compta/sociales/class/chargesociales.class.php';
115}
116if (isModEnabled('stocktransfer')) {
117 require_once DOL_DOCUMENT_ROOT.'/product/stock/stocktransfer/class/stocktransfer.class.php';
118 require_once DOL_DOCUMENT_ROOT.'/product/stock/stocktransfer/class/stocktransferline.class.php';
119}
120
121// Load translation files required by the page
122$langs->loadLangs(array('projects', 'companies', 'suppliers', 'compta'));
123if (isModEnabled('invoice')) {
124 $langs->load("bills");
125}
126if (isModEnabled('order')) {
127 $langs->load("orders");
128}
129if (isModEnabled("propal")) {
130 $langs->load("propal");
131}
132if (isModEnabled('intervention')) {
133 $langs->load("interventions");
134}
135if (isModEnabled('deplacement')) {
136 $langs->load("trips");
137}
138if (isModEnabled('expensereport')) {
139 $langs->load("trips");
140}
141if (isModEnabled('don')) {
142 $langs->load("donations");
143}
144if (isModEnabled('loan')) {
145 $langs->load("loan");
146}
147if (isModEnabled('salaries')) {
148 $langs->load("salaries");
149}
150if (isModEnabled('mrp')) {
151 $langs->load("mrp");
152}
153if (isModEnabled('eventorganization')) {
154 $langs->load("eventorganization");
155}
156
157$id = GETPOSTINT('id');
158$ref = GETPOST('ref', 'alpha');
159$action = GETPOST('action', 'aZ09');
160$datesrfc = GETPOST('datesrfc'); // deprecated
161$dateerfc = GETPOST('dateerfc'); // deprecated
162$dates = dol_mktime(0, 0, 0, GETPOSTINT('datesmonth'), GETPOSTINT('datesday'), GETPOSTINT('datesyear'));
163$datee = dol_mktime(23, 59, 59, GETPOSTINT('dateemonth'), GETPOSTINT('dateeday'), GETPOSTINT('dateeyear'));
164if (empty($dates) && !empty($datesrfc)) { // deprecated
165 $dates = dol_stringtotime($datesrfc);
166}
167if (empty($datee) && !empty($dateerfc)) { // deprecated
168 $datee = dol_stringtotime($dateerfc);
169}
170if (!GETPOSTISSET('datesrfc') && !GETPOSTISSET('datesday') && getDolGlobalString('PROJECT_LINKED_ELEMENT_DEFAULT_FILTER_YEAR')) {
171 $new = dol_now();
172 $tmp = dol_getdate($new);
173 //$datee=$now
174 //$dates=dol_time_plus_duree($datee, -1, 'y');
175 $dates = dol_get_first_day($tmp['year'], 1);
176}
177if ($id == '' && $ref == '') {
178 setEventMessage($langs->trans('ErrorBadParameters'), 'errors');
179 header('Location: list.php');
180 exit();
181}
182
183$mine = GETPOST('mode') == 'mine' ? 1 : 0;
184
185$object = new Project($db);
186
187include DOL_DOCUMENT_ROOT.'/core/actions_fetchobject.inc.php'; // Must be 'include', not 'include_once'
188if (getDolGlobalString('PROJECT_ALLOW_COMMENT_ON_PROJECT') && method_exists($object, 'fetchComments') && empty($object->comments)) {
189 $object->fetchComments();
190}
191
192// Security check
193$socid = $object->socid;
194
195$hookmanager->initHooks(array('projectOverview'));
196
197//if ($user->socid > 0) $socid = $user->socid; // For external user, no check is done on company because readability is managed by public status of project and assignment.
198$result = restrictedArea($user, 'projet', $object->id, 'projet&project');
199
200// Check if user has access to any financial module (not just project time)
201$canSeeFinancials = (
202 (isModEnabled('invoice') && $user->hasRight('facture', 'lire'))
203 || (isModEnabled('supplier_invoice') && ($user->hasRight('fournisseur', 'facture', 'lire') || $user->hasRight('supplier_invoice', 'lire')))
204 || (isModEnabled('salaries') && $user->hasRight('salaries', 'read'))
205 || (isModEnabled('expensereport') && $user->hasRight('expensereport', 'lire'))
206 || (isModEnabled('don') && $user->hasRight('don', 'lire'))
207 || (isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire'))
208 || (isModEnabled('bank') && $user->hasRight('banque', 'lire'))
209);
210
211$total_duration = 0;
212$total_ttc_by_line = 0;
213$total_ht_by_line = 0;
214$expensereport = null;
215$othermessage = '';
216$tmpprojtime = array();
217$nbAttendees = 0;
218
219$extrafields->fetch_name_optionals_label($object->table_element);
220$object->fetch_optionals();
221
222$permissiontoadd = $user->hasRight('projet', 'creer');
223$permissiontodelete = $user->hasRight('projet', 'supprimer');
224$permissiondellink = $user->hasRight('projet', 'creer'); // Used by the include of actions_dellink.inc.php
225$permissiontoeditextra = $permissiontoadd;
226if (GETPOST('attribute', 'aZ09') && isset($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')])) {
227 // For action 'update_extras', is there a specific permission set for the attribute to update
228 $permissiontoeditextra = dol_eval($extrafields->attributes[$object->table_element]['perms'][GETPOST('attribute', 'aZ09')]);
229}
230
231/*
232 * Actions
233 */
234
235// Quick edit for extrafields
236if ($action == 'update_extras' && $permissiontoeditextra) {
237 $error = 0;
238 $object->oldcopy = dol_clone($object, 2); // @phan-suppress-current-line PhanTypeMismatchProperty
239
240 $attribute_name = GETPOST('attribute', 'aZ09');
241
242 // Fill array 'array_options' with data from update form
243 $ret = $extrafields->setOptionalsFromPost(null, $object, $attribute_name);
244 if ($ret < 0) {
245 $error++;
246 }
247
248 if (!$error) {
249 $result = $object->updateExtraField($attribute_name, 'PROJECT_MODIFY');
250 if ($result < 0) {
251 setEventMessages($object->error, $object->errors, 'errors');
252 $error++;
253 }
254 }
255
256 if ($error) {
257 $action = 'edit_extras';
258 }
259}
260if (($action == 'updateundefinedwithlasthourlyrate' || $action == 'updateallwithlasthourlyrate') && $permissiontoadd) {
261 $error = 0;
262 if (!GETPOSTISSET('taskid')) {
263 $error++;
264 }
265 if (!$error) {
266 $taskid = GETPOSTINT("taskid");
267
268 $sql = "SELECT et.rowid as id, u.thm as thmuser";
269 $sql .= " FROM ".MAIN_DB_PREFIX."element_time as et";
270 $sql .= " INNER JOIN ".MAIN_DB_PREFIX."user as u ON u.rowid = et.fk_user";
271 $sql .= " WHERE et.elementtype = 'task'";
272 $sql .= " AND et.fk_element = ".((int) $taskid);
273 if ($action == 'updateundefinedwithlasthourlyrate') { // Test on permission already done
274 $sql .= " AND et.thm IS NULL"; // Note: If 0, it is defined, we won't update it.
275 }
276
277 $resql = $db->query($sql);
278 if ($resql) {
279 $num = $db->num_rows($resql);
280 $i = 0;
281 while ($i < $num) {
282 $obj = $db->fetch_object($resql);
283 if (empty($obj->thmuser)) {
284 $error++;
285 break;
286 }
287 $timespent = new TimeSpent($db);
288 $res = $timespent->fetch($obj->id);
289 if ($res <= 0) {
290 setEventMessages($timespent->error, $timespent->errors, 'errors');
291 $error++;
292 break;
293 }
294 $timespent->thm = $obj->thmuser;
295 $res = $timespent->update($user);
296 if ($res <= 0) {
297 setEventMessages($timespent->error, $timespent->errors, 'errors');
298 $error++;
299 break;
300 }
301 $i++;
302 }
303 } else {
304 dol_print_error($db);
305 $error++;
306 }
307 }
308 if (!$error) {
309 $db->commit();
310 setEventMessages($langs->trans("TaskHourlyRateUpdated"), null);
311 $action = '';
312 } else {
313 $db->rollback();
314 }
315}
316
317
318/*
319 * View
320 */
321
322$title = $langs->trans('ProjectReferers').' - '.$object->ref.' '.$object->name;
323if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/projectnameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) {
324 $title = $object->ref.' '.$object->name.' - '.$langs->trans('ProjectReferers');
325}
326
327$help_url = 'EN:Module_Projects|FR:Module_Projets|ES:M&oacute;dulo_Proyectos|DE:Modul_Projekte';
328
329llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-project page-card_element');
330
331$form = new Form($db);
332$formproject = new FormProjets($db);
333$formfile = new FormFile($db);
334
335$userstatic = new User($db);
336
337// To verify role of users
338$userAccess = $object->restrictedProjectArea($user);
339
340$head = project_prepare_head($object);
341print dol_get_fiche_head($head, 'element', $langs->trans("Project"), -1, ($object->public ? 'projectpub' : 'project'));
342
343
344// Project card
345
346if (!empty($_SESSION['pageforbacktolist']) && !empty($_SESSION['pageforbacktolist']['project'])) {
347 $tmpurl = $_SESSION['pageforbacktolist']['project'];
348 $tmpurl = preg_replace('/__SOCID__/', (string) $object->socid, $tmpurl);
349 $linkback = '<a href="'.$tmpurl.(preg_match('/\?/', $tmpurl) ? '&' : '?'). 'restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
350} else {
351 $linkback = '<a href="'.DOL_URL_ROOT.'/projet/list.php?restore_lastsearch_values=1">'.$langs->trans("BackToList").'</a>';
352}
353
354$morehtmlref = '<div class="refidno">';
355// Title
356$morehtmlref .= $object->title;
357// Thirdparty
358if (!empty($object->thirdparty->id) && $object->thirdparty->id > 0) {
359 $morehtmlref .= '<br>'.$object->thirdparty->getNomUrl(1, 'project');
360}
361$morehtmlref .= '</div>';
362
363// Define a complementary filter for search of next/prev ref.
364if (!$user->hasRight('projet', 'all', 'lire')) {
365 $objectsListId = $object->getProjectsAuthorizedForUser($user, 0, 0);
366 $object->next_prev_filter = "te.rowid:IN:".$db->sanitize(count($objectsListId) ? implode(',', array_keys($objectsListId)) : '0');
367}
368
369dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref);
370
371
372print '<div class="fichecenter">';
373print '<div class="fichehalfleft">';
374print '<div class="underbanner clearboth"></div>';
375
376print '<table class="border tableforfield centpercent">';
377
378// Usage
379if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') || !getDolGlobalString('PROJECT_HIDE_TASKS') || isModEnabled('eventorganization')) {
380 print '<tr><td class="tdtop">';
381 print $langs->trans("Usage");
382 print '</td>';
383 print '<td>';
384 if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES')) {
385 print '<input type="checkbox" disabled name="usage_opportunity"'.(GETPOSTISSET('usage_opportunity') ? (GETPOST('usage_opportunity', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_opportunity ? ' checked="checked"' : '')).'"> ';
386 $htmltext = $langs->trans("ProjectFollowOpportunity");
387 print $form->textwithpicto($langs->trans("ProjectFollowOpportunity"), $htmltext);
388 print '<br>';
389 }
390 if (!getDolGlobalString('PROJECT_HIDE_TASKS')) {
391 print '<input type="checkbox" disabled name="usage_task"'.(GETPOSTISSET('usage_task') ? (GETPOST('usage_task', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_task ? ' checked="checked"' : '')).'"> ';
392 $htmltext = $langs->trans("ProjectFollowTasks");
393 print $form->textwithpicto($langs->trans("ProjectFollowTasks"), $htmltext);
394 print '<br>';
395 }
396 if (!getDolGlobalString('PROJECT_HIDE_TASKS') && getDolGlobalString('PROJECT_BILL_TIME_SPENT')) {
397 print '<input type="checkbox" disabled name="usage_bill_time"'.(GETPOSTISSET('usage_bill_time') ? (GETPOST('usage_bill_time', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_bill_time ? ' checked="checked"' : '')).'"> ';
398 $htmltext = $langs->trans("ProjectBillTimeDescription");
399 print $form->textwithpicto($langs->trans("BillTime"), $htmltext);
400 print '<br>';
401 }
402 if (isModEnabled('eventorganization')) {
403 print '<input type="checkbox" disabled name="usage_organize_event"'.(GETPOSTISSET('usage_organize_event') ? (GETPOST('usage_organize_event', 'alpha') != '' ? ' checked="checked"' : '') : ($object->usage_organize_event ? ' checked="checked"' : '')).'"> ';
404 $htmltext = $langs->trans("EventOrganizationDescriptionLong");
405 print $form->textwithpicto($langs->trans("ManageOrganizeEvent"), $htmltext);
406 }
407 print '</td></tr>';
408}
409
410if (getDolGlobalString('PROJECT_USE_OPPORTUNITIES') && !empty($object->usage_opportunity)) {
411 // Opportunity status
412 print '<tr><td>'.$langs->trans("OpportunityStatus").'</td><td>';
413 $percent_value = (GETPOSTISSET('opp_percent') ? GETPOSTINT('opp_percent') : (strcmp($object->opp_percent, '') ? vatrate($object->opp_percent) : ''));
414 print $formproject->formOpportunityStatus($_SERVER['PHP_SELF'].'?socid='.$object->id, (string) $object->opp_status, $percent_value, 'none', 'none', '', 1);
415 print '</td></tr>';
416
417 // Opportunity Amount
418 print '<tr><td>'.$langs->trans("OpportunityAmount").'</td><td>';
419 if (strcmp($object->opp_amount, '')) {
420 print '<span class="amount">'.price($object->opp_amount, 0, $langs, 1, 0, -1, $conf->currency).'</span>';
421 if (strcmp($object->opp_percent, '')) {
422 print ' &nbsp; &nbsp; &nbsp; <span title="'.dol_escape_htmltag($langs->trans('OpportunityWeightedAmount')).'"><span class="opacitymedium">'.$langs->trans("OpportunityWeightedAmountShort").'</span>: <span class="amount">'.price($object->opp_amount * $object->opp_percent / 100, 0, $langs, 1, 0, -1, $conf->currency).'</span></span>';
423 }
424 }
425 print '</td></tr>';
426}
427
428// Budget
429print '<tr><td>'.$langs->trans("Budget").'</td><td>';
430if (!is_null($object->budget_amount) && strcmp($object->budget_amount, '')) {
431 print '<span class="amount">'.price($object->budget_amount, 0, $langs, 1, 0, 0, $conf->currency).'</span>';
432}
433print '</td></tr>';
434
435// Date start - end project
436print '<tr><td>'.$langs->trans("Dates").'</td><td>';
437$start = dol_print_date($object->date_start, 'day');
438print($start ? $start : '?');
439$end = dol_print_date($object->date_end, 'day');
440print ' - ';
441print($end ? $end : '?');
442if ($object->hasDelay()) {
443 print img_warning("Late");
444}
445print '</td></tr>';
446
447// Visibility
448print '<tr><td class="titlefield">'.$langs->trans("Visibility").'</td><td>';
449if ($object->public) {
450 print img_picto($langs->trans('SharedProject'), 'world', 'class="paddingrightonly"');
451 print $langs->trans('SharedProject');
452} else {
453 print img_picto($langs->trans('PrivateProject'), 'private', 'class="paddingrightonly"');
454 print $langs->trans('PrivateProject');
455}
456print '</td></tr>';
457
458// Other attributes
459$cols = 2;
460include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_view.tpl.php';
461
462print '</table>';
463
464print '</div>';
465print '<div class="fichehalfright">';
466print '<div class="underbanner clearboth"></div>';
467
468print '<table class="border tableforfield centpercent">';
469
470// Categories
471if (isModEnabled('category')) {
472 print '<tr><td class="valignmiddle">'.$langs->trans("Categories").'</td><td>';
473 print $form->showCategories($object->id, Categorie::TYPE_PROJECT, 1);
474 print "</td></tr>";
475}
476
477// Description
478print '<tr><td class="titlefield'.($object->description ? ' noborderbottom' : '').'" colspan="2">'.$langs->trans("Description").'</td></tr>';
479if ($object->description) {
480 print '<tr><td class="nottitleforfield" colspan="2">';
481 print '<div class="longmessagecut">';
482 print dolPrintHTML($object->description);
483 print '</div>';
484 print '</td></tr>';
485}
486
487print '</table>';
488
489print '</div>';
490print '</div>';
491
492print '<div class="clearboth"></div>';
493
494print dol_get_fiche_end();
495
496print '<br>';
497
498/*
499 * Referrer types
500 */
501
502$listofreferent = array(
503 'entrepot' => array(
504 'name' => "Warehouse",
505 'title' => "ListWarehouseAssociatedProject",
506 'class' => 'Entrepot',
507 'table' => 'entrepot',
508 'datefieldname' => 'date_entrepot',
509 'urlnew' => DOL_URL_ROOT.'/product/stock/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
510 'lang' => 'entrepot',
511 'buttonnew' => 'AddWarehouse',
512 'project_field' => 'fk_project',
513 'testnew' => $user->hasRight('stock', 'creer'),
514 'test' => isModEnabled('stock') && $user->hasRight('stock', 'lire') && getDolGlobalString('WAREHOUSE_ASK_WAREHOUSE_DURING_PROJECT')
515 ),
516 'propal' => array(
517 'name' => "Proposals",
518 'title' => "ListProposalsAssociatedProject",
519 'class' => 'Propal',
520 'table' => 'propal',
521 'datefieldname' => 'datep',
522 'urlnew' => DOL_URL_ROOT.'/comm/propal/card.php?action=create&origin=project&originid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
523 'lang' => 'propal',
524 'buttonnew' => 'AddProp',
525 'testnew' => $user->hasRight('propal', 'creer'),
526 'test' => isModEnabled('propal') && $user->hasRight('propal', 'lire')
527 ),
528 'order' => array(
529 'name' => "CustomersOrders",
530 'title' => "ListOrdersAssociatedProject",
531 'class' => 'Commande',
532 'table' => 'commande',
533 'datefieldname' => 'date_commande',
534 'urlnew' => DOL_URL_ROOT.'/commande/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
535 'lang' => 'orders',
536 'buttonnew' => 'CreateOrder',
537 'testnew' => $user->hasRight('commande', 'creer'),
538 'test' => isModEnabled('order') && $user->hasRight('commande', 'lire')
539 ),
540 'invoice' => array(
541 'name' => "CustomersInvoices",
542 'title' => "ListInvoicesAssociatedProject",
543 'class' => 'Facture',
544 'margin' => 'add',
545 'table' => 'facture',
546 'datefieldname' => 'datef',
547 'urlnew' => DOL_URL_ROOT.'/compta/facture/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
548 'lang' => 'bills',
549 'buttonnew' => 'CreateBill',
550 'testnew' => $user->hasRight('facture', 'creer'),
551 'test' => isModEnabled('invoice') && $user->hasRight('facture', 'lire')
552 ),
553 'invoice_predefined' => array(
554 'name' => "PredefinedInvoices",
555 'title' => "ListPredefinedInvoicesAssociatedProject",
556 'class' => 'FactureRec',
557 'table' => 'facture_rec',
558 'datefieldname' => 'datec',
559 'urlnew' => DOL_URL_ROOT.'/compta/facture/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
560 'lang' => 'bills',
561 'buttonnew' => 'CreateBill',
562 'testnew' => $user->hasRight('facture', 'creer'),
563 'test' => isModEnabled('invoice') && $user->hasRight('facture', 'lire')
564 ),
565 'proposal_supplier' => array(
566 'name' => "SupplierProposals",
567 'title' => "ListSupplierProposalsAssociatedProject",
568 'class' => 'SupplierProposal',
569 'table' => 'supplier_proposal',
570 'datefieldname' => 'date_valid',
571 'urlnew' => DOL_URL_ROOT.'/supplier_proposal/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id), // No socid parameter here, the socid is often the customer and we create a supplier object
572 'lang' => 'supplier_proposal',
573 'buttonnew' => 'AddSupplierProposal',
574 'testnew' => $user->hasRight('supplier_proposal', 'creer'),
575 'test' => isModEnabled('supplier_proposal') && $user->hasRight('supplier_proposal', 'lire')
576 ),
577 'order_supplier' => array(
578 'name' => "SuppliersOrders",
579 'title' => "ListSupplierOrdersAssociatedProject",
580 'class' => 'CommandeFournisseur',
581 'table' => 'commande_fournisseur',
582 'datefieldname' => 'date_commande',
583 'urlnew' => DOL_URL_ROOT.'/fourn/commande/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id), // No socid parameter here, the socid is often the customer and we create a supplier object
584 'lang' => 'suppliers',
585 'buttonnew' => 'AddSupplierOrder',
586 'testnew' => $user->hasRight('fournisseur', 'commande', 'creer') || $user->hasRight('supplier_order', 'creer'),
587 'test' => isModEnabled('supplier_order') && $user->hasRight('fournisseur', 'commande', 'lire') || $user->hasRight('supplier_order', 'lire')
588 ),
589 'invoice_supplier' => array(
590 'name' => "BillsSuppliers",
591 'title' => "ListSupplierInvoicesAssociatedProject",
592 'class' => 'FactureFournisseur',
593 'margin' => 'minus',
594 'table' => 'facture_fourn',
595 'datefieldname' => 'datef',
596 'urlnew' => DOL_URL_ROOT.'/fourn/facture/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id), // No socid parameter here, the socid is often the customer and we create a supplier object
597 'lang' => 'suppliers',
598 'buttonnew' => 'AddSupplierInvoice',
599 'testnew' => $user->hasRight('fournisseur', 'facture', 'creer') || $user->hasRight('supplier_invoice', 'creer'),
600 'test' => isModEnabled('supplier_invoice') && $user->hasRight('fournisseur', 'facture', 'lire') || $user->hasRight('supplier_invoice', 'lire')
601 ),
602 'contract' => array(
603 'name' => "Contracts",
604 'title' => "ListContractAssociatedProject",
605 'class' => 'Contrat',
606 'table' => 'contrat',
607 'datefieldname' => 'date_contrat',
608 'urlnew' => DOL_URL_ROOT.'/contrat/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
609 'lang' => 'contracts',
610 'buttonnew' => 'AddContract',
611 'testnew' => $user->hasRight('contrat', 'creer'),
612 'test' => isModEnabled('contract') && $user->hasRight('contrat', 'lire')
613 ),
614 'intervention' => array(
615 'name' => "Interventions",
616 'title' => "ListFichinterAssociatedProject",
617 'class' => 'Fichinter',
618 'table' => 'fichinter',
619 'datefieldname' => 'date_valid',
620 'disableamount' => 0,
621 'margin' => '',
622 'urlnew' => DOL_URL_ROOT.'/fichinter/card.php?action=create&origin=project&originid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
623 'lang' => 'interventions',
624 'buttonnew' => 'AddIntervention',
625 'testnew' => $user->hasRight('ficheinter', 'creer'),
626 'test' => isModEnabled('intervention') && $user->hasRight('ficheinter', 'lire')
627 ),
628 'shipping' => array(
629 'name' => "Shippings",
630 'title' => "ListShippingAssociatedProject",
631 'class' => 'Expedition',
632 'table' => 'expedition',
633 'datefieldname' => 'date_valid',
634 'urlnew' => DOL_URL_ROOT.'/expedition/card.php?action=create&origin=project&originid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
635 'lang' => 'sendings',
636 'buttonnew' => 'CreateShipment',
637 'testnew' => 0,
638 'test' => isModEnabled('shipping') && $user->hasRight('expedition', 'lire')
639 ),
640 'mrp' => array(
641 'name' => "MO",
642 'title' => "ListMOAssociatedProject",
643 'class' => 'Mo',
644 'table' => 'mrp_mo',
645 'datefieldname' => 'date_valid',
646 'urlnew' => DOL_URL_ROOT.'/mrp/mo_card.php?action=create&origin=project&originid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
647 'lang' => 'mrp',
648 'buttonnew' => 'CreateMO',
649 'testnew' => $user->hasRight('mrp', 'write'),
650 'project_field' => 'fk_project',
651 'nototal' => 1,
652 'test' => isModEnabled('mrp') && $user->hasRight('mrp', 'read')
653 ),
654 'expensereport' => array(
655 'name' => "ExpenseReports",
656 'title' => "ListExpenseReportsAssociatedProject",
657 'class' => 'ExpenseReportLine',
658 'table' => 'expensereport_det',
659 'datefieldname' => 'date',
660 'margin' => 'minus',
661 'disableamount' => 0,
662 'urlnew' => DOL_URL_ROOT.'/expensereport/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
663 'lang' => 'trips',
664 'buttonnew' => 'AddTrip',
665 'testnew' => $user->hasRight('expensereport', 'creer'),
666 'test' => isModEnabled('expensereport') && $user->hasRight('expensereport', 'lire')
667 ),
668 'donation' => array(
669 'name' => "Donation",
670 'title' => "ListDonationsAssociatedProject",
671 'class' => 'Don',
672 'margin' => 'add',
673 'table' => 'don',
674 'datefieldname' => 'datedon',
675 'disableamount' => 0,
676 'urlnew' => DOL_URL_ROOT.'/don/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
677 'lang' => 'donations',
678 'buttonnew' => 'AddDonation',
679 'testnew' => $user->hasRight('don', 'creer'),
680 'test' => isModEnabled('don') && $user->hasRight('don', 'lire')
681 ),
682 'loan' => array(
683 'name' => "Loan",
684 'title' => "ListLoanAssociatedProject",
685 'class' => 'Loan',
686 'margin' => '',
687 'table' => 'loan',
688 'datefieldname' => 'datestart',
689 'disableamount' => 0,
690 'urlnew' => DOL_URL_ROOT.'/loan/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
691 'lang' => 'loan',
692 'buttonnew' => 'AddLoan',
693 'testnew' => $user->hasRight('loan', 'write'),
694 'test' => isModEnabled('loan') && $user->hasRight('loan', 'read')
695 ),
696 'chargesociales' => array(
697 'name' => "SocialContribution",
698 'title' => "ListSocialContributionAssociatedProject",
699 'class' => 'ChargeSociales',
700 'margin' => 'minus',
701 'table' => 'chargesociales',
702 'datefieldname' => 'date_ech',
703 'disableamount' => 0,
704 'urlnew' => DOL_URL_ROOT.'/compta/sociales/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
705 'lang' => 'compta',
706 'buttonnew' => 'AddSocialContribution',
707 'testnew' => $user->hasRight('tax', 'charges', 'lire'),
708 'test' => isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')
709 ),
710 'project_task' => array(
711 'name' => "TaskTimeSpent",
712 'title' => "ListTaskTimeUserProject",
713 'class' => 'Task',
714 'margin' => 'minus',
715 'table' => 'projet_task',
716 'datefieldname' => 'element_date',
717 'disableamount' => ($canSeeFinancials ? 0 : 1),
718 'urlnew' => DOL_URL_ROOT.'/projet/tasks/time.php?withproject=1&action=createtime&projectid='.$id.'&token='.newToken().'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
719 'buttonnew' => 'AddTimeSpent',
720 'testnew' => $user->hasRight('project', 'creer'),
721 'test' => isModEnabled('project') && $user->hasRight('projet', 'lire') && !getDolGlobalString('PROJECT_HIDE_TASKS')
722 ),
723 'stocktransfer' => array(
724 'name' => "StockTransfer",
725 'title' => "ListStockTransferProject",
726 'class' => 'StockTransfer',
727 'table' => 'stocktransfer_stocktransfer',
728 'datefieldname' => 'datem',
729 'margin' => '',
730 'project_field' => 'fk_project',
731 'disableamount' => 1,
732 'urlnew' => DOL_URL_ROOT.'/product/stock/stocktransfer/stocktransfer_card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
733 'lang' => 'stocks',
734 'buttonnew' => 'StockTransferNew',
735 'testnew' => $user->hasRight('stocktransfer', 'stocktransfer', 'write'),
736 'test' => isModEnabled('stocktransfer') && $user->hasRight('stocktransfer', 'stocktransfer', 'read')
737 ),
738 'stock_mouvement' => array(
739 'name' => "MouvementStockAssociated",
740 'title' => "ListMouvementStockProject",
741 'class' => 'MouvementStock',
742 'table' => 'stock_mouvement',
743 'datefieldname' => 'datem',
744 'margin' => 'minus',
745 'project_field' => 'fk_project',
746 'disableamount' => 0,
747 'test' => isModEnabled('stock') && $user->hasRight('stock', 'mouvement', 'lire') && getDolGlobalString('STOCK_MOVEMENT_INTO_PROJECT_OVERVIEW')
748 ),
749 'salaries' => array(
750 'name' => "Salaries",
751 'title' => "ListSalariesAssociatedProject",
752 'class' => 'Salary',
753 'table' => 'salary',
754 'datefieldname' => 'datesp',
755 'margin' => 'minus',
756 'disableamount' => 0,
757 'urlnew' => DOL_URL_ROOT.'/salaries/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
758 'lang' => 'salaries',
759 'buttonnew' => 'AddSalary',
760 'testnew' => $user->hasRight('salaries', 'write'),
761 'test' => isModEnabled('salaries') && $user->hasRight('salaries', 'read')
762 ),
763 'variouspayment' => array(
764 'name' => "VariousPayments",
765 'title' => "ListVariousPaymentsAssociatedProject",
766 'class' => 'PaymentVarious',
767 'table' => 'payment_various',
768 'datefieldname' => 'datev',
769 'margin' => 'minus',
770 'disableamount' => 0,
771 'urlnew' => DOL_URL_ROOT.'/compta/bank/various_payment/card.php?action=create&projectid='.$id.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
772 'lang' => 'banks',
773 'buttonnew' => 'AddVariousPayment',
774 'testnew' => $user->hasRight('banque', 'modifier'),
775 'test' => isModEnabled("bank") && $user->hasRight('banque', 'lire') && !getDolGlobalString('BANK_USE_OLD_VARIOUS_PAYMENT')
776 ),
777 /* No need for this, available on dedicated tab "Agenda/Events"
778 'agenda'=>array(
779 'name'=>"Agenda",
780 'title'=>"ListActionsAssociatedProject",
781 'class'=>'ActionComm',
782 'table'=>'actioncomm',
783 'datefieldname'=>'datep',
784 'disableamount'=>1,
785 'urlnew'=>DOL_URL_ROOT.'/comm/action/card.php?action=create&projectid='.$id.'&socid='.$socid.'&backtopage='.urlencode($_SERVER['PHP_SELF'].'?id='.$id),
786 'lang'=>'agenda',
787 'buttonnew'=>'AddEvent',
788 'testnew'=>$user->rights->agenda->myactions->create,
789 'test'=> isModEnabled('agenda') && $user->hasRight('agenda', 'myactions', 'read')),
790 */
791);
792
793// Change rules for profit/benefit calculation
794if (getDolGlobalString('PROJECT_ELEMENTS_FOR_PLUS_MARGIN')) {
795 foreach ($listofreferent as $key => $element) {
796 if ($listofreferent[$key]['margin'] == 'add') {
797 unset($listofreferent[$key]['margin']);
798 }
799 }
800 $newelementforplusmargin = explode(',', getDolGlobalString('PROJECT_ELEMENTS_FOR_PLUS_MARGIN'));
801 foreach ($newelementforplusmargin as $value) {
802 $listofreferent[trim($value)]['margin'] = 'add';
803 }
804}
805if (getDolGlobalString('PROJECT_ELEMENTS_FOR_MINUS_MARGIN')) {
806 foreach ($listofreferent as $key => $element) {
807 if ($listofreferent[$key]['margin'] == 'minus') {
808 unset($listofreferent[$key]['margin']);
809 }
810 }
811 $newelementforminusmargin = explode(',', getDolGlobalString('PROJECT_ELEMENTS_FOR_MINUS_MARGIN'));
812 foreach ($newelementforminusmargin as $value) {
813 $listofreferent[trim($value)]['margin'] = 'minus';
814 }
815}
816
817
818$parameters = array('listofreferent' => $listofreferent);
819$resHook = $hookmanager->executeHooks('completeListOfReferent', $parameters, $object, $action);
820
821if (!empty($hookmanager->resArray)) {
822 $listofreferent = array_merge($listofreferent, $hookmanager->resArray);
823} elseif ($resHook > 0 && !empty($hookmanager->resPrint)) {
824 $listofreferent = $hookmanager->resPrint;
825}
826
827if (in_array($action, ['addelement', 'unlink'])) {
828 // Only an element type listed (and allowed) on this page can be linked or unlinked, using the project field it declares
829 $tablename = GETPOST("tablename", "aZ09");
830 $projectField = '';
831 $excludeselect = ['payment_various'];
832 foreach ($listofreferent as $value) {
833 if (!empty($value['test']) && isset($value['table']) && $value['table'] === $tablename) {
834 $projectField = empty($value['project_field']) ? 'fk_projet' : $value['project_field'];
835 if (!empty($value['exclude_select_element'])) {
836 $excludeselect[] = $value['exclude_select_element'];
837 }
838 break;
839 }
840 }
841 if (!$permissiontoadd || $projectField === ''
842 || ($action == 'addelement' && (getDolGlobalString('PROJECT_LINK_ON_OVERWIEW_DISABLED') || in_array($tablename, $excludeselect)))
843 || ($action == 'unlink' && (in_array($tablename, ['projet_task', 'stock_mouvement']) || (getDolGlobalString('PROJECT_DISABLE_UNLINK_FROM_OVERVIEW') && !$user->admin)))) {
844 accessforbidden('', 0, 0);
845 }
846
847 $elementselectid = GETPOSTINT("elementselect");
848 if ($action == "addelement") {
849 $result = $object->update_element($tablename, $elementselectid);
850 } else {
851 $result = $object->remove_element($tablename, $elementselectid, $projectField);
852 }
853 if ($result < 0) {
854 setEventMessages($object->error, $object->errors, 'errors');
855 }
856}
857
858$elementuser = new User($db);
859
860
861
862$showdatefilter = 0;
863// Show the filter on date on top of element list
864if (!$showdatefilter) {
865 print '<div class="center centpercent">';
866 print '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="POST">';
867 print '<input type="hidden" name="token" value="'.newToken().'">';
868 print '<input type="hidden" name="tablename" value="'.(empty($tablename) ? '' : $tablename).'">';
869 print '<input type="hidden" name="action" value="view">';
870 print '<div class="inline-block">';
871 print $form->selectDate($dates, 'dates', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("From"));
872 print '</div>';
873 print '<div class="inline-block">';
874 print $form->selectDate($datee, 'datee', 0, 0, 1, '', 1, 0, 0, '', '', '', '', 1, '', $langs->trans("to"));
875 print '</div>';
876 print '<div class="inline-block">';
877 print '<input type="submit" name="refresh" value="'.$langs->trans("Refresh").'" class="button small">';
878 print '</div>';
879 print '</form>';
880 print '</div>';
881
882 $showdatefilter++;
883}
884
885
886
887// Show balance for whole project
888
889$langs->loadLangs(array("suppliers", "bills", "orders", "proposals", "margins"));
890
891if (isModEnabled('stock') || isModEnabled('stocktransfer')) {
892 $langs->load('stocks');
893}
894
895print '<!-- Begin PROFIT table -->';
896print load_fiche_titre($langs->trans("Profit"), '', 'title_accountancy');
897
898print '<div class="div-table-responsive">';
899print '<table class="noborder centpercent">';
900print '<tr class="liste_titre">';
901print '<td class="left" width="200">';
902$tooltiponprofit = $langs->trans("ProfitIsCalculatedWith")."<br>\n";
903$tooltiponprofitplus = $tooltiponprofitminus = '';
904foreach ($listofreferent as $key => $value) {
905 if (!empty($value['lang'])) {
906 $langs->load($value['lang']);
907 }
908 $name = $langs->trans($value['name']);
909 $qualified = $value['test'];
910 $margin = empty($value['margin']) ? '' : $value['margin'];
911 if ($qualified && $margin) { // If this element must be included into profit calculation ($margin is 'minus' or 'add')
912 if ($margin === 'add') {
913 $tooltiponprofitplus .= ' &gt; '.$name." (+)<br>\n";
914 } elseif ($margin === 'minus') {
915 $tooltiponprofitminus .= ' &gt; '.$name." (-)<br>\n";
916 }
917 }
918}
919$tooltiponprofit .= $tooltiponprofitplus;
920$tooltiponprofit .= $tooltiponprofitminus;
921print $form->textwithpicto($langs->trans("Element"), $tooltiponprofit);
922print '</td>';
923print '<td class="right" width="100">'.$langs->trans("Number").'</td>';
924print '<td class="right" width="100">'.$langs->trans("AmountHT").'</td>';
925print '<td class="right" width="100">'.$langs->trans("AmountTTC").'</td>';
926print '</tr>';
927
928$total_revenue_ht = 0;
929$balance_ht = 0;
930$balance_ttc = 0;
931
932// Loop on each element type (proposal, sale order, invoices, ...)
933foreach ($listofreferent as $key => $value) {
934 $parameters = array(
935 'total_revenue_ht' => & $total_revenue_ht,
936 'balance_ht' => & $balance_ht,
937 'balance_ttc' => & $balance_ttc,
938 'key' => $key,
939 'value' => & $value,
940 'dates' => $dates,
941 'datee' => $datee
942 );
943 $reshook = $hookmanager->executeHooks('printOverviewProfit', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
944 if ($reshook < 0) {
945 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
946 } elseif ($reshook > 0) {
947 print $hookmanager->resPrint;
948 continue;
949 }
950
951 $name = $langs->trans($value['name']);
952 $title = $value['title'];
953 $classname = $value['class'];
954 $tablename = $value['table'];
955 $datefieldname = $value['datefieldname'];
956 $qualified = $value['test'];
957 // Hide project_task amounts in profit section for users without financial access
958 if ($key === 'project_task' && !$canSeeFinancials) {
959 $qualified = false;
960 }
961 $margin = empty($value['margin']) ? 0 : $value['margin'];
962 $project_field = empty($value['project_field']) ? '' : $value['project_field'];
963 if ($qualified) { // If this element must be included into profit summary table ($margin is '', 'minus' or 'add')
964 $element = new $classname($db);
965
966 $elementarray = $object->get_element_list($key, $tablename, $datefieldname, $dates, $datee, !empty($project_field) ? $project_field : 'fk_projet');
967
968 if (is_array($elementarray) && count($elementarray) > 0) {
969 $total_ht = 0;
970 $total_ttc = 0;
971 $i = 0;
972
973 // Loop on each object for the current element type
974 $num = count($elementarray);
975 for ($i = 0; $i < $num; $i++) {
976 $tmp = explode('_', $elementarray[$i]);
977 $idofelement = (int) $tmp[0];
978 $idofelementuser = !empty($tmp[1]) ? (int) $tmp[1] : 0;
979
980 $element->fetch($idofelement);
981 if ($idofelementuser) {
982 $elementuser->fetch($idofelementuser);
983 }
984
985 // Define if record must be used for total or not
986 $qualifiedfortotal = true;
987 if ($key == 'invoice') {
988 if (!empty($element->close_code) && $element->close_code == 'replaced') {
989 $qualifiedfortotal = false; // Replacement invoice, do not include into total
990 }
991 if (getDolGlobalString('FACTURE_DEPOSITS_ARE_JUST_PAYMENTS') && $element->type == Facture::TYPE_DEPOSIT) {
992 $qualifiedfortotal = false; // If hidden option to use deposits as payment (deprecated, not recommended to use this), deposits are not included
993 }
994 if (getDolGlobalString('PROJECT_ONLY_PAYED_INVOICE_ON_PROFIT') && $element->status != Facture::STATUS_CLOSED) {
995 $qualifiedfortotal = false; // Only paid invoices qualify
996 }
997 }
998 if ($key == 'propal') {
999 if ($element->status != Propal::STATUS_SIGNED && $element->status != Propal::STATUS_BILLED) {
1000 $qualifiedfortotal = false; // Only signed proposal must not be included in total
1001 }
1002 }
1003
1004 if ($tablename != 'expensereport_det' && method_exists($element, 'fetch_thirdparty')) {
1005 $element->fetch_thirdparty();
1006 }
1007
1008 // Define $total_ht_by_line
1009 if ($tablename == 'don' || $tablename == 'chargesociales' || $tablename == 'payment_various' || $tablename == 'salary') {
1010 '@phan-var-force ChargeSociales|PaymentVarious|Salary $element';
1011 $total_ht_by_line = $element->amount;
1012 } elseif ($tablename == 'fichinter') {
1013 '@phan-var-force Fichinter $element';
1014 $total_ht_by_line = $element->getAmount();
1015 } elseif ($tablename == 'stock_mouvement') {
1016 '@phan-var-force MouvementStock $element';
1017 $total_ht_by_line = $element->price * abs($element->qty);
1018 } elseif ($tablename == 'projet_task') {
1019 '@phan-var-force Task $element';
1020 $tmp = $element->getSumOfAmount($idofelementuser ? $elementuser : '', (string) $dates, (string) $datee);
1021 $total_ht_by_line = price2num($tmp['amount'], 'MT');
1022 } elseif ($key == 'loan') {
1023 '@phan-var-force Loan $element';
1024 if ((empty($dates) && empty($datee)) || (intval($dates) <= $element->datestart && intval($datee) >= $element->dateend)) {
1025 // Get total loan
1026 $total_ht_by_line = -$element->capital;
1027 } else {
1028 // Get loan schedule according to date filter
1029 $total_ht_by_line = 0;
1030 $loanScheduleStatic = new LoanSchedule($element->db);
1031 $loanScheduleStatic->fetchAll($element->id);
1032 if (!empty($loanScheduleStatic->lines)) {
1033 foreach ($loanScheduleStatic->lines as $loanSchedule) {
1037 if (($loanSchedule->datep >= $dates && $loanSchedule->datep <= $datee) // dates filter is defined
1038 || !empty($dates) && empty($datee) && $loanSchedule->datep >= $dates && $loanSchedule->datep <= dol_now()
1039 || empty($dates) && !empty($datee) && $loanSchedule->datep <= $datee
1040 ) {
1041 $total_ht_by_line -= $loanSchedule->amount_capital;
1042 }
1043 }
1044 }
1045 }
1046 } else {
1047 $total_ht_by_line = $element->total_ht;
1048 }
1049
1050 // Define $total_ttc_by_line
1051 if ($tablename == 'don' || $tablename == 'chargesociales' || $tablename == 'payment_various' || $tablename == 'salary') {
1052 '@phan-var-force ChargeSociales|PaymentVarious|Salary $element';
1053 $total_ttc_by_line = $element->amount;
1054 } elseif ($tablename == 'fichinter') {
1055 '@phan-var-force Fichinter $element';
1056 $total_ttc_by_line = $element->getAmount();
1057 } elseif ($tablename == 'stock_mouvement') {
1058 '@phan-var-force MouvementStock $element';
1059 $total_ttc_by_line = $element->price * abs($element->qty);
1060 } elseif ($tablename == 'projet_task') {
1061 '@phan-var-force Task $element';
1062 $defaultvat = get_default_tva($mysoc, $mysoc);
1063 $reg = array();
1064 if (preg_replace('/^(\d+\.)\s\‍(.*\‍)/', $defaultvat, $reg)) {
1065 // @phan-suppress-next-line PhanTypeInvalidDimOffset
1066 $defaultvat = $reg[1];
1067 }
1068 $total_ttc_by_line = price2num($total_ht_by_line * (1 + ((float) $defaultvat / 100)), 'MT');
1069 } elseif ($key == 'loan') {
1070 $total_ttc_by_line = $total_ht_by_line; // For loan there is actually no taxe managed in Dolibarr
1071 } else {
1072 $total_ttc_by_line = $element->total_ttc;
1073 }
1074
1075 // Change sign of $total_ht_by_line and $total_ttc_by_line for various payments
1076 if ($tablename == 'payment_various') {
1077 if ($element->sens == 1) {
1078 $total_ht_by_line = -$total_ht_by_line;
1079 $total_ttc_by_line = -$total_ttc_by_line;
1080 }
1081 }
1082
1083 // Change sign of $total_ht_by_line and $total_ttc_by_line for supplier proposal and supplier order.
1084 // Skip when the element already participates to the margin computation via margin='minus'
1085 // (line 1095 below will revert sign too, and double-negation would silently flip the value
1086 // back to positive - see PROJECT_ELEMENTS_FOR_MINUS_MARGIN=order_supplier in #34684).
1087 if (($tablename == 'commande_fournisseur' || $tablename == 'supplier_proposal') && $margin !== 'minus') {
1088 $total_ht_by_line = -$total_ht_by_line;
1089 $total_ttc_by_line = -$total_ttc_by_line;
1090 }
1091
1092 // Add total if we have to
1093 if ($qualifiedfortotal) {
1094 $total_ht += $total_ht_by_line;
1095 $total_ttc += $total_ttc_by_line;
1096 }
1097 }
1098
1099 // Each element with at least one line is output
1100
1101 // Calculate margin
1102 if ($margin) {
1103 if ($margin === 'add') {
1104 $total_revenue_ht += $total_ht;
1105 }
1106
1107 if ($margin === "minus") { // Revert sign
1108 $total_ht = -$total_ht;
1109 $total_ttc = -$total_ttc;
1110 }
1111
1112 $balance_ht += $total_ht;
1113 $balance_ttc += $total_ttc;
1114 }
1115
1116 print '<tr class="oddeven">';
1117 // Module
1118 print '<!-- // Module '.$name.' with tablename '.$tablename.' -->';
1119 print '<td class="left"><a href="#table_'.$tablename.'">'.$name.'</a></td>';
1120 // Nb
1121 print '<td class="right">'.$i.'</td>';
1122 // Amount HT
1123 print '<td class="right">';
1124 if ($key == 'intervention' && !$margin) {
1125 print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NA"), $langs->trans("AmountOfInteventionNotIncludedByDefault")).'</span>';
1126 } elseif ($key == 'stocktransfer') {
1127 print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NA"), $langs->trans("NoAmountforStockTransfer")).'</span>';
1128 } else {
1129 if ($key == 'propal') {
1130 print '<span class="opacitymedium">'.$form->textwithpicto('', $langs->trans("SignedOnly")).'</span>';
1131 }
1132 print price($total_ht);
1133 }
1134 print '</td>';
1135 // Amount TTC
1136 print '<td class="right">';
1137 if ($key == 'intervention' && !$margin) {
1138 print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NA"), $langs->trans("AmountOfInteventionNotIncludedByDefault")).'</span>';
1139 } elseif ($key == 'stocktransfer') {
1140 print '<span class="opacitymedium">'.$form->textwithpicto($langs->trans("NA"), $langs->trans("NoAmountforStockTransfer")).'</span>';
1141 } else {
1142 if ($key == 'propal') {
1143 print '<span class="opacitymedium">'.$form->textwithpicto('', $langs->trans("SignedOnly")).'</span>';
1144 }
1145 print price($total_ttc);
1146 }
1147 print '</td>';
1148 print '</tr>';
1149 }
1150 }
1151}
1152// and the final balance
1153print '<tr class="liste_total">';
1154print '<td class="right" colspan="2">'.$langs->trans("Profit").'</td>';
1155print '<td class="right">'.price(price2num($balance_ht, 'MT')).'</td>';
1156print '<td class="right">'.price(price2num($balance_ttc, 'MT')).'</td>';
1157print '</tr>';
1158
1159// and the cost per attendee
1160if ($object->usage_organize_event) {
1161 require_once DOL_DOCUMENT_ROOT.'/eventorganization/class/conferenceorboothattendee.class.php';
1162 $conforboothattendee = new ConferenceOrBoothAttendee($db);
1163 $result = $conforboothattendee->fetchAll('', '', 0, 0, '(t.fk_project:=:'.((int) $object->id).') AND (t.status:=:'.ConferenceOrBoothAttendee::STATUS_VALIDATED.')');
1164
1165 if (!is_array($result) && $result < 0) {
1166 setEventMessages($conforboothattendee->error, $conforboothattendee->errors, 'errors');
1167 } else {
1168 $nbAttendees = count($result);
1169 }
1170
1171 if ($nbAttendees >= 2) {
1172 $costperattendee_ht = $balance_ht / $nbAttendees;
1173 $costperattendee_ttc = $balance_ttc / $nbAttendees;
1174 print '<tr class="liste_total">';
1175 print '<td class="right" colspan="2">'.$langs->trans("ProfitPerValidatedAttendee").'</td>';
1176 print '<td class="right">'.price(price2num($costperattendee_ht, 'MT')).'</td>';
1177 print '<td class="right">'.price(price2num($costperattendee_ttc, 'MT')).'</td>';
1178 print '</tr>';
1179 }
1180}
1181
1182// and the margin (profit / revenues)
1183if ($total_revenue_ht) {
1184 print '<tr class="liste_total">';
1185 print '<td class="right" colspan="2">'.$langs->trans("Margin").'</td>';
1186 print '<td class="right">'.round(100 * $balance_ht / $total_revenue_ht, 1).'%</td>';
1187 print '<td class="right"></td>';
1188 print '</tr>';
1189}
1190
1191print "</table>";
1192print '</div>';
1193print '<!-- End PROFIT table -->';
1194
1195
1196print '<br><br>';
1197print '<br>';
1198
1199
1200$total_time = 0;
1201
1202// Detail
1203foreach ($listofreferent as $key => $value) {
1204 $parameters = array(
1205 'key' => $key,
1206 'value' => & $value,
1207 'dates' => $dates,
1208 'datee' => $datee
1209 );
1210 $reshook = $hookmanager->executeHooks('printOverviewDetail', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1211 if ($reshook < 0) {
1212 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1213 } elseif ($reshook > 0) {
1214 print $hookmanager->resPrint;
1215 continue;
1216 }
1217
1218 $title = $value['title'];
1219 $classname = $value['class'];
1220 $tablename = $value['table'];
1221 $datefieldname = $value['datefieldname'];
1222 $qualified = $value['test'];
1223 $urlnew = empty($value['urlnew']) ? '' : $value['urlnew'];
1224 $buttonnew = empty($value['buttonnew']) ? '' : $value['buttonnew'];
1225 $testnew = empty($value['testnew']) ? '' : $value['testnew'];
1226 $project_field = empty($value['project_field']) ? '' : $value['project_field'];
1227 $nototal = empty($value['nototal']) ? 0 : 1;
1228
1229 $exclude_select_element = array('payment_various');
1230 if (!empty($value['exclude_select_element'])) {
1231 $exclude_select_element[] = $value['exclude_select_element'];
1232 }
1233
1234 if ($qualified && $tablename !== null) {
1235 // If we want the project task array to have details of users
1236 //if ($key == 'project_task') $key = 'project_task_time';
1237
1238 $element = new $classname($db);
1239
1240 $addform = '';
1241
1242 $idtofilterthirdparty = 0;
1243 $array_of_element_linkable_with_different_thirdparty = array('facture_fourn', 'commande_fournisseur');
1244 if (!in_array($tablename, $array_of_element_linkable_with_different_thirdparty)) {
1245 $idtofilterthirdparty = empty($object->thirdparty->id) ? 0 : $object->thirdparty->id;
1246 if (getDolGlobalString('PROJECT_OTHER_THIRDPARTY_ID_TO_ADD_ELEMENTS')) {
1247 $idtofilterthirdparty .= ',' . getDolGlobalString('PROJECT_OTHER_THIRDPARTY_ID_TO_ADD_ELEMENTS');
1248 }
1249 }
1250
1251 $elementarray = $object->get_element_list($key, $tablename, $datefieldname, $dates, $datee, !empty($project_field) ? $project_field : 'fk_projet');
1252
1253
1254 if ($permissiontoadd && !getDolGlobalString('PROJECT_LINK_ON_OVERWIEW_DISABLED') && $idtofilterthirdparty && !in_array($tablename, $exclude_select_element)) {
1255 $selectList = $formproject->select_element($tablename, $idtofilterthirdparty, 'minwidth300 minwidth75imp', -2, empty($project_field) ? 'fk_projet' : $project_field, $langs->trans("SelectElement"));
1256 if ((int) $selectList < 0) { // cast to int because ''<0 is true.
1257 setEventMessages($formproject->error, $formproject->errors, 'errors');
1258 } elseif ($selectList) {
1259 // Define form with the combo list of elements to link
1260 $addform .= '<div class="inline-block valignmiddle">';
1261 $addform .= '<form action="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'" method="post">';
1262 $addform .= '<input type="hidden" name="token" value="'.newToken().'">';
1263 $addform .= '<input type="hidden" name="tablename" value="'.$tablename.'">';
1264 $addform .= '<input type="hidden" name="action" value="addelement">';
1265 $addform .= '<input type="hidden" name="datesrfc" value="'.dol_print_date($dates, 'dayhourrfc').'">';
1266 $addform .= '<input type="hidden" name="dateerfc" value="'.dol_print_date($datee, 'dayhourrfc').'">';
1267 $addform .= '<table><tr>';
1268 //$addform .= '<td><span class="hideonsmartphone opacitymedium">'.$langs->trans("SelectElement").'</span></td>';
1269 $addform .= '<td>'.$selectList.'</td>';
1270 $addform .= '<td><input type="submit" class="button button-linkto smallpaddingimp" value="'.dol_escape_htmltag($langs->trans("LinkToElementShort")).'"></td>';
1271 $addform .= '</tr></table>';
1272 $addform .= '</form>';
1273 $addform .= '</div>';
1274 }
1275 }
1276 if (!getDolGlobalString('PROJECT_CREATE_ON_OVERVIEW_DISABLED') && $urlnew) {
1277 $addform .= '<div class="inline-block valignmiddle">';
1278 if ($testnew) {
1279 $addform .= '<a class="buttonxxx marginleftonly" href="'.$urlnew.'" title="'.dol_escape_htmltag($langs->trans($buttonnew)).'"><span class="fa fa-plus-circle valignmiddle paddingleft"></span></a>';
1280 } elseif (!getDolGlobalString('MAIN_BUTTON_HIDE_UNAUTHORIZED')) {
1281 $addform .= '<span title="'.dol_escape_htmltag($langs->trans($buttonnew)).'"><a class="buttonxxx marginleftonly buttonRefused" disabled="disabled" href="#"><span class="fa fa-plus-circle valignmiddle paddingleft"></span></a></span>';
1282 }
1283 $addform .= '<div>';
1284 }
1285
1286 if (is_array($elementarray) && count($elementarray) > 0 && $key == "order_supplier") {
1287 $addform .= '<div class="inline-block valignmiddle"><a id="btnShow" class="buttonxxx marginleftonly" href="#" onClick="return false;">
1288 <span id="textBtnShow" class="valignmiddle text-plus-circle hideonsmartphone">'.$langs->trans("CanceledShown").'</span><span id="minus-circle" class="fa fa-eye valignmiddle paddingleft"></span>
1289 </a>
1290 <script>
1291 $("#btnShow").on("click", function () {
1292 console.log("We click to show or hide the canceled lines");
1293 var attr = $(this).attr("data-canceledarehidden");
1294 if (typeof attr !== "undefined" && attr !== false) {
1295 console.log("Show canceled");
1296 $(".tr_canceled").show();
1297 $("#textBtnShow").text(\''.dol_escape_js($langs->transnoentitiesnoconv("CanceledShown")).'\');
1298 $("#btnShow").removeAttr("data-canceledarehidden");
1299 $("#minus-circle").removeClass("fa-eye-slash").addClass("fa-eye");
1300 } else {
1301 console.log("Hide canceled");
1302 $(".tr_canceled").hide();
1303 $("#textBtnShow").text(\''.dol_escape_js($langs->transnoentitiesnoconv("CanceledHidden")).'\');
1304 $("#btnShow").attr("data-canceledarehidden", 1);
1305 $("#minus-circle").removeClass("fa-eye").addClass("fa-eye-slash");
1306 }
1307 });
1308 </script></div>';
1309
1310 $addform .= '<div class="inline-block valignmiddle"><a id="btnShowPaid" class="buttonxxx marginleftonly" href="#" onClick="return false;">
1311 <span id="textBtnShowPaid" class="valignmiddle text-plus-circle hideonsmartphone">'.$langs->trans("PaidShown").'</span><span id="minus-circle-paid" class="fa fa-eye valignmiddle paddingleft"></span>
1312 </a>
1313 <script>
1314 $("#btnShowPaid").on("click", function () {
1315 console.log("We click to show or hide the paid lines");
1316 var attr = $(this).attr("data-paidarehidden");
1317 if (typeof attr !== "undefined" && attr !== false) {
1318 console.log("Show paid");
1319 $(".tr_paid").show();
1320 $("#textBtnShowPaid").text(\''.dol_escape_js($langs->transnoentitiesnoconv("PaidShown")).'\');
1321 $("#btnShowPaid").removeAttr("data-paidarehidden");
1322 $("#minus-circle-paid").removeClass("fa-eye-slash").addClass("fa-eye");
1323 } else {
1324 console.log("Hide paid");
1325 $(".tr_paid").hide();
1326 $("#textBtnShowPaid").text(\''.dol_escape_js($langs->transnoentitiesnoconv("PaidHidden")).'\');
1327 $("#btnShowPaid").attr("data-paidarehidden", 1);
1328 $("#minus-circle-paid").removeClass("fa-eye").addClass("fa-eye-slash");
1329 }
1330 });
1331 </script></div>';
1332 }
1333
1334 print '<a id="table_'.$tablename.'"></a>';
1335 print load_fiche_titre($langs->trans($title), $addform, '');
1336
1337 print "\n".'<!-- Table for tablename = '.$tablename.' -->'."\n";
1338 print '<div class="div-table-responsive">';
1339 print '<table class="noborder centpercent">';
1340
1341 print '<tr class="liste_titre">';
1342 $stocktransfercolstyle = ($key == 'stocktransfer' ? ' style="width: 9%"' : '');
1343 // Remove link column
1344 print '<td style="width: 24px"></td>';
1345 // Ref
1346 if ($key == 'stocktransfer') {
1347 print '<td'.$stocktransfercolstyle.'>'.$langs->trans("Ref").'</td>';
1348 } else {
1349 print '<td'.(($tablename != 'actioncomm' && $tablename != 'projet_task') ? ' style="width: 200px"' : '').'>'.$langs->trans("Ref").'</td>';
1350 }
1351 // Product and qty on stock_movement
1352 if ('MouvementStock' == $classname) {
1353 print '<td style="width: 200px">'.$langs->trans("Product").'</td>';
1354 print '<td style="width: 50px">'.$langs->trans("Qty").'</td>';
1355 }
1356 // Date
1357 if ($key != 'stocktransfer') {
1358 print '<td'.(($tablename != 'actioncomm' && $tablename != 'projet_task') ? ' style="width: 200px"' : '').' class="center">';
1359 if (in_array($tablename, array('projet_task'))) {
1360 print $langs->trans("TimeSpent");
1361 }
1362 if (!in_array($tablename, array('projet_task'))) {
1363 print $langs->trans("Date");
1364 }
1365 print '</td>';
1366 }
1367 if ($key == 'stocktransfer') {
1368 print '<td'.$stocktransfercolstyle.'>'.$langs->trans("WarehouseSource").'</td>';
1369 print '<td'.$stocktransfercolstyle.'>'.$langs->trans("WarehouseDestination").'</td>';
1370 print '<td class="center"'.$stocktransfercolstyle.'>'.$langs->trans("DatePrevueDepart").'</td>';
1371 print '<td class="center"'.$stocktransfercolstyle.'>'.$langs->trans("DateReelleDepart").'</td>';
1372 print '<td class="center"'.$stocktransfercolstyle.'>'.$langs->trans("DatePrevueArrivee").'</td>';
1373 print '<td class="center"'.$stocktransfercolstyle.'>'.$langs->trans("DateReelleArrivee").'</td>';
1374 }
1375 // Thirdparty or user
1376 print '<td'.($key == 'stocktransfer' ? $stocktransfercolstyle : '').'>';
1377 if (in_array($tablename, array('projet_task')) && $key == 'project_task') {
1378 print ''; // if $key == 'project_task', we don't want details per user
1379 } elseif (in_array($tablename, array('payment_various'))) {
1380 print $langs->trans("Label"); // complementary info about the payment
1381 } elseif (in_array($tablename, array('expensereport_det', 'don', 'projet_task', 'stock_mouvement', 'salary'))) {
1382 print $langs->trans("User");
1383 } else {
1384 print $langs->trans("ThirdParty");
1385 }
1386 print '</td>';
1387 // Duration of intervention
1388 if ($tablename == 'fichinter') {
1389 print '<td>';
1390 print $langs->trans("TotalDuration");
1391 $total_duration = 0;
1392 print '</td>';
1393 }
1394 // Type from Expense Report
1395 if ($tablename == 'expensereport_det') {
1396 print '<td id="expensereport_type">';
1397 print $langs->trans("Type");
1398 print '</td>';
1399 }
1400 // Description from Expense Report
1401 if ($tablename == 'expensereport_det') {
1402 print '<td id="expensereport_description">';
1403 print $langs->trans("Description");
1404 print '</td>';
1405 }
1406
1407 // Additional columns from hooks
1408 $parameters = array('key' => $key, 'value' => $value, 'tablename' => $tablename);
1409 $reshook = $hookmanager->executeHooks('printOverviewDetailTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1410 if ($reshook < 0) {
1411 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1412 }
1413 print $hookmanager->resPrint;
1414
1415 // Amount HT
1416 //if (empty($value['disableamount']) && ! in_array($tablename, array('projet_task'))) print '<td class="right" width="120">'.$langs->trans("AmountHT").'</td>';
1417 //elseif (empty($value['disableamount']) && in_array($tablename, array('projet_task'))) print '<td class="right" width="120">'.$langs->trans("Amount").'</td>';
1418 if ($key == 'loan') {
1419 print '<td class="right" width="120">'.$langs->trans("LoanCapital").'</td>';
1420 } elseif (empty($value['disableamount'])) {
1421 if ($key == 'stocktransfer') {
1422 print '<td class="right"'.$stocktransfercolstyle.'>'.$langs->trans("AmountHT").'</td>';
1423 } else {
1424 print '<td class="right" width="120">'.$langs->trans("AmountHT").'</td>';
1425 }
1426 } else {
1427 if ($key == 'stocktransfer') {
1428 print '<td'.$stocktransfercolstyle.'></td>';
1429 } else {
1430 print '<td width="120"></td>';
1431 }
1432 }
1433 // Amount TTC
1434 //if (empty($value['disableamount']) && ! in_array($tablename, array('projet_task'))) print '<td class="right" width="120">'.$langs->trans("AmountTTC").'</td>';
1435 if ($key == 'loan') {
1436 print '<td class="right" width="120">'.$langs->trans("RemainderToPay").'</td>';
1437 } elseif (empty($value['disableamount'])) {
1438 if ($key == 'stocktransfer') {
1439 print '<td class="right"'.$stocktransfercolstyle.'>'.$langs->trans("AmountTTC").'</td>';
1440 } else {
1441 print '<td class="right" width="120">'.$langs->trans("AmountTTC").'</td>';
1442 }
1443 } else {
1444 if ($key == 'stocktransfer') {
1445 print '<td'.$stocktransfercolstyle.'></td>';
1446 } else {
1447 print '<td width="120"></td>';
1448 }
1449 }
1450 // Status
1451 if (in_array($tablename, array('projet_task'))) {
1452 print '<td class="right" width="200">'.$langs->trans("ProgressDeclared").'</td>';
1453 } else {
1454 if ($key == 'stocktransfer') {
1455 print '<td class="right"'.$stocktransfercolstyle.'>'.$langs->trans("Status").'</td>';
1456 } else {
1457 print '<td class="right" width="200">'.$langs->trans("Status").'</td>';
1458 }
1459 }
1460 print '</tr>';
1461
1462 if (is_array($elementarray) && count($elementarray) > 0) {
1463 $total_ht = 0;
1464 $total_ttc = 0;
1465 $i = 0;
1466
1467 $total_ht_by_third = 0;
1468 $total_ttc_by_third = 0;
1469
1470 $saved_third_id = 0;
1471 $breakline = '';
1472
1473 if (canApplySubtotalOn($tablename)) {
1474 // Sort
1475 $elementarray = sortElementsByClientName($elementarray);
1476 }
1477
1478 $num = count($elementarray);
1479 $total_time = 0;
1480 for ($i = 0; $i < $num; $i++) {
1481 $tmp = explode('_', $elementarray[$i]);
1482 $idofelement = (int) $tmp[0];
1483 $idofelementuser = isset($tmp[1]) ? (int) $tmp[1] : 0;
1484
1485 $element->fetch($idofelement);
1486 if ($idofelementuser) {
1487 $elementuser->fetch($idofelementuser);
1488 }
1489
1490 // Special cases
1491 if ($tablename != 'expensereport_det') {
1492 if (method_exists($element, 'fetch_thirdparty')) {
1493 $element->fetch_thirdparty();
1494 }
1495 } else {
1496 $expensereport = new ExpenseReport($db);
1497 $expensereport->fetch($element->fk_expensereport);
1498 }
1499
1500 //print 'xxx'.$tablename.'yyy'.$classname;
1501
1502 if ($breakline && $saved_third_id != $element->thirdparty->id) {
1503 print $breakline;
1504
1505 $saved_third_id = $element->thirdparty->id;
1506 $breakline = '';
1507
1508 $total_ht_by_third = 0;
1509 $total_ttc_by_third = 0;
1510 }
1511
1512 $saved_third_id = empty($element->thirdparty->id) ? 0 : $element->thirdparty->id;
1513
1514 $qualifiedfortotal = true;
1515 if ($key == 'invoice') {
1516 if (!empty($element->close_code) && $element->close_code == 'replaced') {
1517 $qualifiedfortotal = false; // Replacement invoice, do not include into total
1518 }
1519 } elseif ($key == 'order_supplier' && ($element->status == 6 || $element->status == 7)) {
1520 $qualifiedfortotal = false; // It makes no sense to include canceled orders in the total
1521 }
1522
1523 if ($key == "order_supplier" && ($element->status == 6 || $element->status == 7)) {
1524 print '<tr class="oddeven tr_canceled">';
1525 } elseif ($key == "order_supplier" && ($element->billed)) {
1526 print '<tr class="oddeven tr_paid">';
1527 } else {
1528 print '<tr class="oddeven" >';
1529 }
1530
1531
1532 // Remove link
1533 print '<td style="width: 24px">';
1534 if ($tablename != 'projet_task' && $tablename != 'stock_mouvement') {
1535 if ($permissiontoadd && (!getDolGlobalString('PROJECT_DISABLE_UNLINK_FROM_OVERVIEW') || $user->admin)) { // PROJECT_DISABLE_UNLINK_FROM_OVERVIEW is empty by default, so this test true
1536 print '<a href="'.$_SERVER["PHP_SELF"].'?id='.$object->id.'&action=unlink&token='.newToken().'&tablename='.$tablename.'&elementselect='.$element->id.($project_field ? '&projectfield='.$project_field : '').'" class="reposition">';
1537 print img_picto($langs->trans('Unlink'), 'unlink');
1538 print '</a>';
1539 }
1540 }
1541 print "</td>\n";
1542
1543 // Ref
1544 print '<td class="left nowraponall">';
1545 if ($tablename == 'expensereport_det') {
1546 print $expensereport->getNomUrl(1);
1547 } else {
1548 print '<table><tr><td style="border-bottom: none;">';
1549 // Show ref with link
1550 if ($element instanceof Task) {
1551 print $element->getNomUrl(1, 'withproject', 'time');
1552 print ' - '.dol_trunc($element->label, 48);
1553 } elseif ($key == 'loan') {
1554 print $element->getNomUrl(1);
1555 print ' - '.dol_trunc($element->label, 48);
1556 } else {
1557 print $element->getNomUrl(1);
1558 }
1559
1560 $element_doc = $element->element;
1561 $filename = dol_sanitizeFileName($element->ref);
1562 if (!empty($conf->$element_doc)) {
1563 $confelementdoc = $conf->$element_doc;
1564 $filedir = $confelementdoc->multidir_output[$element->entity ?? $conf->entity].'/'.dol_sanitizeFileName($element->ref);
1565 } else {
1566 $filedir = '';
1567 }
1568
1569 if ($element_doc === 'order_supplier') {
1570 $element_doc = 'commande_fournisseur';
1571 $filedir = $conf->fournisseur->commande->multidir_output[$element->entity ?? $conf->entity].'/'.dol_sanitizeFileName($element->ref);
1572 } elseif ($element_doc === 'invoice_supplier') {
1573 $element_doc = 'facture_fournisseur';
1574 $filename = get_exdir($element->id, 2, 0, 0, $element, 'invoice_supplier').dol_sanitizeFileName($element->ref);
1575 $filedir = $conf->fournisseur->facture->multidir_output[$element->entity ?? $conf->entity].'/'.$filename;
1576 }
1577
1578 print '<div class="inline-block valignmiddle">';
1579 if ($filedir) {
1580 print $formfile->getDocumentsLink($element_doc, $filename, $filedir);
1581 }
1582 print '</div>';
1583
1584 print '</td>';
1585
1586 print '<td class="tdoverflowmax250" style="border-bottom: none;">';
1587
1588 // Show supplier ref
1589 if (!empty($element->ref_supplier)) {
1590 print ' - '.$element->ref_supplier;
1591 }
1592 // Show customer ref
1593 if (!empty($element->ref_customer)) {
1594 print ' - '.$element->ref_customer;
1595 }
1596 // Compatibility propale
1597 if (empty($element->ref_customer) && !empty($element->ref_client)) {
1598 print ' - '.$element->ref_client;
1599 }
1600
1601 print '</td></tr></table>';
1602 }
1603 print "</td>\n";
1604 // Product and qty on stock movement
1605 if ('MouvementStock' == $classname) {
1606 '@phan-var-force MouvementStock $element';
1607 $mvsProd = new Product($element->db);
1608 $mvsProd->fetch($element->product_id);
1609 print '<td>'.$mvsProd->getNomUrl(1).'</td>';
1610 print '<td>'.$element->qty.'</td>';
1611 }
1612 // Date or TimeSpent
1613 $date = '';
1614 $total_time_by_line = 0;
1615 if ($tablename == 'expensereport_det') {
1616 '@phan-var-force ExpenseReportLine $element';
1617 $date = $element->date; // No draft status on lines
1618 } elseif ($tablename == 'stock_mouvement') {
1619 '@phan-var-force MouvementStock $element';
1620 $date = $element->datem;
1621 } elseif ($tablename == 'salary') {
1622 '@phan-var-force Salary $element';
1623 $date = $element->datesp;
1624 } elseif ($tablename == 'payment_various') {
1625 '@phan-var-force PaymentVarious $element';
1626 $date = $element->datev;
1627 } elseif ($tablename == 'chargesociales') {
1628 '@phan-var-force ChargeSociales $element';
1629 $date = $element->date_ech;
1630 } elseif (!empty($element->status) || !empty($element->statut) || !empty($element->fk_status)) {
1631 if ($tablename == 'don') {
1632 '@phan-var-force Don $element';
1633 $date = $element->date;
1634 }
1635 if ($tablename == 'commande_fournisseur' || $tablename == 'supplier_order') {
1636 '@phan-var-force CommandeFournisseur $element';
1637 $date = ($element->date_commande ? $element->date_commande : $element->date_valid);
1638 } elseif ($tablename == 'supplier_proposal') {
1639 '@phan-var-force SupplierProposal $element';
1640 $date = $element->date_validation; // There is no other date for this
1641 } elseif ($tablename == 'fichinter') {
1642 '@phan-var-force Fichinter $element';
1643 $date = $element->datev; // There is no other date for this
1644 } elseif ($tablename == 'projet_task') {
1645 '@phan-var-force Task $element';
1646 $date = ''; // We show no date. Showing date of beginning of task make user think it is date of time consumed
1647 } else {
1648 $date = $element->date; // invoice, ...
1649 if (empty($date)) {
1650 $date = $element->date_contrat;
1651 }
1652 if (empty($date)) {
1653 $date = $element->datev;
1654 }
1655 if (empty($date) && !empty($datefieldname)) {
1656 // @phan-suppress-next-line PhanUndeclaredProperty
1657 $date = $element->$datefieldname;
1658 }
1659 }
1660 } elseif ($key == 'loan') {
1661 '@phan-var-force Loan $element';
1662 $date = $element->datestart;
1663 }
1664
1665 if ($key != 'stocktransfer') {
1666 print '<td class="center">';
1667 if ($tablename == 'actioncomm') {
1668 '@phan-var-force ActionComm $element';
1669 print dol_print_date($element->datep, 'dayhour');
1670 if ($element->datef && $element->datef > $element->datep) {
1671 print " - ".dol_print_date($element->datef, 'dayhour');
1672 }
1673 } elseif (in_array($tablename, array('projet_task'))) {
1674 '@phan-var-force Task $element';
1675 $tmpprojtime = $element->getSumOfAmount($idofelementuser ? $elementuser : '', (string) $dates, (string) $datee); // $element is a task. $elementuser may be empty
1676 print '<a href="'.DOL_URL_ROOT.'/projet/tasks/time.php?id='.$idofelement.'&withproject=1">';
1677 print convertSecondToTime($tmpprojtime['nbseconds'], 'allhourmin');
1678 print '</a>';
1679 $total_time_by_line = $tmpprojtime['nbseconds'];
1680 } else {
1681 print dol_print_date($date, 'day');
1682 }
1683 print '</td>';
1684 }
1685
1686 if ($key == 'stocktransfer') {
1687 $warehouseSource = new Entrepot($db);
1688 $warehouseDestination = new Entrepot($db);
1689 print '<td class="tdoverflowmax150">';
1690 if (!empty($element->fk_warehouse_source) && $warehouseSource->fetch($element->fk_warehouse_source) > 0) {
1691 print $warehouseSource->getNomUrl(1);
1692 }
1693 print '</td>';
1694 print '<td class="tdoverflowmax150">';
1695 if (!empty($element->fk_warehouse_destination) && $warehouseDestination->fetch($element->fk_warehouse_destination) > 0) {
1696 print $warehouseDestination->getNomUrl(1);
1697 }
1698 print '</td>';
1699 print '<td class="center">'.dol_print_date($element->date_prevue_depart, 'day').'</td>';
1700 print '<td class="center">'.dol_print_date($element->date_reelle_depart, 'day').'</td>';
1701 print '<td class="center">'.dol_print_date($element->date_prevue_arrivee, 'day').'</td>';
1702 print '<td class="center">'.dol_print_date($element->date_reelle_arrivee, 'day').'</td>';
1703 }
1704
1705 // Third party or user
1706 print '<td class="tdoverflowmax150">';
1707 if (is_object($element->thirdparty)) {
1708 print $element->thirdparty->getNomUrl(1, '', 48);
1709 } elseif ($tablename == 'expensereport_det') {
1710 $tmpuser = new User($db);
1711 $tmpuser->fetch($expensereport->fk_user_author);
1712 print $tmpuser->getNomUrl(1, '', 48);
1713 } elseif ($tablename == 'salary') {
1714 $tmpuser = new User($db);
1715 $tmpuser->fetch($element->fk_user);
1716 print $tmpuser->getNomUrl(1, '', 48);
1717 } elseif ($tablename == 'don' || $tablename == 'stock_mouvement') {
1718 '@phan-var-force Don|MouvementStock $element';
1719 if ($element->fk_user_author > 0) {
1720 $tmpuser2 = new User($db);
1721 $tmpuser2->fetch($element->fk_user_author);
1722 print $tmpuser2->getNomUrl(1, '', 48);
1723 }
1724 } elseif ($tablename == 'projet_task' && $key == 'element_time') { // if $key == 'project_task', we don't want details per user
1725 print $elementuser->getNomUrl(1);
1726 } elseif ($tablename == 'payment_various') { // payment label
1727 '@phan-var-force PaymentVarious $element';
1728 print $element->label;
1729 }
1730 print '</td>';
1731
1732 // Add duration and store it in counter for fichinter
1733 if ($tablename == 'fichinter') {
1734 '@phan-var-force FichInter $element';
1735 print '<td>';
1736 print convertSecondToTime($element->duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY);
1737 $total_duration += $element->duration;
1738 print '</td>';
1739 }
1740
1741 // Type from Expense Report
1742 if ($tablename == 'expensereport_det') {
1743 print '<td class="left linecoltype">';
1744 $labeltype = ($langs->trans(($element->type_fees_code)) == $element->type_fees_code ? $element->type_fees_libelle : $langs->trans($element->type_fees_code));
1745 print (string) $labeltype;
1746 print '</td>';
1747 }
1748 // Description from Expense Report
1749 if ($tablename == 'expensereport_det') {
1750 print '<td class="left linecolcomment">';
1751 print (string) $element->comments;
1752 print '</td>';
1753 }
1754
1755 // Additional columns from hooks
1756 $parameters = array('key' => $key, 'value' => $value, 'tablename' => $tablename, 'element' => $element, 'i' => $i, 'qualifiedfortotal' => $qualifiedfortotal);
1757 $reshook = $hookmanager->executeHooks('printOverviewDetailValue', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1758 if ($reshook < 0) {
1759 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1760 }
1761 print $hookmanager->resPrint;
1762
1763 // Amount without tax
1764 $warning = '';
1765 if (empty($value['disableamount'])) {
1766 $total_ht_by_line = null;
1767 $othermessage = '';
1768 if ($tablename == 'don' || $tablename == 'chargesociales' || $tablename == 'payment_various' || $tablename == 'salary') {
1769 '@phan-var-force Don|ChargeSociales|PaymentVarious|Salary $element';
1770 $total_ht_by_line = $element->amount;
1771 } elseif ($tablename == 'fichinter') {
1772 '@phan-var-force FichInter $element';
1773 $total_ht_by_line = $element->getAmount();
1774 } elseif ($tablename == 'stock_mouvement') {
1775 '@phan-var-force MouvementStock $element';
1776 $total_ht_by_line = $element->price * abs($element->qty);
1777 } elseif (in_array($tablename, array('projet_task'))) {
1778 if (isModEnabled('salaries')) {
1779 // TODO Permission to read daily rate to show value
1780 $total_ht_by_line = price2num($tmpprojtime['amount'], 'MT');
1781 if (isset($tmpprojtime['nblinesnull']) && ($tmpprojtime['nblinesnull'] > 0)) {
1782 $langs->load("errors");
1783 $warning = $langs->trans("WarningSomeLinesWithNullHourlyRate", $conf->currency);
1784 }
1785 } else {
1786 $othermessage = $form->textwithpicto($langs->trans("NotAvailable"), $langs->trans("ModuleSalaryToDefineHourlyRateMustBeEnabled"));
1787 }
1788 } elseif ($key == 'loan') {
1789 '@phan-var-force Loan $element';
1790 $total_ht_by_line = $element->capital;
1791 } else {
1792 $total_ht_by_line = $element->total_ht;
1793 }
1794
1795 // Change sign of $total_ht_by_line and $total_ttc_by_line for some cases
1796 if ($tablename == 'payment_various') {
1797 if ($element->sens == 0) {
1798 $total_ht_by_line = -$total_ht_by_line;
1799 }
1800 }
1801
1802 print '<td class="right">';
1803 if ($othermessage) {
1804 print '<span class="opacitymedium">'.$othermessage.'</span>';
1805 }
1806 if (isset($total_ht_by_line)) {
1807 if (!$qualifiedfortotal) {
1808 print '<strike>';
1809 }
1810 print '<span class="amount">'.price($total_ht_by_line).'</span>';
1811 if (!$qualifiedfortotal) {
1812 print '</strike>';
1813 }
1814 }
1815 if ($warning) {
1816 print ' '.img_warning($warning);
1817 }
1818 if (isset($tmpprojtime['nblinesnull']) && ($tmpprojtime['nblinesnull'] > 0)) {
1819 if ($tmpprojtime['nbuserthmnull'] > 0) {
1820 $title = $langs->trans("EnterUsersHourlyRateFirst");
1821 print ' '.img_picto($title, "sync", '', 0, 0, 0, '', 'opacitymedium');
1822 } else {
1823 $title = $langs->trans("UpdateUndefinedWithLastHourlyRate");
1824 print ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=updateundefinedwithlasthourlyrate&taskid='.$idofelement.'&token='.currentToken().'">'.img_picto($title, "sync", '', 0, 0, 0, '', 'warning').'</a>';
1825 }
1826 }
1827 if (getDolGlobalString('PROJECT_CAN_OVERWRITE_TIMESTPENT_HOURLY_RATE_WITH_LASTONE')) {
1828 $title = $langs->trans("UpdateWithLastHourlyRate");
1829 print ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=updateallwithlasthourlyrate&taskid='.$idofelement.'&token='.currentToken().'">'.img_picto($title, "sync", '', 0, 0, 0, '', '').'</a>';
1830 }
1831 print '</td>';
1832 } else {
1833 print '<td></td>';
1834 }
1835
1836 // Amount inc tax
1837 if (empty($value['disableamount'])) {
1838 $total_ttc_by_line = null;
1839 if ($tablename == 'don' || $tablename == 'chargesociales' || $tablename == 'payment_various' || $tablename == 'salary') {
1840 '@phan-var-force Don|ChargeSociales|PaymentVarious $element';
1841 $total_ttc_by_line = $element->amount;
1842 } elseif ($tablename == 'fichinter') {
1843 '@phan-var-force Fichinter $element';
1844 $total_ttc_by_line = $element->getAmount();
1845 } elseif ($tablename == 'stock_mouvement') {
1846 '@phan-var-force MouvementStock $element';
1847 $total_ttc_by_line = $element->price * abs($element->qty);
1848 } elseif ($tablename == 'projet_task') {
1849 if (isModEnabled('salaries')) {
1850 // TODO Permission to read daily rate
1851 $defaultvat = get_default_tva($mysoc, $mysoc);
1852 $total_ttc_by_line = price2num($total_ht_by_line * (1 + ($defaultvat / 100)), 'MT');
1853 } else {
1854 $othermessage = $form->textwithpicto($langs->trans("NotAvailable"), $langs->trans("ModuleSalaryToDefineHourlyRateMustBeEnabled"));
1855 }
1856 } elseif ($key == 'loan') {
1857 '@phan-var-force Loan $element';
1858 $total_ttc_by_line = $element->capital - $element->getSumPayment();
1859 } else {
1860 $total_ttc_by_line = $element->total_ttc;
1861 }
1862
1863 // Change sign of $total_ht_by_line and $total_ttc_by_line for some cases
1864 if ($tablename == 'payment_various') {
1865 if ($element->sens == 0) {
1866 $total_ttc_by_line = -$total_ttc_by_line;
1867 }
1868 }
1869
1870 print '<td class="right">';
1871 if ($othermessage) {
1872 print $othermessage;
1873 }
1874 if (isset($total_ttc_by_line)) {
1875 if (!$qualifiedfortotal) {
1876 print '<strike>';
1877 }
1878 print '<span class="amount">'.price($total_ttc_by_line).'</span>';
1879 if (!$qualifiedfortotal) {
1880 print '</strike>';
1881 }
1882 }
1883 if ($warning) {
1884 print ' '.img_warning($warning);
1885 }
1886 if (isset($tmpprojtime['nblinesnull']) && ($tmpprojtime['nblinesnull'] > 0)) {
1887 if ($tmpprojtime['nbuserthmnull'] > 0) {
1888 $title = $langs->trans("EnterUsersHourlyRateFirst");
1889 print ' '.img_picto($title, "sync", '', 0, 0, 0, '', 'opacitymedium');
1890 } else {
1891 $title = $langs->trans("UpdateUndefinedWithLastHourlyRate");
1892 print ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=updateundefinedwithlasthourlyrate&taskid='.$idofelement.'&token='.currentToken().'">'.img_picto($title, "sync", '', 0, 0, 0, '', 'warning').'</a>';
1893 }
1894 }
1895 if (getDolGlobalString('PROJECT_CAN_OVERWRITE_TIMESTPENT_HOURLY_RATE_WITH_LASTONE')) {
1896 $title = $langs->trans("UpdateWithLastHourlyRate");
1897 print ' <a class="reposition" href="'.$_SERVER["PHP_SELF"].'?id='.$id.'&action=updateallwithlasthourlyrate&taskid='.$idofelement.'&token='.currentToken().'">'.img_picto($title, "sync").'</a>';
1898 }
1899 print '</td>';
1900 } else {
1901 print '<td></td>';
1902 }
1903
1904 // Status
1905 print '<td class="right">';
1906 if ($tablename == 'expensereport_det') {
1907 print $expensereport->getLibStatut(5);
1908 } elseif ($element instanceof CommonInvoice) {
1909 //This applies for Facture and FactureFournisseur
1910 print $element->getLibStatut(5, $element->getSommePaiement());
1911 } elseif ($element instanceof Task) {
1912 if ($element->progress != '') {
1913 print $element->progress.' %';
1914 }
1915 } elseif ($tablename == 'stock_mouvement') {
1916 '@phan-var-force MouvementStock $element';
1917 print $element->getLibStatut(3);
1918 } else {
1919 print $element->getLibStatut(5);
1920 }
1921 print '</td>';
1922
1923 print '</tr>';
1924
1925 if ($qualifiedfortotal) {
1926 $total_ht += $total_ht_by_line;
1927 $total_ttc += $total_ttc_by_line;
1928
1929 $total_ht_by_third += $total_ht_by_line;
1930 $total_ttc_by_third += $total_ttc_by_line;
1931
1932 if (!isset($total_time)) {
1933 $total_time = $total_time_by_line;
1934 } else {
1935 $total_time += $total_time_by_line;
1936 }
1937 }
1938
1939 if (canApplySubtotalOn($tablename)) {
1940 $breakline = '<tr class="liste_total liste_sub_total">';
1941 $breakline .= '<td colspan="2">';
1942 $breakline .= '</td>';
1943 $breakline .= '<td>';
1944 $breakline .= '</td>';
1945 $breakline .= '<td class="right">';
1946 $breakline .= $langs->trans('SubTotal').' : ';
1947 if (is_object($element->thirdparty)) {
1948 $breakline .= $element->thirdparty->getNomUrl(0, '', 48);
1949 }
1950 $breakline .= '</td>';
1951 $breakline .= '<td class="right">'.price($total_ht_by_third).'</td>';
1952 $breakline .= '<td class="right">'.price($total_ttc_by_third).'</td>';
1953 $breakline .= '<td></td>';
1954 $breakline .= '</tr>';
1955 }
1956
1957 //var_dump($element->thirdparty->name.' - '.$saved_third_id.' - '.$element->thirdparty->id);
1958 }
1959
1960 if ($breakline) {
1961 print $breakline;
1962 }
1963
1964 // Total
1965 if (empty($nototal)) {
1966 $colspan = 4;
1967 if (in_array($tablename, array('projet_task'))) {
1968 $colspan = 2;
1969 }
1970 if ($key == 'stocktransfer') {
1971 $colspan = 9;
1972 }
1973
1974 print '<tr class="liste_total"><td colspan="'.$colspan.'">'.$langs->trans("Number").': '.$i.'</td>';
1975 if (in_array($tablename, array('projet_task'))) {
1976 print '<td class="center">';
1977 print convertSecondToTime((int) $total_time, 'allhourmin');
1978 print '</td>';
1979 print '<td>';
1980 print '</td>';
1981 }
1982 //if (empty($value['disableamount']) && ! in_array($tablename, array('projet_task'))) print '<td class="right" width="100">'.$langs->trans("TotalHT").' : '.price($total_ht).'</td>';
1983 //elseif (empty($value['disableamount']) && in_array($tablename, array('projet_task'))) print '<td class="right" width="100">'.$langs->trans("Total").' : '.price($total_ht).'</td>';
1984 // If fichinter add the total_duration
1985 if ($tablename == 'fichinter') {
1986 print '<td class="left">'.convertSecondToTime($total_duration, 'all', $conf->global->MAIN_DURATION_OF_WORKDAY).'</td>';
1987 }
1988 // Additional total columns from hooks
1989 $parameters = array('key' => $key, 'value' => $value, 'tablename' => $tablename, 'nbelement' => $i);
1990 $reshook = $hookmanager->executeHooks('printOverviewDetailTotal', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
1991 if ($reshook < 0) {
1992 setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
1993 }
1994 print $hookmanager->resPrint;
1995 print '<td class="right">';
1996 if (empty($value['disableamount'])) {
1997 if ($key == 'loan') {
1998 print $langs->trans("Total").' '.$langs->trans("LoanCapital").' : '.price($total_ttc);
1999 } elseif ($tablename != 'projet_task' || isModEnabled('salaries')) {
2000 print ''.$langs->trans("TotalHT").' : '.price($total_ht);
2001 }
2002 }
2003 print '</td>';
2004 //if (empty($value['disableamount']) && ! in_array($tablename, array('projet_task'))) print '<td class="right" width="100">'.$langs->trans("TotalTTC").' : '.price($total_ttc).'</td>';
2005 //elseif (empty($value['disableamount']) && in_array($tablename, array('projet_task'))) print '<td class="right" width="100"></td>';
2006 print '<td class="right">';
2007 if (empty($value['disableamount'])) {
2008 if ($key == 'loan') {
2009 print $langs->trans("Total").' '.$langs->trans("RemainderToPay").' : '.price($total_ttc);
2010 } elseif ($tablename != 'projet_task' || isModEnabled('salaries')) {
2011 print $langs->trans("TotalTTC").' : '.price($total_ttc);
2012 }
2013 }
2014 print '</td>';
2015 print '<td>&nbsp;</td>';
2016 // Because of the added Type and Description columns to Expense Reports
2017 if ($tablename == 'expensereport_det') {
2018 print '<td>&nbsp;</td>';
2019 print '<td>&nbsp;</td>';
2020 }
2021 print '</tr>';
2022 }
2023 } else {
2024 if (!is_array($elementarray)) { // error
2025 print '<tr><td>'.$elementarray.'</td></tr>';
2026 } else {
2027 $colspan = 7;
2028 if ($tablename == 'fichinter') {
2029 $colspan++;
2030 }
2031 if ($key == 'stocktransfer') {
2032 $colspan = 12;
2033 }
2034 print '<tr><td colspan="'.$colspan.'"><span class="opacitymedium">'.$langs->trans("None").'</td></tr>';
2035 }
2036 }
2037 print "</table>";
2038 print '</div>';
2039 print "<br>\n";
2040 }
2041}
2042
2043// Enhance with select2
2044if ($conf->use_javascript_ajax) {
2045 include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php';
2046 $comboenhancement = ajax_combobox('.elementselect');
2047
2048 print $comboenhancement;
2049}
2050
2051// End of page
2052llxFooter();
2053$db->close();
2054
2055
2056
2063function canApplySubtotalOn($tablename)
2064{
2065 global $conf;
2066
2067 if (!getDolGlobalString('PROJECT_ADD_SUBTOTAL_LINES')) {
2068 return false;
2069 }
2070 return in_array($tablename, array('facture_fourn', 'commande_fournisseur'));
2071}
2072
2079function sortElementsByClientName($elementarray)
2080{
2081 global $db, $classname;
2082 '@phan-var-force string $classname';
2083
2084 $element = new $classname($db);
2085 '@phan-var-force CommonObject $element';
2086
2087 $clientname = array();
2088 foreach ($elementarray as $key => $id) { // id = id of object
2089 if (empty($clientname[$id])) {
2090 $element->fetch($id);
2091 $element->fetch_thirdparty();
2092
2093 $clientname[$id] = $element->thirdparty->name;
2094 }
2095 }
2096
2097 //var_dump($clientname);
2098 asort($clientname); // sort on name
2099
2100 $elementarray = array();
2101 foreach ($clientname as $id => $name) {
2102 $elementarray[] = $id;
2103 }
2104
2105 return $elementarray;
2106}
$id
Support class for third parties, contacts, members, users or resources.
Definition account.php:47
if(! $sortfield) if(! $sortorder) $object
Definition account.php:100
ajax_combobox($htmlname, $events=array(), $minLengthToAutocomplete=0, $forcefocus=0, $widthTypeOfAutocomplete='resolve', $idforemptyvalue='-1', $morecss='', $placeholder='')
Convert a html select field into an ajax combobox.
Definition ajax.lib.php:477
llxFooter($comment='', $zone='private', $disabledoutputofmessages=0)
Empty footer.
Definition wrapper.php:91
if(!defined('NOREQUIRESOC')) if(!defined( 'NOREQUIRETRAN')) if(!defined('NOTOKENRENEWAL')) if(!defined( 'NOREQUIREMENU')) if(!defined('NOREQUIREHTML')) if(!defined( 'NOREQUIREAJAX')) llxHeader($head='', $title='', $help_url='', $target='', $disablejs=0, $disablehead=0, $arrayofjs='', $arrayofcss='', $morequerystring='', $morecssonbody='', $replacemainareaby='', $disablenofollow=0, $disablenoindex=0)
Empty header.
Definition wrapper.php:73
Superclass for invoice classes.
Class for ConferenceOrBoothAttendee.
Class to manage warehouses.
Class to manage Trips and Expenses.
const TYPE_DEPOSIT
Deposit invoice.
const STATUS_CLOSED
Classified paid.
Class to offer components to list and upload files.
Class to manage generation of HTML components Only common components must be here.
Class to manage building of HTML components.
Class to manage Schedule of loans.
Class to manage stock movements.
Class to manage products or services.
Class to manage projects.
const STATUS_SIGNED
Signed quote.
const STATUS_BILLED
Billed or processed quote.
Class to manage tasks.
Class for TimeSpent.
Class to manage Dolibarr users.
global $mysoc
dol_get_first_day($year, $month=1, $gm=false)
Return GMT time for first day of a month or year.
Definition date.lib.php:616
convertSecondToTime($iSecond, $format='all', $lengthOfDay=86400, $lengthOfWeek=7)
Return, in clear text, value of a number of seconds in days, hours and minutes.
Definition date.lib.php:253
dol_stringtotime($string, $gm=1, $processnotimeasnoon=0)
Convert a string date into a GM Timestamps date Warning: YYYY-MM-DDTHH:MM:SS+02:00 (RFC3339) is not s...
Definition date.lib.php:442
sortElementsByClientName($elementarray)
sortElementsByClientName
Definition element.php:2079
canApplySubtotalOn($tablename)
Return if we should do a group by customer with sub-total.
Definition element.php:2063
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $conf
The main.inc.php has been included so the following variable are now defined:
dol_now($mode='gmt')
Return date for now.
dol_mktime($hour, $minute, $second, $month, $day, $year, $gm='auto', $check=1)
Return a timestamp date built from detailed information (by default a local PHP server timestamp) Rep...
vatrate($rate, $addpercent=false, $info_bits=0, $usestarfornpr=0, $html=0)
Return a string with VAT rate label formatted for view output Used into pdf and HTML pages.
price2num($amount, $rounding='', $option=0)
Function that return a number with universal decimal format (decimal separator is '.
currentToken()
Return the value of token currently saved into session with name 'token'.
dol_eval($s, $returnvalue=1, $hideerrors=1, $onlysimplestring='1')
Replace eval function to add more security.
dol_sanitizeFileName($str, $newstr='_', $unaccent=1, $includequotes=0, $allowdash=0)
Clean a string to use it as a file name.
price($amount, $form=0, $outlangs='', $trunc=1, $rounding=-1, $forcerounding=-1, $currency_code='')
Function to format a value into an amount for visual output Function used into PDF and HTML pages.
dol_escape_js($stringtoescape, $mode=0, $noescapebackslashn=0)
Returns text escaped for inclusion into JavaScript code.
newToken()
Return the value of token currently saved into session with name 'newtoken'.
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0, $nodefault=0)
Return value of a param into GET or POST supervariable.
GETPOSTINT($paramname, $method=0, $nodefault=0)
Return the value of a $_GET or $_POST supervariable, converted into integer.
dol_clone($srcobject, $native=2)
Create a clone of instance of object (new instance with same value for each properties) With native =...
dol_print_date($time, $format='', $tzoutput='auto', $outputlangs=null, $encodetooutput=false, $decorate=0)
Output date in a string format according to outputlangs (or langs if not defined).
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
get_default_tva(Societe $thirdparty_seller, Societe $thirdparty_buyer, $idprod=0, $idprodfournprice=0)
Function that return vat rate of a product line (according to seller, buyer and product vat rate) VAT...
get_exdir($num, $level, $alpha, $withoutslash, $object, $modulepart='')
Return a path to have a the directory according to object where files are stored.
dol_getdate($timestamp, $fast=false, $forcetimezone='')
Return an array with locale date info.
treeview li table
No Email.
dol_get_fiche_head($links=array(), $active='', $title='', $notab=0, $picto='', $pictoisfullpath=0, $morehtmlright='', $morecss='', $limittoshow=0, $moretabssuffix='', $dragdropfile=0, $morecssdiv='')
Show tabs of a record.
Definition html.lib.php:540
dol_get_fiche_end($notab=0)
Return tab footer of a card.
Definition html.lib.php:738
load_fiche_titre($title, $morehtmlright='', $picto='generic', $pictoisfullpath=0, $id='', $morecssontable='', $morehtmlcenter='', $morecssonpicto='widthpictotitle')
Load a title with picto.
dol_escape_htmltag($stringtoescape, $keepb=0, $keepn=0, $noescapetags='', $escapeonlyhtmltags=0, $cleanalsojavascript=0)
Definition html.lib.php:181
project_prepare_head(Project $project, $moreparam='')
Prepare array with list of tabs.
$conf db user
Active Directory does not allow anonymous connections.
Definition repair.php:141
restrictedArea(User $user, $features, $object=0, $tableandshare='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid', $isdraft=0, $nodie=0, $mode='')
Check permissions of a user to show a page and an object.
accessforbidden($message='', $printheader=1, $printfooter=1, $showonlymessage=0, $params=null)
Show a message to say access is forbidden and stop program.