diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index 04c5baa642a..eeede7b3810 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -2282,7 +2282,7 @@ class Adherent extends CommonObject $sql.= " WHERE a.fk_adherent_type = t.rowid"; $sql.= " AND a.statut = 1"; $sql.= " AND a.entity IN (".getEntity('adherent').")"; - $sql.= " AND ((a.datefin IS NULL or a.datefin < '".$this->db->idate($now)."') AND t.subscription = 1)"; + $sql.= " AND ((a.datefin IS NULL or a.datefin < '".$this->db->idate($now)."') AND t.subscription = '1')"; $resql=$this->db->query($sql); if ($resql) diff --git a/htdocs/compta/bank/releve.php b/htdocs/compta/bank/releve.php index a16927bda0b..5ef3fbf0953 100644 --- a/htdocs/compta/bank/releve.php +++ b/htdocs/compta/bank/releve.php @@ -179,7 +179,7 @@ $sqlrequestforbankline = $sql; if ($action == 'confirm_editbankreceipt' && !empty($oldbankreceipt) && !empty($newbankreceipt)) { // TODO Add a test to check newbankreceipt does not exists yet - $sqlupdate = 'UPDATE '.MAIN_DB_PREFIX.'bank SET num_releve = "'.$db->escape($newbankreceipt).'" WHERE num_releve = "'.$db->escape($oldbankreceipt).'"'; + $sqlupdate = 'UPDATE '.MAIN_DB_PREFIX.'bank SET num_releve = "'.$db->escape($newbankreceipt).'" WHERE num_releve = "'.$db->escape($oldbankreceipt).'" AND fk_account = '.$id; $result = $db->query($sqlupdate); if ($result < 0) dol_print_error($db); diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index c726e1d8fed..0bb22c4c794 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -1208,7 +1208,7 @@ if (empty($reshook)) } // Add link between credit note and origin - if (!empty($object->fk_facture_source)) { + if (!empty($object->fk_facture_source) && $id > 0) { $facture_source->fetch($object->fk_facture_source); $facture_source->fetchObjectLinked(); diff --git a/htdocs/compta/prelevement/bons.php b/htdocs/compta/prelevement/bons.php index 88162263297..e4c11c0c60c 100644 --- a/htdocs/compta/prelevement/bons.php +++ b/htdocs/compta/prelevement/bons.php @@ -31,6 +31,8 @@ require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php'; // Load translation files required by the page $langs->loadLangs(array('banks', 'categories', 'widthdrawals')); +$contextpage = GETPOST('contextpage', 'aZ') ?GETPOST('contextpage', 'aZ') : 'contractlist'; // To manage different context of search + // Security check $socid = GETPOST('socid', 'int'); if ($user->socid) $socid=$user->socid; @@ -102,7 +104,9 @@ if ($result) $num = $db->num_rows($result); $i = 0; - $urladd = "&statut=".$statut; + $param = ''; + $param .= "&statut=".$statut; + if ($limit != $conf->liste_limit) $param .= '&limit=' . $limit; $selectedfields = ''; @@ -123,7 +127,7 @@ if ($result) print ''; print ''; - print_barre_liste($langs->trans("WithdrawalsReceipts"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); + print_barre_liste($langs->trans("WithdrawalsReceipts"), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'generic', 0, $newcardbutton, '', $limit); $moreforfilter = ''; diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index b86e7bd692c..dc5b02286eb 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -1030,14 +1030,18 @@ if (!$error && $massaction == "builddoc" && $permissiontoread && !GETPOST('butto $input_files .= ' '.escapeshellarg($f); } - $cmd = 'pdftk '.escapeshellarg($input_files).' cat output '.escapeshellarg($file); + $cmd = 'pdftk ' . $input_files . ' cat output '.escapeshellarg($file); exec($cmd); - if (!empty($conf->global->MAIN_UMASK)) - @chmod($file, octdec($conf->global->MAIN_UMASK)); - - $langs->load("exports"); - setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs'); + // check if pdftk is installed + if (file_exists($file)) { + if (!empty($conf->global->MAIN_UMASK)) + @chmod($file, octdec($conf->global->MAIN_UMASK)); + $langs->load("exports"); + setEventMessages($langs->trans('FileSuccessfullyBuilt', $filename.'_'.dol_print_date($now, 'dayhourlog')), null, 'mesgs'); + } else { + setEventMessages($langs->trans('ErrorPDFTkOutputFileNotFound'), null, 'errors'); + } } else { diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 56910b43e4a..4a8e097fd6d 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -212,8 +212,8 @@ abstract class CommonDocGenerator 'company_idprof6'=>$object->idprof6, 'company_note_public'=>$object->note_public, 'company_note_private'=>$object->note_private, - 'company_default_bank_iban'=>$object->bank_account->iban, - 'company_default_bank_bic'=>$object->bank_account->bic + 'company_default_bank_iban'=>(is_object($object->bank_account) ? $object->bank_account->iban : ''), + 'company_default_bank_bic'=>(is_object($object->bank_account) ? $object->bank_account->bic : '') ); // Retrieve extrafields diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index ac388b1ef83..f938426d4ba 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -1686,8 +1686,13 @@ class ExtraFields } elseif ($type == 'select') { - if ($langfile && $param['options'][$value]) $value = $langs->trans($param['options'][$value]); - else $value = $param['options'][$value]; + $valstr = $param['options'][$value]; + if (($pos = strpos($valstr, "|")) !== false) + { + $valstr = substr($valstr, 0, $pos); + } + if ($langfile && $valstr) $value = $langs->trans($valstr); + else $value = $valstr; } elseif ($type == 'sellist') { diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 078cfb2b5f2..0b4660711c3 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3711,7 +3711,8 @@ class Form $sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc'; $sql .= ' FROM '.MAIN_DB_PREFIX.'facture'; $sql .= ' WHERE entity IN ('.getEntity('invoice').')'; - $sql .= ' AND situation_counter>=1'; + $sql .= ' AND situation_counter >= 1'; + $sql .= ' AND type <> 2'; $sql .= ' ORDER by situation_cycle_ref, situation_counter desc'; $resql = $this->db->query($sql); if ($resql && $this->db->num_rows($resql) > 0) { diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index ec9dff5f1a3..97a4bdf1948 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -1269,7 +1269,8 @@ class FormFile } else { - print dol_trunc($file['name'], 200); + $filenametoshow = preg_replace('/\.noexe$/', '', $file['name']); + print dol_trunc($filenametoshow, 200); print ''; } // Preview link diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 41d7bf1b294..6614b22e5ed 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -870,7 +870,7 @@ function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $te { $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore); $rel_filetorenameafter = preg_replace('/^[\\/]/', '', $rel_filetorenameafter); - //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter); + //var_dump($rel_filetorenamebefore.' - '.$rel_filetorenameafter);exit; dol_syslog("Try to rename also entries in database for full relative path before = ".$rel_filetorenamebefore." after = ".$rel_filetorenameafter, LOG_DEBUG); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; @@ -893,6 +893,7 @@ function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $te $ecmfile->filepath = $rel_dir; $ecmfile->filename = $filename; + $resultecm = $ecmfile->update($user); } elseif ($resultecm == 0) // If no entry were found for src files, create/update target file @@ -995,7 +996,7 @@ function dolCheckVirus($src_file) * @param integer $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error']) * @param int $nohook Disable all hooks * @param string $varfiles _FILES var name - * @return int|string >0 if OK, <0 or string if KO + * @return int|string 1 if OK, 2 if OK and .noexe appended, <0 or string if KO * @see dol_move() */ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile') @@ -1005,6 +1006,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $reshook = 0; $file_name = $dest_file; + $successcode = 1; if (empty($nohook)) { @@ -1055,6 +1057,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable if (isAFileWithExecutableContent($dest_file) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) { $file_name .= '.noexe'; + $successcode = 2; } // Security: @@ -1109,7 +1112,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable { if (!empty($conf->global->MAIN_UMASK)) @chmod($file_name_osencoded, octdec($conf->global->MAIN_UMASK)); dol_syslog("Files.lib::dol_move_uploaded_file Success to move ".$src_file." to ".$file_name." - Umask=".$conf->global->MAIN_UMASK, LOG_DEBUG); - return 1; // Success + return $successcode; // Success } else { @@ -1118,7 +1121,7 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable } } - return 1; // Success + return $successcode; // Success } /** @@ -1173,8 +1176,6 @@ function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, } else { - $error = 0; - //print "x".$file." ".$disableglob;exit; $file_osencoded = dol_osencode($file); // New filename encoded in OS filesystem encoding charset if (empty($disableglob) && !empty($file_osencoded)) @@ -1197,10 +1198,11 @@ function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename); if (!preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) // If not a tmp file { - $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete); - if (is_object($db) && $indexdatabase) // $db may not be defined when lib is in a context with define('NOREQUIREDB',1) { + $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete); + $rel_filetodelete = preg_replace('/\.noexe$/', '', $rel_filetodelete); + dol_syslog("Try to remove also entries in database for full relative path = ".$rel_filetodelete, LOG_DEBUG); include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; $ecmfile = new EcmFiles($db); @@ -1564,6 +1566,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess $destfile = dol_string_nohtmltag($destfile); $destfull = dol_string_nohtmltag($destfull); + // Move file from temp directory to final directory. A .noexe may also be appended on file name. $resupload = dol_move_uploaded_file($TFile['tmp_name'][$i], $destfull, $allowoverwrite, 0, $TFile['error'][$i], 0, $varfiles); if (is_numeric($resupload) && $resupload > 0) // $resupload can be 'ErrorFileAlreadyExists' @@ -1600,10 +1603,10 @@ function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesess // Update table of files if ($donotupdatesession == 1) { - $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile), $TFile['name'][$i], 'uploaded', 0); + $result = addFileIntoDatabaseIndex($upload_dir, basename($destfile).($resupload == 2 ? '.noexe' : ''), $TFile['name'][$i], 'uploaded', 0); if ($result < 0) { - setEventMessages('FailedToAddFileIntoDatabaseIndex', '', 'warnings'); + setEventMessages('WarningFailedToAddFileIntoDatabaseIndex', '', 'warnings'); } } @@ -1714,7 +1717,7 @@ function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletef * See also commonGenerateDocument that also add/update database index when a file is generated. * * @param string $dir Directory name (full real path without ending /) - * @param string $file File name + * @param string $file File name (May end with '.noexe') * @param string $fullpathorig Full path of origin for file (can be '') * @param string $mode How file was created ('uploaded', 'generated', ...) * @param int $setsharekey Set also the share key @@ -1730,7 +1733,7 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uplo if (!preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir { - $filename = basename($file); + $filename = basename(preg_replace('/\.noexe$/', '', $file)); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); $rel_dir = preg_replace('/^[\\/]/', '', $rel_dir); diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index bfa15ebd4b1..a32ba1308a3 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -1275,7 +1275,7 @@ class pdf_crabe extends ModelePDFFactures $pdf->MultiCell($col2x - $col1x, $tab2_hl, $totalvat, 0, 'L', 1); $pdf->SetXY($col2x, $tab2_top + $tab2_hl * $index); - $pdf->MultiCell($largcol2, $tab2_hl, price($tvaval, 0, $outputlangs), 0, 'R', 1); + $pdf->MultiCell($largcol2, $tab2_hl, price(price2num($tvaval, 'MT'), 0, $outputlangs), 0, 'R', 1); } } diff --git a/htdocs/core/tpl/filemanager.tpl.php b/htdocs/core/tpl/filemanager.tpl.php index 3a3395432de..f95286bbcfc 100644 --- a/htdocs/core/tpl/filemanager.tpl.php +++ b/htdocs/core/tpl/filemanager.tpl.php @@ -178,7 +178,7 @@ if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg print ''; } - else // Show filtree when ajax is disabled (rare) + else // Show file tree when ajax is disabled (rare) { print ''; @@ -212,7 +212,7 @@ if (empty($action) || $action == 'editfile' || $action == 'file_manager' || preg
'.$langs->trans('ReductionShort').'situation_cycle_ref) { print '' . $langs->trans('Progress') . ''; - print '' . $langs->trans('TotalHT100Short') . ''; + print '' . $form->textwithpicto($langs->trans('TotalHT100Short'), $langs->trans('UnitPriceXQtyLessDiscount')) . ''; } if ($usemargins && ! empty($conf->margin->enabled) && empty($user->socid)) diff --git a/htdocs/ecm/class/ecmfiles.class.php b/htdocs/ecm/class/ecmfiles.class.php index 01f6228ad83..8f1b2c91d78 100644 --- a/htdocs/ecm/class/ecmfiles.class.php +++ b/htdocs/ecm/class/ecmfiles.class.php @@ -138,7 +138,7 @@ class EcmFiles extends CommonObject $this->entity = trim($this->entity); } if (isset($this->filename)) { - $this->filename = trim($this->filename); + $this->filename = preg_replace('/\.noexe$/', '', trim($this->filename)); } if (isset($this->filepath)) { $this->filepath = trim($this->filepath); @@ -346,12 +346,13 @@ class EcmFiles extends CommonObject $sql .= " t.src_object_id"; $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t'; $sql.= ' WHERE 1 = 1'; - /* Fetching this table depends on filepath+filename, it must not depends on entity + /* Fetching this table depends on filepath+filename, it must not depends on entity because filesystem on disk does not know what is Dolibarr entities if (! empty($conf->multicompany->enabled)) { $sql .= " AND entity IN (" . getEntity('ecmfiles') . ")"; }*/ if ($relativepath) { - $sql .= " AND t.filepath = '" . $this->db->escape(dirname($relativepath)) . "' AND t.filename = '".$this->db->escape(basename($relativepath))."'"; + $relativepathwithnoexe = preg_replace('/\.noexe$/', '', $relativepath); // We must never have the .noexe into the database + $sql .= " AND t.filepath = '" . $this->db->escape(dirname($relativepath)) . "' AND t.filename = '".$this->db->escape(basename($relativepathwithnoexe))."'"; $sql .= " AND t.entity = ".$conf->entity; // unique key include the entity so each company has its own index } elseif (! empty($ref)) { // hash of file path @@ -552,46 +553,47 @@ class EcmFiles extends CommonObject // Clean parameters if (isset($this->ref)) { - $this->ref = trim($this->ref); + $this->ref = trim($this->ref); } if (isset($this->label)) { - $this->label = trim($this->label); + $this->label = trim($this->label); } if (isset($this->share)) { - $this->share = trim($this->share); + $this->share = trim($this->share); } if (isset($this->entity)) { - $this->entity = trim($this->entity); + $this->entity = trim($this->entity); } if (isset($this->filename)) { - $this->filename = trim($this->filename); + $this->filename = preg_replace('/\.noexe$/', '', trim($this->filename)); } if (isset($this->filepath)) { - $this->filepath = trim($this->filepath); + $this->filepath = trim($this->filepath); + $this->filepath = preg_replace('/[\\/]+$/', '', $this->filepath); // Remove last / } if (isset($this->fullpath_orig)) { - $this->fullpath_orig = trim($this->fullpath_orig); + $this->fullpath_orig = trim($this->fullpath_orig); } if (isset($this->description)) { - $this->description = trim($this->description); + $this->description = trim($this->description); } if (isset($this->keywords)) { - $this->keywords = trim($this->keywords); + $this->keywords = trim($this->keywords); } if (isset($this->cover)) { - $this->cover = trim($this->cover); + $this->cover = trim($this->cover); } if (isset($this->gen_or_uploaded)) { - $this->gen_or_uploaded = trim($this->gen_or_uploaded); + $this->gen_or_uploaded = trim($this->gen_or_uploaded); } if (isset($this->extraparams)) { - $this->extraparams = trim($this->extraparams); + $this->extraparams = trim($this->extraparams); } if (isset($this->fk_user_m)) { - $this->fk_user_m = trim($this->fk_user_m); + $this->fk_user_m = trim($this->fk_user_m); } if (isset($this->acl)) { - $this->acl = trim($this->acl); + $this->acl = trim($this->acl); } if (isset($this->src_object_type)) { $this->src_object_type = trim($this->src_object_type); diff --git a/htdocs/ecm/file_card.php b/htdocs/ecm/file_card.php index 3664a2e7f28..e1796068370 100644 --- a/htdocs/ecm/file_card.php +++ b/htdocs/ecm/file_card.php @@ -139,6 +139,12 @@ if ($action == 'update') $oldfile = $olddir.$oldlabel; $newfile = $newdir.$newlabel; + $newfileformove = $newfile; + // If old file end with .noexe, new file must also end with .noexe + if (preg_match('/\.noexe$/', $oldfile) && ! preg_match('/\.noexe$/', $newfileformove)) { + $newfileformove .= '.noexe'; + } + //var_dump($oldfile);var_dump($newfile);exit; // Now we update index of file $db->begin(); @@ -146,7 +152,7 @@ if ($action == 'update') //print $oldfile.' - '.$newfile; if ($newlabel != $oldlabel) { - $result = dol_move($oldfile, $newfile); // This include update of database + $result = dol_move($oldfile, $newfileformove); // This include update of database if (!$result) { $langs->load('errors'); @@ -190,7 +196,7 @@ if ($action == 'update') $object->entity = $conf->entity; $object->filepath = preg_replace('/[\\/]+$/', '', $newdirrelativetodocument); $object->filename = $newlabel; - $object->label = md5_file(dol_osencode($newfile)); // hash of file content + $object->label = md5_file(dol_osencode($newfileformove)); // hash of file content $object->fullpath_orig = ''; $object->gen_or_uploaded = 'unknown'; $object->description = ''; // indexed content @@ -208,6 +214,11 @@ if ($action == 'update') $db->commit(); $urlfile = $newlabel; + // If old file end with .noexe, new file must also end with .noexe + if (preg_match('/\.noexe$/', $newfileformove)) { + $urlfile .= '.noexe'; + } + header('Location: '.$_SERVER["PHP_SELF"].'?urlfile='.urlencode($urlfile).'§ion='.urlencode($section)); exit; } @@ -264,9 +275,13 @@ while ($tmpecmdir && $result > 0) $i++; } +$urlfiletoshow = preg_replace('/\.noexe$/', '', $urlfile); + $s = img_picto('', 'object_dir').' '.$langs->trans("ECMRoot").' -> '.$s.' -> '; -if ($action == 'edit') $s .= ''; -else $s .= $urlfile; +if ($action == 'edit') $s .= ''; +else $s .= $urlfiletoshow; + +$morehtml = ''; $object->ref = ''; // Force to hide ref dol_banner_tab($object, '', $morehtml, 0, '', '', $s); @@ -289,10 +304,9 @@ print dol_print_size($totalsize); print ''; */ +// Hash of file content print ''.$langs->trans("HashOfFileContent").''; $object = new EcmFiles($db); -//$filenametosearch=basename($filepath); -//$filedirtosearch=basedir($filepath); $object->fetch(0, '', $filepathtodocument); if (!empty($object->label)) { diff --git a/htdocs/ecm/index.php b/htdocs/ecm/index.php index e51efb01aaa..852d148e258 100644 --- a/htdocs/ecm/index.php +++ b/htdocs/ecm/index.php @@ -124,15 +124,17 @@ if ($action == 'confirm_deletefile') if (GETPOST('confirm') == 'yes') { // GETPOST('urlfile','alpha') is full relative URL from ecm root dir. Contains path of all sections. - //var_dump(GETPOST('urlfile'));exit; $upload_dir = $conf->ecm->dir_output.($relativepath?'/'.$relativepath:''); $file = $upload_dir . "/" . GETPOST('urlfile', 'alpha'); + //var_dump($file);exit; $ret=dol_delete_file($file); // This include also the delete from file index in database. if ($ret) { - setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile', 'alpha')), null, 'mesgs'); + $urlfiletoshow = GETPOST('urlfile', 'alpha'); + $urlfiletoshow = preg_replace('/\.noexe$/', '', $urlfiletoshow); + setEventMessages($langs->trans("FileWasRemoved", $urlfiletoshow), null, 'mesgs'); $result=$ecmdir->changeNbOfFiles('-'); } else diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index 048bdb5d493..5e93397fe66 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -2318,7 +2318,7 @@ class ExpenseReport extends CommonObject public function load_state_board() { // phpcs:enable - global $conf; + global $conf, $user; $this->nb = array(); @@ -2326,6 +2326,12 @@ class ExpenseReport extends CommonObject $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex"; $sql .= " WHERE ex.fk_statut > 0"; $sql .= " AND ex.entity IN (".getEntity('expensereport').")"; + if (empty($user->rights->expensereport->readall)) + { + $userchildids = $user->getAllChildIds(1); + $sql .= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; + $sql .= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + } $resql = $this->db->query($sql); if ($resql) { @@ -2360,15 +2366,17 @@ class ExpenseReport extends CommonObject $now = dol_now(); - $userchildids = $user->getAllChildIds(1); - $sql = "SELECT ex.rowid, ex.date_valid"; $sql .= " FROM ".MAIN_DB_PREFIX."expensereport as ex"; if ($option == 'toapprove') $sql .= " WHERE ex.fk_statut = 2"; else $sql .= " WHERE ex.fk_statut = 5"; $sql .= " AND ex.entity IN (".getEntity('expensereport').")"; - $sql .= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; - $sql .= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + if (empty($user->rights->expensereport->readall)) + { + $userchildids = $user->getAllChildIds(1); + $sql .= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; + $sql .= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + } $resql = $this->db->query($sql); if ($resql) diff --git a/htdocs/fichinter/list.php b/htdocs/fichinter/list.php index fd45d2daecb..ef6b9241c8d 100644 --- a/htdocs/fichinter/list.php +++ b/htdocs/fichinter/list.php @@ -75,8 +75,6 @@ $pagenext = $page + 1; if (!$sortorder) $sortorder = "DESC"; if (!$sortfield) { - //if (empty($conf->global->FICHINTER_DISABLE_DETAILS)) $sortfield="fd.date"; - //else $sortfield = "f.ref"; } @@ -203,7 +201,7 @@ foreach ($arrayfields as $tmpkey => $tmpval) $sql = "SELECT"; $sql .= " f.ref, f.rowid, f.fk_statut, f.description, f.datec as date_creation, f.tms as date_update, f.note_private,"; -if (empty($conf->global->FICHINTER_DISABLE_DETAILS) && $atleastonefieldinlines) $sql .= "fd.rowid as lineid, fd.description as descriptiondetail, fd.date as dp, fd.duree,"; +if (empty($conf->global->FICHINTER_DISABLE_DETAILS) && $atleastonefieldinlines) $sql .= " fd.rowid as lineid, fd.description as descriptiondetail, fd.date as dp, fd.duree,"; $sql .= " s.nom as name, s.rowid as socid, s.client"; if (!empty($conf->projet->enabled)) { $sql .= ", pr.rowid as projet_id, pr.ref as projet_ref, pr.title as projet_title"; @@ -245,7 +243,7 @@ if ($search_contrat_ref) { $sql .= natural_search('c.ref', $search_contrat_ref); } if ($search_desc) { - if (empty($conf->global->FICHINTER_DISABLE_DETAILS)) $sql .= natural_search(array('f.description', 'fd.description'), $search_desc); + if (empty($conf->global->FICHINTER_DISABLE_DETAILS) && $atleastonefieldinlines) $sql .= natural_search(array('f.description', 'fd.description'), $search_desc); else $sql .= natural_search(array('f.description'), $search_desc); } if ($search_status != '' && $search_status >= 0) { diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 7de6f6a770e..278e6640ff2 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1881,7 +1881,6 @@ class CommandeFournisseur extends CommonOrder if ($result < 0) { $error++; - return -1; } // End call triggers } @@ -1989,6 +1988,7 @@ class CommandeFournisseur extends CommonOrder { $this->errors[] = 'ErrorWhenRunningTrigger'; dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); return -1; } // End call triggers diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index acd4be35b79..2e61c014532 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -2173,12 +2173,20 @@ class Holiday extends CommonObject public function load_state_board() { // phpcs:enable + global $user; + $this->nb = array(); $sql = "SELECT count(h.rowid) as nb"; $sql .= " FROM ".MAIN_DB_PREFIX."holiday as h"; $sql .= " WHERE h.statut > 1"; $sql .= " AND h.entity IN (".getEntity('holiday').")"; + if (empty($user->rights->expensereport->read_all)) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; + $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + } $resql = $this->db->query($sql); if ($resql) { @@ -2212,14 +2220,16 @@ class Holiday extends CommonObject $now=dol_now(); - $userchildids = $user->getAllChildIds(1); - $sql = "SELECT h.rowid, h.date_debut"; $sql.= " FROM ".MAIN_DB_PREFIX."holiday as h"; $sql.= " WHERE h.statut = 2"; $sql.= " AND h.entity IN (".getEntity('holiday').")"; - $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; - $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + if(!$user->rights->expensereport->read_all) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; + $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + } $resql=$this->db->query($sql); if ($resql) diff --git a/htdocs/index.php b/htdocs/index.php index 250a0c1736b..ec23af5eb34 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -322,7 +322,7 @@ if (empty($user->socid) && empty($conf->global->MAIN_DISABLE_GLOBAL_BOXSTATS)) include_once $includes[$key]; // Loading a class cost around 1Mb $board = new $classe($db); - $board->load_state_board($user); + $board->load_state_board(); $boardloaded[$classe] = $board; } else diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 24d077654da..b21429a4d1b 100644 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -491,8 +491,13 @@ UPDATE llx_accounting_bookkeeping set date_creation = tms where date_creation IS -- UPDATE llx_facturedet_rec set label = NULL WHERE label IS NOT NULL; + UPDATE llx_facturedet SET situation_percent = 100 WHERE situation_percent IS NULL AND fk_prev_id IS NULL; +-- Test inconsistency of data into situation invoices: If it differs, it may be the total_ht that is wrong and situation_percent that is good. +-- select f.rowid, f.type, qty, subprice, situation_percent, total_ht, total_ttc, total_tva, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, (situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) +-- from llx_facturedet as fd, llx_facture as f where fd.fk_facture = f.rowid AND (total_ht - situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) > 0.01 and f.type = 5; + -- Note to make all deposit as payed when there is already a discount generated from it. --drop table tmp_invoice_deposit_mark_as_available; @@ -501,6 +506,7 @@ UPDATE llx_facturedet SET situation_percent = 100 WHERE situation_percent IS NUL + -- Note to migrate from old counter aquarium to new one -- drop table tmp; -- create table tmp select rowid, code_client, concat(substr(code_client, 1, 6),'-0',substr(code_client, 8, 5)) as code_client2 from llx_societe where code_client like 'CU____-____'; diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index 6e26ecb6835..ac521ad8102 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -574,3 +574,4 @@ AutoFillDateTo=Set end date for service line with next invoice date AutoFillDateToShort=Set end date MaxNumberOfGenerationReached=Max number of gen. reached BILL_DELETEInDolibarr=Invoice deleted +UnitPriceXQtyLessDiscount=Unit price x Qty - Discount diff --git a/htdocs/langs/en_US/errors.lang b/htdocs/langs/en_US/errors.lang index c5b61e50ed6..d145e75bad6 100644 --- a/htdocs/langs/en_US/errors.lang +++ b/htdocs/langs/en_US/errors.lang @@ -255,3 +255,4 @@ WarningNumberOfRecipientIsRestrictedInMassAction=Warning, number of different re WarningDateOfLineMustBeInExpenseReportRange=Warning, the date of line is not in the range of the expense report WarningProjectClosed=Project is closed. You must re-open it first. WarningSomeBankTransactionByChequeWereRemovedAfter=Some bank transaction were removed after that the receipt including them were generated. So nb of cheques and total of receipt may differ from number and total in list. +WarningFailedToAddFileIntoDatabaseIndex=Warnin, failed to add file entry into ECM database index table \ No newline at end of file diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang index 31e0d5a1c8d..051dde11ff7 100644 --- a/htdocs/langs/en_US/main.lang +++ b/htdocs/langs/en_US/main.lang @@ -837,6 +837,7 @@ Sincerely=Sincerely ConfirmDeleteObject=Are you sure you want to delete this object? DeleteLine=Delete line ConfirmDeleteLine=Are you sure you want to delete this line? +ErrorPDFTkOutputFileNotFound=Error: the file was not generated. Please check that the 'pdftk' command is installed in a directory included in the $PATH environment variable (linux/unix only) or contact your system administrator. NoPDFAvailableForDocGenAmongChecked=No PDF were available for the document generation among checked record TooManyRecordForMassAction=Too many records selected for mass action. The action is restricted to a list of %s records. NoRecordSelected=No record selected @@ -1017,4 +1018,4 @@ ContactDefault_ticket=Ticket ContactAddedAutomatically=Contact added from contact thirdparty roles More=More ShowDetails=Show details -CustomReports=Custom reports \ No newline at end of file +CustomReports=Custom reports diff --git a/htdocs/product/stock/class/entrepot.class.php b/htdocs/product/stock/class/entrepot.class.php index 03ba46a4068..0b259018cfc 100644 --- a/htdocs/product/stock/class/entrepot.class.php +++ b/htdocs/product/stock/class/entrepot.class.php @@ -692,7 +692,7 @@ class Entrepot extends CommonObject */ public function getNomUrl($withpicto = 0, $option = '', $showfullpath = 0, $notooltip = 0) { - global $conf, $langs; + global $conf, $langs, $hookmanager; $langs->load("stocks"); if (! empty($conf->dol_no_mouse_hover)) $notooltip=1; // Force disable tooltips @@ -731,6 +731,16 @@ class Entrepot extends CommonObject if ($withpicto != 2) $result.= ($showfullpath ? $this->get_full_arbo() : (empty($this->label)?$this->libelle:$this->label)); $result .= $linkend; + global $action; + $hookmanager->initHooks(array('warehousedao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result, 'withpicto' => $withpicto, 'option' => $option, 'showfullpath' => $showfullpath, 'notooltip'=> $notooltip); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) { + $result = $hookmanager->resPrint; + } else { + $result .= $hookmanager->resPrint; + } + return $result; } diff --git a/htdocs/product/stock/massstockmove.php b/htdocs/product/stock/massstockmove.php index 8d98f028d23..7a0472e226d 100644 --- a/htdocs/product/stock/massstockmove.php +++ b/htdocs/product/stock/massstockmove.php @@ -34,6 +34,9 @@ require_once DOL_DOCUMENT_ROOT.'/product/class/html.formproduct.class.php'; // Load translation files required by the page $langs->loadLangs(array('products', 'stocks', 'orders', 'productbatch')); +//init Hook +$hookmanager->initHooks(array('massstockmove')); + // Security check if ($user->socid) { $socid = $user->socid; diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 5802ad20e56..a5e1c197f8b 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -34,27 +34,27 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; class Project extends CommonObject { - /** + /** * @var string ID to identify managed object */ public $element = 'project'; - /** + /** * @var string Name of table without prefix where object is stored */ public $table_element = 'projet'; - /** + /** * @var int Name of subtable line */ public $table_element_line = 'projet_task'; - /** + /** * @var int Name of field date */ public $table_element_date; - /** + /** * @var int Field with ID of parent key if this field has a parent */ public $fk_element = 'fk_projet'; @@ -63,19 +63,19 @@ class Project extends CommonObject * 0=No test on entity, 1=Test with field entity, 2=Test with link by societe * @var int */ - public $ismultientitymanaged = 1; + public $ismultientitymanaged = 1; - /** - * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png - */ - public $picto = 'projectpub'; + /** + * @var string String with name of icon for myobject. Must be the part after the 'object_' into object_myobject.png + */ + public $picto = 'projectpub'; - /** - * {@inheritdoc} - */ - protected $table_ref_field = 'ref'; + /** + * {@inheritdoc} + */ + protected $table_ref_field = 'ref'; - /** + /** * @var string description */ public $description; @@ -83,41 +83,41 @@ class Project extends CommonObject /** * @var string */ - public $title; + public $title; - public $date_start; - public $date_end; - public $date_close; + public $date_start; + public $date_end; + public $date_close; - public $socid; // To store id of thirdparty - public $thirdparty_name; // To store name of thirdparty (defined only in some cases) + public $socid; // To store id of thirdparty + public $thirdparty_name; // To store name of thirdparty (defined only in some cases) - public $user_author_id; //!< Id of project creator. Not defined if shared project. + public $user_author_id; //!< Id of project creator. Not defined if shared project. - /** - * @var int user close id - */ - public $fk_user_close; + /** + * @var int user close id + */ + public $fk_user_close; - /** - * @var int user close id - */ + /** + * @var int user close id + */ public $user_close_id; - public $public; //!< Tell if this is a public or private project - public $budget_amount; - public $usage_bill_time; // Is the time spent on project must be invoiced or not + public $public; //!< Tell if this is a public or private project + public $budget_amount; + public $usage_bill_time; // Is the time spent on project must be invoiced or not - public $statuts_short; - public $statuts_long; + public $statuts_short; + public $statuts_long; - public $statut; // 0=draft, 1=opened, 2=closed - public $opp_status; // opportunity status, into table llx_c_lead_status + public $statut; // 0=draft, 1=opened, 2=closed + public $opp_status; // opportunity status, into table llx_c_lead_status public $opp_percent; // opportunity probability - public $oldcopy; + public $oldcopy; - public $weekWorkLoad; // Used to store workload details of a projet - public $weekWorkLoadPerTask; // Used to store workload details of tasks of a projet + public $weekWorkLoad; // Used to store workload details of a projet + public $weekWorkLoadPerTask; // Used to store workload details of tasks of a projet /** * @var int Creation date @@ -196,406 +196,406 @@ class Project extends CommonObject ); - /** - * Constructor - * - * @param DoliDB $db Database handler - */ - public function __construct($db) - { - $this->db = $db; + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; - $this->statuts_short = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); - $this->statuts_long = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); - } + $this->statuts_short = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); + $this->statuts_long = array(0 => 'Draft', 1 => 'Opened', 2 => 'Closed'); + } - /** - * Create a project into database - * - * @param User $user User making creation - * @param int $notrigger Disable triggers - * @return int <0 if KO, id of created project if OK - */ - public function create($user, $notrigger = 0) - { - global $conf, $langs; + /** + * Create a project into database + * + * @param User $user User making creation + * @param int $notrigger Disable triggers + * @return int <0 if KO, id of created project if OK + */ + public function create($user, $notrigger = 0) + { + global $conf, $langs; - $error = 0; - $ret = 0; + $error = 0; + $ret = 0; - $now = dol_now(); + $now = dol_now(); - // Clean parameters - $this->note_private = dol_substr($this->note_private, 0, 65535); - $this->note_public = dol_substr($this->note_public, 0, 65535); + // Clean parameters + $this->note_private = dol_substr($this->note_private, 0, 65535); + $this->note_public = dol_substr($this->note_public, 0, 65535); - // Check parameters - if (!trim($this->ref)) - { - $this->error = 'ErrorFieldsRequired'; - dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR); - return -1; - } - if (!empty($conf->global->PROJECT_THIRDPARTY_REQUIRED) && !($this->socid > 0)) - { - $this->error = 'ErrorFieldsRequired'; - dol_syslog(get_class($this)."::create error -1 thirdparty not defined and option PROJECT_THIRDPARTY_REQUIRED is set", LOG_ERR); - return -1; - } + // Check parameters + if (!trim($this->ref)) + { + $this->error = 'ErrorFieldsRequired'; + dol_syslog(get_class($this)."::create error -1 ref null", LOG_ERR); + return -1; + } + if (!empty($conf->global->PROJECT_THIRDPARTY_REQUIRED) && !($this->socid > 0)) + { + $this->error = 'ErrorFieldsRequired'; + dol_syslog(get_class($this)."::create error -1 thirdparty not defined and option PROJECT_THIRDPARTY_REQUIRED is set", LOG_ERR); + return -1; + } - // Create project - $this->db->begin(); + // Create project + $this->db->begin(); - $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet ("; - $sql .= "ref"; - $sql .= ", title"; - $sql .= ", description"; - $sql .= ", fk_soc"; - $sql .= ", fk_user_creat"; - $sql .= ", fk_statut"; - $sql .= ", fk_opp_status"; - $sql .= ", opp_percent"; - $sql .= ", public"; - $sql .= ", datec"; - $sql .= ", dateo"; - $sql .= ", datee"; - $sql .= ", opp_amount"; - $sql .= ", budget_amount"; - $sql .= ", usage_opportunity"; - $sql .= ", usage_task"; - $sql .= ", usage_bill_time"; - $sql .= ", usage_organize_event"; - $sql .= ", note_private"; - $sql .= ", note_public"; - $sql .= ", entity"; - $sql .= ") VALUES ("; - $sql .= "'".$this->db->escape($this->ref)."'"; - $sql .= ", '".$this->db->escape($this->title)."'"; - $sql .= ", '".$this->db->escape($this->description)."'"; - $sql .= ", ".($this->socid > 0 ? $this->socid : "null"); - $sql .= ", ".$user->id; - $sql .= ", ".(is_numeric($this->statut) ? $this->statut : '0'); - $sql .= ", ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'NULL'); - $sql .= ", ".(is_numeric($this->opp_percent) ? $this->opp_percent : 'NULL'); - $sql .= ", ".($this->public ? 1 : 0); - $sql .= ", '".$this->db->idate($now)."'"; - $sql .= ", ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); - $sql .= ", ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); - $sql .= ", ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : 'null'); - $sql .= ", ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : 'null'); - $sql .= ", ".($this->usage_opportunity ? 1 : 0); - $sql .= ", ".($this->usage_task ? 1 : 0); - $sql .= ", ".($this->usage_bill_time ? 1 : 0); - $sql .= ", ".($this->usage_organize_event ? 1 : 0); - $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : 'null'); - $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null'); - $sql .= ", ".$conf->entity; - $sql .= ")"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."projet ("; + $sql .= "ref"; + $sql .= ", title"; + $sql .= ", description"; + $sql .= ", fk_soc"; + $sql .= ", fk_user_creat"; + $sql .= ", fk_statut"; + $sql .= ", fk_opp_status"; + $sql .= ", opp_percent"; + $sql .= ", public"; + $sql .= ", datec"; + $sql .= ", dateo"; + $sql .= ", datee"; + $sql .= ", opp_amount"; + $sql .= ", budget_amount"; + $sql .= ", usage_opportunity"; + $sql .= ", usage_task"; + $sql .= ", usage_bill_time"; + $sql .= ", usage_organize_event"; + $sql .= ", note_private"; + $sql .= ", note_public"; + $sql .= ", entity"; + $sql .= ") VALUES ("; + $sql .= "'".$this->db->escape($this->ref)."'"; + $sql .= ", '".$this->db->escape($this->title)."'"; + $sql .= ", '".$this->db->escape($this->description)."'"; + $sql .= ", ".($this->socid > 0 ? $this->socid : "null"); + $sql .= ", ".$user->id; + $sql .= ", ".(is_numeric($this->statut) ? $this->statut : '0'); + $sql .= ", ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'NULL'); + $sql .= ", ".(is_numeric($this->opp_percent) ? $this->opp_percent : 'NULL'); + $sql .= ", ".($this->public ? 1 : 0); + $sql .= ", '".$this->db->idate($now)."'"; + $sql .= ", ".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); + $sql .= ", ".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); + $sql .= ", ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : 'null'); + $sql .= ", ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : 'null'); + $sql .= ", ".($this->usage_opportunity ? 1 : 0); + $sql .= ", ".($this->usage_task ? 1 : 0); + $sql .= ", ".($this->usage_bill_time ? 1 : 0); + $sql .= ", ".($this->usage_organize_event ? 1 : 0); + $sql .= ", ".($this->note_private ? "'".$this->db->escape($this->note_private)."'" : 'null'); + $sql .= ", ".($this->note_public ? "'".$this->db->escape($this->note_public)."'" : 'null'); + $sql .= ", ".$conf->entity; + $sql .= ")"; - dol_syslog(get_class($this)."::create", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet"); - $ret = $this->id; + dol_syslog(get_class($this)."::create", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $this->id = $this->db->last_insert_id(MAIN_DB_PREFIX."projet"); + $ret = $this->id; - if (!$notrigger) - { - // Call trigger - $result = $this->call_trigger('PROJECT_CREATE', $user); - if ($result < 0) { $error++; } - // End call triggers - } - } - else - { - $this->error = $this->db->lasterror(); - $this->errno = $this->db->lasterrno(); - $error++; - } + if (!$notrigger) + { + // Call trigger + $result = $this->call_trigger('PROJECT_CREATE', $user); + if ($result < 0) { $error++; } + // End call triggers + } + } + else + { + $this->error = $this->db->lasterror(); + $this->errno = $this->db->lasterrno(); + $error++; + } - // Update extrafield - if (!$error) { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result = $this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } + // Update extrafield + if (!$error) { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result = $this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } - if (!$error && !empty($conf->global->MAIN_DISABLEDRAFTSTATUS)) - { - $res = $this->setValid($user); - if ($res < 0) $error++; - } + if (!$error && !empty($conf->global->MAIN_DISABLEDRAFTSTATUS)) + { + $res = $this->setValid($user); + if ($res < 0) $error++; + } - if (!$error) - { - $this->db->commit(); - return $ret; - } - else - { - $this->db->rollback(); - return -1; - } - } + if (!$error) + { + $this->db->commit(); + return $ret; + } + else + { + $this->db->rollback(); + return -1; + } + } - /** - * Update a project - * - * @param User $user User object of making update - * @param int $notrigger 1=Disable all triggers - * @return int <=0 if KO, >0 if OK - */ - public function update($user, $notrigger = 0) - { - global $langs, $conf; + /** + * Update a project + * + * @param User $user User object of making update + * @param int $notrigger 1=Disable all triggers + * @return int <=0 if KO, >0 if OK + */ + public function update($user, $notrigger = 0) + { + global $langs, $conf; - $error = 0; + $error = 0; - // Clean parameters - $this->title = trim($this->title); - $this->description = trim($this->description); + // Clean parameters + $this->title = trim($this->title); + $this->description = trim($this->description); if ($this->opp_amount < 0) $this->opp_amount = ''; if ($this->opp_percent < 0) $this->opp_percent = ''; - if ($this->date_end && $this->date_end < $this->date_start) - { - $this->error = $langs->trans("ErrorDateEndLowerThanDateStart"); - $this->errors[] = $this->error; - $this->db->rollback(); - dol_syslog(get_class($this)."::update error -3 ".$this->error, LOG_ERR); - return -3; - } + if ($this->date_end && $this->date_end < $this->date_start) + { + $this->error = $langs->trans("ErrorDateEndLowerThanDateStart"); + $this->errors[] = $this->error; + $this->db->rollback(); + dol_syslog(get_class($this)."::update error -3 ".$this->error, LOG_ERR); + return -3; + } - if (dol_strlen(trim($this->ref)) > 0) - { - $this->db->begin(); + if (dol_strlen(trim($this->ref)) > 0) + { + $this->db->begin(); - $sql = "UPDATE ".MAIN_DB_PREFIX."projet SET"; - $sql .= " ref='".$this->db->escape($this->ref)."'"; - $sql .= ", title = '".$this->db->escape($this->title)."'"; - $sql .= ", description = '".$this->db->escape($this->description)."'"; - $sql .= ", fk_soc = ".($this->socid > 0 ? $this->socid : "null"); - $sql .= ", fk_statut = ".$this->statut; - $sql .= ", fk_opp_status = ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'null'); + $sql = "UPDATE ".MAIN_DB_PREFIX."projet SET"; + $sql .= " ref='".$this->db->escape($this->ref)."'"; + $sql .= ", title = '".$this->db->escape($this->title)."'"; + $sql .= ", description = '".$this->db->escape($this->description)."'"; + $sql .= ", fk_soc = ".($this->socid > 0 ? $this->socid : "null"); + $sql .= ", fk_statut = ".$this->statut; + $sql .= ", fk_opp_status = ".((is_numeric($this->opp_status) && $this->opp_status > 0) ? $this->opp_status : 'null'); $sql .= ", opp_percent = ".((is_numeric($this->opp_percent) && $this->opp_percent != '') ? $this->opp_percent : 'null'); - $sql .= ", public = ".($this->public ? 1 : 0); - $sql .= ", datec=".($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null'); - $sql .= ", dateo=".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); - $sql .= ", datee=".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); - $sql .= ", date_close=".($this->date_close != '' ? "'".$this->db->idate($this->date_close)."'" : 'null'); - $sql .= ", fk_user_close=".($this->fk_user_close > 0 ? $this->fk_user_close : "null"); - $sql .= ", opp_amount = ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : "null"); - $sql .= ", budget_amount = ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : "null"); - $sql .= ", fk_user_modif = ".$user->id; - $sql .= ", usage_opportunity = ".($this->usage_opportunity ? 1 : 0); - $sql .= ", usage_task = ".($this->usage_task ? 1 : 0); - $sql .= ", usage_bill_time = ".($this->usage_bill_time ? 1 : 0); - $sql .= ", usage_organize_event = ".($this->usage_organize_event ? 1 : 0); - $sql .= " WHERE rowid = ".$this->id; + $sql .= ", public = ".($this->public ? 1 : 0); + $sql .= ", datec=".($this->date_c != '' ? "'".$this->db->idate($this->date_c)."'" : 'null'); + $sql .= ", dateo=".($this->date_start != '' ? "'".$this->db->idate($this->date_start)."'" : 'null'); + $sql .= ", datee=".($this->date_end != '' ? "'".$this->db->idate($this->date_end)."'" : 'null'); + $sql .= ", date_close=".($this->date_close != '' ? "'".$this->db->idate($this->date_close)."'" : 'null'); + $sql .= ", fk_user_close=".($this->fk_user_close > 0 ? $this->fk_user_close : "null"); + $sql .= ", opp_amount = ".(strcmp($this->opp_amount, '') ? price2num($this->opp_amount) : "null"); + $sql .= ", budget_amount = ".(strcmp($this->budget_amount, '') ? price2num($this->budget_amount) : "null"); + $sql .= ", fk_user_modif = ".$user->id; + $sql .= ", usage_opportunity = ".($this->usage_opportunity ? 1 : 0); + $sql .= ", usage_task = ".($this->usage_task ? 1 : 0); + $sql .= ", usage_bill_time = ".($this->usage_bill_time ? 1 : 0); + $sql .= ", usage_organize_event = ".($this->usage_organize_event ? 1 : 0); + $sql .= " WHERE rowid = ".$this->id; - dol_syslog(get_class($this)."::update", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - // Update extrafield - if (!$error) - { - if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used - { - $result = $this->insertExtraFields(); - if ($result < 0) - { - $error++; - } - } - } + dol_syslog(get_class($this)."::update", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + // Update extrafield + if (!$error) + { + if (empty($conf->global->MAIN_EXTRAFIELDS_DISABLED)) // For avoid conflicts if trigger used + { + $result = $this->insertExtraFields(); + if ($result < 0) + { + $error++; + } + } + } - if (!$error && !$notrigger) - { - // Call trigger - $result = $this->call_trigger('PROJECT_MODIFY', $user); - if ($result < 0) { $error++; } - // End call triggers - } + if (!$error && !$notrigger) + { + // Call trigger + $result = $this->call_trigger('PROJECT_MODIFY', $user); + if ($result < 0) { $error++; } + // End call triggers + } - if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) - { - // We remove directory - if ($conf->projet->dir_output) - { - $olddir = $conf->projet->dir_output."/".dol_sanitizeFileName($this->oldcopy->ref); - $newdir = $conf->projet->dir_output."/".dol_sanitizeFileName($this->ref); - if (file_exists($olddir)) - { + if (!$error && (is_object($this->oldcopy) && $this->oldcopy->ref !== $this->ref)) + { + // We remove directory + if ($conf->projet->dir_output) + { + $olddir = $conf->projet->dir_output."/".dol_sanitizeFileName($this->oldcopy->ref); + $newdir = $conf->projet->dir_output."/".dol_sanitizeFileName($this->ref); + if (file_exists($olddir)) + { include_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; $res = @rename($olddir, $newdir); if (!$res) - { - $langs->load("errors"); + { + $langs->load("errors"); $this->error = $langs->trans('ErrorFailToRenameDir', $olddir, $newdir); - $error++; - } - } - } - } - if (!$error) - { - $this->db->commit(); - $result = 1; - } - else + $error++; + } + } + } + } + if (!$error) { - $this->db->rollback(); - $result = -1; - } - } - else + $this->db->commit(); + $result = 1; + } + else + { + $this->db->rollback(); + $result = -1; + } + } + else { - $this->error = $this->db->lasterror(); - $this->errors[] = $this->error; - $this->db->rollback(); - if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') - { - $result = -4; - } - else - { - $result = -2; - } - dol_syslog(get_class($this)."::update error ".$result." ".$this->error, LOG_ERR); - } - } - else - { - dol_syslog(get_class($this)."::update ref null"); - $result = -1; - } + $this->error = $this->db->lasterror(); + $this->errors[] = $this->error; + $this->db->rollback(); + if ($this->db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') + { + $result = -4; + } + else + { + $result = -2; + } + dol_syslog(get_class($this)."::update error ".$result." ".$this->error, LOG_ERR); + } + } + else + { + dol_syslog(get_class($this)."::update ref null"); + $result = -1; + } - return $result; - } + return $result; + } - /** - * Get object from database - * - * @param int $id Id of object to load - * @param string $ref Ref of project - * @return int >0 if OK, 0 if not found, <0 if KO - */ - public function fetch($id, $ref = '') - { - global $conf; + /** + * Get object from database + * + * @param int $id Id of object to load + * @param string $ref Ref of project + * @return int >0 if OK, 0 if not found, <0 if KO + */ + public function fetch($id, $ref = '') + { + global $conf; - if (empty($id) && empty($ref)) return -1; + if (empty($id) && empty($ref)) return -1; - $sql = "SELECT rowid, ref, title, description, public, datec, opp_amount, budget_amount,"; - $sql .= " tms, dateo, datee, date_close, fk_soc, fk_user_creat, fk_user_modif, fk_user_close, fk_statut, fk_opp_status, opp_percent,"; - $sql .= " note_private, note_public, model_pdf, usage_opportunity, usage_task, usage_bill_time, usage_organize_event, entity"; - $sql .= " FROM ".MAIN_DB_PREFIX."projet"; - if (!empty($id)) - { - $sql .= " WHERE rowid=".$id; - } - elseif (!empty($ref)) - { - $sql .= " WHERE ref='".$this->db->escape($ref)."'"; - $sql .= " AND entity IN (".getEntity('project').")"; - } + $sql = "SELECT rowid, ref, title, description, public, datec, opp_amount, budget_amount,"; + $sql .= " tms, dateo, datee, date_close, fk_soc, fk_user_creat, fk_user_modif, fk_user_close, fk_statut, fk_opp_status, opp_percent,"; + $sql .= " note_private, note_public, model_pdf, usage_opportunity, usage_task, usage_bill_time, usage_organize_event, entity"; + $sql .= " FROM ".MAIN_DB_PREFIX."projet"; + if (!empty($id)) + { + $sql .= " WHERE rowid=".$id; + } + elseif (!empty($ref)) + { + $sql .= " WHERE ref='".$this->db->escape($ref)."'"; + $sql .= " AND entity IN (".getEntity('project').")"; + } - dol_syslog(get_class($this)."::fetch", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - $num_rows = $this->db->num_rows($resql); + dol_syslog(get_class($this)."::fetch", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + $num_rows = $this->db->num_rows($resql); - if ($num_rows) - { - $obj = $this->db->fetch_object($resql); + if ($num_rows) + { + $obj = $this->db->fetch_object($resql); - $this->id = $obj->rowid; - $this->ref = $obj->ref; - $this->title = $obj->title; - $this->description = $obj->description; - $this->date_c = $this->db->jdate($obj->datec); - $this->datec = $this->db->jdate($obj->datec); // TODO deprecated - $this->date_m = $this->db->jdate($obj->tms); - $this->datem = $this->db->jdate($obj->tms); // TODO deprecated - $this->date_start = $this->db->jdate($obj->dateo); - $this->date_end = $this->db->jdate($obj->datee); - $this->date_close = $this->db->jdate($obj->date_close); - $this->note_private = $obj->note_private; - $this->note_public = $obj->note_public; - $this->socid = $obj->fk_soc; - $this->user_author_id = $obj->fk_user_creat; - $this->user_modification_id = $obj->fk_user_modif; - $this->user_close_id = $obj->fk_user_close; - $this->public = $obj->public; - $this->statut = $obj->fk_statut; - $this->opp_status = $obj->fk_opp_status; - $this->opp_amount = $obj->opp_amount; - $this->opp_percent = $obj->opp_percent; - $this->budget_amount = $obj->budget_amount; - $this->modelpdf = $obj->model_pdf; - $this->usage_opportunity = (int) $obj->usage_opportunity; - $this->usage_task = (int) $obj->usage_task; - $this->usage_bill_time = (int) $obj->usage_bill_time; - $this->usage_organize_event = (int) $obj->usage_organize_event; - $this->entity = $obj->entity; + $this->id = $obj->rowid; + $this->ref = $obj->ref; + $this->title = $obj->title; + $this->description = $obj->description; + $this->date_c = $this->db->jdate($obj->datec); + $this->datec = $this->db->jdate($obj->datec); // TODO deprecated + $this->date_m = $this->db->jdate($obj->tms); + $this->datem = $this->db->jdate($obj->tms); // TODO deprecated + $this->date_start = $this->db->jdate($obj->dateo); + $this->date_end = $this->db->jdate($obj->datee); + $this->date_close = $this->db->jdate($obj->date_close); + $this->note_private = $obj->note_private; + $this->note_public = $obj->note_public; + $this->socid = $obj->fk_soc; + $this->user_author_id = $obj->fk_user_creat; + $this->user_modification_id = $obj->fk_user_modif; + $this->user_close_id = $obj->fk_user_close; + $this->public = $obj->public; + $this->statut = $obj->fk_statut; + $this->opp_status = $obj->fk_opp_status; + $this->opp_amount = $obj->opp_amount; + $this->opp_percent = $obj->opp_percent; + $this->budget_amount = $obj->budget_amount; + $this->modelpdf = $obj->model_pdf; + $this->usage_opportunity = (int) $obj->usage_opportunity; + $this->usage_task = (int) $obj->usage_task; + $this->usage_bill_time = (int) $obj->usage_bill_time; + $this->usage_organize_event = (int) $obj->usage_organize_event; + $this->entity = $obj->entity; - $this->db->free($resql); + $this->db->free($resql); - // Retreive all extrafield - // fetch optionals attributes and labels - $this->fetch_optionals(); + // Retreive all extrafield + // fetch optionals attributes and labels + $this->fetch_optionals(); - return 1; - } + return 1; + } - $this->db->free($resql); + $this->db->free($resql); - return 0; - } - else - { - $this->error = $this->db->lasterror(); - return -1; - } - } + return 0; + } + else + { + $this->error = $this->db->lasterror(); + return -1; + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Return list of elements for type, linked to a project - * - * @param string $type 'propal','order','invoice','order_supplier','invoice_supplier',... - * @param string $tablename name of table associated of the type - * @param string $datefieldname name of date field for filter - * @param int $dates Start date - * @param int $datee End date + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Return list of elements for type, linked to a project + * + * @param string $type 'propal','order','invoice','order_supplier','invoice_supplier',... + * @param string $tablename name of table associated of the type + * @param string $datefieldname name of date field for filter + * @param int $dates Start date + * @param int $datee End date * @param string $projectkey Equivalent key to fk_projet for actual type - * @return mixed Array list of object ids linked to project, < 0 or string if error - */ - public function get_element_list($type, $tablename, $datefieldname = '', $dates = '', $datee = '', $projectkey = 'fk_projet') - { - // phpcs:enable - $elements = array(); + * @return mixed Array list of object ids linked to project, < 0 or string if error + */ + public function get_element_list($type, $tablename, $datefieldname = '', $dates = '', $datee = '', $projectkey = 'fk_projet') + { + // phpcs:enable + $elements = array(); - if ($this->id <= 0) return $elements; + if ($this->id <= 0) return $elements; - $ids = $this->id; + $ids = $this->id; if ($type == 'agenda') - { - $sql = "SELECT id as rowid FROM ".MAIN_DB_PREFIX."actioncomm WHERE fk_project IN (".$ids.") AND entity IN (".getEntity('agenda').")"; - } - elseif ($type == 'expensereport') { - $sql = "SELECT ed.rowid FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet IN (".$ids.")"; + $sql = "SELECT id as rowid FROM ".MAIN_DB_PREFIX."actioncomm WHERE fk_project IN (".$ids.") AND entity IN (".getEntity('agenda').")"; } - elseif ($type == 'project_task') + elseif ($type == 'expensereport') + { + $sql = "SELECT ed.rowid FROM ".MAIN_DB_PREFIX."expensereport as e, ".MAIN_DB_PREFIX."expensereport_det as ed WHERE e.rowid = ed.fk_expensereport AND e.entity IN (".getEntity('expensereport').") AND ed.fk_projet IN (".$ids.")"; + } + elseif ($type == 'project_task') { $sql = "SELECT DISTINCT pt.rowid FROM ".MAIN_DB_PREFIX."projet_task as pt WHERE pt.fk_projet IN (".$ids.")"; } @@ -607,18 +607,18 @@ class Project extends CommonObject { $sql = 'SELECT ms.rowid, ms.fk_user_author as fk_user FROM '.MAIN_DB_PREFIX."stock_mouvement as ms, ".MAIN_DB_PREFIX."entrepot as e WHERE e.rowid = ms.fk_entrepot AND e.entity IN (".getEntity('stock').") AND ms.origintype = 'project' AND ms.fk_origin IN (".$ids.") AND ms.type_mouvement = 1"; } - elseif ($type == 'loan') - { - $sql = 'SELECT l.rowid, l.fk_user_author as fk_user FROM '.MAIN_DB_PREFIX."loan as l WHERE l.entity IN (".getEntity('loan').") AND l.fk_projet IN (".$ids.")"; - } - else + elseif ($type == 'loan') { - $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$tablename." WHERE ".$projectkey." IN (".$ids.") AND entity IN (".getEntity($type).")"; - } + $sql = 'SELECT l.rowid, l.fk_user_author as fk_user FROM '.MAIN_DB_PREFIX."loan as l WHERE l.entity IN (".getEntity('loan').") AND l.fk_projet IN (".$ids.")"; + } + else + { + $sql = "SELECT rowid FROM ".MAIN_DB_PREFIX.$tablename." WHERE ".$projectkey." IN (".$ids.") AND entity IN (".getEntity($type).")"; + } - if($dates > 0 && $type == 'loan'){ - $sql .= " AND (dateend > '".$this->db->idate($dates)."' OR dateend IS NULL)"; - } + if($dates > 0 && $type == 'loan'){ + $sql .= " AND (dateend > '".$this->db->idate($dates)."' OR dateend IS NULL)"; + } elseif ($dates > 0 && ($type != 'project_task')) // For table project_taks, we want the filter on date apply on project_time_spent table { if (empty($datefieldname) && !empty($this->table_element_date)) $datefieldname = $this->table_element_date; @@ -626,10 +626,10 @@ class Project extends CommonObject $sql .= " AND (".$datefieldname." >= '".$this->db->idate($dates)."' OR ".$datefieldname." IS NULL)"; } - if($datee > 0 && $type == 'loan'){ - $sql .= " AND (datestart < '".$this->db->idate($datee)."' OR datestart IS NULL)"; - } - elseif ($datee > 0 && ($type != 'project_task')) // For table project_taks, we want the filter on date apply on project_time_spent table + if($datee > 0 && $type == 'loan'){ + $sql .= " AND (datestart < '".$this->db->idate($datee)."' OR datestart IS NULL)"; + } + elseif ($datee > 0 && ($type != 'project_task')) // For table project_taks, we want the filter on date apply on project_time_spent table { if (empty($datefieldname) && !empty($this->table_element_date)) $datefieldname = $this->table_element_date; if (empty($datefieldname)) return 'Error this object has no date field defined'; @@ -637,94 +637,94 @@ class Project extends CommonObject } if (!$sql) return -1; - //print $sql; - dol_syslog(get_class($this)."::get_element_list", LOG_DEBUG); - $result = $this->db->query($sql); - if ($result) - { - $nump = $this->db->num_rows($result); - if ($nump) - { - $i = 0; - while ($i < $nump) - { - $obj = $this->db->fetch_object($result); + //print $sql; + dol_syslog(get_class($this)."::get_element_list", LOG_DEBUG); + $result = $this->db->query($sql); + if ($result) + { + $nump = $this->db->num_rows($result); + if ($nump) + { + $i = 0; + while ($i < $nump) + { + $obj = $this->db->fetch_object($result); - $elements[$i] = $obj->rowid.(empty($obj->fk_user) ? '' : '_'.$obj->fk_user); + $elements[$i] = $obj->rowid.(empty($obj->fk_user) ? '' : '_'.$obj->fk_user); - $i++; - } - $this->db->free($result); - } + $i++; + } + $this->db->free($result); + } - /* Return array even if empty*/ - return $elements; - } - else - { - dol_print_error($this->db); - } - } + /* Return array even if empty*/ + return $elements; + } + else + { + dol_print_error($this->db); + } + } - /** - * Delete a project from database - * - * @param User $user User - * @param int $notrigger Disable triggers - * @return int <0 if KO, 0 if not possible, >0 if OK - */ - public function delete($user, $notrigger = 0) - { - global $langs, $conf; - require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; + /** + * Delete a project from database + * + * @param User $user User + * @param int $notrigger Disable triggers + * @return int <0 if KO, 0 if not possible, >0 if OK + */ + public function delete($user, $notrigger = 0) + { + global $langs, $conf; + require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; - $error = 0; + $error = 0; - $this->db->begin(); + $this->db->begin(); - if (!$error) - { - // Delete linked contacts - $res = $this->delete_linked_contact(); - if ($res < 0) - { - $this->error = 'ErrorFailToDeleteLinkedContact'; - //$error++; - $this->db->rollback(); - return 0; - } - } + if (!$error) + { + // Delete linked contacts + $res = $this->delete_linked_contact(); + if ($res < 0) + { + $this->error = 'ErrorFailToDeleteLinkedContact'; + //$error++; + $this->db->rollback(); + return 0; + } + } - // Set fk_projet into elements to null - $listoftables = array( - 'propal'=>'fk_projet', 'commande'=>'fk_projet', 'facture'=>'fk_projet', - 'supplier_proposal'=>'fk_projet', 'commande_fournisseur'=>'fk_projet', 'facture_fourn'=>'fk_projet', - 'expensereport_det'=>'fk_projet', 'contrat'=>'fk_projet', 'fichinter'=>'fk_projet', 'don'=>'fk_projet', - 'actioncomm'=>'fk_project' - ); - foreach ($listoftables as $key => $value) - { - $sql = "UPDATE ".MAIN_DB_PREFIX.$key." SET ".$value." = NULL where ".$value." = ".$this->id; - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $this->db->lasterror(); - $error++; - break; - } - } + // Set fk_projet into elements to null + $listoftables = array( + 'propal'=>'fk_projet', 'commande'=>'fk_projet', 'facture'=>'fk_projet', + 'supplier_proposal'=>'fk_projet', 'commande_fournisseur'=>'fk_projet', 'facture_fourn'=>'fk_projet', + 'expensereport_det'=>'fk_projet', 'contrat'=>'fk_projet', 'fichinter'=>'fk_projet', 'don'=>'fk_projet', + 'actioncomm'=>'fk_project' + ); + foreach ($listoftables as $key => $value) + { + $sql = "UPDATE ".MAIN_DB_PREFIX.$key." SET ".$value." = NULL where ".$value." = ".$this->id; + $resql = $this->db->query($sql); + if (!$resql) + { + $this->errors[] = $this->db->lasterror(); + $error++; + break; + } + } - // Remove linked categories. - if (!$error) { - $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_project"; - $sql .= " WHERE fk_project = ".$this->id; + // Remove linked categories. + if (!$error) { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."categorie_project"; + $sql .= " WHERE fk_project = ".$this->id; - $result = $this->db->query($sql); - if (!$result) { - $error++; - $this->errors[] = $this->db->lasterror(); - } - } + $result = $this->db->query($sql); + if (!$result) { + $error++; + $this->errors[] = $this->db->lasterror(); + } + } // Fetch tasks $this->getLinesArray($user); @@ -754,575 +754,577 @@ class Project extends CommonObject - // Delete project - if (!$error) - { - $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet"; - $sql .= " WHERE rowid=".$this->id; + // Delete project + if (!$error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet"; + $sql .= " WHERE rowid=".$this->id; - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $langs->trans("CantRemoveProject"); - $error++; - } - } + $resql = $this->db->query($sql); + if (!$resql) + { + $this->errors[] = $langs->trans("CantRemoveProject"); + $error++; + } + } - if (!$error) - { - $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_extrafields"; - $sql .= " WHERE fk_object=".$this->id; + if (!$error) + { + $sql = "DELETE FROM ".MAIN_DB_PREFIX."projet_extrafields"; + $sql .= " WHERE fk_object=".$this->id; - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $this->db->lasterror(); - $error++; - } - } + $resql = $this->db->query($sql); + if (!$resql) + { + $this->errors[] = $this->db->lasterror(); + $error++; + } + } - if (empty($error)) { - // We remove directory - $projectref = dol_sanitizeFileName($this->ref); - if ($conf->projet->dir_output) { - $dir = $conf->projet->dir_output."/".$projectref; - if (file_exists($dir)) { - $res = @dol_delete_dir_recursive($dir); - if (!$res) { - $this->errors[] = 'ErrorFailToDeleteDir'; - $error++; - } - } - } + if (empty($error)) { + // We remove directory + $projectref = dol_sanitizeFileName($this->ref); + if ($conf->projet->dir_output) { + $dir = $conf->projet->dir_output."/".$projectref; + if (file_exists($dir)) { + $res = @dol_delete_dir_recursive($dir); + if (!$res) { + $this->errors[] = 'ErrorFailToDeleteDir'; + $error++; + } + } + } - if (!$notrigger) - { - // Call trigger - $result = $this->call_trigger('PROJECT_DELETE', $user); + if (!$notrigger) + { + // Call trigger + $result = $this->call_trigger('PROJECT_DELETE', $user); - if ($result < 0) { - $error++; - } - // End call triggers - } - } + if ($result < 0) { + $error++; + } + // End call triggers + } + } - if (empty($error)) - { - $this->db->commit(); - return 1; - } - else - { - foreach ($this->errors as $errmsg) - { + if (empty($error)) + { + $this->db->commit(); + return 1; + } + else + { + foreach ($this->errors as $errmsg) + { dol_syslog(get_class($this)."::delete ".$errmsg, LOG_ERR); $this->error .= ($this->error ? ', '.$errmsg : $errmsg); } - dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); - $this->db->rollback(); - return -1; - } - } + dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); + return -1; + } + } - /** - * Delete tasks with no children first, then task with children recursively - * - * @param User $user User - * @return int <0 if KO, 1 if OK - */ - public function deleteTasks($user) - { - $countTasks = count($this->lines); - $deleted = false; - if ($countTasks) - { - foreach ($this->lines as $task) - { - if ($task->hasChildren() <= 0) { // If there is no children (or error to detect them) - $deleted = true; - $ret = $task->delete($user); - if ($ret <= 0) - { - $this->errors[] = $this->db->lasterror(); - return -1; - } - } - } - } - $this->getLinesArray($user); - if ($deleted && count($this->lines) < $countTasks) - { - if (count($this->lines)) $this->deleteTasks($this->lines); - } - - return 1; - } - - /** - * Validate a project - * - * @param User $user User that validate - * @param int $notrigger 1=Disable triggers - * @return int <0 if KO, >0 if OK - */ - public function setValid($user, $notrigger = 0) - { - global $langs, $conf; - - $error = 0; - - if ($this->statut != 1) - { - // Check parameters - if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->title)) - { - $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("Label")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf")); - return -1; - } - - $this->db->begin(); - - $sql = "UPDATE ".MAIN_DB_PREFIX."projet"; - $sql .= " SET fk_statut = 1"; - $sql .= " WHERE rowid = ".$this->id; - $sql .= " AND entity = ".$conf->entity; - - dol_syslog(get_class($this)."::setValid", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - // Call trigger - if (empty($notrigger)) - { - $result = $this->call_trigger('PROJECT_VALIDATE', $user); - if ($result < 0) { $error++; } - // End call triggers - } - - if (!$error) - { - $this->statut = 1; - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - $this->error = join(',', $this->errors); - dol_syslog(get_class($this)."::setValid ".$this->error, LOG_ERR); - return -1; - } - } - else - { - $this->db->rollback(); - $this->error = $this->db->lasterror(); - return -1; - } - } - } - - /** - * Close a project - * - * @param User $user User that close project - * @return int <0 if KO, 0 if already closed, >0 if OK - */ - public function setClose($user) - { - global $langs, $conf; - - $now = dol_now(); - - $error = 0; - - if ($this->statut != 2) - { - $this->db->begin(); - - $sql = "UPDATE ".MAIN_DB_PREFIX."projet"; - $sql .= " SET fk_statut = 2, fk_user_close = ".$user->id.", date_close = '".$this->db->idate($now)."'"; - $sql .= " WHERE rowid = ".$this->id; - $sql .= " AND entity = ".$conf->entity; - $sql .= " AND fk_statut = 1"; - - if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) - { - // TODO What to do if fk_opp_status is not code 'WON' or 'LOST' - } - - dol_syslog(get_class($this)."::setClose", LOG_DEBUG); - $resql = $this->db->query($sql); - if ($resql) - { - // Call trigger - $result = $this->call_trigger('PROJECT_CLOSE', $user); - if ($result < 0) { $error++; } - // End call triggers - - if (!$error) - { - $this->statut = 2; - $this->db->commit(); - return 1; - } - else - { - $this->db->rollback(); - $this->error = join(',', $this->errors); - dol_syslog(get_class($this)."::setClose ".$this->error, LOG_ERR); - return -1; - } - } - else - { - $this->db->rollback(); - $this->error = $this->db->lasterror(); - return -1; - } - } - - return 0; - } - - /** - * Return status label of object - * - * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto - * @return string Label - */ - public function getLibStatut($mode = 0) - { - return $this->LibStatut($this->statut, $mode); - } - - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Renvoi status label for a status - * - * @param int $status id status - * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto - * @return string Label - */ - public function LibStatut($status, $mode = 0) - { - // phpcs:enable - global $langs; - - $statustrans = array( - 0 => 'status0', - 1 => 'status4', - 2 => 'status6', - ); - - $statusClass = 'status0'; - if (!empty($statustrans[$status])) { - $statusClass = $statustrans[$status]; - } - - return dolGetStatus($langs->trans($this->statuts_long[$status]), $langs->trans($this->statuts_short[$status]), '', $statusClass, $mode); - } - - /** - * Return clicable name (with picto eventually) - * - * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto - * @param string $option Variant ('', 'nolink') - * @param int $addlabel 0=Default, 1=Add label into string, >1=Add first chars into string - * @param string $moreinpopup Text to add into popup - * @param string $sep Separator between ref and label if option addlabel is set - * @param int $notooltip 1=Disable tooltip - * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking - * @return string String with URL - */ - public function getNomUrl($withpicto = 0, $option = '', $addlabel = 0, $moreinpopup = '', $sep = ' - ', $notooltip = 0, $save_lastsearch_value = -1) - { - global $conf, $langs, $user, $hookmanager; - - if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips - - $result = ''; - - $label = ''; - if ($option != 'nolink') $label = ''.$langs->trans("ShowProject").''; - $label .= ($label ? '
' : '').''.$langs->trans('Ref').': '.$this->ref; // The space must be after the : to not being explode when showing the title in img_picto - $label .= ($label ? '
' : '').''.$langs->trans('Label').': '.$this->title; // The space must be after the : to not being explode when showing the title in img_picto - if (!empty($this->thirdparty_name)) - $label .= ($label ? '
' : '').''.$langs->trans('ThirdParty').': '.$this->thirdparty_name; // The space must be after the : to not being explode when showing the title in img_picto - if (!empty($this->dateo)) - $label .= ($label ? '
' : '').''.$langs->trans('DateStart').': '.dol_print_date($this->dateo, 'day'); // The space must be after the : to not being explode when showing the title in img_picto - if (!empty($this->datee)) - $label .= ($label ? '
' : '').''.$langs->trans('DateEnd').': '.dol_print_date($this->datee, 'day'); // The space must be after the : to not being explode when showing the title in img_picto - if ($moreinpopup) $label .= '
'.$moreinpopup; - - $url = ''; - if ($option != 'nolink') - { - if (preg_match('/\.php$/', $option)) { - $url = dol_buildpath($option, 1).'?id='.$this->id; - } - elseif ($option == 'task') - { - $url = DOL_URL_ROOT.'/projet/tasks.php?id='.$this->id; - } - else - { - $url = DOL_URL_ROOT.'/projet/card.php?id='.$this->id; - } - // Add param to save lastsearch_values or not - $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); - if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1; - if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1'; - } - - $linkclose = ''; - if (empty($notooltip) && $user->rights->projet->lire) - { - if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) - { - $label = $langs->trans("ShowProject"); - $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; - } - $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; - $linkclose .= ' class="classfortooltip"'; - - /* - $hookmanager->initHooks(array('projectdao')); - $parameters=array('id'=>$this->id); - // Note that $action and $object may have been modified by some hooks - $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action); - if ($reshook > 0) - $linkclose = $hookmanager->resPrint; - */ + /** + * Delete tasks with no children first, then task with children recursively + * + * @param User $user User + * @return int <0 if KO, 1 if OK + */ + public function deleteTasks($user) + { + $countTasks = count($this->lines); + $deleted = false; + if ($countTasks) + { + foreach ($this->lines as $task) + { + if ($task->hasChildren() <= 0) { // If there is no children (or error to detect them) + $deleted = true; + $ret = $task->delete($user); + if ($ret <= 0) + { + $this->errors[] = $this->db->lasterror(); + return -1; + } + } + } + } + $this->getLinesArray($user); + if ($deleted && count($this->lines) < $countTasks) + { + if (count($this->lines)) $this->deleteTasks($this->lines); } - $picto = 'projectpub'; - if (!$this->public) $picto = 'project'; + return 1; + } - $linkstart = ''; - $linkend = ''; + /** + * Validate a project + * + * @param User $user User that validate + * @param int $notrigger 1=Disable triggers + * @return int <0 if KO, >0 if OK + */ + public function setValid($user, $notrigger = 0) + { + global $langs, $conf; - $result .= $linkstart; - if ($withpicto) $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); - if ($withpicto != 2) $result .= $this->ref; - $result .= $linkend; - if ($withpicto != 2) $result .= (($addlabel && $this->title) ? $sep.dol_trunc($this->title, ($addlabel > 1 ? $addlabel : 0)) : ''); + $error = 0; - global $action; - $hookmanager->initHooks(array('projectdao')); - $parameters = array('id'=>$this->id, 'getnomurl'=>$result); - $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks - if ($reshook > 0) $result = $hookmanager->resPrint; - else $result .= $hookmanager->resPrint; - - return $result; - } - - /** - * Initialise an instance with random values. - * Used to build previews or test instances. - * id must be 0 if object instance is a specimen. - * - * @return void - */ - public function initAsSpecimen() - { - global $user, $langs, $conf; - - $now = dol_now(); - - // Initialise parameters - $this->id = 0; - $this->ref = 'SPECIMEN'; - $this->specimen = 1; - $this->socid = 1; - $this->date_c = $now; - $this->date_m = $now; - $this->date_start = $now; - $this->date_end = $now + (3600 * 24 * 365); - $this->note_public = 'SPECIMEN'; - $this->fk_ele = 20000; - $this->opp_amount = 20000; - $this->budget_amount = 10000; - - $this->usage_opportunity = 1; - $this->usage_task = 1; - $this->usage_bill_time = 1; - $this->usage_organize_event = 1; - - /* - $nbp = mt_rand(1, 9); - $xnbp = 0; - while ($xnbp < $nbp) - { - $line = new Task($this->db); - $line->fk_project = 0; - $line->label = $langs->trans("Label") . " " . $xnbp; - $line->description = $langs->trans("Description") . " " . $xnbp; - - $this->lines[]=$line; - $xnbp++; - } - */ - } - - /** - * Check if user has permission on current project - * - * @param User $user Object user to evaluate - * @param string $mode Type of permission we want to know: 'read', 'write' - * @return int >0 if user has permission, <0 if user has no permission - */ - public function restrictedProjectArea($user, $mode = 'read') - { - // To verify role of users - $userAccess = 0; - if (($mode == 'read' && !empty($user->rights->projet->all->lire)) || ($mode == 'write' && !empty($user->rights->projet->all->creer)) || ($mode == 'delete' && !empty($user->rights->projet->all->supprimer))) - { - $userAccess = 1; - } - elseif ($this->public && (($mode == 'read' && !empty($user->rights->projet->lire)) || ($mode == 'write' && !empty($user->rights->projet->creer)) || ($mode == 'delete' && !empty($user->rights->projet->supprimer)))) - { - $userAccess = 1; - } - else + if ($this->statut != 1) { - foreach (array('internal', 'external') as $source) - { - $userRole = $this->liste_contact(4, $source); - $num = count($userRole); + // Check parameters + if (preg_match('/^'.preg_quote($langs->trans("CopyOf").' ').'/', $this->title)) + { + $this->error = $langs->trans("ErrorFieldFormat", $langs->transnoentities("Label")).'. '.$langs->trans('RemoveString', $langs->transnoentitiesnoconv("CopyOf")); + return -1; + } - $nblinks = 0; - while ($nblinks < $num) - { - if ($source == 'internal' && preg_match('/^PROJECT/', $userRole[$nblinks]['code']) && $user->id == $userRole[$nblinks]['id']) - { - if ($mode == 'read' && $user->rights->projet->lire) $userAccess++; - if ($mode == 'write' && $user->rights->projet->creer) $userAccess++; - if ($mode == 'delete' && $user->rights->projet->supprimer) $userAccess++; - } - $nblinks++; - } - } - //if (empty($nblinks)) // If nobody has permission, we grant creator - //{ - // if ((!empty($this->user_author_id) && $this->user_author_id == $user->id)) - // { - // $userAccess = 1; - // } - //} - } + $this->db->begin(); - return ($userAccess ? $userAccess : -1); - } + $sql = "UPDATE ".MAIN_DB_PREFIX."projet"; + $sql .= " SET fk_statut = 1"; + $sql .= " WHERE rowid = ".$this->id; + $sql .= " AND entity = ".$conf->entity; - /** - * Return array of projects a user has permission on, is affected to, or all projects - * - * @param User $user User object - * @param int $mode 0=All project I have permission on (assigned to me or public), 1=Projects assigned to me only, 2=Will return list of all projects with no test on contacts - * @param int $list 0=Return array, 1=Return string list - * @param int $socid 0=No filter on third party, id of third party - * @param string $filter additionnal filter on project (statut, ref, ...) - * @return array or string Array of projects id, or string with projects id separated with "," if list is 1 - */ - public function getProjectsAuthorizedForUser($user, $mode = 0, $list = 0, $socid = 0, $filter = '') - { - $projects = array(); - $temp = array(); + dol_syslog(get_class($this)."::setValid", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + // Call trigger + if (empty($notrigger)) + { + $result = $this->call_trigger('PROJECT_VALIDATE', $user); + if ($result < 0) { $error++; } + // End call triggers + } - $sql = "SELECT ".(($mode == 0 || $mode == 1) ? "DISTINCT " : "")."p.rowid, p.ref"; - $sql.= " FROM " . MAIN_DB_PREFIX . "projet as p"; - if ($mode == 0) - { - $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "element_contact as ec ON ec.element_id = p.rowid"; - } - elseif ($mode == 1) - { - $sql.= ", " . MAIN_DB_PREFIX . "element_contact as ec"; - } - elseif ($mode == 2) - { - // No filter. Use this if user has permission to see all project - } - $sql.= " WHERE p.entity IN (".getEntity('project').")"; - // Internal users must see project he is contact to even if project linked to a third party he can't see. - //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - if ($socid > 0) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = " . $socid . ")"; + if (!$error) + { + $this->statut = 1; + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + $this->error = join(',', $this->errors); + dol_syslog(get_class($this)."::setValid ".$this->error, LOG_ERR); + return -1; + } + } + else + { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + return -1; + } + } + } - // Get id of types of contacts for projects (This list never contains a lot of elements) - $listofprojectcontacttype=array(); - $sql2 = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc"; - $sql2.= " WHERE ctc.element = '" . $this->db->escape($this->element) . "'"; - $sql2.= " AND ctc.source = 'internal'"; - $resql = $this->db->query($sql2); - if ($resql) - { - while($obj = $this->db->fetch_object($resql)) - { - $listofprojectcontacttype[$obj->rowid]=$obj->code; - } - } - else dol_print_error($this->db); - if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0'; // To avoid syntax error if not found + /** + * Close a project + * + * @param User $user User that close project + * @return int <0 if KO, 0 if already closed, >0 if OK + */ + public function setClose($user) + { + global $langs, $conf; - if ($mode == 0) - { - $sql.= " AND ( p.public = 1"; - $sql.= " OR ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; - $sql.= " AND ec.fk_socpeople = ".$user->id.")"; - $sql.= " )"; - } - elseif ($mode == 1) - { - $sql.= " AND ec.element_id = p.rowid"; - $sql.= " AND ("; - $sql.= " ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; - $sql.= " AND ec.fk_socpeople = ".$user->id.")"; - $sql.= " )"; - } - elseif ($mode == 2) - { - // No filter. Use this if user has permission to see all project - } + $now = dol_now(); + + $error = 0; + + if ($this->statut != self::STATUS_CLOSED) + { + $this->db->begin(); + + $sql = "UPDATE ".MAIN_DB_PREFIX."projet"; + $sql .= " SET fk_statut = ".self::STATUS_CLOSED.", fk_user_close = ".$user->id.", date_close = '".$this->db->idate($now)."'"; + $sql .= " WHERE rowid = ".$this->id; + $sql .= " AND fk_statut = ".self::STATUS_VALIDATED; + + if (!empty($conf->global->PROJECT_USE_OPPORTUNITIES)) + { + // TODO What to do if fk_opp_status is not code 'WON' or 'LOST' + } + + dol_syslog(get_class($this)."::setClose", LOG_DEBUG); + $resql = $this->db->query($sql); + if ($resql) + { + // Call trigger + $result = $this->call_trigger('PROJECT_CLOSE', $user); + if ($result < 0) { $error++; } + // End call triggers + + if (!$error) + { + $this->statut = 2; + $this->db->commit(); + return 1; + } + else + { + $this->db->rollback(); + $this->error = join(',', $this->errors); + dol_syslog(get_class($this)."::setClose ".$this->error, LOG_ERR); + return -1; + } + } + else + { + $this->db->rollback(); + $this->error = $this->db->lasterror(); + return -1; + } + } + + return 0; + } + + /** + * Return status label of object + * + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto + * @return string Label + */ + public function getLibStatut($mode = 0) + { + return $this->LibStatut($this->statut, $mode); + } + + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Renvoi status label for a status + * + * @param int $status id status + * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto + * @return string Label + */ + public function LibStatut($status, $mode = 0) + { + // phpcs:enable + global $langs; + + $statustrans = array( + 0 => 'status0', + 1 => 'status4', + 2 => 'status6', + ); + + $statusClass = 'status0'; + if (!empty($statustrans[$status])) { + $statusClass = $statustrans[$status]; + } + + return dolGetStatus($langs->trans($this->statuts_long[$status]), $langs->trans($this->statuts_short[$status]), '', $statusClass, $mode); + } + + /** + * Return clicable name (with picto eventually) + * + * @param int $withpicto 0=No picto, 1=Include picto into link, 2=Only picto + * @param string $option Variant ('', 'nolink') + * @param int $addlabel 0=Default, 1=Add label into string, >1=Add first chars into string + * @param string $moreinpopup Text to add into popup + * @param string $sep Separator between ref and label if option addlabel is set + * @param int $notooltip 1=Disable tooltip + * @param int $save_lastsearch_value -1=Auto, 0=No save of lastsearch_values when clicking, 1=Save lastsearch_values whenclicking + * @return string String with URL + */ + public function getNomUrl($withpicto = 0, $option = '', $addlabel = 0, $moreinpopup = '', $sep = ' - ', $notooltip = 0, $save_lastsearch_value = -1) + { + global $conf, $langs, $user, $hookmanager; + + if (!empty($conf->dol_no_mouse_hover)) $notooltip = 1; // Force disable tooltips + + $result = ''; + + $label = ''; + if ($option != 'nolink') $label = ''.$langs->trans("ShowProject").''; + $label .= ($label ? '
' : '').''.$langs->trans('Ref').': '.$this->ref; // The space must be after the : to not being explode when showing the title in img_picto + $label .= ($label ? '
' : '').''.$langs->trans('Label').': '.$this->title; // The space must be after the : to not being explode when showing the title in img_picto + if (!empty($this->thirdparty_name)) { + $label .= ($label ? '
' : '').''.$langs->trans('ThirdParty').': '.$this->thirdparty_name; // The space must be after the : to not being explode when showing the title in img_picto + } + if (!empty($this->dateo)) { + $label .= ($label ? '
' : '').''.$langs->trans('DateStart').': '.dol_print_date($this->dateo, 'day'); // The space must be after the : to not being explode when showing the title in img_picto + } + if (!empty($this->datee)) { + $label .= ($label ? '
' : '').''.$langs->trans('DateEnd').': '.dol_print_date($this->datee, 'day'); // The space must be after the : to not being explode when showing the title in img_picto + } + if ($moreinpopup) $label .= '
'.$moreinpopup; + + $url = ''; + if ($option != 'nolink') + { + if (preg_match('/\.php$/', $option)) { + $url = dol_buildpath($option, 1).'?id='.$this->id; + } + elseif ($option == 'task') + { + $url = DOL_URL_ROOT.'/projet/tasks.php?id='.$this->id; + } + else + { + $url = DOL_URL_ROOT.'/projet/card.php?id='.$this->id; + } + // Add param to save lastsearch_values or not + $add_save_lastsearch_values = ($save_lastsearch_value == 1 ? 1 : 0); + if ($save_lastsearch_value == -1 && preg_match('/list\.php/', $_SERVER["PHP_SELF"])) $add_save_lastsearch_values = 1; + if ($add_save_lastsearch_values) $url .= '&save_lastsearch_values=1'; + } + + $linkclose = ''; + if (empty($notooltip) && $user->rights->projet->lire) + { + if (!empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) + { + $label = $langs->trans("ShowProject"); + $linkclose .= ' alt="'.dol_escape_htmltag($label, 1).'"'; + } + $linkclose .= ' title="'.dol_escape_htmltag($label, 1).'"'; + $linkclose .= ' class="classfortooltip"'; + + /* + $hookmanager->initHooks(array('projectdao')); + $parameters=array('id'=>$this->id); + // Note that $action and $object may have been modified by some hooks + $reshook=$hookmanager->executeHooks('getnomurltooltip',$parameters,$this,$action); + if ($reshook > 0) + $linkclose = $hookmanager->resPrint; + */ + } + + $picto = 'projectpub'; + if (!$this->public) $picto = 'project'; + + $linkstart = ''; + $linkend = ''; + + $result .= $linkstart; + if ($withpicto) $result .= img_object(($notooltip ? '' : $label), $picto, ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="'.(($withpicto != 2) ? 'paddingright ' : '').'classfortooltip"'), 0, 0, $notooltip ? 0 : 1); + if ($withpicto != 2) $result .= $this->ref; + $result .= $linkend; + if ($withpicto != 2) $result .= (($addlabel && $this->title) ? $sep.dol_trunc($this->title, ($addlabel > 1 ? $addlabel : 0)) : ''); + + global $action; + $hookmanager->initHooks(array('projectdao')); + $parameters = array('id'=>$this->id, 'getnomurl'=>$result); + $reshook = $hookmanager->executeHooks('getNomUrl', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks + if ($reshook > 0) $result = $hookmanager->resPrint; + else $result .= $hookmanager->resPrint; + + return $result; + } + + /** + * Initialise an instance with random values. + * Used to build previews or test instances. + * id must be 0 if object instance is a specimen. + * + * @return void + */ + public function initAsSpecimen() + { + global $user, $langs, $conf; + + $now = dol_now(); + + // Initialise parameters + $this->id = 0; + $this->ref = 'SPECIMEN'; + $this->specimen = 1; + $this->socid = 1; + $this->date_c = $now; + $this->date_m = $now; + $this->date_start = $now; + $this->date_end = $now + (3600 * 24 * 365); + $this->note_public = 'SPECIMEN'; + $this->fk_ele = 20000; + $this->opp_amount = 20000; + $this->budget_amount = 10000; + + $this->usage_opportunity = 1; + $this->usage_task = 1; + $this->usage_bill_time = 1; + $this->usage_organize_event = 1; + + /* + $nbp = mt_rand(1, 9); + $xnbp = 0; + while ($xnbp < $nbp) + { + $line = new Task($this->db); + $line->fk_project = 0; + $line->label = $langs->trans("Label") . " " . $xnbp; + $line->description = $langs->trans("Description") . " " . $xnbp; + + $this->lines[]=$line; + $xnbp++; + } + */ + } + + /** + * Check if user has permission on current project + * + * @param User $user Object user to evaluate + * @param string $mode Type of permission we want to know: 'read', 'write' + * @return int >0 if user has permission, <0 if user has no permission + */ + public function restrictedProjectArea($user, $mode = 'read') + { + // To verify role of users + $userAccess = 0; + if (($mode == 'read' && !empty($user->rights->projet->all->lire)) || ($mode == 'write' && !empty($user->rights->projet->all->creer)) || ($mode == 'delete' && !empty($user->rights->projet->all->supprimer))) + { + $userAccess = 1; + } + elseif ($this->public && (($mode == 'read' && !empty($user->rights->projet->lire)) || ($mode == 'write' && !empty($user->rights->projet->creer)) || ($mode == 'delete' && !empty($user->rights->projet->supprimer)))) + { + $userAccess = 1; + } + else + { + foreach (array('internal', 'external') as $source) + { + $userRole = $this->liste_contact(4, $source); + $num = count($userRole); + + $nblinks = 0; + while ($nblinks < $num) + { + if ($source == 'internal' && preg_match('/^PROJECT/', $userRole[$nblinks]['code']) && $user->id == $userRole[$nblinks]['id']) + { + if ($mode == 'read' && $user->rights->projet->lire) $userAccess++; + if ($mode == 'write' && $user->rights->projet->creer) $userAccess++; + if ($mode == 'delete' && $user->rights->projet->supprimer) $userAccess++; + } + $nblinks++; + } + } + //if (empty($nblinks)) // If nobody has permission, we grant creator + //{ + // if ((!empty($this->user_author_id) && $this->user_author_id == $user->id)) + // { + // $userAccess = 1; + // } + //} + } + + return ($userAccess ? $userAccess : -1); + } + + /** + * Return array of projects a user has permission on, is affected to, or all projects + * + * @param User $user User object + * @param int $mode 0=All project I have permission on (assigned to me or public), 1=Projects assigned to me only, 2=Will return list of all projects with no test on contacts + * @param int $list 0=Return array, 1=Return string list + * @param int $socid 0=No filter on third party, id of third party + * @param string $filter additionnal filter on project (statut, ref, ...) + * @return array or string Array of projects id, or string with projects id separated with "," if list is 1 + */ + public function getProjectsAuthorizedForUser($user, $mode = 0, $list = 0, $socid = 0, $filter = '') + { + $projects = array(); + $temp = array(); + + $sql = "SELECT ".(($mode == 0 || $mode == 1) ? "DISTINCT " : "")."p.rowid, p.ref"; + $sql.= " FROM " . MAIN_DB_PREFIX . "projet as p"; + if ($mode == 0) + { + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "element_contact as ec ON ec.element_id = p.rowid"; + } + elseif ($mode == 1) + { + $sql.= ", " . MAIN_DB_PREFIX . "element_contact as ec"; + } + elseif ($mode == 2) + { + // No filter. Use this if user has permission to see all project + } + $sql.= " WHERE p.entity IN (".getEntity('project').")"; + // Internal users must see project he is contact to even if project linked to a third party he can't see. + //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; + if ($socid > 0) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = " . $socid . ")"; + + // Get id of types of contacts for projects (This list never contains a lot of elements) + $listofprojectcontacttype=array(); + $sql2 = "SELECT ctc.rowid, ctc.code FROM ".MAIN_DB_PREFIX."c_type_contact as ctc"; + $sql2.= " WHERE ctc.element = '" . $this->db->escape($this->element) . "'"; + $sql2.= " AND ctc.source = 'internal'"; + $resql = $this->db->query($sql2); + if ($resql) + { + while($obj = $this->db->fetch_object($resql)) + { + $listofprojectcontacttype[$obj->rowid]=$obj->code; + } + } + else dol_print_error($this->db); + if (count($listofprojectcontacttype) == 0) $listofprojectcontacttype[0]='0'; // To avoid syntax error if not found + + if ($mode == 0) + { + $sql.= " AND ( p.public = 1"; + $sql.= " OR ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; + $sql.= " AND ec.fk_socpeople = ".$user->id.")"; + $sql.= " )"; + } + elseif ($mode == 1) + { + $sql.= " AND ec.element_id = p.rowid"; + $sql.= " AND ("; + $sql.= " ( ec.fk_c_type_contact IN (".join(',', array_keys($listofprojectcontacttype)).")"; + $sql.= " AND ec.fk_socpeople = ".$user->id.")"; + $sql.= " )"; + } + elseif ($mode == 2) + { + // No filter. Use this if user has permission to see all project + } $sql.= $filter; - //print $sql; + //print $sql; - $resql = $this->db->query($sql); - if ($resql) - { - $num = $this->db->num_rows($resql); - $i = 0; - while ($i < $num) - { - $row = $this->db->fetch_row($resql); - $projects[$row[0]] = $row[1]; - $temp[] = $row[0]; - $i++; - } + $resql = $this->db->query($sql); + if ($resql) + { + $num = $this->db->num_rows($resql); + $i = 0; + while ($i < $num) + { + $row = $this->db->fetch_row($resql); + $projects[$row[0]] = $row[1]; + $temp[] = $row[0]; + $i++; + } - $this->db->free($resql); + $this->db->free($resql); - if ($list) - { - if (empty($temp)) return '0'; - $result = implode(',', $temp); - return $result; - } - } - else - { - dol_print_error($this->db); - } + if ($list) + { + if (empty($temp)) return '0'; + $result = implode(',', $temp); + return $result; + } + } + else + { + dol_print_error($this->db); + } - return $projects; - } + return $projects; + } - /** - * Load an object from its id and create a new one in database + /** + * Load an object from its id and create a new one in database * * @param User $user User making the clone * @param int $fromid Id of object to clone @@ -1330,14 +1332,14 @@ class Project extends CommonObject * @param bool $clone_task Clone task of project * @param bool $clone_project_file Clone file of project * @param bool $clone_task_file Clone file of task (if task are copied) - * @param bool $clone_note Clone note of project - * @param bool $move_date Move task date on clone - * @param integer $notrigger No trigger flag - * @param int $newthirdpartyid New thirdparty id + * @param bool $clone_note Clone note of project + * @param bool $move_date Move task date on clone + * @param integer $notrigger No trigger flag + * @param int $newthirdpartyid New thirdparty id * @return int New id of clone */ - public function createFromClone(User $user, $fromid, $clone_contact = false, $clone_task = true, $clone_project_file = false, $clone_task_file = false, $clone_note = true, $move_date = true, $notrigger = 0, $newthirdpartyid = 0) - { + public function createFromClone(User $user, $fromid, $clone_contact = false, $clone_task = true, $clone_project_file = false, $clone_task_file = false, $clone_note = true, $move_date = true, $notrigger = 0, $newthirdpartyid = 0) + { global $langs, $conf; $error = 0; @@ -1363,40 +1365,40 @@ class Project extends CommonObject $clone_project->id = 0; if ($move_date) { - $clone_project->date_start = $now; - if (!(empty($clone_project->date_end))) - { - $clone_project->date_end = $clone_project->date_end + ($now - $orign_dt_start); - } + $clone_project->date_start = $now; + if (!(empty($clone_project->date_end))) + { + $clone_project->date_end = $clone_project->date_end + ($now - $orign_dt_start); + } } - $clone_project->datec = $now; + $clone_project->datec = $now; - if (!$clone_note) - { - $clone_project->note_private = ''; - $clone_project->note_public = ''; - } + if (!$clone_note) + { + $clone_project->note_private = ''; + $clone_project->note_public = ''; + } //Generate next ref $defaultref = ''; - $obj = empty($conf->global->PROJECT_ADDON) ? 'mod_project_simple' : $conf->global->PROJECT_ADDON; - // Search template files - $file = ''; $classname = ''; $filefound = 0; - $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); - foreach ($dirmodels as $reldir) - { - $file = dol_buildpath($reldir."core/modules/project/".$obj.'.php', 0); - if (file_exists($file)) - { - $filefound = 1; - dol_include_once($reldir."core/modules/project/".$obj.'.php'); - $modProject = new $obj; - $defaultref = $modProject->getNextValue(is_object($clone_project->thirdparty) ? $clone_project->thirdparty : null, $clone_project); - break; - } - } - if (is_numeric($defaultref) && $defaultref <= 0) $defaultref = ''; + $obj = empty($conf->global->PROJECT_ADDON) ? 'mod_project_simple' : $conf->global->PROJECT_ADDON; + // Search template files + $file = ''; $classname = ''; $filefound = 0; + $dirmodels = array_merge(array('/'), (array) $conf->modules_parts['models']); + foreach ($dirmodels as $reldir) + { + $file = dol_buildpath($reldir."core/modules/project/".$obj.'.php', 0); + if (file_exists($file)) + { + $filefound = 1; + dol_include_once($reldir."core/modules/project/".$obj.'.php'); + $modProject = new $obj; + $defaultref = $modProject->getNextValue(is_object($clone_project->thirdparty) ? $clone_project->thirdparty : null, $clone_project); + break; + } + } + if (is_numeric($defaultref) && $defaultref <= 0) $defaultref = ''; $clone_project->ref = $defaultref; $clone_project->title = $langs->trans("CopyOf").' '.$clone_project->title; @@ -1417,14 +1419,14 @@ class Project extends CommonObject $clone_project_id = $clone_project->id; //Note Update - if (!$clone_note) - { - $clone_project->note_private = ''; - $clone_project->note_public = ''; - } - else - { - $this->db->begin(); + if (!$clone_note) + { + $clone_project->note_private = ''; + $clone_project->note_public = ''; + } + else + { + $this->db->begin(); $res = $clone_project->update_note(dol_html_entity_decode($clone_project->note_public, ENT_QUOTES), '_public'); if ($res < 0) { @@ -1449,7 +1451,7 @@ class Project extends CommonObject { $this->db->commit(); } - } + } //Duplicate contact if ($clone_contact) @@ -1526,44 +1528,44 @@ class Project extends CommonObject $tab_conv_child_parent=array(); // Loop on each task, to clone it - foreach ($tasksarray as $tasktoclone) - { + foreach ($tasksarray as $tasktoclone) + { $result_clone = $taskstatic->createFromClone($user, $tasktoclone->id, $clone_project_id, $tasktoclone->fk_parent, $move_date, true, false, $clone_task_file, true, false); if ($result_clone <= 0) - { - $this->error .= $result_clone->error; + { + $this->error .= $result_clone->error; $error++; - } - else - { - $new_task_id = $result_clone; - $taskstatic->fetch($tasktoclone->id); + } + else + { + $new_task_id = $result_clone; + $taskstatic->fetch($tasktoclone->id); - //manage new parent clone task id - // if the current task has child we store the original task id and the equivalent clone task id + //manage new parent clone task id + // if the current task has child we store the original task id and the equivalent clone task id if (($taskstatic->hasChildren()) && !array_key_exists($tasktoclone->id, $tab_conv_child_parent)) { $tab_conv_child_parent[$tasktoclone->id] = $new_task_id; } - } - } + } + } - //Parse all clone node to be sure to update new parent - $tasksarray = $taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0); - foreach ($tasksarray as $task_cloned) - { - $taskstatic->fetch($task_cloned->id); - if ($taskstatic->fk_task_parent != 0) - { - $taskstatic->fk_task_parent = $tab_conv_child_parent[$taskstatic->fk_task_parent]; - } - $res = $taskstatic->update($user, $notrigger); - if ($result_clone <= 0) - { - $this->error .= $taskstatic->error; + //Parse all clone node to be sure to update new parent + $tasksarray = $taskstatic->getTasksArray(0, 0, $clone_project_id, $socid, 0); + foreach ($tasksarray as $task_cloned) + { + $taskstatic->fetch($task_cloned->id); + if ($taskstatic->fk_task_parent != 0) + { + $taskstatic->fk_task_parent = $tab_conv_child_parent[$taskstatic->fk_task_parent]; + } + $res = $taskstatic->update($user, $notrigger); + if ($result_clone <= 0) + { + $this->error .= $taskstatic->error; $error++; - } - } + } + } } } @@ -1580,17 +1582,17 @@ class Project extends CommonObject dol_syslog(get_class($this)."::createFromClone nbError: ".$error." error : ".$this->error, LOG_ERR); return -1; } - } + } - /** + /** * Shift project task date from current date to delta * * @param integer $old_project_dt_start Old project start date * @return int 1 if OK or < 0 if KO */ - public function shiftTaskDate($old_project_dt_start) - { + public function shiftTaskDate($old_project_dt_start) + { global $user, $langs, $conf; $error=0; @@ -1603,65 +1605,65 @@ class Project extends CommonObject $tasksarray=$taskstatic->getTasksArray(0, 0, $this->id, $socid, 0); - foreach ($tasksarray as $tasktoshiftdate) - { - $to_update=false; - // Fetch only if update of date will be made - if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end))) - { - //dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG); - $to_update=true; - $task = new Task($this->db); - $result = $task->fetch($tasktoshiftdate->id); - if (!$result) - { - $error++; - $this->error.=$task->error; - } - } + foreach ($tasksarray as $tasktoshiftdate) + { + $to_update=false; + // Fetch only if update of date will be made + if ((!empty($tasktoshiftdate->date_start)) || (!empty($tasktoshiftdate->date_end))) + { + //dol_syslog(get_class($this)."::shiftTaskDate to_update", LOG_DEBUG); + $to_update=true; + $task = new Task($this->db); + $result = $task->fetch($tasktoshiftdate->id); + if (!$result) + { + $error++; + $this->error.=$task->error; + } + } //print "$this->date_start + $tasktoshiftdate->date_start - $old_project_dt_start";exit; - //Calcultate new task start date with difference between old proj start date and origin task start date - if (!empty($tasktoshiftdate->date_start)) - { + //Calcultate new task start date with difference between old proj start date and origin task start date + if (!empty($tasktoshiftdate->date_start)) + { $task->date_start = $this->date_start + ($tasktoshiftdate->date_start - $old_project_dt_start); - } + } - //Calcultate new task end date with difference between origin proj end date and origin task end date - if (!empty($tasktoshiftdate->date_end)) - { + //Calcultate new task end date with difference between origin proj end date and origin task end date + if (!empty($tasktoshiftdate->date_end)) + { $task->date_end = $this->date_start + ($tasktoshiftdate->date_end - $old_project_dt_start); - } + } if ($to_update) { - $result = $task->update($user); - if (!$result) - { - $error++; - $this->error .= $task->error; - } + $result = $task->update($user); + if (!$result) + { + $error++; + $this->error .= $task->error; + } } - } - if ($error != 0) - { - return -1; - } - return $result; + } + if ($error != 0) + { + return -1; + } + return $result; } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Associate element to a project * * @param string $tableName Table of the element to update * @param int $elementSelectId Key-rowid of the line of the element to update * @return int 1 if OK or < 0 if KO - */ + */ public function update_element($tableName, $elementSelectId) { - // phpcs:enable + // phpcs:enable $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName; if ($tableName == "actioncomm") @@ -1685,19 +1687,19 @@ class Project extends CommonObject } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Associate element to a project * * @param string $tableName Table of the element to update * @param int $elementSelectId Key-rowid of the line of the element to update * @param string $projectfield The column name that stores the link with the project - * + * * @return int 1 if OK or < 0 if KO */ public function remove_element($tableName, $elementSelectId, $projectfield = 'fk_projet') { - // phpcs:enable + // phpcs:enable $sql = "UPDATE ".MAIN_DB_PREFIX.$tableName; if ($tableName == "actioncomm") @@ -1761,130 +1763,130 @@ class Project extends CommonObject * @param int $userid Time spent by a particular user * @return int <0 if OK, >0 if KO */ - public function loadTimeSpent($datestart, $taskid = 0, $userid = 0) - { - $error=0; + public function loadTimeSpent($datestart, $taskid = 0, $userid = 0) + { + $error=0; - $this->weekWorkLoad=array(); - $this->weekWorkLoadPerTask=array(); + $this->weekWorkLoad=array(); + $this->weekWorkLoadPerTask=array(); - if (empty($datestart)) dol_print_error('', 'Error datestart parameter is empty'); + if (empty($datestart)) dol_print_error('', 'Error datestart parameter is empty'); - $sql = "SELECT ptt.rowid as taskid, ptt.task_duration, ptt.task_date, ptt.task_datehour, ptt.fk_task"; - $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt"; - $sql.= " WHERE ptt.fk_task = pt.rowid"; - $sql.= " AND pt.fk_projet = ".$this->id; - $sql.= " AND (ptt.task_date >= '".$this->db->idate($datestart)."' "; - $sql.= " AND ptt.task_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'w') - 1)."')"; - if ($taskid) $sql.= " AND ptt.fk_task=".$taskid; - if (is_numeric($userid)) $sql.= " AND ptt.fk_user=".$userid; + $sql = "SELECT ptt.rowid as taskid, ptt.task_duration, ptt.task_date, ptt.task_datehour, ptt.fk_task"; + $sql.= " FROM ".MAIN_DB_PREFIX."projet_task_time AS ptt, ".MAIN_DB_PREFIX."projet_task as pt"; + $sql.= " WHERE ptt.fk_task = pt.rowid"; + $sql.= " AND pt.fk_projet = ".$this->id; + $sql.= " AND (ptt.task_date >= '".$this->db->idate($datestart)."' "; + $sql.= " AND ptt.task_date <= '".$this->db->idate(dol_time_plus_duree($datestart, 1, 'w') - 1)."')"; + if ($taskid) $sql.= " AND ptt.fk_task=".$taskid; + if (is_numeric($userid)) $sql.= " AND ptt.fk_user=".$userid; - //print $sql; - $resql=$this->db->query($sql); - if ($resql) - { - $daylareadyfound=array(); + //print $sql; + $resql=$this->db->query($sql); + if ($resql) + { + $daylareadyfound=array(); - $num = $this->db->num_rows($resql); - $i = 0; - // Loop on each record found, so each couple (project id, task id) + $num = $this->db->num_rows($resql); + $i = 0; + // Loop on each record found, so each couple (project id, task id) while ($i < $num) - { - $obj=$this->db->fetch_object($resql); - $day=$this->db->jdate($obj->task_date); // task_date is date without hours + { + $obj=$this->db->fetch_object($resql); + $day=$this->db->jdate($obj->task_date); // task_date is date without hours if (empty($daylareadyfound[$day])) - { + { $this->weekWorkLoad[$day] = $obj->task_duration; $this->weekWorkLoadPerTask[$day][$obj->fk_task] = $obj->task_duration; } else - { + { $this->weekWorkLoad[$day] += $obj->task_duration; $this->weekWorkLoadPerTask[$day][$obj->fk_task] += $obj->task_duration; } - $daylareadyfound[$day]=1; - $i++; + $daylareadyfound[$day]=1; + $i++; } - $this->db->free($resql); - return 1; - } - else - { - $this->error = "Error ".$this->db->lasterror(); - dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); - return -1; - } - } + $this->db->free($resql); + return 1; + } + else + { + $this->error = "Error ".$this->db->lasterror(); + dol_syslog(get_class($this)."::fetch ".$this->error, LOG_ERR); + return -1; + } + } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps - /** - * Load indicators for dashboard (this->nbtodo and this->nbtodolate) - * - * @param User $user Objet user - * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK - */ - public function load_board($user) - { - // phpcs:enable - global $conf, $langs; + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + /** + * Load indicators for dashboard (this->nbtodo and this->nbtodolate) + * + * @param User $user Objet user + * @return WorkboardResponse|int <0 if KO, WorkboardResponse if OK + */ + public function load_board($user) + { + // phpcs:enable + global $conf, $langs; - // For external user, no check is done on company because readability is managed by public status of project and assignement. - //$socid=$user->socid; + // For external user, no check is done on company because readability is managed by public status of project and assignement. + //$socid=$user->socid; $projectsListId = null; - if (!$user->rights->projet->all->lire) $projectsListId = $this->getProjectsAuthorizedForUser($user, 0, 1); + if (!$user->rights->projet->all->lire) $projectsListId = $this->getProjectsAuthorizedForUser($user, 0, 1); - $sql = "SELECT p.rowid, p.fk_statut as status, p.fk_opp_status, p.datee as datee"; - $sql .= " FROM (".MAIN_DB_PREFIX."projet as p"; - $sql .= ")"; - $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; - // For external user, no check is done on company permission because readability is managed by public status of project and assignement. - //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; - $sql .= " WHERE p.fk_statut = 1"; - $sql .= " AND p.entity IN (".getEntity('project').')'; - if (!empty($projectsListId)) $sql .= " AND p.rowid IN (".$projectsListId.")"; - // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser - //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - // For external user, no check is done on company permission because readability is managed by public status of project and assignement. - //if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; + $sql = "SELECT p.rowid, p.fk_statut as status, p.fk_opp_status, p.datee as datee"; + $sql .= " FROM (".MAIN_DB_PREFIX."projet as p"; + $sql .= ")"; + $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; + // For external user, no check is done on company permission because readability is managed by public status of project and assignement. + //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; + $sql .= " WHERE p.fk_statut = 1"; + $sql .= " AND p.entity IN (".getEntity('project').')'; + if (!empty($projectsListId)) $sql .= " AND p.rowid IN (".$projectsListId.")"; + // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser + //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; + // For external user, no check is done on company permission because readability is managed by public status of project and assignement. + //if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; - //print $sql; - $resql = $this->db->query($sql); - if ($resql) - { - $project_static = new Project($this->db); + //print $sql; + $resql = $this->db->query($sql); + if ($resql) + { + $project_static = new Project($this->db); - $response = new WorkboardResponse(); - $response->warning_delay = $conf->projet->warning_delay / 60 / 60 / 24; - $response->label = $langs->trans("OpenedProjects"); - $response->labelShort = $langs->trans("Opened"); - if ($user->rights->projet->all->lire) $response->url = DOL_URL_ROOT.'/projet/list.php?search_status=1&mainmenu=project'; - else $response->url = DOL_URL_ROOT.'/projet/list.php?search_project_user=-1&search_status=1&mainmenu=project'; - $response->img = img_object('', "projectpub"); + $response = new WorkboardResponse(); + $response->warning_delay = $conf->projet->warning_delay / 60 / 60 / 24; + $response->label = $langs->trans("OpenedProjects"); + $response->labelShort = $langs->trans("Opened"); + if ($user->rights->projet->all->lire) $response->url = DOL_URL_ROOT.'/projet/list.php?search_status=1&mainmenu=project'; + else $response->url = DOL_URL_ROOT.'/projet/list.php?search_project_user=-1&search_status=1&mainmenu=project'; + $response->img = img_object('', "projectpub"); - // This assignment in condition is not a bug. It allows walking the results. - while ($obj = $this->db->fetch_object($resql)) - { - $response->nbtodo++; + // This assignment in condition is not a bug. It allows walking the results. + while ($obj = $this->db->fetch_object($resql)) + { + $response->nbtodo++; - $project_static->statut = $obj->status; - $project_static->opp_status = $obj->opp_status; - $project_static->datee = $this->db->jdate($obj->datee); + $project_static->statut = $obj->status; + $project_static->opp_status = $obj->opp_status; + $project_static->datee = $this->db->jdate($obj->datee); - if ($project_static->hasDelay()) { - $response->nbtodolate++; - } - } + if ($project_static->hasDelay()) { + $response->nbtodolate++; + } + } - return $response; - } - else - { - $this->error = $this->db->error(); - return -1; - } - } + return $response; + } + else + { + $this->error = $this->db->error(); + return -1; + } + } /** @@ -1905,7 +1907,7 @@ class Project extends CommonObject } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Charge indicateurs this->nb pour le tableau de bord * @@ -1913,37 +1915,37 @@ class Project extends CommonObject */ public function load_state_board() { - // phpcs:enable - global $user; + // phpcs:enable + global $user; - $this->nb = array(); + $this->nb = array(); - $sql = "SELECT count(p.rowid) as nb"; - $sql .= " FROM ".MAIN_DB_PREFIX."projet as p"; - $sql .= " WHERE"; - $sql .= " p.entity IN (".getEntity('project').")"; + $sql = "SELECT count(p.rowid) as nb"; + $sql .= " FROM ".MAIN_DB_PREFIX."projet as p"; + $sql .= " WHERE"; + $sql .= " p.entity IN (".getEntity('project').")"; if (!$user->rights->projet->all->lire) { $projectsListId = $this->getProjectsAuthorizedForUser($user, 0, 1); $sql .= "AND p.rowid IN (".$projectsListId.")"; } - $resql = $this->db->query($sql); - if ($resql) - { - while ($obj = $this->db->fetch_object($resql)) - { - $this->nb["projects"] = $obj->nb; - } - $this->db->free($resql); - return 1; - } - else - { - dol_print_error($this->db); - $this->error = $this->db->error(); - return -1; - } + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $this->nb["projects"] = $obj->nb; + } + $this->db->free($resql); + return 1; + } + else + { + dol_print_error($this->db); + $this->error = $this->db->error(); + return -1; + } } @@ -1954,14 +1956,14 @@ class Project extends CommonObject */ public function hasDelay() { - global $conf; + global $conf; - if (!($this->statut == self::STATUS_VALIDATED)) return false; - if (!$this->datee && !$this->date_end) return false; + if (!($this->statut == self::STATUS_VALIDATED)) return false; + if (!$this->datee && !$this->date_end) return false; - $now = dol_now(); + $now = dol_now(); - return ($this->datee ? $this->datee : $this->date_end) < ($now - $conf->projet->warning_delay); + return ($this->datee ? $this->datee : $this->date_end) < ($now - $conf->projet->warning_delay); } @@ -1973,43 +1975,43 @@ class Project extends CommonObject */ public function info($id) { - $sql = 'SELECT c.rowid, datec as datec, tms as datem,'; - $sql .= ' date_close as datecloture,'; - $sql .= ' fk_user_creat as fk_user_author, fk_user_close as fk_use_cloture'; - $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as c'; - $sql .= ' WHERE c.rowid = '.$id; - $result = $this->db->query($sql); - if ($result) - { - if ($this->db->num_rows($result)) - { - $obj = $this->db->fetch_object($result); - $this->id = $obj->rowid; - if ($obj->fk_user_author) - { - $cuser = new User($this->db); - $cuser->fetch($obj->fk_user_author); - $this->user_creation = $cuser; - } + $sql = 'SELECT c.rowid, datec as datec, tms as datem,'; + $sql .= ' date_close as datecloture,'; + $sql .= ' fk_user_creat as fk_user_author, fk_user_close as fk_use_cloture'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'projet as c'; + $sql .= ' WHERE c.rowid = '.$id; + $result = $this->db->query($sql); + if ($result) + { + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + $this->id = $obj->rowid; + if ($obj->fk_user_author) + { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } - if ($obj->fk_user_cloture) - { - $cluser = new User($this->db); - $cluser->fetch($obj->fk_user_cloture); - $this->user_cloture = $cluser; - } + if ($obj->fk_user_cloture) + { + $cluser = new User($this->db); + $cluser->fetch($obj->fk_user_cloture); + $this->user_cloture = $cluser; + } - $this->date_creation = $this->db->jdate($obj->datec); - $this->date_modification = $this->db->jdate($obj->datem); - $this->date_cloture = $this->db->jdate($obj->datecloture); - } + $this->date_creation = $this->db->jdate($obj->datec); + $this->date_modification = $this->db->jdate($obj->datem); + $this->date_cloture = $this->db->jdate($obj->datecloture); + } - $this->db->free($result); - } - else - { - dol_print_error($this->db); - } + $this->db->free($result); + } + else + { + dol_print_error($this->db); + } } /** @@ -2020,7 +2022,7 @@ class Project extends CommonObject * Existing categories are left untouch. * * @param int[]|int $categories Category or categories IDs - * @return void + * @return void */ public function setCategories($categories) { @@ -2079,9 +2081,9 @@ class Project extends CommonObject */ public function getLinesArray($user) { - require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; - $taskstatic = new Task($this->db); + require_once DOL_DOCUMENT_ROOT.'/projet/class/task.class.php'; + $taskstatic = new Task($this->db); - $this->lines = $taskstatic->getTasksArray(0, $user, $this->id, 0, 0); + $this->lines = $taskstatic->getTasksArray(0, $user, $this->id, 0, 0); } } diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 9cc36dbb7b4..67bdbf5142c 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -636,6 +636,12 @@ class Societe extends CommonObject */ public $multicurrency_code; + /** + * @var Account Default BAN account + */ + public $bank_account; + + /** * Constructor * @@ -4155,6 +4161,17 @@ class Societe extends CommonObject } } + if (! isset($this->bank_account)) { + require_once DOL_DOCUMENT_ROOT.'/societe/class/companybankaccount.class.php'; + $bac = new CompanyBankAccount($this->db); + $result = $bac->fetch(0, $this->id); + if ($result > 0) { + $this->bank_account = $bac; + } else { + $this->bank_account = ''; + } + } + $modelpath = "core/modules/societe/doc/"; $result = $this->commonGenerateDocument($modelpath, $modele, $outputlangs, $hidedetails, $hidedesc, $hideref, $moreparams);