From 51028c845de6e827f48ae26fe2de1d14c3eec682 Mon Sep 17 00:00:00 2001 From: Gerhard Stephan Date: Thu, 15 Feb 2018 10:15:27 +0100 Subject: [PATCH 1/3] Export to PDF using LibreOffice 5 command line --- htdocs/includes/odtphp/odf.php | 143 ++++++++++++++++++--------------- 1 file changed, 78 insertions(+), 65 deletions(-) diff --git a/htdocs/includes/odtphp/odf.php b/htdocs/includes/odtphp/odf.php index 19fd3390937..0b3501be6be 100644 --- a/htdocs/includes/odtphp/odf.php +++ b/htdocs/includes/odtphp/odf.php @@ -574,85 +574,98 @@ IMG; dol_syslog(get_class($this).'::exportAsAttachedPDF $name='.$name, LOG_DEBUG); $this->saveToDisk($name); - $execmethod=(empty($conf->global->MAIN_EXEC_USE_POPEN)?1:2); // 1 or 2 - // Method 1 sometimes hang the server. - - if (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF)) + // Export to PDF using LibreOffice + if ($conf->global->MAIN_ODT_AS_PDF == 'libreoffice') { - // If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87 - - // MAIN_ODT_AS_PDF should be "sudo -u unoconv /usr/bin/unoconv" and userunoconv must have sudo to be root by adding file /etc/sudoers.d/unoconv with content www-data ALL=(unoconv) NOPASSWD: /usr/bin/unoconv . - - // Try this with www-data user: /usr/bin/unoconv -vvvv -f pdf /tmp/document-example.odt - // It must return: - //Verbosity set to level 4 - //Using office base path: /usr/lib/libreoffice - //Using office binary path: /usr/lib/libreoffice/program - //DEBUG: Connection type: socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext - //DEBUG: Existing listener not found. - //DEBUG: Launching our own listener using /usr/lib/libreoffice/program/soffice.bin. - //LibreOffice listener successfully started. (pid=9287) - //Input file: /tmp/document-example.odt - //unoconv: file `/tmp/document-example.odt' does not exist. - //unoconv: RuntimeException during import phase: - //Office probably died. Unsupported URL : "type detection failed" - //DEBUG: Terminating LibreOffice instance. - //DEBUG: Waiting for LibreOffice instance to exit - - // It fails: - // - set shel of user to bash instead of nologin. - // - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back - - $command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name); - //$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name); + // Executing convert to PDF using libreoffice 5 (using windows libreoffice must be in path) + $command ='soffice.exe -headless -convert-to pdf -outdir '. escapeshellarg(dirname($name)). " ".escapeshellarg($name); + exec($command, $output_arr, $retval); + + // Split extension from name to allow deleting the source using MAIN_ODT_AS_PDF_DEL_SOURCE + $name=preg_replace('/\.odt/i', '', $name); } else { - // deprecated old method - $name=preg_replace('/\.odt/i', '', $name); + $execmethod=(empty($conf->global->MAIN_EXEC_USE_POPEN)?1:2); // 1 or 2 + // Method 1 sometimes hang the server. - if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) + if (preg_match('/unoconv/', $conf->global->MAIN_ODT_AS_PDF)) { - $command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); + // If issue with unoconv, see https://github.com/dagwieers/unoconv/issues/87 + + // MAIN_ODT_AS_PDF should be "sudo -u unoconv /usr/bin/unoconv" and userunoconv must have sudo to be root by adding file /etc/sudoers.d/unoconv with content www-data ALL=(unoconv) NOPASSWD: /usr/bin/unoconv . + + // Try this with www-data user: /usr/bin/unoconv -vvvv -f pdf /tmp/document-example.odt + // It must return: + //Verbosity set to level 4 + //Using office base path: /usr/lib/libreoffice + //Using office binary path: /usr/lib/libreoffice/program + //DEBUG: Connection type: socket,host=127.0.0.1,port=2002;urp;StarOffice.ComponentContext + //DEBUG: Existing listener not found. + //DEBUG: Launching our own listener using /usr/lib/libreoffice/program/soffice.bin. + //LibreOffice listener successfully started. (pid=9287) + //Input file: /tmp/document-example.odt + //unoconv: file `/tmp/document-example.odt' does not exist. + //unoconv: RuntimeException during import phase: + //Office probably died. Unsupported URL : "type detection failed" + //DEBUG: Terminating LibreOffice instance. + //DEBUG: Waiting for LibreOffice instance to exit + + // It fails: + // - set shel of user to bash instead of nologin. + // - set permission to read/write to user on home directory /var/www so user can create the libreoffice , dconf and .cache dir and files then set permission back + + $command = $conf->global->MAIN_ODT_AS_PDF.' '.escapeshellcmd($name); + //$command = '/usr/bin/unoconv -vvv '.escapeshellcmd($name); } else { - dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING); - $command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); - } - } + // deprecated old method + $name=preg_replace('/\.odt/i', '', $name); - //$dirname=dirname($name); - //$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname; - - dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command,LOG_DEBUG); - if ($execmethod == 1) - { - exec($command, $output_arr, $retval); - } - if ($execmethod == 2) - { - $outputfile = DOL_DATA_ROOT.'/odt2pdf.log'; - - $ok=0; - $handle = fopen($outputfile, 'w'); - if ($handle) - { - dol_syslog(get_class($this)."Run command ".$command,LOG_DEBUG); - fwrite($handle, $command."\n"); - $handlein = popen($command, 'r'); - while (!feof($handlein)) + if (!empty($conf->global->MAIN_DOL_SCRIPTS_ROOT)) { - $read = fgets($handlein); - fwrite($handle, $read); - $output_arr[]=$read; + $command = $conf->global->MAIN_DOL_SCRIPTS_ROOT.'/scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); + } + else + { + dol_syslog(get_class($this).'::exportAsAttachedPDF is used but the constant MAIN_DOL_SCRIPTS_ROOT with path to script directory was not defined.', LOG_WARNING); + $command = '../../scripts/odt2pdf/odt2pdf.sh '.escapeshellcmd($name).' '.(is_numeric($conf->global->MAIN_ODT_AS_PDF)?'jodconverter':$conf->global->MAIN_ODT_AS_PDF); } - pclose($handlein); - fclose($handle); } - if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK)); - } + //$dirname=dirname($name); + //$command = DOL_DOCUMENT_ROOT.'/includes/odtphp/odt2pdf.sh '.$name.' '.$dirname; + + dol_syslog(get_class($this).'::exportAsAttachedPDF $execmethod='.$execmethod.' Run command='.$command,LOG_DEBUG); + if ($execmethod == 1) + { + exec($command, $output_arr, $retval); + } + if ($execmethod == 2) + { + $outputfile = DOL_DATA_ROOT.'/odt2pdf.log'; + + $ok=0; + $handle = fopen($outputfile, 'w'); + if ($handle) + { + dol_syslog(get_class($this)."Run command ".$command,LOG_DEBUG); + fwrite($handle, $command."\n"); + $handlein = popen($command, 'r'); + while (!feof($handlein)) + { + $read = fgets($handlein); + fwrite($handle, $read); + $output_arr[]=$read; + } + pclose($handlein); + fclose($handle); + } + if (! empty($conf->global->MAIN_UMASK)) @chmod($outputfile, octdec($conf->global->MAIN_UMASK)); + } + } + if ($retval == 0) { dol_syslog(get_class($this).'::exportAsAttachedPDF $ret_val='.$retval, LOG_DEBUG); From 634f3bc025fe7e5ffed57d3ace07df6b6d12b582 Mon Sep 17 00:00:00 2001 From: dolibarr95 <24292300+dolibarr95@users.noreply.github.com> Date: Thu, 15 Feb 2018 13:38:21 +0100 Subject: [PATCH 2/3] Bad copy/paste --- htdocs/core/lib/functions.lib.php | 58 +++++++++++++++---------------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 89e31d00703..3c1dcab3378 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2229,14 +2229,14 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone=($separ!=''?'(':'').substr($newphone,0,3).($separ!=''?')':'').$separ.substr($newphone,3,3).($separ!=''?'-':'').substr($newphone,6,4); } } - elseif (strtoupper($parameters['countrycode']) == "PT" ) + elseif (strtoupper($countrycode) == "PT" ) {//Portugal if (dol_strlen($object) == 13) {//ex: +351_ABC_DEF_GHI $newphone= substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,3).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "SR" ) + elseif (strtoupper($countrycode) == "SR" ) {//Suriname if (dol_strlen($object) == 10) {//ex: +597_ABC_DEF @@ -2247,7 +2247,7 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone= substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,4); } } - elseif (strtoupper($parameters['countrycode']) == "DE" ) + elseif (strtoupper($countrycode) == "DE" ) {//Allemagne if (dol_strlen($object) == 14) {//ex: +49_ABCD_EFGH_IJK @@ -2258,42 +2258,42 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone= substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,4).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "ES") + elseif (strtoupper($countrycode) == "ES") {//Espagne if (dol_strlen($object) == 12) {//ex: +34_ABC_DEF_GHI $newphone= substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,3); } } - elseif (strtoupper($parameters['countrycode']) == "BF") + elseif (strtoupper($countrycode) == "BF") {// Burkina Faso if (dol_strlen($newphone) == 12) {//ex : +22 A BC_DE_FG_HI $newphone= substr($newphone,0,3).$separ.substr($newphone,3,1).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "RO") + elseif (strtoupper($countrycode) == "RO") {// Roumanie if (dol_strlen($newphone) == 12) {//ex : +40 AB_CDE_FG_HI $newphone= substr($newphone,0,3).$separ.substr($newphone,3,2).$separ.substr($newphone,5,3).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "TR") + elseif (strtoupper($countrycode) == "TR") {//Turquie if (dol_strlen($object) == 13) {//ex : +90 ABC_DEF_GHIJ $newphone= substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,4); } } - elseif (strtoupper($parameters['countrycode']) == "US") + elseif (strtoupper($countrycode) == "US") {//Etat-Unis if (dol_strlen($newphone) == 12) {//ex: +1 ABC_DEF_GHIJ $newphone= substr($newphone,0,2).$separ.substr($newphone,2,3).$separ.substr($newphone,5,3).$separ.substr($newphone,8,4); } } - elseif (strtoupper($parameters['countrycode']) == "MX") + elseif (strtoupper($countrycode) == "MX") {//Mexique if (dol_strlen($newphone) == 12) {//ex: +52 ABCD_EFG_HI @@ -2308,14 +2308,14 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,4); } } - elseif (strtoupper($parameters['countrycode']) == "ML") + elseif (strtoupper($countrycode) == "ML") {//Mali if(dol_strlen($newphone) == 12) {//ex: +223 AB_CD_EF_GH $newphone = substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "TH") + elseif (strtoupper($countrycode) == "TH") {//Thaïlande if(dol_strlen($newphone) == 11) {//ex: +66_ABC_DE_FGH @@ -2326,7 +2326,7 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,3).$separ.substr($newphone,3,1).$separ.substr($newphone,4,3).$separ.substr($newphone,7,2).$separ.substr($newphone,9,3); } } - elseif (strtoupper($parameters['countrycode']) == "MU") + elseif (strtoupper($countrycode) == "MU") {//Maurice if(dol_strlen($newphone) == 11) {//ex: +230_ABC_DE_FG @@ -2337,14 +2337,14 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,4).$separ.substr($newphone,4,4).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "ZA") + elseif (strtoupper($countrycode) == "ZA") {//Afrique du sud if(dol_strlen($newphone) == 12) {//ex: +27_AB_CDE_FG_HI $newphone = substr($newphone,0,3).$separ.substr($newphone,3,2).$separ.substr($newphone,5,3).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "SY") + elseif (strtoupper($countrycode) == "SY") {//Syrie if(dol_strlen($newphone) == 12) {//ex: +963_AB_CD_EF_GH @@ -2355,7 +2355,7 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "AE") + elseif (strtoupper($countrycode) == "AE") {//Emirats Arabes Unis if(dol_strlen($newphone) == 12) {//ex: +971_ABC_DEF_GH @@ -2370,14 +2370,14 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,3).$separ.substr($newphone,10,4); } } - elseif (strtoupper($parameters['countrycode']) == "DZ") + elseif (strtoupper($countrycode) == "DZ") {//Algérie if(dol_strlen($newphone) == 13) {//ex: +213_ABC_DEF_GHI $newphone = substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,3).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "BE") + elseif (strtoupper($countrycode) == "BE") {//Belgique if(dol_strlen($newphone) == 11) {//ex: +32_ABC_DE_FGH @@ -2388,42 +2388,42 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,3); } } - elseif (strtoupper($parameters['countrycode']) == "PF") + elseif (strtoupper($countrycode) == "PF") {//Polynésie française if(dol_strlen($newphone) == 12) {//ex: +689_AB_CD_EF_GH $newphone = substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,2); } } - elseif (strtoupper($parameters['countrycode']) == "CO") + elseif (strtoupper($countrycode) == "CO") {//Colombie if(dol_strlen($newphone) == 13) {//ex: +57_ABC_DEF_GH_IJ $newphone = substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,2).$separ.substr($newphone,11,2); } } - elseif (strtoupper($parameters['countrycode']) == "JO") + elseif (strtoupper($countrycode) == "JO") {//Jordanie if(dol_strlen($newphone) == 12) {//ex: +962_A_BCD_EF_GH $newphone = substr($newphone,0,4).$separ.substr($newphone,4,1).$separ.substr($newphone,5,3).$separ.substr($newphone,7,2).$separ.substr($newphone,9,2); } } - elseif (strtoupper($parameters['countrycode']) == "MG") + elseif (strtoupper($countrycode) == "MG") {//Madagascar if(dol_strlen($newphone) == 13) {//ex: +261_AB_CD_EF_GHI $newphone = substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,2).$separ.substr($newphone,8,2).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "GB") + elseif (strtoupper($countrycode) == "GB") {//Royaume uni if(dol_strlen($newphone) == 13) {//ex: +44_ABCD_EFG_HIJ $newphone = substr($newphone,0,3).$separ.substr($newphone,3,4).$separ.substr($newphone,7,3).$separ.substr($newphone,10,3); } } - elseif (strtoupper($parameters['countrycode']) == "CH") + elseif (strtoupper($countrycode) == "CH") {//Suisse if(dol_strlen($newphone) == 12) {//ex: +41_AB_CDE_FG_HI @@ -2434,35 +2434,35 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone =$newphone = substr($newphone,0,3).$separ.substr($newphone,3,2).$separ.substr($newphone,5,3).$separ.substr($newphone,8,3).$separ.substr($newphone,11,4); } } - elseif (strtoupper($parameters['countrycode']) == "TN") + elseif (strtoupper($countrycode) == "TN") {//Tunisie if(dol_strlen($newphone) == 12) {//ex: +216_AB_CDE_FGH $newphone = substr($newphone,0,4).$separ.substr($newphone,4,2).$separ.substr($newphone,6,3).$separ.substr($newphone,9,3); } } - elseif (strtoupper($parameters['countrycode']) == "GF") + elseif (strtoupper($countrycode) == "GF") {//Guyane francaise if(dol_strlen($newphone) == 13) {//ex: +594_ABC_DE_FG_HI (ABC=594 de nouveau) $newphone = substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,2).$separ.substr($newphone,9,2).$separ.substr($newphone,11,2); } } - elseif (strtoupper($parameters['countrycode']) == "GP") + elseif (strtoupper($countrycode) == "GP") {//Guadeloupe if(dol_strlen($newphone) == 13) {//ex: +590_ABC_DE_FG_HI (ABC=590 de nouveau) $newphone = substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,2).$separ.substr($newphone,9,2).$separ.substr($newphone,11,2); } } - elseif (strtoupper($parameters['countrycode']) == "MQ") + elseif (strtoupper($countrycode) == "MQ") {//Martinique if(dol_strlen($newphone) == 13) {//ex: +596_ABC_DE_FG_HI (ABC=596 de nouveau) $newphone = substr($newphone,0,4).$separ.substr($newphone,4,3).$separ.substr($newphone,7,2).$separ.substr($newphone,9,2).$separ.substr($newphone,11,2); } } - elseif (strtoupper($parameters['countrycode']) == "IT") + elseif (strtoupper($countrycode) == "IT") {//Italie if(dol_strlen($newphone) == 12) {//ex: +39_ABC_DEF_GHI @@ -2473,7 +2473,7 @@ function dol_print_phone($phone,$countrycode='',$cid=0,$socid=0,$addlink='',$sep $newphone = substr($newphone,0,3).$separ.substr($newphone,3,3).$separ.substr($newphone,6,3).$separ.substr($newphone,9,2).$separ.substr($newphone,11,2); } } - elseif(strtoupper($parameters['countrycode']) == "AU") + elseif(strtoupper($countrycode) == "AU") {//Australie if(dol_strlen($newphone) == 12) {//ex: +61_A_BCDE_FGHI From 93965e857baa5d4ed5d5ff18f70ef2b6ad67183b Mon Sep 17 00:00:00 2001 From: Gerhard Stephan Date: Thu, 15 Feb 2018 16:02:13 +0100 Subject: [PATCH 3/3] fetched from dolibarr/dolibarr --- ChangeLog | 8 +- htdocs/adherents/type.php | 4 +- htdocs/comm/propal/card.php | 10 +- htdocs/compta/facture/class/facture.class.php | 3 + .../sociales/class/chargesociales.class.php | 14 +- htdocs/compta/tva/class/tva.class.php | 3 + htdocs/contrat/card.php | 16 +- htdocs/contrat/services_list.php | 3 +- htdocs/contrat/tpl/linkedobjectblock.tpl.php | 17 +- htdocs/core/actions_linkedfiles.inc.php | 85 ++++-- .../core/class/commondocgenerator.class.php | 18 +- htdocs/core/class/commonobject.class.php | 2 +- htdocs/core/class/html.form.class.php | 11 +- htdocs/core/class/html.formfile.class.php | 61 +++- htdocs/core/class/translate.class.php | 2 +- htdocs/core/lib/ajax.lib.php | 18 -- htdocs/core/lib/company.lib.php | 2 +- htdocs/core/lib/files.lib.php | 7 +- htdocs/core/lib/functions.lib.php | 276 +++++++++++++++++- htdocs/core/lib/images.lib.php | 2 +- .../commande/doc/pdf_einstein.modules.php | 12 +- htdocs/core/modules/modBlockedLog.class.php | 4 +- htdocs/core/modules/modWebsite.class.php | 2 +- htdocs/core/tpl/ajaxrow.tpl.php | 3 +- htdocs/document.php | 31 +- htdocs/ecm/file_card.php | 4 - htdocs/fourn/card.php | 33 ++- .../fourn/class/fournisseur.facture.class.php | 2 + htdocs/install/check.php | 6 +- htdocs/install/repair.php | 64 +++- htdocs/install/step5.php | 6 + htdocs/install/upgrade2.php | 177 ++++++++++- htdocs/langs/en_US/companies.lang | 10 +- htdocs/langs/en_US/install.lang | 2 + htdocs/langs/en_US/website.lang | 6 +- htdocs/product/class/product.class.php | 40 ++- htdocs/product/fournisseurs.php | 4 +- htdocs/product/list.php | 4 +- htdocs/societe/card.php | 4 +- htdocs/viewimage.php | 112 ++++++- htdocs/website/class/websitepage.class.php | 2 + htdocs/website/index.php | 24 +- test/phpunit/CodingPhpTest.php | 4 +- 43 files changed, 926 insertions(+), 192 deletions(-) diff --git a/ChangeLog b/ChangeLog index 9b985647586..8c04eaf7a42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -14,11 +14,13 @@ Following changes may create regressions for some external modules, but were nec ***** ChangeLog for 7.0.0 compared to 6.0.5 ***** For users: +NEW: Add a preview icon after files that can be previewed (pdf + images) NEW: When payment is registered, PDF of invoices are also regenerated so payments appears with no need to click on regenerate. NEW: #5711 Add shipment line deleting and editing for draft shipments. +NEW: Accept substitution key __(ABC)__ replaced with value of translation of key ABC NEW: Accept substitution key __[ABC]__ replaced with value of const ABC -NEW: Accountancy Add variant on sell account for intracommunity sales & export sales +NEW: Accountancy Add fields for sale accounting account for intracommunity sales & export sales NEW: Add a button "Activate all services" on contracts NEW: Add a confirmation for all mass action 'delete' NEW: Add a group task line for tasks on same level on gantt diagram @@ -583,7 +585,9 @@ Following changes may create regression for some external modules, but were nece exists, but if an external module need action on it, it must provides itself its trigger file. * Use $conf->global->MULTICOMPANY_TRANSVERSE_MODE instead $conf->multicompany->transverse_mode. So, if you set var $multicompany_transverse_mode to 1 into your conf file, you must remove this line and a new key into - the Home - setup - other admin page. + the Home - setup - other admin page. +* If you use Multicompany transverse mode, it will be necessary to check the activation of the modules in the children + entities and to review completely the rights of the groups and the users. * Use getEntity('xxx') instead getEntity('xxx', 1) and use getEntity('xxx', 0) instead getEntity('xxx') * Some other change were done in the way we read permission of a user when module multicompany is enabled. You can retreive the old behavior by adding constant MULTICOMPANY_BACKWARD_COMPATIBILITY to 1. diff --git a/htdocs/adherents/type.php b/htdocs/adherents/type.php index eb44809178f..cc9fd872062 100644 --- a/htdocs/adherents/type.php +++ b/htdocs/adherents/type.php @@ -107,7 +107,7 @@ if ($action == 'add' && $user->rights->adherent->configurer) $object->subscription = (int) trim($subscription); $object->note = trim($comment); $object->mail_valid = trim($mail_valid); - $object->vote = trim($vote); + $object->vote = (boolean) trim($vote); // Fill array 'array_options' with data from add form $ret = $extrafields->setOptionalsFromPost($extralabels,$object); @@ -160,7 +160,7 @@ if ($action == 'update' && $user->rights->adherent->configurer) $object->subscription = (int) trim($subscription); $object->note = trim($comment); $object->mail_valid = trim($mail_valid); - $object->vote = trim($vote); + $object->vote = (boolean) trim($vote); // Fill array 'array_options' with data from add form $ret = $extrafields->setOptionalsFromPost($extralabels,$object); diff --git a/htdocs/comm/propal/card.php b/htdocs/comm/propal/card.php index 8bd9f7ffa98..54e3cf36c45 100644 --- a/htdocs/comm/propal/card.php +++ b/htdocs/comm/propal/card.php @@ -104,8 +104,11 @@ if ($id > 0 || ! empty($ref)) { $ret = $object->fetch($id, $ref); if ($ret > 0) $ret = $object->fetch_thirdparty(); - if ($ret < 0) - dol_print_error('', $object->error); + if ($ret <= 0) + { + setEventMessages($object->error, $object->errors, 'errors'); + $action = ''; + } } // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context @@ -1711,7 +1714,7 @@ if ($action == 'create') print ''; } -} else { +} elseif ($object->id > 0) { /* * Show object in view mode */ @@ -1818,7 +1821,6 @@ if ($action == 'create') $linkback = '' . $langs->trans("BackToList") . ''; - $morehtmlref='
'; // Ref customer $morehtmlref.=$form->editfieldkey("RefCustomer", 'ref_client', $object->ref_client, $object, $user->rights->propal->creer, 'string', '', 0, 1); diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 35ab14454ef..12d6fa10769 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -3004,6 +3004,9 @@ class Facture extends CommonInvoice $line->total_ttc = $tabprice[2]; $line->total_localtax1 = $tabprice[9]; $line->total_localtax2 = $tabprice[10]; + $line->multicurrency_total_ht = $tabprice[16]; + $line->multicurrency_total_tva = $tabprice[17]; + $line->multicurrency_total_ttc = $tabprice[18]; $line->update($user); $this->update_price(1); $this->db->commit(); diff --git a/htdocs/compta/sociales/class/chargesociales.class.php b/htdocs/compta/sociales/class/chargesociales.class.php index 61728562d2e..2d75584cbda 100644 --- a/htdocs/compta/sociales/class/chargesociales.class.php +++ b/htdocs/compta/sociales/class/chargesociales.class.php @@ -156,6 +156,7 @@ class ChargeSociales extends CommonObject function create($user) { global $conf; + $error=0; $now=dol_now(); @@ -191,8 +192,17 @@ class ChargeSociales extends CommonObject $this->id=$this->db->last_insert_id(MAIN_DB_PREFIX."chargesociales"); //dol_syslog("ChargesSociales::create this->id=".$this->id); - $this->db->commit(); - return $this->id; + $result=$this->call_trigger('PAYMENTSOCIALCONTRIBUTION_CREATE',$user); + if ($result < 0) $error++; + + if(empty($error)) { + $this->db->commit(); + return $this->id; + } + else { + $this->db->rollback(); + return -1*$error; + } } else { diff --git a/htdocs/compta/tva/class/tva.class.php b/htdocs/compta/tva/class/tva.class.php index d575d1a97b9..c9db79e6202 100644 --- a/htdocs/compta/tva/class/tva.class.php +++ b/htdocs/compta/tva/class/tva.class.php @@ -670,6 +670,9 @@ class Tva extends CommonObject $linkclose=''; if (empty($notooltip)) { + + + if (! empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { $label=$langs->trans("ShowMyObject"); diff --git a/htdocs/contrat/card.php b/htdocs/contrat/card.php index 92290ee0656..c2b6e03ee5b 100644 --- a/htdocs/contrat/card.php +++ b/htdocs/contrat/card.php @@ -1561,7 +1561,7 @@ else if ($action != 'editline' || GETPOST('rowid') != $objp->rowid) { - print ''; + print ''; // Label if ($objp->fk_product > 0) { @@ -1571,12 +1571,10 @@ else $productstatic->ref=$objp->pref; $productstatic->entity=$objp->pentity; $productstatic->label=$objp->plabel; - $text = $productstatic->getNomUrl(1,'',20); + $text = $productstatic->getNomUrl(1,'',32); if ($objp->plabel) { $text .= ' - '; - //$productstatic->ref=$objp->label; - //$text .= $productstatic->getNomUrl(0,'',16); $text .= $objp->plabel; } $description = $objp->description; @@ -1713,8 +1711,8 @@ else $productstatic->type=$objp->ptype; $productstatic->ref=$objp->pref; $productstatic->entity=$objp->pentity; - print $productstatic->getNomUrl(1,'',20); - print $objp->label?' - '.dol_trunc($objp->label,16):''; + print $productstatic->getNomUrl(1,'',32); + print $objp->label?' - '.dol_trunc($objp->label,32):''; print '
'; } else @@ -1822,7 +1820,7 @@ else 'text' => $langs->trans("ConfirmMoveToAnotherContractQuestion"), array('type' => 'select', 'name' => 'newcid', 'values' => $arraycontractid)); - $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid'),$langs->trans("MoveToAnotherContract"),$langs->trans("ConfirmMoveToAnotherContract"),"confirm_move",$formquestion); + print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&lineid=".GETPOST('rowid'),$langs->trans("MoveToAnotherContract"),$langs->trans("ConfirmMoveToAnotherContract"),"confirm_move",$formquestion); print '
'; } @@ -1834,7 +1832,7 @@ else $dateactstart = dol_mktime(12, 0, 0, GETPOST('remonth'), GETPOST('reday'), GETPOST('reyear')); $dateactend = dol_mktime(12, 0, 0, GETPOST('endmonth'), GETPOST('endday'), GETPOST('endyear')); $comment = GETPOST('comment','alpha'); - $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment),$langs->trans("ActivateService"),$langs->trans("ConfirmActivateService",dol_print_date($dateactstart,"%A %d %B %Y")),"confirm_active", '', 0, 1); + print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment),$langs->trans("ActivateService"),$langs->trans("ConfirmActivateService",dol_print_date($dateactstart,"%A %d %B %Y")),"confirm_active", '', 0, 1); print '
'; } @@ -1853,7 +1851,7 @@ else } else { - $form->form_confirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne','int')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment), $langs->trans("CloseService"), $langs->trans("ConfirmCloseService",dol_print_date($dateactend,"%A %d %B %Y")), "confirm_closeline", '', 0, 1); + print $form->formconfirm($_SERVER["PHP_SELF"]."?id=".$object->id."&ligne=".GETPOST('ligne','int')."&date=".$dateactstart."&dateend=".$dateactend."&comment=".urlencode($comment), $langs->trans("CloseService"), $langs->trans("ConfirmCloseService",dol_print_date($dateactend,"%A %d %B %Y")), "confirm_closeline", '', 0, 1); } print '
'; } diff --git a/htdocs/contrat/services_list.php b/htdocs/contrat/services_list.php index 5bede6be358..108fb6d4403 100644 --- a/htdocs/contrat/services_list.php +++ b/htdocs/contrat/services_list.php @@ -75,7 +75,7 @@ $opclotureyear=GETPOST('opclotureyear'); $filter_opcloture=GETPOST('filter_opcloture'); // Initialize context for list -$contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'servicelist'.$mode; +$contextpage=GETPOST('contextpage','aZ')?GETPOST('contextpage','aZ'):'contractservicelist'.$mode; // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager->initHooks(array($contextpage)); @@ -483,7 +483,6 @@ if (! empty($arrayfields['cd.date_cloture']['checked'])) print ''; } // Extra fields -// Extra fields include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_search_input.tpl.php'; // Fields from hook diff --git a/htdocs/contrat/tpl/linkedobjectblock.tpl.php b/htdocs/contrat/tpl/linkedobjectblock.tpl.php index e0b76ba689b..a44f20679b8 100644 --- a/htdocs/contrat/tpl/linkedobjectblock.tpl.php +++ b/htdocs/contrat/tpl/linkedobjectblock.tpl.php @@ -1,5 +1,6 @@ + * Copyright (C) 2018 Juanjo Menent * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -50,10 +51,22 @@ foreach($linkedObjectBlock as $key => $objectlink) getNomUrl(1); ?> date_contrat,'day'); ?> - total_ttc); ?> + rights->contrat->lire && empty($conf->global->CONTRACT_SHOW_TOTAL_OF_PRODUCT_AS_PRICE)) + { + $totalcontrat = 0; + foreach ($objectlink->lines as $linecontrat) { + $totalcontrat = $totalcontrat + $linecontrat->total_ht; + $total = $total + $linecontrat->total_ht; + } + echo price($totalcontrat); + } ?> getLibStatut(7); ?> ">transnoentitiesnoconv("RemoveLink")); ?> - \ No newline at end of file + diff --git a/htdocs/core/actions_linkedfiles.inc.php b/htdocs/core/actions_linkedfiles.inc.php index 0e0c444af33..7f938ba9b6c 100644 --- a/htdocs/core/actions_linkedfiles.inc.php +++ b/htdocs/core/actions_linkedfiles.inc.php @@ -182,37 +182,70 @@ elseif ($action == 'renamefile' && GETPOST('renamefilesave','alpha')) $filenamefrom=dol_sanitizeFileName(GETPOST('renamefilefrom','alpha'), '_', 0); // Do not remove accents $filenameto=dol_sanitizeFileName(GETPOST('renamefileto','alpha'), '_', 0); // Do not remove accents - // Security: - // Disallow file with some extensions. We rename them. - // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code. - if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$filenameto) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) + if ($filenamefrom != $filenameto) { - $filenameto.= '.noexe'; - } + // Security: + // Disallow file with some extensions. We rename them. + // Because if we put the documents directory into a directory inside web root (very bad), this allows to execute on demand arbitrary code. + if (preg_match('/\.htm|\.html|\.php|\.pl|\.cgi$/i',$filenameto) && empty($conf->global->MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED)) + { + $filenameto.= '.noexe'; + } - if ($filenamefrom && $filenameto) - { - $srcpath = $upload_dir.'/'.$filenamefrom; - $destpath = $upload_dir.'/'.$filenameto; + if ($filenamefrom && $filenameto) + { + $srcpath = $upload_dir.'/'.$filenamefrom; + $destpath = $upload_dir.'/'.$filenameto; - $result = dol_move($srcpath, $destpath); - if ($result) - { - if ($object->id) - { - $object->addThumbs($destpath); - } + $result = dol_move($srcpath, $destpath); + if ($result) + { + if ($object->id) + { + $object->addThumbs($destpath); + } - // TODO Add revert function of addThumbs to remove for old name - //$object->delThumbs($srcpath); + // TODO Add revert function of addThumbs to remove for old name + //$object->delThumbs($srcpath); - setEventMessages($langs->trans("FileRenamed"), null); - } - else - { - $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now. - setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors'); - } + setEventMessages($langs->trans("FileRenamed"), null); + } + else + { + $langs->load("errors"); // key must be loaded because we can't rely on loading during output, we need var substitution to be done now. + setEventMessages($langs->trans("ErrorFailToRenameFile", $filenamefrom, $filenameto), null, 'errors'); + } + } } } + + // Update properties in ECM table + if (GETPOST('ecmfileid', 'int') > 0) + { + $shareenabled = GETPOST('shareenabled', 'alpha'); + + include_once DOL_DOCUMENT_ROOT.'/ecm/class/ecmfiles.class.php'; + $ecmfile=new EcmFiles($db); + $result = $ecmfile->fetch(GETPOST('ecmfileid', 'int')); + if ($result > 0) + { + if ($shareenabled) + { + if (empty($ecmfile->share)) + { + require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php'; + $ecmfile->share = getRandomPassword(true); + } + } + else + { + $ecmfile->share = ''; + } + $result = $ecmfile->update($user); + if ($result < 0) + { + setEventMessages($ecmfile->error, $ecmfile->errors, 'warnings'); + } + } + } } diff --git a/htdocs/core/class/commondocgenerator.class.php b/htdocs/core/class/commondocgenerator.class.php index 015173f1f05..aeca3d5a102 100644 --- a/htdocs/core/class/commondocgenerator.class.php +++ b/htdocs/core/class/commondocgenerator.class.php @@ -425,7 +425,7 @@ abstract class CommonDocGenerator { $object->fetch_projet(); } - + $resarray[$array_key.'_project_ref'] = $object->project->ref; $resarray[$array_key.'_project_title'] = $object->project->title; $resarray[$array_key.'_project_description'] = $object->project->description; @@ -510,7 +510,7 @@ abstract class CommonDocGenerator 'line_multicurrency_total_tva_locale' => price($line->multicurrency_total_tva, 0, $outputlangs), 'line_multicurrency_total_ttc_locale' => price($line->multicurrency_total_ttc, 0, $outputlangs), ); - + // Units if ($conf->global->PRODUCT_USE_UNITS) { @@ -527,16 +527,16 @@ abstract class CommonDocGenerator $line->fetch_optionals($line->rowid,$extralabels); $resarray = $this->fill_substitutionarray_with_extrafields($line,$resarray,$extrafields,$array_key=$array_key,$outputlangs); - + // Load product data optional fields to the line -> enables to use "line_options_{extrafield}" - if (isset($line->product_ref)) + if (isset($line->fk_product) && $line->fk_product > 0) { - $product = new Product($this->db); - $result = $product->fetch(null, $line->product_ref); - foreach($product->array_options as $key=>$label) + $tmpproduct = new Product($this->db); + $result = $tmpproduct->fetch($line->fk_product); + foreach($tmpproduct->array_options as $key=>$label) $resarray["line_".$key] = $label; - } - + } + return $resarray; } diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 69002d9ae93..0dd9a245136 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -3496,7 +3496,7 @@ abstract class CommonObject /** * Return if a country is inside the EEC (European Economic Community) - * @deprecated + * @deprecated Use function isInEEC function instead * * @return boolean true = country inside EEC, false = country outside EEC */ diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index cbd2eb5c3b3..4e8f67d6552 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -646,9 +646,10 @@ class Form * @param integer $maxlength Max length for labels (0=no limit) * @param string $morecss More css class * @param string $usecodeaskey 'code3'=Use code on 3 alpha as key, 'code2"=Use code on 2 alpha as key + * @param int $showempty Show empty choice * @return string HTML string with select */ - function select_country($selected='',$htmlname='country_id',$htmloption='',$maxlength=0,$morecss='minwidth300',$usecodeaskey='') + function select_country($selected='', $htmlname='country_id', $htmloption='', $maxlength=0, $morecss='minwidth300', $usecodeaskey='', $showempty=1) { global $conf,$langs; @@ -693,20 +694,22 @@ class Form foreach ($countryArray as $row) { + if (empty($showempty) && empty($row['rowid'])) continue; + if ($row['favorite'] && $row['code_iso']) $atleastonefavorite++; if (empty($row['favorite']) && $atleastonefavorite) { $atleastonefavorite=0; - $out.= ''; + $out.= ''; } if ($selected && $selected != '-1' && ($selected == $row['rowid'] || $selected == $row['code_iso'] || $selected == $row['code_iso3'] || $selected == $row['label']) ) { $foundselected=true; - $out.= '