From 26cd0ac0c69ad0dd009748ce353dcff7e91f220e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 13:19:08 +0100 Subject: [PATCH 01/16] Fix duplicate field --- htdocs/fichinter/class/fichinter.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/fichinter/class/fichinter.class.php b/htdocs/fichinter/class/fichinter.class.php index 147850223cf..c177eb7965c 100644 --- a/htdocs/fichinter/class/fichinter.class.php +++ b/htdocs/fichinter/class/fichinter.class.php @@ -153,7 +153,6 @@ class Fichinter extends CommonObject $sql.= ", ".$conf->entity; $sql.= ", ".$user->id; $sql.= ", ".$user->id; - $sql.= ", ".$user->id; $sql.= ", ".($this->description?"'".$this->db->escape($this->description)."'":"null"); $sql.= ", '".$this->db->escape($this->modelpdf)."'"; $sql.= ", ".($this->fk_project ? $this->fk_project : 0); From 426e9297ea0a5013b7475df67dd8d2038c9178a0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 13:42:49 +0100 Subject: [PATCH 02/16] Prepare code to match cron rule: 0 if ok, !=0 if error --- htdocs/admin/tools/purge.php | 7 +++-- htdocs/core/class/utils.class.php | 12 ++++++--- htdocs/core/lib/files.lib.php | 4 ++- htdocs/cron/class/cronjob.class.php | 42 +++++++++++++++++++---------- htdocs/cron/list.php | 14 +++++----- 5 files changed, 49 insertions(+), 30 deletions(-) diff --git a/htdocs/admin/tools/purge.php b/htdocs/admin/tools/purge.php index 1bc3fea3909..170c37a79bf 100644 --- a/htdocs/admin/tools/purge.php +++ b/htdocs/admin/tools/purge.php @@ -50,10 +50,9 @@ if ($action=='purge' && ! preg_match('/^confirm/i',$choice) && ($choice != 'allf { require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; $utils = new Utils($db); - $count = $utils->purgeFiles($choice); - - if ($count) $mesg=$langs->trans("PurgeNDirectoriesDeleted", $count); - else $mesg=$langs->trans("PurgeNothingToDelete"); + $result = $utils->purgeFiles($choice); + + $mesg = $utils->output; setEventMessages($mesg, null, 'mesgs'); } diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 3132423d614..4cd7b84f150 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -44,11 +44,11 @@ class Utils * Purge files into directory of data files. * * @param string $choice Choice of purge mode ('tempfiles', 'tempfilesold' to purge temp older than 24h, 'allfiles', 'logfiles') - * @return int Nb of files deleted + * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ function purgeFiles($choice='tempfilesold') { - global $conf, $dolibarr_main_data_root; + global $conf, $langs, $dolibarr_main_data_root; dol_syslog("Utils::purgeFiles choice=".$choice, LOG_DEBUG); require_once DOL_DOCUMENT_ROOT.'/core/lib/files.lib.php'; @@ -123,7 +123,11 @@ class Utils $result = $ecmdirstatic->refreshcachenboffile(1); } } - - return $count; + + if ($count > 0) $this->output=$langs->trans("PurgeNDirectoriesDeleted", $count); + else $this->output=$langs->trans("PurgeNothingToDelete"); + + //return $count; + return 0; // This function can be called by cron so must return 0 if OK } } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 29e86fac636..18c87b6796e 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -1176,6 +1176,8 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n else $ok=unlink($filename); if ($ok) dol_syslog("Removed file ".$filename, LOG_DEBUG); else dol_syslog("Failed to remove file ".$filename, LOG_WARNING); + // TODO Failure to remove can be because file was already removed or because of permission + // If error because of not exists, we must can return true but we should return false if this is a permission problem } } else dol_syslog("No files to delete found", LOG_WARNING); @@ -1186,7 +1188,7 @@ function dol_delete_file($file,$disableglob=0,$nophperrors=0,$nohook=0,$object=n if ($nophperrors) $ok=@unlink($file_osencoded); else $ok=unlink($file_osencoded); if ($ok) dol_syslog("Removed file ".$file_osencoded, LOG_DEBUG); - else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING); + else dol_syslog("Failed to remove file ".$file_osencoded, LOG_WARNING); } return $ok; diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index a22b4aa21c0..18713622476 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -829,10 +829,10 @@ class Cronjob extends CommonObject /** * Run a job. - * Once job is finished, status and nb of of run is updated. + * Once job is finished, status and nb of run is updated. * This function does not plan the next run. This is done by function ->reprogram_jobs * - * @param string $userlogin User login + * @param string $userlogin User login * @return int <0 if KO, >0 if OK */ function run_jobs($userlogin) @@ -947,17 +947,19 @@ class Cronjob extends CommonObject $result = call_user_func_array(array($object, $this->methodename), $params_arr); } - if ($result===false) + if ($result===false || $result != 0) { - dol_syslog(get_class($this)."::run_jobs ".$object->error, LOG_ERR); - $this->lastoutput = $object->error; - $this->lastresult = -1; + $langs->load("errors"); + dol_syslog(get_class($this)."::run_jobs result=".$result." error=".$object->error, LOG_ERR); + $this->error = $object->error?$object->error:$langs->trans('ErrorUnknown'); + $this->lastoutput = $this->error; + $this->lastresult = is_numeric($result)?$result:-1; $retval = $this->lastresult; $error++; } else { - $this->lastoutput='NA'; + $this->lastoutput=$object->output; $this->lastresult=var_export($result,true); $retval = $this->lastresult; } @@ -993,13 +995,15 @@ class Cronjob extends CommonObject $result = call_user_func_array($this->methodename, $params_arr); } - if ($result === false) + if ($result === false || $result != 0) { - dol_syslog(get_class($this) . "::run_jobs " . $object->error, LOG_ERR); - - $this->lastoutput = $object->error; - $this->lastresult = -1; - $retval = $this->lastresult; + $langs->load("errors"); + dol_syslog(get_class($this)."::run_jobs result=".$result, LOG_ERR); + $this->error = $langs->trans('ErrorUnknown'); + $this->lastoutput = $this->error; + $this->lastresult = is_numeric($result)?$result:-1; + $retval = $this->lastresult; + $error++; } else { @@ -1024,6 +1028,16 @@ class Cronjob extends CommonObject if ($execmethod == 1) { exec($command, $output_arr, $retval); + if ($retval != 0) + { + $langs->load("errors"); + dol_syslog(get_class($this)."::run_jobs retval=".$retval, LOG_ERR); + $this->error = 'Error '.$retval; + $this->lastoutput = ''; // Will be filled later + $this->lastresult = $retval; + $retval = $this->lastresult; + $error++; + } } if ($execmethod == 2) { @@ -1046,7 +1060,7 @@ class Cronjob extends CommonObject } } - dol_syslog(get_class($this)."::run_jobs output_arr:".var_export($output_arr,true), LOG_DEBUG); + dol_syslog(get_class($this)."::run_jobs output_arr:".var_export($output_arr,true)." lastoutput=".$this->lastoutput." lastresult=".$this->lastresult, LOG_DEBUG); // Update with result if (is_array($output_arr) && count($output_arr)>0) diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index 3ff7e974408..41b08acbdd5 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -99,7 +99,7 @@ if ($action == 'confirm_execute' && $confirm == "yes" && $user->rights->cron->ex $now = dol_now(); // Date we start - $resrunjob = $object->run_jobs($user->login); + $resrunjob = $object->run_jobs($user->login); // Return -1 if KO, 1 if OK if ($resrunjob < 0) { setEventMessages($object->error, $object->errors, 'errors'); } @@ -110,8 +110,8 @@ if ($action == 'confirm_execute' && $confirm == "yes" && $user->rights->cron->ex { if ($resrunjob >= 0) // We add result of reprogram ony if no error message already reported { - if ($object->lastresult > 0) setEventMessages($langs->trans("JobFinished"), null, 'warnings'); - else setEventMessages($langs->trans("JobFinished"), null, 'mesgs'); + if ($object->lastresult >= 0) setEventMessages($langs->trans("JobFinished"), null, 'mesgs'); + else setEventMessages($langs->trans("JobFinished"), null, 'errors'); } $action=''; } @@ -252,15 +252,15 @@ if ($num > 0) $texttoshow.=$langs->trans('CronClass').': '. $line->classesname.'
'; $texttoshow.=$langs->trans('CronObject').': '. $line->objectname.'
'; $texttoshow.=$langs->trans('CronMethod').': '. $line->methodename; - $texttoshow.='
'.$langs->trans('CronArgs').':'. $line->params; - $texttoshow.='
'.$langs->trans('Comment').':'. $line->note; + $texttoshow.='
'.$langs->trans('CronArgs').': '. $line->params; + $texttoshow.='
'.$langs->trans('Comment').': '. $langs->trans($line->note); } elseif ($line->jobtype=='command') { $text=$langs->trans('CronCommand'); $texttoshow=$langs->trans('CronCommand').': '.dol_trunc($line->command); - $texttoshow.='
'.$langs->trans('CronArgs').':'. $line->params; - $texttoshow.='
'.$langs->trans('Comment').':'. $line->note; + $texttoshow.='
'.$langs->trans('CronArgs').': '. $line->params; + $texttoshow.='
'.$langs->trans('Comment').': '. $langs->trans($line->note); } print $form->textwithpicto($text, $texttoshow, 1); print ''; From 928336c8350bd779eff75d2d3362746e99bd3ac7 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 14:58:04 +0100 Subject: [PATCH 03/16] NEW Clean and enhance code for cron engine --- htdocs/admin/tools/export.php | 59 +++++++++---------- htdocs/core/lib/functions.lib.php | 2 +- htdocs/core/modules/DolibarrModules.class.php | 12 +++- htdocs/core/modules/modCron.class.php | 5 +- htdocs/core/modules/modFacture.class.php | 2 +- htdocs/cron/class/cronjob.class.php | 48 ++++++++++----- htdocs/cron/list.php | 2 + .../install/mysql/migration/3.9.0-4.0.0.sql | 1 + htdocs/install/mysql/tables/llx_cronjob.sql | 1 + htdocs/langs/en_US/cron.lang | 2 + 10 files changed, 81 insertions(+), 53 deletions(-) diff --git a/htdocs/admin/tools/export.php b/htdocs/admin/tools/export.php index c89fafbe052..3cfb3baf496 100644 --- a/htdocs/admin/tools/export.php +++ b/htdocs/admin/tools/export.php @@ -107,6 +107,10 @@ $dump_buffer_len = 0; $time_start = time(); +$outputdir = $conf->admin->dir_output.'/backup'; +$result=dol_mkdir($outputdir); + + // MYSQL if ($what == 'mysql') { @@ -116,7 +120,6 @@ if ($what == 'mysql') dolibarr_set_const($db, 'SYSTEMTOOLS_MYSQLDUMP', $cmddump,'chaine',0,'',$conf->entity); } - $outputdir = $conf->admin->dir_output.'/backup'; $outputfile = $outputdir.'/'.$file; // for compression format, we add extension $compression=GETPOST('compression') ? GETPOST('compression','alpha') : 'none'; @@ -185,8 +188,6 @@ if ($what == 'mysql') $errormsg=''; - $result=dol_mkdir($outputdir); - // Debut appel methode execution $fullcommandcrypted=$command." ".$paramcrypted." 2>&1"; $fullcommandclear=$command." ".$paramclear." 2>&1"; @@ -254,7 +255,6 @@ if ($what == 'mysql') if ($what == 'mysqlnobin') { - $outputdir = $conf->admin->dir_output.'/backup'; $outputfile = $outputdir.'/'.$file; $outputfiletemp = $outputfile.'-TMP.sql'; // for compression format, we add extension @@ -288,7 +288,6 @@ if ($what == 'postgresql') dolibarr_set_const($db, 'SYSTEMTOOLS_POSTGRESQLDUMP', $cmddump,'chaine',0,'',$conf->entity); } - $outputdir = $conf->admin->dir_output.'/backup'; $outputfile = $outputdir.'/'.$file; // for compression format, we add extension $compression=GETPOST('compression') ? GETPOST('compression','alpha') : 'none'; @@ -299,7 +298,7 @@ if ($what == 'postgresql') // Parameteres execution $command=$cmddump; - if (preg_match("/\s/",$command)) $command=$command=escapeshellarg($command); // Use quotes on command + if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // Use quotes on command //$param=escapeshellarg($dolibarr_main_db_name)." -h ".escapeshellarg($dolibarr_main_db_host)." -u ".escapeshellarg($dolibarr_main_db_user)." -p".escapeshellarg($dolibarr_main_db_pass); //$param="-F c"; @@ -352,38 +351,34 @@ if ($what == 'postgresql') +if ($errormsg) +{ + setEventMessages($langs->trans("Error")." : ".$errormsg, null, 'errors'); -// Si on a demande une generation -//if ($what) -//{ - if ($errormsg) - { - setEventMessages($langs->trans("Error")." : ".$errormsg, null, 'errors'); + $resultstring=''; + $resultstring.='
'.$langs->trans("Error")." : ".$errormsg.'
'; - $resultstring=''; - $resultstring.='
'.$langs->trans("Error")." : ".$errormsg.'
'; + $_SESSION["commandbackupresult"]=$resultstring; +} +else +{ + if ($what) + { + setEventMessages($langs->trans("BackupFileSuccessfullyCreated").'.
'.$langs->trans("YouCanDownloadBackupFile"), null, 'mesgs'); + + $resultstring='
'; + $resultstring.=$langs->trans("BackupFileSuccessfullyCreated").'.
'; + $resultstring.=$langs->trans("YouCanDownloadBackupFile"); + $resultstring.='
'; $_SESSION["commandbackupresult"]=$resultstring; - } - else + } + else { - if ($what) - { - setEventMessages($langs->trans("BackupFileSuccessfullyCreated").'.
'.$langs->trans("YouCanDownloadBackupFile"), null, 'mesgs'); + setEventMessages($langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user), null, 'mesgs'); + } +} - $resultstring='
'; - $resultstring.=$langs->trans("BackupFileSuccessfullyCreated").'.
'; - $resultstring.=$langs->trans("YouCanDownloadBackupFile"); - $resultstring.='
'; - - $_SESSION["commandbackupresult"]=$resultstring; - } - else - { - setEventMessages($langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user), null, 'mesgs'); - } - } -//} /* $filearray=dol_dir_list($conf->admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 7a0d8d5ec5a..acdf123e4ce 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -306,7 +306,7 @@ function dol_getprefix() * To link to a module file from a core file, then this function can be used (call by hook / trigger / speciales pages) * * @param string $relpath Relative path to file (Ie: mydir/myfile, ../myfile, ...) - * @param string $classname Class name + * @param string $classname Class name (deprecated) * @return bool True if load is a success, False if it fails */ function dol_include_once($relpath, $classname='') diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php index 06b3bc89860..8f0d161bb5b 100644 --- a/htdocs/core/modules/DolibarrModules.class.php +++ b/htdocs/core/modules/DolibarrModules.class.php @@ -913,7 +913,10 @@ class DolibarrModules // Can not be abstract, because we need to insta $comment = isset($this->cronjobs[$key]['comment'])?$this->cronjobs[$key]['comment']:''; $frequency = isset($this->cronjobs[$key]['frequency'])?$this->cronjobs[$key]['frequency']:''; $unitfrequency = isset($this->cronjobs[$key]['unitfrequency'])?$this->cronjobs[$key]['unitfrequency']:''; - + $status = isset($this->cronjobs[$key]['status'])?$this->cronjobs[$key]['status']:''; + $priority = isset($this->cronjobs[$key]['priority'])?$this->cronjobs[$key]['priority']:''; + $test = isset($this->cronjobs[$key]['test'])?$this->cronjobs[$key]['test']:''; + // Search if boxes def already present $sql = "SELECT count(*) as nb FROM ".MAIN_DB_PREFIX."cronjob"; $sql.= " WHERE module_name = '".$this->db->escape($this->rights_class)."'"; @@ -936,7 +939,7 @@ class DolibarrModules // Can not be abstract, because we need to insta if (! $err) { - $sql = "INSERT INTO ".MAIN_DB_PREFIX."cronjob (module_name, datec, datestart, label, jobtype, classesname, objectname, methodename, command, params, note, frequency, unitfrequency, entity)"; + $sql = "INSERT INTO ".MAIN_DB_PREFIX."cronjob (module_name, datec, datestart, label, jobtype, classesname, objectname, methodename, command, params, note, frequency, unitfrequency, priority, status, entity, test)"; $sql.= " VALUES ("; $sql.= "'".$this->db->escape($this->rights_class)."', "; $sql.= "'".$this->db->idate($now)."', "; @@ -951,7 +954,10 @@ class DolibarrModules // Can not be abstract, because we need to insta $sql.= ($comment?"'".$this->db->escape($comment)."'":"null").","; $sql.= "'".$this->db->escape($frequency)."', "; $sql.= "'".$this->db->escape($unitfrequency)."', "; - $sql.= $conf->entity; + $sql.= "'".$this->db->escape($priority)."', "; + $sql.= "'".$this->db->escape($status)."', "; + $sql.= $conf->entity.","; + $sql.= "'".$this->db->escape($test)."'"; $sql.= ")"; dol_syslog(get_class($this)."::insert_cronjobs", LOG_DEBUG); diff --git a/htdocs/core/modules/modCron.class.php b/htdocs/core/modules/modCron.class.php index 4981eeb0089..33491ea9a5a 100644 --- a/htdocs/core/modules/modCron.class.php +++ b/htdocs/core/modules/modCron.class.php @@ -101,8 +101,9 @@ class modCron extends DolibarrModules // Cronjobs $this->cronjobs = array( - 0=>array('label'=>'PurgeDeleteTemporaryFilesShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'purgeFiles', 'parameters'=>'', 'comment'=>'PurgeDeleteTemporaryFiles', 'frequency'=>1, 'unitfrequency'=>3600 * 24 * 7), - // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24) + 0=>array('label'=>'PurgeDeleteTemporaryFilesShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'purgeFiles', 'parameters'=>'', 'comment'=>'PurgeDeleteTemporaryFiles', 'frequency'=>1, 'unitfrequency'=>3600 * 24 * 7, 'priority'=>10, 'status'=>1, 'test'=>'1'), + 1=>array('label'=>'MakeLocalDatabaseDumpShort', 'jobtype'=>'method', 'class'=>'core/class/utils.class.php', 'objectname'=>'Utils', 'method'=>'dumpDatabase', 'parameters'=>'', 'comment'=>'MakeLocalDatabaseDump', 'frequency'=>1, 'unitfrequency'=>3600 * 24 * 7, 'priority'=>20, 'status'=>0, 'test'=>'0'), + // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>1, 'unitfrequency'=>3600*24) ); $this->rights[$r][0] = 23001; diff --git a/htdocs/core/modules/modFacture.class.php b/htdocs/core/modules/modFacture.class.php index eaba97d093b..b642873c82d 100644 --- a/htdocs/core/modules/modFacture.class.php +++ b/htdocs/core/modules/modFacture.class.php @@ -107,7 +107,7 @@ class modFacture extends DolibarrModules // Cronjobs $this->cronjobs = array( - 0=>array('label'=>'RecurringInvoices', 'jobtype'=>'method', 'class'=>'compta/facture/class/facture-rec.class.php', 'objectname'=>'Facture', 'method'=>'generateRecurringInvoices', 'parameters'=>'', 'comment'=>'Generate recurring invoices', 'frequency'=>1, 'unitfrequency'=>3600*24), + 0=>array('label'=>'RecurringInvoices', 'jobtype'=>'method', 'class'=>'compta/facture/class/facture-rec.class.php', 'objectname'=>'FactureRec', 'method'=>'generateRecurringInvoices', 'parameters'=>'', 'comment'=>'Generate recurring invoices', 'frequency'=>1, 'unitfrequency'=>3600*24), // 1=>array('label'=>'My label', 'jobtype'=>'command', 'command'=>'', 'parameters'=>'', 'comment'=>'Comment', 'frequency'=>3600, 'unitfrequency'=>3600) ); // List of cron jobs entries to add diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index 18713622476..31b4fc39c7c 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -391,9 +391,10 @@ class Cronjob extends CommonObject $sql.= " t.fk_user_author,"; $sql.= " t.fk_user_mod,"; $sql.= " t.note,"; - $sql.= " t.nbrun"; - $sql .= ", t.libname"; - + $sql.= " t.nbrun,"; + $sql.= " t.libname,"; + $sql.= " t.test"; + $sql.= " FROM ".MAIN_DB_PREFIX."cronjob as t"; $sql.= " WHERE 1 = 1"; if ($status >= 0) $sql.= " AND t.status = ".(empty($status)?'0':'1'); @@ -465,7 +466,8 @@ class Cronjob extends CommonObject $line->fk_user_mod = $obj->fk_user_mod; $line->note = $obj->note; $line->nbrun = $obj->nbrun; - $line->libname = $obj->libname; + $line->libname = $obj->libname; + $line->test = $obj->test; $this->lines[]=$line; $i++; @@ -905,25 +907,43 @@ class Cronjob extends CommonObject if ($this->jobtype=='method') { // load classes - $ret=dol_include_once($this->classesname,$this->objectname); - if (! $error && $ret===false) + if (! $error) { - $this->error=$langs->trans('CronCannotLoadClass',$this->classesname,$this->objectname); - dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); - $this->lastoutput = $this->error; - $this->lastresult = -1; - $retval = $this->lastresult; - $error++; + $ret=dol_include_once($this->classesname); + if ($ret===false || (! class_exists($this->objectname))) + { + $this->error=$langs->trans('CronCannotLoadClass',$this->classesname,$this->objectname); + dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); + $this->lastoutput = $this->error; + $this->lastresult = -1; + $retval = $this->lastresult; + $error++; + } } + // test if method exists + if (! $error) + { + if (! method_exists($this->objectname, $this->methodename)) + { + $this->error=$langs->trans('CronMethodDoesNotExists',$this->objectname,$this->methodename); + dol_syslog(get_class($this)."::run_jobs ".$this->error, LOG_ERR); + $this->lastoutput = $this->error; + $this->lastresult = -1; + $retval = $this->lastresult; + $error++; + } + } + // Load langs if (! $error) { $result=$langs->load($this->module_name.'@'.$this->module_name); - if ($result<0) + if ($result < 0) { dol_syslog(get_class($this)."::run_jobs Cannot load module lang file - ".$langs->error, LOG_ERR); - $this->lastoutput = $langs->error; + $this->error = $langs->error; + $this->lastoutput = $this->error; $this->lastresult = -1; $retval = $this->lastresult; $error++; diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index 41b08acbdd5..b6d830dd201 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -220,6 +220,8 @@ if ($num > 0) $style='pair'; foreach($object->lines as $line) { + if (! verifCond($line->test)) continue; // Discard line with test = false + // title profil if ($style=='pair') {$style='impair';} else {$style='pair';} diff --git a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql index f2b3ff181cc..3ffb260f415 100644 --- a/htdocs/install/mysql/migration/3.9.0-4.0.0.sql +++ b/htdocs/install/mysql/migration/3.9.0-4.0.0.sql @@ -35,6 +35,7 @@ UPDATE llx_projet as p set opp_percent = (SELECT percent from llx_c_lead_status ALTER TABLE llx_overwrite_trans ADD UNIQUE INDEX uk_overwrite_trans(lang, transkey); ALTER TABLE llx_cronjob MODIFY COLUMN unitfrequency varchar(255) NOT NULL DEFAULT '3600'; +ALTER TABLE llx_cronjob ADD COLUMN test varchar(255) DEFAULT '1'; ALTER TABLE llx_facture ADD INDEX idx_facture_fk_statut (fk_statut); diff --git a/htdocs/install/mysql/tables/llx_cronjob.sql b/htdocs/install/mysql/tables/llx_cronjob.sql index a70051d4c11..f9d2ac1ab7a 100644 --- a/htdocs/install/mysql/tables/llx_cronjob.sql +++ b/htdocs/install/mysql/tables/llx_cronjob.sql @@ -46,6 +46,7 @@ CREATE TABLE llx_cronjob nbrun integer, -- nb of run complete (failed or not) autodelete integer DEFAULT 0, -- 0=Job is kept unchanged once nbrun > maxrun or date > dateend, 2=Job must be archived (archive = status 2) once nbrun > maxrun or date > dateend status integer NOT NULL DEFAULT 1, -- 0=disabled, 1=enabled, 2=archived + test varchar(255) DEFAULT '1', fk_user_author integer DEFAULT NULL, fk_user_mod integer DEFAULT NULL, fk_mailing integer DEFAULT NULL, -- id of emailing if job was queued to send mass emailing diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index b7cdb069346..f2184b50b08 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -89,3 +89,5 @@ CronMenu=Cron CronCannotLoadClass=Cannot load class %s or object %s UseMenuModuleToolsToAddCronJobs=Go into menu "Home - Modules tools - Job list" to see and edit scheduled jobs. TaskDisabled=Job disabled +MakeLocalDatabaseDumpShort=Local database backup +MakeLocalDatabaseDump=Create a local database dump From 2cde6f39ff6865c343ede5e9c08cdc1d6a53a998 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 15:16:45 +0100 Subject: [PATCH 04/16] Missing error message --- htdocs/langs/en_US/cron.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/langs/en_US/cron.lang b/htdocs/langs/en_US/cron.lang index f2184b50b08..57e61b2f381 100644 --- a/htdocs/langs/en_US/cron.lang +++ b/htdocs/langs/en_US/cron.lang @@ -16,6 +16,7 @@ KeyForCronAccess=Security key for URL to launch cron jobs FileToLaunchCronJobs=Command line to launch cron jobs CronExplainHowToRunUnix=On Unix environment you should use the following crontab entry to run the command line each 5 minutes CronExplainHowToRunWin=On Microsoft(tm) Windows environement you can use Scheduled task tools to run the command line each 5 minutes +CronMethodDoesNotExists=Class %s does not contains any method %s # Menu CronJobs=Scheduled jobs CronListActive=List of enabled/scheduled jobs From 475cc24e13cb78a97ad7f4806187d5853e93d44c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 15:37:23 +0100 Subject: [PATCH 05/16] NEW Can edit next execution date of a cron job. --- htdocs/core/class/html.form.class.php | 2 +- htdocs/cron/card.php | 21 +++++++++++++++++- htdocs/cron/class/cronjob.class.php | 32 +++++++++++++-------------- htdocs/cron/list.php | 2 +- htdocs/public/cron/cron_run_jobs.php | 6 ++--- 5 files changed, 41 insertions(+), 22 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 2230aebdbb5..c6d32ac2ea3 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -4134,7 +4134,7 @@ class Form * - local date in user area, if set_time is '' (so if set_time is '', output may differs when done from two different location) * - Empty (fields empty), if set_time is -1 (in this case, parameter empty must also have value 1) * - * @param timestamp $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date. + * @param timestamp $set_time Pre-selected date (must be a local PHP server timestamp), -1 to keep date not preselected, '' to use current date (emptydate must be 0). * @param string $prefix Prefix for fields name * @param int $h 1=Show also hours * @param int $m 1=Show also minutes diff --git a/htdocs/cron/card.php b/htdocs/cron/card.php index 76781d6645e..79b1cfa996c 100644 --- a/htdocs/cron/card.php +++ b/htdocs/cron/card.php @@ -142,6 +142,7 @@ if ($action=='add') $object->note=GETPOST('note'); $object->datestart=dol_mktime(GETPOST('datestarthour','int'), GETPOST('datestartmin','int'), 0, GETPOST('datestartmonth','int'), GETPOST('datestartday','int'), GETPOST('datestartyear','int')); $object->dateend=dol_mktime(GETPOST('dateendhour','int'), GETPOST('dateendmin','int'), 0, GETPOST('dateendmonth','int'), GETPOST('dateendday','int'), GETPOST('dateendyear','int')); + $object->datenextrun=dol_mktime(GETPOST('datenextrunhour','int'), GETPOST('datenextrunmin','int'), 0, GETPOST('datenextrunmonth','int'), GETPOST('datenextrunday','int'), GETPOST('datenextrunyear','int')); $object->unitfrequency=GETPOST('unitfrequency','int'); $object->frequency=GETPOST('nbfrequency','int'); $object->maxrun=GETPOST('maxrun','int'); @@ -177,6 +178,7 @@ if ($action=='update') $object->note=GETPOST('note'); $object->datestart=dol_mktime(GETPOST('datestarthour','int'), GETPOST('datestartmin','int'), 0, GETPOST('datestartmonth','int'), GETPOST('datestartday','int'), GETPOST('datestartyear','int')); $object->dateend=dol_mktime(GETPOST('dateendhour','int'), GETPOST('dateendmin','int'), 0, GETPOST('dateendmonth','int'), GETPOST('dateendday','int'), GETPOST('dateendyear','int')); + $object->datenextrun=dol_mktime(GETPOST('datenextrunhour','int'), GETPOST('datenextrunmin','int'), 0, GETPOST('datenextrunmonth','int'), GETPOST('datenextrunday','int'), GETPOST('datenextrunyear','int')); $object->unitfrequency=GETPOST('unitfrequency','int'); $object->frequency=GETPOST('nbfrequency','int'); $object->maxrun=GETPOST('maxrun','int'); @@ -475,7 +477,7 @@ if (($action=="create") || ($action=="edit")) $form->select_date($object->dateend,'dateend',1,1,'',"cronform"); } else{ - $form->select_date('','dateend',1,1,1,"cronform"); + $form->select_date(-1,'dateend',1,1,1,"cronform"); } print ""; print ""; @@ -506,6 +508,23 @@ if (($action=="create") || ($action=="edit")) print ""; print "\n"; + print ''; + print $langs->trans('CronDtNextLaunch'); + print ' ('.$langs->trans('CronFrom').')'; + print ""; + if(!empty($object->datenextrun)) + { + $form->select_date($object->datenextrun,'datenextrun',1,1,'',"cronform"); + } + else + { + $form->select_date(-1,'datenextrun',1,1,'',"cronform"); + } + print ""; + print ""; + print ""; + print ""; + print ''; dol_fiche_end(); diff --git a/htdocs/cron/class/cronjob.class.php b/htdocs/cron/class/cronjob.class.php index 31b4fc39c7c..9ef47c30ea7 100644 --- a/htdocs/cron/class/cronjob.class.php +++ b/htdocs/cron/class/cronjob.class.php @@ -107,7 +107,8 @@ class Cronjob extends CommonObject if (isset($this->note)) $this->note=trim($this->note); if (isset($this->nbrun)) $this->nbrun=trim($this->nbrun); if (isset($this->libname)) $this->libname = trim($this->libname); - + if (isset($this->test)) $this->test = trim($this->test); + // Check parameters // Put here code to add a control on parameters values if (dol_strlen($this->datestart)==0) { @@ -177,11 +178,9 @@ class Cronjob extends CommonObject $sql.= "note,"; $sql.= "nbrun,"; $sql.= "maxrun,"; - $sql.= "libname"; - - + $sql.= "libname,"; + $sql.= "test"; $sql.= ") VALUES ("; - $sql.= " '".$this->db->idate($now)."',"; $sql.= " ".(! isset($this->jobtype)?'NULL':"'".$this->db->escape($this->jobtype)."'").","; $sql.= " ".(! isset($this->label)?'NULL':"'".$this->db->escape($this->label)."'").","; @@ -208,7 +207,8 @@ class Cronjob extends CommonObject $sql.= " ".(! isset($this->note)?'NULL':"'".$this->db->escape($this->note)."'").","; $sql.= " ".(! isset($this->nbrun)?'0':"'".$this->db->escape($this->nbrun)."'").","; $sql.= " ".(empty($this->maxrun)?'null':"'".$this->db->escape($this->maxrun)."'").","; - $sql.= " ".(! isset($this->libname)?'NULL':"'".$this->db->escape($this->libname)."'").""; + $sql.= " ".(! isset($this->libname)?'NULL':"'".$this->db->escape($this->libname)."'").","; + $sql.= " ".(! isset($this->test)?'NULL':"'".$this->db->escape($this->test)."'").""; $sql.= ")"; $this->db->begin(); @@ -292,9 +292,8 @@ class Cronjob extends CommonObject $sql.= " t.note,"; $sql.= " t.nbrun,"; $sql.= " t.maxrun,"; - $sql.= " t.libname"; - - + $sql.= " t.libname,"; + $sql.= " t.test"; $sql.= " FROM ".MAIN_DB_PREFIX."cronjob as t"; $sql.= " WHERE t.rowid = ".$id; @@ -337,7 +336,7 @@ class Cronjob extends CommonObject $this->nbrun = $obj->nbrun; $this->maxrun = $obj->maxrun; $this->libname = $obj->libname; - + $this->test = $obj->test; } $this->db->free($resql); @@ -394,7 +393,6 @@ class Cronjob extends CommonObject $sql.= " t.nbrun,"; $sql.= " t.libname,"; $sql.= " t.test"; - $sql.= " FROM ".MAIN_DB_PREFIX."cronjob as t"; $sql.= " WHERE 1 = 1"; if ($status >= 0) $sql.= " AND t.status = ".(empty($status)?'0':'1'); @@ -521,7 +519,8 @@ class Cronjob extends CommonObject if (isset($this->nbrun)) $this->nbrun=trim($this->nbrun); if (isset($this->maxrun)) $this->maxrun=trim($this->maxrun); if (isset($this->libname)) $this->libname = trim($this->libname); - + if (isset($this->test)) $this->test = trim($this->test); + // Check parameters // Put here code to add a control on parameters values if (dol_strlen($this->datestart)==0) { @@ -588,10 +587,11 @@ class Cronjob extends CommonObject $sql.= " status=".(isset($this->status)?$this->status:"null").","; $sql.= " fk_user_mod=".$user->id.","; $sql.= " note=".(isset($this->note)?"'".$this->db->escape($this->note)."'":"null").","; - $sql.= " nbrun=".(isset($this->nbrun)?$this->nbrun:"null").","; - $sql.= " maxrun=".(isset($this->maxrun)?$this->maxrun:"null").","; - $sql.= " libname=".(isset($this->libname)?"'".$this->db->escape($this->libname)."'":"null"); - $sql.= " WHERE rowid=".$this->id; + $sql.= " nbrun=".((isset($this->nbrun) && $this->nbrun >0)?$this->nbrun:"null").","; + $sql.= " maxrun=".((isset($this->maxrun) && $this->maxrun > 0)?$this->maxrun:"null").","; + $sql.= " libname=".(isset($this->libname)?"'".$this->db->escape($this->libname)."'":"null").","; + $sql.= " test=".(isset($this->test)?"'".$this->db->escape($this->test)."'":"null"); + $sql.= " WHERE rowid=".$this->id; $this->db->begin(); diff --git a/htdocs/cron/list.php b/htdocs/cron/list.php index b6d830dd201..49f5878d436 100644 --- a/htdocs/cron/list.php +++ b/htdocs/cron/list.php @@ -228,7 +228,7 @@ if ($num > 0) print ''; - print ''; + print ''; print ''; print img_picto('', 'object_cron').' '; print $line->id; diff --git a/htdocs/public/cron/cron_run_jobs.php b/htdocs/public/cron/cron_run_jobs.php index cfd4b28711d..fc8e15aeed6 100644 --- a/htdocs/public/cron/cron_run_jobs.php +++ b/htdocs/public/cron/cron_run_jobs.php @@ -144,7 +144,7 @@ if (is_array($object->lines) && (count($object->lines)>0)) $result=$cronjob->fetch($line->id); if ($result<0) { - echo "Error:".$cronjob->error; + echo "Error:".$cronjob->error."
\n"; dol_syslog("cron_run_jobs.php:: fetch Error".$cronjob->error, LOG_ERR); exit; } @@ -152,7 +152,7 @@ if (is_array($object->lines) && (count($object->lines)>0)) $result=$cronjob->run_jobs($userlogin); if ($result < 0) { - echo "Error:".$cronjob->error; + echo "Error:".$cronjob->error."
\n"; dol_syslog("cron_run_jobs.php:: run_jobs Error".$cronjob->error, LOG_ERR); $nbofjobslaunchedko++; } @@ -165,7 +165,7 @@ if (is_array($object->lines) && (count($object->lines)>0)) $result=$cronjob->reprogram_jobs($userlogin, $now); if ($result<0) { - echo "Error:".$cronjob->error; + echo "Error:".$cronjob->error."
\n"; dol_syslog("cron_run_jobs.php:: reprogram_jobs Error".$cronjob->error, LOG_ERR); exit; } From d9e089256e3f4af66baefdff07e372d2c3b9c352 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 16:16:46 +0100 Subject: [PATCH 06/16] Fix path to copyrighted files --- build/debian/copyright | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/debian/copyright b/build/debian/copyright index 73109152034..deccd8cbe52 100644 --- a/build/debian/copyright +++ b/build/debian/copyright @@ -159,7 +159,7 @@ Comments: Those files are not shipped in the binary package as we configure Dolibarr to use Dejavu fonts from "fonts-dejavu-core". -Files: docs/images/* +Files: doc/images/* Copyright: Laurent Destailleur License: CC-BY-SA-3.0 You are free: @@ -176,7 +176,7 @@ License: CC-BY-SA-3.0 . For more information, see http://creativecommons.org/licenses/by-sa/3.0/ -Files: htdocs/includes/fpdi/* +Files: htdocs/includes/fpdfi/* Copyright: 2004-2011 Setasign - Jan Slabon License: GPL-2+ This program is free software; you can redistribute it From 6002adb04c4fa188e8bec7079a38f3023d36e8f3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 20:38:11 +0100 Subject: [PATCH 07/16] Fix bad transaction level due to code of situation invoices --- htdocs/compta/facture/class/facture.class.php | 27 ++++++++++++------- test/phpunit/NumberingModulesTest.php | 9 ++++--- 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 91221118f2a..4ce50666b5a 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1992,14 +1992,18 @@ class Facture extends CommonInvoice $this->brouillon=0; $this->date_validation=$now; $i = 0; - $final = True; - while ($i < count($this->lines) && $final == True) { - $final = ($this->lines[$i]->situation_percent == 100); - $i++; - } - if ($final) { - $this->setFinal(); - } + + if (!empty($conf->global->INVOICE_USE_SITUATION)) + { + $final = True; + while ($i < count($this->lines) && $final == True) { + $final = ($this->lines[$i]->situation_percent == 100); + $i++; + } + if ($final) { + $this->setFinal(); + } + } } } else @@ -2277,7 +2281,7 @@ class Facture extends CommonInvoice $this->line->context = $this->context; - $this->line->situpation_percent = $situation_percent; + $this->line->situation_percent = $situation_percent; $this->line->fk_facture=$this->id; $this->line->label=$label; // deprecated $this->line->desc=$desc; @@ -3770,11 +3774,14 @@ class Facture extends CommonInvoice function setFinal() { global $conf, $langs, $user; + + $this->db->begin(); + $this->situation_final = 1; $sql = 'update ' . MAIN_DB_PREFIX . 'facture set situation_final = ' . $this->situation_final . ' where rowid = ' . $this->id; $resql = $this->db->query($sql); if ($resql) { - // FIXME: call triggers? + // FIXME: call triggers MODIFY because we modify invoice $this->db->commit(); return 1; } else { diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 904c102e0a8..0107edc1f8d 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -75,7 +75,8 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase public static function setUpBeforeClass() { global $conf,$user,$langs,$db; - $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. print __METHOD__."\n"; } @@ -145,10 +146,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $result2=$localobject->create($user,1); $result3=$localobject->validate($user, $result); // create invoice by forcing ref print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); // counter must start to 1 + $this->assertEquals('1915-0001', $result, 'Test for {yyyy}-{0000}, 1st invoice'); // counter must start to 1 $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result, 'Test for {yyyy}-{0000}, 1st invoice'); // Can be deleted + $this->assertEquals(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); @@ -156,7 +157,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $numbering=new mod_facture_mercure(); $result=$numbering->getNextValue($mysoc, $localobject2, 'last'); print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); + $this->assertEquals('1915-0001', $result, "Test to get last value with param 'last'"); $result=$numbering->getNextValue($mysoc, $localobject2); $result2=$localobject2->create($user,1); $result3=$localobject2->validate($user, $result); // create invoice by forcing ref From 0e1bb06d01e1c5ab8db5453824fab739169cd512 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 20:41:35 +0100 Subject: [PATCH 08/16] Fix duplicate set --- htdocs/compta/facture/class/facture.class.php | 1 - 1 file changed, 1 deletion(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 4ce50666b5a..502bb7d212e 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -2281,7 +2281,6 @@ class Facture extends CommonInvoice $this->line->context = $this->context; - $this->line->situation_percent = $situation_percent; $this->line->fk_facture=$this->id; $this->line->label=$label; // deprecated $this->line->desc=$desc; From 7b15ac11797a52d89e8004a41f980200b52230b1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 20:38:11 +0100 Subject: [PATCH 09/16] Fix bad transaction level due to code of situation invoices Conflicts: htdocs/compta/facture/class/facture.class.php --- htdocs/compta/facture/class/facture.class.php | 25 ++++++++++++------- test/phpunit/NumberingModulesTest.php | 9 ++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index f8bb53cf9ed..c66bbb6d1c2 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1919,14 +1919,18 @@ class Facture extends CommonInvoice $this->brouillon=0; $this->date_validation=$now; $i = 0; - $final = True; - while ($i < count($this->lines) && $final == True) { - $final = ($this->lines[$i]->situation_percent == 100); - $i++; - } - if ($final) { - $this->setFinal(); - } + + if (!empty($conf->global->INVOICE_USE_SITUATION)) + { + $final = True; + while ($i < count($this->lines) && $final == True) { + $final = ($this->lines[$i]->situation_percent == 100); + $i++; + } + if ($final) { + $this->setFinal(); + } + } } } else @@ -3619,11 +3623,14 @@ class Facture extends CommonInvoice function setFinal() { global $conf, $langs, $user; + + $this->db->begin(); + $this->situation_final = 1; $sql = 'update ' . MAIN_DB_PREFIX . 'facture set situation_final = ' . $this->situation_final . ' where rowid = ' . $this->id; $resql = $this->db->query($sql); if ($resql) { - // FIXME: call triggers? + // FIXME: call triggers MODIFY because we modify invoice $this->db->commit(); return 1; } else { diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 904c102e0a8..0107edc1f8d 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -75,7 +75,8 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase public static function setUpBeforeClass() { global $conf,$user,$langs,$db; - $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. print __METHOD__."\n"; } @@ -145,10 +146,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $result2=$localobject->create($user,1); $result3=$localobject->validate($user, $result); // create invoice by forcing ref print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); // counter must start to 1 + $this->assertEquals('1915-0001', $result, 'Test for {yyyy}-{0000}, 1st invoice'); // counter must start to 1 $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result, 'Test for {yyyy}-{0000}, 1st invoice'); // Can be deleted + $this->assertEquals(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); @@ -156,7 +157,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $numbering=new mod_facture_mercure(); $result=$numbering->getNextValue($mysoc, $localobject2, 'last'); print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); + $this->assertEquals('1915-0001', $result, "Test to get last value with param 'last'"); $result=$numbering->getNextValue($mysoc, $localobject2); $result2=$localobject2->create($user,1); $result3=$localobject2->validate($user, $result); // create invoice by forcing ref From 2d0c823ffec39a6ba88f509e01ac9c9dca4384f2 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 20:38:11 +0100 Subject: [PATCH 10/16] Fix bad transaction level due to code of situation invoices Conflicts: htdocs/compta/facture/class/facture.class.php --- htdocs/compta/facture/class/facture.class.php | 25 ++++++++++++------- test/phpunit/NumberingModulesTest.php | 9 ++++--- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 628fd45f1ed..614c7d3f33a 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1953,14 +1953,18 @@ class Facture extends CommonInvoice $this->brouillon=0; $this->date_validation=$now; $i = 0; - $final = True; - while ($i < count($this->lines) && $final == True) { - $final = ($this->lines[$i]->situation_percent == 100); - $i++; - } - if ($final) { - $this->setFinal(); - } + + if (!empty($conf->global->INVOICE_USE_SITUATION)) + { + $final = True; + while ($i < count($this->lines) && $final == True) { + $final = ($this->lines[$i]->situation_percent == 100); + $i++; + } + if ($final) { + $this->setFinal(); + } + } } } else @@ -3654,11 +3658,14 @@ class Facture extends CommonInvoice function setFinal() { global $conf, $langs, $user; + + $this->db->begin(); + $this->situation_final = 1; $sql = 'update ' . MAIN_DB_PREFIX . 'facture set situation_final = ' . $this->situation_final . ' where rowid = ' . $this->id; $resql = $this->db->query($sql); if ($resql) { - // FIXME: call triggers? + // FIXME: call triggers MODIFY because we modify invoice $this->db->commit(); return 1; } else { diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 904c102e0a8..0107edc1f8d 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -75,7 +75,8 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase public static function setUpBeforeClass() { global $conf,$user,$langs,$db; - $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. + + $db->begin(); // This is to have all actions inside a transaction even if test launched without suite. print __METHOD__."\n"; } @@ -145,10 +146,10 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $result2=$localobject->create($user,1); $result3=$localobject->validate($user, $result); // create invoice by forcing ref print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); // counter must start to 1 + $this->assertEquals('1915-0001', $result, 'Test for {yyyy}-{0000}, 1st invoice'); // counter must start to 1 $result=$localobject->is_erasable(); print __METHOD__." is_erasable=".$result."\n"; - $this->assertEquals(1, $result, 'Test for {yyyy}-{0000}, 1st invoice'); // Can be deleted + $this->assertEquals(1, $result, 'Test for is_erasable, 1st invoice'); // Can be deleted $localobject2=new Facture($this->savdb); $localobject2->initAsSpecimen(); @@ -156,7 +157,7 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $numbering=new mod_facture_mercure(); $result=$numbering->getNextValue($mysoc, $localobject2, 'last'); print __METHOD__." result=".$result."\n"; - $this->assertEquals('1915-0001', $result); + $this->assertEquals('1915-0001', $result, "Test to get last value with param 'last'"); $result=$numbering->getNextValue($mysoc, $localobject2); $result2=$localobject2->create($user,1); $result3=$localobject2->validate($user, $result); // create invoice by forcing ref From b11fe5f4c7e8d53d39d480e325ceaba5d0022435 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 20:46:27 +0100 Subject: [PATCH 11/16] Update debian doc --- build/debian/README.howto | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/build/debian/README.howto b/build/debian/README.howto index 28f5ed6e2b1..1d6f94e9cd0 100644 --- a/build/debian/README.howto +++ b/build/debian/README.howto @@ -14,8 +14,8 @@ with format .DEB (for Debian, Ubuntu, ...). # To build a debian package, you need first # With Ubuntu 12.04 # apt-get install debhelper dpkg-source gpg lintian git-buildpackage pkg-php-tools schroot sbuild dh-linktree dh-make-php -# With Debian 7 -# apt-get install debhelper dpkg gnupg lintian git-buildpackage pkg-php-tools schroot sbuild dh-linktree dh-make-php +# With Ubuntu 14.04 ou Debian 7 +# apt-get install debhelper dpkg gnupg lintian git-buildpackage pkg-php-tools schroot sbuild dh-linktree dh-make-php packaging-dev # To generate gpg key for email used into changelog @@ -49,6 +49,7 @@ Other example: export DEBFULLNAME="Laurent Destailleur" export DEBEMAIL="eldy@destailleur.fr" +export QUILT_PATCHES=debian/patches # To use Alioth.debian.org * Create an account login @@ -287,17 +288,24 @@ Then check/modify also the user/date signature: - Name and email must match value into debian/control file (Entry added here is used by next step). -To update dolibarr debian package when only files into debian has changed, or if you include manually backport: +To update dolibarr debian package when only files into debian has changed: * Change files and commit. * Add a tag debian/x.y.z+dfsgw-2 (increase the last 1 into 2, 3...) +To update dolibarr debian package when only files into debian has changed: + +* Manually, add patches into debian/patches and update file debian/series, or do the 2 steps with "quilt import filepatch.patch" +* You can test patching of serie with "quilt push" (autant de fois que de patch). Avec "quilt pop -a", on revien a l'état du upstream sans les patch. + Once files has been prepared, it's time to test: * Try to build package > rm -fr ../build-area; -> git-buildpackage -us -uc --git-debian-branch=[master|jessie] --git-upstream-branch=[upstream|upstream-3.5.x] +> git-buildpackage -us -uc --git-debian-branch=[master|jessie] --git-upstream-branch=[upstream|upstream-3.5.x|3.5.5] +ou +> git-buildpackage -us -uc --git-ignore-branch --git-upstream-branch=[upstream|upstream-3.5.x|3.5.5] Note: To build an old version, do: git checkout oldtagname -b newbranchname; git-buildpackage -us -uc --git-debian-branch=newbranchname --git-upstream-branch=[upstream|upstream-3.5.x] Note: You can use git-buildpackage -us -uc --git-ignore-new if you want to test build with uncommited file From 640adcc66659337a904d3afa60462c553fef7070 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 21:23:30 +0100 Subject: [PATCH 12/16] Missing translation --- htdocs/langs/en_US/languages.lang | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/langs/en_US/languages.lang b/htdocs/langs/en_US/languages.lang index 27b533c3f2d..bda34ce2299 100644 --- a/htdocs/langs/en_US/languages.lang +++ b/htdocs/langs/en_US/languages.lang @@ -32,6 +32,7 @@ Language_es_MX=Spanish (Mexico) Language_es_PY=Spanish (Paraguay) Language_es_PE=Spanish (Peru) Language_es_PR=Spanish (Puerto Rico) +Language_es_VE=Spanish (Venezuela) Language_et_EE=Estonian Language_eu_ES=Basque Language_fa_IR=Persian From e9256913b150bdf633d6899fe7e74acf4c8f75fc Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 31 Jan 2016 21:32:15 +0100 Subject: [PATCH 13/16] Fix set INVOICE_CAN_ALWAYS_BE_REMOVED to have phpunit test ok --- test/phpunit/NumberingModulesTest.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/phpunit/NumberingModulesTest.php b/test/phpunit/NumberingModulesTest.php index 0107edc1f8d..b29cd03b2c9 100644 --- a/test/phpunit/NumberingModulesTest.php +++ b/test/phpunit/NumberingModulesTest.php @@ -137,7 +137,8 @@ class NumberingModulesTest extends PHPUnit_Framework_TestCase $conf->global->FACTURE_ADDON='mercure'; $conf->global->FACTURE_MERCURE_MASK_CREDIT='{yyyy}-{0000}'; $conf->global->FACTURE_MERCURE_MASK_INVOICE='{yyyy}-{0000}'; - + $conf->global->INVOICE_CAN_ALWAYS_BE_REMOVED=0; + $localobject=new Facture($this->savdb); $localobject->initAsSpecimen(); $localobject->date=dol_mktime(12, 0, 0, 1, 1, 1915); // we use year 1915 to be sure to not have existing invoice for this year From f22373b70b0b071b1c5e1888d996a1d225b29994 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 1 Feb 2016 01:19:37 +0100 Subject: [PATCH 14/16] Fix bad management of option MAIN_HTML_TITLE --- htdocs/core/class/conf.class.php | 3 +++ htdocs/core/class/html.form.class.php | 2 +- htdocs/main.inc.php | 2 +- htdocs/projet/card.php | 6 +++--- 4 files changed, 8 insertions(+), 5 deletions(-) diff --git a/htdocs/core/class/conf.class.php b/htdocs/core/class/conf.class.php index 7adcd79d364..0bd28092bff 100644 --- a/htdocs/core/class/conf.class.php +++ b/htdocs/core/class/conf.class.php @@ -394,6 +394,9 @@ class Conf // By default, suppliers objects can be linked to all projects $this->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS = 1; + // MAIN_HTML_TITLE + if (! isset($conf->global->MAIN_HTML_TITLE)) $conf->global->MAIN_HTML_TITLE='noapp,thirdpartynameonly,contactnameonly,projectnameonly'; + // conf->liste_limit = constante de taille maximale des listes if (empty($this->global->MAIN_SIZE_LISTE_LIMIT)) $this->global->MAIN_SIZE_LISTE_LIMIT=25; $this->liste_limit=$this->global->MAIN_SIZE_LISTE_LIMIT; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 49d75f6377e..1c9dd350859 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -1018,7 +1018,7 @@ class Form // Do not use textempty = ' ' or ' ' here, or search on key will search on ' key'. //$textifempty=' '; //if (! empty($conf->use_javascript_ajax) || $forcecombo) $textifempty=''; - if (! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) $textifempty.=$langs->trans("NoFilter"); + if (! empty($conf->global->COMPANY_USE_SEARCH_TO_SELECT)) $textifempty.=$langs->trans("All"); if ($showempty) $out.= ''."\n"; $num = $this->db->num_rows($resql); diff --git a/htdocs/main.inc.php b/htdocs/main.inc.php index fffd177fe68..66899a8b2d0 100644 --- a/htdocs/main.inc.php +++ b/htdocs/main.inc.php @@ -1008,7 +1008,7 @@ function top_htmlhead($head, $title='', $disablejs=0, $disablehead=0, $arrayofjs if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE; if ($title && ! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/noapp/',$conf->global->MAIN_HTML_TITLE)) print ''.dol_htmlentities($title).''; - if ($title) print ''.dol_htmlentities($appli.' - '.$title).''; + else if ($title) print ''.dol_htmlentities($appli.' - '.$title).''; else print "".dol_htmlentities($appli).""; print "\n"; diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index 2266f012964..c6511e2a67d 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -395,8 +395,8 @@ $formfile = new FormFile($db); $formproject = new FormProjets($db); $userstatic = new User($db); -$title=$langs->trans("Project").' - '.$object->ref.' '.$object->name; -if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/projectnameonly/',$conf->global->MAIN_HTML_TITLE) && $object->name) $title=$object->ref.' '.$object->name; +$title=$langs->trans("Project").' - '.$object->ref.($object->thirdparty->name?' - '.$object->thirdparty->name:'').($object->title?' - '.$object->title:''); +if (! empty($conf->global->MAIN_HTML_TITLE) && preg_match('/projectnameonly/',$conf->global->MAIN_HTML_TITLE)) $title=$object->ref.($object->thirdparty->name?' - '.$object->thirdparty->name:'').($object->title?' - '.$object->title:''); $help_url="EN:Module_Projects|FR:Module_Projets|ES:Módulo_Proyectos"; llxHeader("",$title,$help_url); @@ -634,7 +634,7 @@ else print ''.$langs->trans("ThirdParty").''; $filteronlist=''; if (! empty($conf->global->PROJECT_FILTER_FOR_THIRDPARTY_LIST)) $filteronlist=$conf->global->PROJECT_FILTER_FOR_THIRDPARTY_LIST; - $text=$form->select_thirdparty_list($object->thirdparty->id,'socid',$filteronlist,1,1); + $text=$form->select_thirdparty_list($object->thirdparty->id, 'socid', $filteronlist, 1, 1); $texthelp=$langs->trans("IfNeedToUseOhterObjectKeepEmpty"); print $form->textwithtooltip($text.' '.img_help(), $texthelp, 1, 0, '', '', 2); print ''; From cd7ae52f92d39ff0da75e2b18345cd63fb118f38 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 1 Feb 2016 03:53:21 +0100 Subject: [PATCH 15/16] Add log --- .travis.yml | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index cfa819cd74f..ad95172334c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -197,6 +197,7 @@ before_script: echo "Create documents directory and set permissions" # and admin/temp subdirectory needed for unit tests mkdir -p documents/admin/temp + echo "first line" > documents/dolibarr.log echo - | @@ -298,14 +299,15 @@ after_success: after_failure: - | + echo "Debugging informations" + # Upgrade log files + cat *.log + echo "Debugging informations" + # Apache log file + sudo cat /var/log/apache2/error.log + # Dolibarr log file + cat documents/dolibarr.log if [ "$DEBUG" = true ]; then - echo "Debugging informations" - # Upgrade log files - cat *.log - # Dolibarr log file - cat documents/dolibarr.log - # Apache log file - sudo cat /var/log/apache2/error.log # MariaDB log file sudo cat /var/log/mysql/error.log # TODO: PostgreSQL log file From de1c6cce63224161bb9c752c532dd664f2449c5f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 1 Feb 2016 10:42:53 +0100 Subject: [PATCH 16/16] Update doc --- build/debian/README.howto | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/build/debian/README.howto b/build/debian/README.howto index 1d6f94e9cd0..01f19e28ccf 100644 --- a/build/debian/README.howto +++ b/build/debian/README.howto @@ -213,7 +213,9 @@ Warning: Name and email must match value into debian/control file (Entry added h * We try to build package > rm -fr ../build-area; -> git-buildpackage -us -uc --git-debian-branch=[master|jessie] --git-upstream-branch=[upstream|upstream-3.5.x] +> git-buildpackage -us -uc --git-debian-branch=[master|jessie] --git-upstream-branch=[upstream|upstream-x.y.z] +ou +> git-buildpackage -us -uc --git-ignore-branch --git-upstream-branch=[upstream|upstream-x.y.z] Note: To build an old version, do: git checkout oldtagname -b newbranchname; git-buildpackage -us -uc --git-debian-branch=newbranchname --git-upstream-branch=[upstream|upstream-3.5.x] Note: You can use git-buildpackage -us -uc --git-ignore-new if you want to test build with uncommited file @@ -221,6 +223,7 @@ Note: You can use git-buildpackage -us -uc -d if you want to test Note: Package is built into directory ../build-area Note: To compare 2 packages: debdiff package1.dsc package2.dsc +* Test package (see dedicated chapter to test it with debian unstable env) * If package .deb is ok: Note: If there was errors managed manually, you may need to make a git commit but do not use option "amend" previous commit