diff --git a/.gitignore b/.gitignore old mode 100755 new mode 100644 diff --git a/ChangeLog b/ChangeLog index 849d8b38855..405aaa9ed9d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -2,6 +2,56 @@ English Dolibarr ChangeLog -------------------------------------------------------------- + +***** ChangeLog for 6.0.7 compared to 6.0.6 ***** +FIX: #8023 +FIX: #8259 can't update contact birthday with REST API +FIX: #8478 !empty instead of count to avoid warning +FIX: #8488 +FIX: actioncomm export: type filtering not working +FIX: addline on invoice supplier manage rank on its own if not provided +FIX: issue #8037 +FIX: label in getnomurl projectlist +FIX: payment term doc-specific label was not used +FIX: payment term doc-specific label was not used (issue #8414) +FIX: project category is type 6 not 5 !! +FIX: some localtaxes errors +FIX: weird password autocompletion in Google Chrome (issue #8479) + +***** ChangeLog for 6.0.6 compared to 6.0.5 ***** +FIX: #7974 Contract - Invalid reference on the document +FIX: #8139 +FIX: #8139 User search does not work if MAIN_USE_OLD_SEARCH_FORM, missing list.php +FIX: #8151 +FIX: #8200 +FIX: add planned delivery to order exports +FIX: a discount is a percent, not an amount, so we use vatrate not price +FIX: Avoid empty value to fk_multicurrency attribute +FIX: Bad localtaxes assignment in cashdesk +FIX: check shipping on delete order +FIX: check verif exped on delete order +FIX: creer into lire +FIX: Delete tasks on project delete will now trigger TASK_DELETE +FIX: Global on $user parameter reset the variable +FIX: if we make a mistake with situation_percent, now we can correct… +FIX: if we make a mistake with situation_percent, now we can correct it. before situation_final was always set to 1 and no way to go back +FIX: Import process must stop after ending line nb to import +FIX: migration script for product photo +FIX: natural search double quote +FIX: reverse field to have object loaded in doaction +FIX: Saving wrong localtax on order addline +FIX: show status on societe banner +FIX: solve column mismatch in user card's usergroup list + code cleanup +FIX: solve column mismatch in user card with multicompany transverse mode + code cleanup +FIX: unset categorie +FIX: update_extras on fourn card +FIX: warning when adding ECM files using old photo path +FIX: Withdrawals lines not filter by company name and not respect dropdown limit lines by page +NEW: Add sale representative einstein_pdf_modules +NEW_einstein_pdf_modules +NEW: field commerciaux and categ export CustomersInvoicesAndPayments + + ***** ChangeLog for 6.0.5 compared to 6.0.4 ***** FIX: security vulnerability reported by ADLab of Venustech CVE-2017-17897, CVE-2017-17898, CVE-2017-17899, CVE-2017-17900 diff --git a/build/makepack-dolibarr.pl b/build/makepack-dolibarr.pl index 7da6d180dcb..31338e44649 100755 --- a/build/makepack-dolibarr.pl +++ b/build/makepack-dolibarr.pl @@ -466,10 +466,12 @@ if ($nboftargetok) { $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr_*.deb`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr_*.dsc`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr_*.tar.gz`; + $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr_*.tar.xz`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.deb`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.rpm`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.tar`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.tar.gz`; + $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.tar.xz`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.tgz`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.xz`; $ret=`rm -f $BUILDROOT/$PROJECT/build/dolibarr-*.zip`; @@ -849,6 +851,8 @@ if ($nboftargetok) { unlink("$NEWDESTI/${FILENAMEDEB}.changes"); print "Remove target ${FILENAMEDEB}.debian.tar.gz...\n"; unlink("$NEWDESTI/${FILENAMEDEB}.debian.tar.gz"); + print "Remove target ${FILENAMEDEB}.debian.tar.xz...\n"; + unlink("$NEWDESTI/${FILENAMEDEB}.debian.tar.xz"); print "Remove target ${FILENAMEDEBNATIVE}.orig.tar.gz...\n"; unlink("$NEWDESTI/${FILENAMEDEBNATIVE}.orig.tar.gz"); @@ -1024,7 +1028,7 @@ if ($nboftargetok) { $ret=`mv $BUILDROOT/*_all.deb "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.dsc "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.orig.tar.gz "$NEWDESTI/"`; - $ret=`mv $BUILDROOT/*.debian.tar.gz "$NEWDESTI/"`; + $ret=`mv $BUILDROOT/*.debian.tar.xz "$NEWDESTI/"`; $ret=`mv $BUILDROOT/*.changes "$NEWDESTI/"`; next; } @@ -1168,7 +1172,7 @@ if ($nboftargetok) { "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'Dolibarr installer for Debian-Ubuntu (DoliDeb)', "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_amd64.changes"=>'none', # none means it won't be published on SF "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.dsc"=>'none', # none means it won't be published on SF - "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.gz"=>'none', # none means it won't be published on SF + "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.xz"=>'none', # none means it won't be published on SF "$DESTI/package_debian-ubuntu/${FILENAMEDEBSHORT}.orig.tar.gz"=>'none', # none means it won't be published on SF "$DESTI/package_windows/$FILENAMEEXEDOLIWAMP.exe"=>'Dolibarr installer for Windows (DoliWamp)', "$DESTI/standard/$FILENAMETGZ.tgz"=>'Dolibarr ERP-CRM', @@ -1181,8 +1185,7 @@ if ($nboftargetok) { "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_all.deb"=>'package_debian-ubuntu', "$DESTI/package_debian-ubuntu/${FILENAMEDEB}_amd64.changes"=>'package_debian-ubuntu', "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.dsc"=>'package_debian-ubuntu', - "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.gz"=>'package_debian-ubuntu', - "$DESTI/package_debian-ubuntu/${FILENAMEDEBSHORT}.orig.tar.gz"=>'package_debian-ubuntu', + "$DESTI/package_debian-ubuntu/${FILENAMEDEB}.debian.tar.xz"=>'package_debian-ubuntu', "$DESTI/package_debian-ubuntu/${FILENAMEDEBSHORT}.orig.tar.gz"=>'package_debian-ubuntu', "$DESTI/package_windows/$FILENAMEEXEDOLIWAMP.exe"=>'package_windows', "$DESTI/standard/$FILENAMETGZ.tgz"=>'standard', diff --git a/htdocs/accountancy/admin/account.php b/htdocs/accountancy/admin/account.php index 905fd8b97ef..1c845716e6b 100644 --- a/htdocs/accountancy/admin/account.php +++ b/htdocs/accountancy/admin/account.php @@ -94,9 +94,9 @@ if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'e if (empty($reshook)) { if (! empty($cancel)) $action = ''; - + include DOL_DOCUMENT_ROOT.'/core/actions_changeselectedfields.inc.php'; - + if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x','alpha') ||GETPOST('button_removefilter','alpha')) // All test are required to be compatible with all browsers { $search_account = ""; @@ -106,13 +106,13 @@ if (empty($reshook)) $search_pcgsubtype = ""; $search_array_options=array(); } - + if (GETPOST('change_chart')) { $chartofaccounts = GETPOST('chartofaccounts', 'int'); - + if (! empty($chartofaccounts)) { - + if (! dolibarr_set_const($db, 'CHARTOFACCOUNTS', $chartofaccounts, 'chaine', 0, '', $conf->entity)) { $error ++; } @@ -120,12 +120,12 @@ if (empty($reshook)) $error ++; } } - + if ($action == 'disable') { if ($accounting->fetch($id)) { $result = $accounting->account_desactivate($id); } - + $action = 'update'; if ($result < 0) { setEventMessages($accounting->error, $accounting->errors, 'errors'); @@ -160,10 +160,10 @@ $pcgver = $conf->global->CHARTOFACCOUNTS; $sql = "SELECT aa.rowid, aa.fk_pcg_version, aa.pcg_type, aa.pcg_subtype, aa.account_number, aa.account_parent , aa.label, aa.active, "; $sql .= " a2.rowid as rowid2, a2.label as label2, a2.account_number as account_number2"; $sql .= " FROM " . MAIN_DB_PREFIX . "accounting_account as aa"; -$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version"; +$sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_system as asy ON aa.fk_pcg_version = asy.pcg_version AND aa.entity = " . $conf->entity; // Dirty hack wainting that foreign key account_parent is an integer to be compared correctly with rowid -if ($db->type == 'pgsql') $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = CAST(aa.account_parent AS INTEGER)"; -else $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = CAST(aa.account_parent AS UNSIGNED)"; +if ($db->type == 'pgsql') $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = CAST(aa.account_parent AS INTEGER) AND a2.entity = " . $conf->entity; +else $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."accounting_account as a2 ON a2.rowid = CAST(aa.account_parent AS UNSIGNED) AND a2.entity = " . $conf->entity; $sql .= " WHERE asy.rowid = " . $pcgver; if (strlen(trim($search_account))) $sql .= natural_search("aa.account_number", $search_account); @@ -179,7 +179,7 @@ if (empty($conf->global->MAIN_DISABLE_FULL_SCANLIST)) { $resql = $db->query($sql); $nbtotalofrecords = $db->num_rows($resql); -} +} $sql .= $db->plimit($limit + 1, $offset); @@ -209,11 +209,11 @@ if ($resql) print ''; print ''; print ''; - + $htmlbuttonadd = '' . $langs->trans("Addanaccount") . ''; - + print_barre_liste($langs->trans('ListAccounts'), $page, $_SERVER["PHP_SELF"], $params, $sortfield, $sortorder, '', $num, $nbtotalofrecords, 'title_accountancy', 0, $htmlbuttonadd); - + // Box to select active chart of account print $langs->trans("Selectchartofaccounts") . " : "; print '"; print ''; - print '
'; + print '
'; print '
'; - + $varpage=empty($contextpage)?$_SERVER["PHP_SELF"]:$contextpage; $selectedfields=$form->multiSelectArrayWithCheckbox('selectedfields', $arrayfields, $varpage); // This also change content of $arrayfields - + print '
'; print ''."\n"; @@ -259,7 +259,7 @@ if ($resql) print $searchpicto; print ''; print ''; - + print ''; if (! empty($arrayfields['aa.account_number']['checked'])) print_liste_field_titre($arrayfields['aa.account_number']['label'], $_SERVER["PHP_SELF"],"aa.account_number","",$param,'',$sortfield,$sortorder); if (! empty($arrayfields['aa.label']['checked'])) print_liste_field_titre($arrayfields['aa.label']['label'], $_SERVER["PHP_SELF"],"aa.label","",$param,'',$sortfield,$sortorder); @@ -274,14 +274,14 @@ if ($resql) $accountparent = new AccountingAccount($db); $i=0; - while ($i < min($num, $limit)) + while ($i < min($num, $limit)) { $obj = $db->fetch_object($resql); $accountstatic->id = $obj->rowid; $accountstatic->label = $obj->label; $accountstatic->account_number = $obj->account_number; - + print ''; // Account number @@ -310,7 +310,7 @@ if ($resql) $accountparent->id = $obj->rowid2; $accountparent->label = $obj->label2; $accountparent->account_number = $obj->account_number2; - + print "\n"; @@ -371,11 +371,11 @@ if ($resql) } print '' . "\n"; if (! $i) $totalarray['nbfield']++; - + print "\n"; $i++; } - + print "
"; print $accountparent->getNomUrl(1); print "
"; print "
"; print ''; diff --git a/htdocs/accountancy/admin/journals_list.php b/htdocs/accountancy/admin/journals_list.php index a3912aebc89..a4718d556f2 100644 --- a/htdocs/accountancy/admin/journals_list.php +++ b/htdocs/accountancy/admin/journals_list.php @@ -86,7 +86,7 @@ $tablib[35]= "DictionaryAccountancyJournal"; // Requests to extract data $tabsql=array(); -$tabsql[35]= "SELECT a.rowid as rowid, a.code as code, a.label, a.nature, a.active FROM ".MAIN_DB_PREFIX."accounting_journal as a"; +$tabsql[35]= "SELECT a.rowid as rowid, a.code as code, a.label, a.nature, a.active FROM ".MAIN_DB_PREFIX."accounting_journal as a WHERE a.entity=".$conf->entity; // Criteria to sort dictionaries $tabsqlsort=array(); @@ -102,7 +102,7 @@ $tabfieldvalue[35]= "code,label,nature"; // Nom des champs dans la table pour insertion d'un enregistrement $tabfieldinsert=array(); -$tabfieldinsert[35]= "code,label,nature"; +$tabfieldinsert[35]= "code,label,nature,entity"; // Nom du rowid si le champ n'est pas de type autoincrement // Example: "" if id field is "rowid" and has autoincrement on diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index 50f9e18fd80..76e2a0b8e20 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -28,7 +28,9 @@ require '../../main.inc.php'; // Class require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT . '/accountancy/class/bookkeeping.class.php'; +require_once DOL_DOCUMENT_ROOT . '/accountancy/class/accountancyexport.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formaccounting.class.php'; require_once DOL_DOCUMENT_ROOT . '/core/class/html.formother.class.php'; diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php index 9012257adee..7deee19d873 100644 --- a/htdocs/accountancy/customer/lines.php +++ b/htdocs/accountancy/customer/lines.php @@ -152,7 +152,7 @@ print ''; diff --git a/htdocs/loan/createschedule.php b/htdocs/loan/createschedule.php index 70688461ae9..4ab2499c265 100644 --- a/htdocs/loan/createschedule.php +++ b/htdocs/loan/createschedule.php @@ -22,14 +22,11 @@ */ require '../main.inc.php'; - require_once DOL_DOCUMENT_ROOT.'/loan/class/loan.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/loan.lib.php'; require_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT.'/loan/class/loanschedule.class.php'; -global $user; - $loanid = GETPOST('loanid', 'int'); $action = GETPOST('action','aZ09'); @@ -107,6 +104,7 @@ $(document).ready(function() { var idcap=echeance-1; idcap = '#hi_capital'+idcap; var capital=$(idcap).val(); + console.log("Change montly amount echeance="+echeance+" idcap="+idcap+" capital="+capital); $.ajax({ dataType: 'json', url: 'calcmens.php', @@ -135,50 +133,59 @@ $(document).ready(function() { print '
'; print ''; print ''; -if(count($echeance->lines)>0){ +if(count($echeance->lines)>0) +{ print ''; }else{ print ''; } print ''; print ''; -print '"; +print ''; print ''; print ''; -Print ''; -Print ''; -Print ''; -Print ''; -Print ''; -print ''; +Print ''; +Print ''; +Print ''; +Print ''; +Print ''; +print ''."\n"; if ($object->nbterm > 0 && count($echeance->lines)==0) { $i=1; $capital = $object->capital; - while($i <$object->nbterm+1){ - $mens = round($echeance->calc_mens($capital, $object->rate/100, $object->nbterm-$i+1),2,PHP_ROUND_HALF_UP); + while($i <$object->nbterm+1) + { + $mens = price2num($echeance->calc_mens($capital, $object->rate/100, $object->nbterm-$i+1), 'MT'); $int = ($capital*($object->rate/12))/100; - $int = round($int,2,PHP_ROUND_HALF_UP); - $cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); + $int = price2num($int, 'MT'); + $cap_rest = price2num($capital - ($mens-$int), 'MT'); print ''; print ''; print ''; print ''; print ''; print ''; - print ''; + print ''."\n"; $i++; $capital = $cap_rest; } -}elseif(count($echeance->lines)>0){ +} +elseif(count($echeance->lines)>0) +{ $i=1; $capital = $object->capital; foreach ($echeance->lines as $line){ $mens = $line->amount_capital+$line->amount_insurance+$line->amount_interest; $int = $line->amount_interest; - $cap_rest = round($capital - ($mens-$int),2,PHP_ROUND_HALF_UP); + $cap_rest = price2num($capital - ($mens-$int), 'MT'); print ''; print ''; print ''; @@ -189,7 +196,7 @@ if ($object->nbterm > 0 && count($echeance->lines)==0) } print ''; print ''; - print ''; + print ''."\n"; $i++; $capital = $cap_rest; } diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index 28786f0d324..dca938afc7f 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -158,6 +158,8 @@ if ($action == 'order' && isset($_POST['valid'])) $line->total_ttc = $line->total_ht + $line->total_tva; $line->remise_percent = $obj->remise_percent; $line->ref_fourn = $obj->ref_fourn; + $line->type = $product->type; + $line->fk_unit = $product->fk_unit; $suppliers[$obj->fk_soc]['lines'][] = $line; } } @@ -202,7 +204,13 @@ if ($action == 'order' && isset($_POST['valid'])) $line->remise_percent, 'HT', 0, - $line->info_bits + $line->type, + 0, + false, + null, + null, + 0, + $line->fk_unit ); } if ($result < 0) { diff --git a/htdocs/product/traduction.php b/htdocs/product/traduction.php index 791da80c05d..20e0bd4c8ad 100644 --- a/htdocs/product/traduction.php +++ b/htdocs/product/traduction.php @@ -251,7 +251,7 @@ if ($action == 'edit') print '
'; print '
' . "Création d'échéancier'; +print $langs->trans("FinancialCommitment"); +print '
Echéance Date Montant Intérêts Capital restant du
'.$langs->trans("DueDate").''.$langs->trans("Date").''.$langs->trans("Amount").''.$langs->trans("InterestAmount").''.$langs->trans("Remain"); +print ' ('.price2num($object->capital).')'; +print ''; +print '
' . $i .'' . dol_print_date(dol_time_plus_duree($object->datestart, $i-1, 'm'),'day') . ''.price($int,0,'',1).' €'.price($cap_rest).' €
' . $i .'' . dol_print_date($line->datep,'day') . ''.price($int,0,'',1).' €'.price($cap_rest).' €
'; - print ''; + print ''; print '
'.$langs->trans('Label').'
'.$langs->trans('Label').'
'.$langs->trans('Description').''; $doleditor = new DolEditor("desc-$key", $object->multilangs[$key]["description"], '', 160, 'dolibarr_notes', '', false, true, $conf->global->FCKEDITOR_ENABLE_PRODUCTDESC, ROWS_3, '90%'); $doleditor->Create(); diff --git a/htdocs/projet/activity/perday.php b/htdocs/projet/activity/perday.php index 36b55ea79ff..b4329ac9237 100644 --- a/htdocs/projet/activity/perday.php +++ b/htdocs/projet/activity/perday.php @@ -49,7 +49,8 @@ $projectid=isset($_GET["id"])?$_GET["id"]:$_POST["projectid"]; // Security check $socid=0; -if ($user->societe_id > 0) $socid=$user->societe_id; +// For external user, no check is done on company because readability is managed by public status of project and assignement. +//if ($user->societe_id > 0) $socid=$user->societe_id; $result = restrictedArea($user, 'projet', $projectid); $now=dol_now(); diff --git a/htdocs/projet/activity/perweek.php b/htdocs/projet/activity/perweek.php index 438d71cbdba..591f8b3ab6f 100644 --- a/htdocs/projet/activity/perweek.php +++ b/htdocs/projet/activity/perweek.php @@ -50,7 +50,8 @@ $projectid=isset($_GET["id"])?$_GET["id"]:$_POST["projectid"]; // Security check $socid=0; -if ($user->societe_id > 0) $socid=$user->societe_id; +// For external user, no check is done on company because readability is managed by public status of project and assignement. +// if ($user->societe_id > 0) $socid=$user->societe_id; $result = restrictedArea($user, 'projet', $projectid); $now=dol_now(); diff --git a/htdocs/projet/class/project.class.php b/htdocs/projet/class/project.class.php index 84050012a5a..551bdcb9d5f 100644 --- a/htdocs/projet/class/project.class.php +++ b/htdocs/projet/class/project.class.php @@ -629,45 +629,13 @@ class Project extends CommonObject } } - // Delete tasks - if (! $error) - { - $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet_task_time"; - $sql.= " WHERE fk_task IN (SELECT rowid FROM " . MAIN_DB_PREFIX . "projet_task WHERE fk_projet=" . $this->id . ")"; + // Fetch tasks + $this->getLinesArray($user); - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $this->db->lasterror(); - $error++; - } - } - - if (! $error) - { - $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet_task_extrafields"; - $sql.= " WHERE fk_object IN (SELECT rowid FROM " . MAIN_DB_PREFIX . "projet_task WHERE fk_projet=" . $this->id . ")"; - - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $this->db->lasterror(); - $error++; - } - } - - if (! $error) - { - $sql = "DELETE FROM " . MAIN_DB_PREFIX . "projet_task"; - $sql.= " WHERE fk_projet=" . $this->id; - - $resql = $this->db->query($sql); - if (!$resql) - { - $this->errors[] = $this->db->lasterror(); - $error++; - } - } + // Delete tasks + foreach($this->lines as &$task) { + $task->delete($user); + } // Delete project if (! $error) @@ -1694,23 +1662,26 @@ class Project extends CommonObject { global $conf, $langs; - $mine=0; $socid=$user->societe_id; - - $projectsListId = $this->getProjectsAuthorizedForUser($user,$mine?$mine:($user->rights->projet->all->lire?2:0),1,$socid); + // For external user, no check is done on company because readability is managed by public status of project and assignement. + //$socid=$user->societe_id; + if (! $user->rights->projet->all->lire) $projectsListId = $this->getProjectsAuthorizedForUser($user,0,1,$socid); + $sql = "SELECT p.rowid, p.fk_statut as status, p.fk_opp_status, p.datee as datee"; $sql.= " FROM (".MAIN_DB_PREFIX."projet as p"; $sql.= ")"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; - if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; + // For external user, no check is done on company permission because readability is managed by public status of project and assignement. + //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; $sql.= " WHERE p.fk_statut = 1"; $sql.= " AND p.entity IN (".getEntity('project', 0).')'; - if ($mine || ! $user->rights->projet->all->lire) $sql.= " AND p.rowid IN (".$projectsListId.")"; + if (! $user->rights->projet->all->lire) $sql.= " AND p.rowid IN (".$projectsListId.")"; // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - if ($socid) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; - + // For external user, no check is done on company permission because readability is managed by public status of project and assignement. + //if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; + + //print $sql; $resql=$this->db->query($sql); if ($resql) { diff --git a/htdocs/projet/class/task.class.php b/htdocs/projet/class/task.class.php index 1c8b1466483..6beafe71a25 100644 --- a/htdocs/projet/class/task.class.php +++ b/htdocs/projet/class/task.class.php @@ -1701,29 +1701,31 @@ class Task extends CommonObject { global $conf, $langs; - $mine=0; $socid=$user->societe_id; - + // For external user, no check is done on company because readability is managed by public status of project and assignement. + //$socid=$user->societe_id; + $projectstatic = new Project($this->db); - $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user,$mine,1,$socid); - + $projectsListId = $projectstatic->getProjectsAuthorizedForUser($user,0,1,$socid); + // List of tasks (does not care about permissions. Filtering will be done later) $sql = "SELECT p.rowid as projectid, p.fk_statut as projectstatus,"; $sql.= " t.rowid as taskid, t.progress as progress, t.fk_statut as status,"; $sql.= " t.dateo as date_start, t.datee as datee"; - $sql.= " FROM ".MAIN_DB_PREFIX."projet as p"; - $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; - if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; - $sql.= ", ".MAIN_DB_PREFIX."projet_task as t"; - $sql.= " WHERE p.entity IN (".getEntity('project', 0).')'; - $sql.= " AND p.fk_statut = 1"; - $sql.= " AND t.fk_projet = p.rowid"; - $sql.= " AND t.progress < 100"; // tasks to do - if ($mine || ! $user->rights->projet->all->lire) $sql.= " AND p.rowid IN (".$projectsListId.")"; - // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser - //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - if ($socid) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; - if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; - //print $sql; + $sql.= " FROM ".MAIN_DB_PREFIX."projet as p"; + $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."societe as s on p.fk_soc = s.rowid"; + //if (! $user->rights->societe->client->voir && ! $socid) $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."societe_commerciaux as sc ON sc.fk_soc = s.rowid"; + $sql.= ", ".MAIN_DB_PREFIX."projet_task as t"; + $sql.= " WHERE p.entity IN (".getEntity('project', 0).')'; + $sql.= " AND p.fk_statut = 1"; + $sql.= " AND t.fk_projet = p.rowid"; + if (! $user->rights->projet->all->lire) $sql.= " AND p.rowid IN (".$projectsListId.")"; + // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser + //if ($socid || ! $user->rights->societe->client->voir) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; + if ($socid) $sql.= " AND (p.fk_soc IS NULL OR p.fk_soc = 0 OR p.fk_soc = ".$socid.")"; + // No need to check company, as filtering of projects must be done by getProjectsAuthorizedForUser + // if (! $user->rights->societe->client->voir && ! $socid) $sql.= " AND ((s.rowid = sc.fk_soc AND sc.fk_user = " .$user->id.") OR (s.rowid IS NULL))"; + + //print $sql; $resql=$this->db->query($sql); if ($resql) { diff --git a/htdocs/projet/contact.php b/htdocs/projet/contact.php index 72b82ac2bb0..6da1028d473 100644 --- a/htdocs/projet/contact.php +++ b/htdocs/projet/contact.php @@ -49,6 +49,7 @@ $socid=0; //if ($user->societe_id > 0) $socid = $user->societe_id; // For external user, no check is done on company because readability is managed by public status of project and assignement. $result = restrictedArea($user, 'projet', $id,'projet&project'); +$hookmanager->initHooks(array('projectcontactcard','globalcard')); /* * Actions @@ -150,26 +151,26 @@ if ($id > 0 || ! empty($ref)) // Project card - + $linkback = ''.$langs->trans("BackToList").''; - + $morehtmlref='
'; // Title $morehtmlref.=$object->title; // Thirdparty - if ($object->thirdparty->id > 0) + if ($object->thirdparty->id > 0) { $morehtmlref.='
'.$langs->trans('ThirdParty') . ' : ' . $object->thirdparty->getNomUrl(1, 'project'); } $morehtmlref.='
'; - + // Define a complementary filter for search of next/prev ref. if (! $user->rights->projet->all->lire) { $objectsListId = $object->getProjectsAuthorizedForUser($user,0,0); $object->next_prev_filter=" rowid in (".(count($objectsListId)?join(',',array_keys($objectsListId)):'0').")"; } - + dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); @@ -178,7 +179,7 @@ if ($id > 0 || ! empty($ref)) print '
'; print ''; - + // Visibility print ''; - + // Opportunity percent print ''; } - + // Date start - end print '
'.$langs->trans("Visibility").''; if ($object->public) print $langs->trans('SharedProject'); @@ -192,7 +193,7 @@ if ($id > 0 || ! empty($ref)) $code = dol_getIdFromCode($db, $object->opp_status, 'c_lead_status', 'rowid', 'code'); if ($code) print $langs->trans("OppStatus".$code); print '
'.$langs->trans("OpportunityProbability").''; if (strcmp($object->opp_percent,'')) print price($object->opp_percent,'',$langs,1,0).' %'; @@ -203,7 +204,7 @@ if ($id > 0 || ! empty($ref)) if (strcmp($object->opp_amount,'')) print price($object->opp_amount,'',$langs,0,0,0,$conf->currency); print '
'.$langs->trans("DateStart").' - '.$langs->trans("DateEnd").''; $start = dol_print_date($object->date_start,'dayhour'); @@ -222,40 +223,40 @@ if ($id > 0 || ! empty($ref)) // Other attributes $cols = 2; include DOL_DOCUMENT_ROOT . '/core/tpl/extrafields_view.tpl.php'; - + print "
"; print ''; print '
'; print '
'; print '
'; - + print ''; - + // Description print ''; - + // Categories if ($conf->categorie->enabled) { print '"; } - + print '
'.$langs->trans("Description").''; print nl2br($object->description); print '
'.$langs->trans("Categories").''; print $form->showCategories($object->id,'project',1); print "
'; - + print '
'; print '
'; print ''; - + print '
'; - + dol_fiche_end(); - + print '
'; - + // Contacts lines (modules that overwrite templates must declare this into descriptor) $dirtpls=array_merge($conf->modules_parts['tpl'],array('/core/tpl')); foreach($dirtpls as $reldir) diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 17b3cbd65f9..85bbf906fef 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -145,7 +145,7 @@ $morehtmlref.=''; if (! $user->rights->projet->all->lire) { $objectsListId = $object->getProjectsAuthorizedForUser($user,0,0); - $object->next_prev_filter=" rowid in (".(count($objectsListId)?join(',',array_keys($objectsListId)):'0').")"; + $object->next_prev_filter=" te.rowid in (".(count($objectsListId)?join(',',array_keys($objectsListId)):'0').")"; } dol_banner_tab($object, 'ref', $linkback, 1, 'ref', 'ref', $morehtmlref); diff --git a/htdocs/projet/list.php b/htdocs/projet/list.php index 6eaf231a5cb..dc3ab9a58ac 100644 --- a/htdocs/projet/list.php +++ b/htdocs/projet/list.php @@ -668,6 +668,7 @@ while ($i < min($num,$limit)) $object->datee = $db->jdate($obj->date_end); $object->statut = $obj->fk_statut; $object->opp_status = $obj->fk_opp_status; + $object->title = $obj->title; $userAccess = $object->restrictedProjectArea($user); // why this ? if ($userAccess >= 0) diff --git a/htdocs/projet/tasks.php b/htdocs/projet/tasks.php index c00e93e239f..9121f0d5776 100644 --- a/htdocs/projet/tasks.php +++ b/htdocs/projet/tasks.php @@ -77,7 +77,9 @@ $planned_workload=$planned_workloadhour*3600+$planned_workloadmin*60; $userAccess=0; - +$parameters=array('id'=>$id); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); /* * Actions */ diff --git a/htdocs/projet/tasks/list.php b/htdocs/projet/tasks/list.php index 3d239921c60..c3f1da54a16 100644 --- a/htdocs/projet/tasks/list.php +++ b/htdocs/projet/tasks/list.php @@ -756,7 +756,7 @@ while ($i < min($num,$limit)) $showlineingray=0;$showproject=1; print '
'; if ($showlineingray) print ''; - else print ''; + else print ''; if ($obj->duration_effective) print convertSecondToTime($obj->duration_effective,$timespentoutputformat); else print '--:--'; if ($showlineingray) print ''; diff --git a/htdocs/projet/tasks/task.php b/htdocs/projet/tasks/task.php index db56534f851..24799c18354 100644 --- a/htdocs/projet/tasks/task.php +++ b/htdocs/projet/tasks/task.php @@ -60,6 +60,9 @@ $projectstatic = new Project($db); // fetch optionals attributes and labels $extralabels=$extrafields->fetch_name_optionals_label($object->table_element); +$parameters=array('id'=>$id); +$reshook=$hookmanager->executeHooks('doActions',$parameters,$object,$action); // Note that $action and $object may have been modified by some hooks +if ($reshook < 0) setEventMessages($hookmanager->error, $hookmanager->errors, 'errors'); /* * Actions diff --git a/htdocs/societe/card.php b/htdocs/societe/card.php index d3f629952b1..204eff383d5 100644 --- a/htdocs/societe/card.php +++ b/htdocs/societe/card.php @@ -10,6 +10,7 @@ * Copyright (C) 2015 Jean-François Ferry * Copyright (C) 2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud + * Copyright (C) 2018 Nicolas ZABOURI * * 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 @@ -72,7 +73,7 @@ $extralabels=$extrafields->fetch_name_optionals_label($object->table_element); // Initialize technical object to manage hooks of page. Note that conf->hooks_modules contains array of hook context $hookmanager->initHooks(array('thirdpartycard','globalcard')); -if ($action == 'view' && $object->fetch($socid)<=0) +if ($object->fetch($socid)<=0 && $action == 'view') { $langs->load("errors"); print($langs->trans('ErrorRecordNotFound')); @@ -291,11 +292,15 @@ if (empty($reshook)) // Fill array 'array_options' with data from update form $extralabels = $extrafields->fetch_name_optionals_label($object->table_element); $ret = $extrafields->setOptionalsFromPost($extralabels, $object, GETPOST('attribute')); - if ($ret < 0) $error++; + if ($ret < 0) { $error++; } if (! $error) { $result = $object->insertExtraFields(); - if ($result < 0) $error++; + if ($result < 0) + { + $error++; + $errors = $object->errors; + } } if ($error) $action = 'edit_extras'; } diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 9a43c5b3cfa..729995a81d0 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -2511,21 +2511,16 @@ class Societe extends CommonObject if (! empty($conf->global->SOCIETE_CODECOMPTA_ADDON)) { - $file=''; + $res=false; $dirsociete=array_merge(array('/core/modules/societe/'), $conf->modules_parts['societe']); foreach ($dirsociete as $dirroot) { - if (file_exists(DOL_DOCUMENT_ROOT.'/'.$dirroot.$conf->global->SOCIETE_CODECOMPTA_ADDON.".php")) - { - $file=$dirroot.$conf->global->SOCIETE_CODECOMPTA_ADDON.".php"; - break; - } + $res=dol_include_once($dirroot.$conf->global->SOCIETE_CODECOMPTA_ADDON.'.php'); + if ($res) break; } - if (! empty($file)) + if ($res) { - dol_include_once($file); - $classname = $conf->global->SOCIETE_CODECOMPTA_ADDON; $mod = new $classname; diff --git a/htdocs/supplier_proposal/card.php b/htdocs/supplier_proposal/card.php index c39f7e1e0ea..050e70c4453 100644 --- a/htdocs/supplier_proposal/card.php +++ b/htdocs/supplier_proposal/card.php @@ -465,15 +465,6 @@ if (empty($reshook)) // Action for direct print include DOL_DOCUMENT_ROOT.'/core/actions_printing.inc.php'; - // Actions to send emails - $trigger_name='SUPPLIER_PROPOSAL_SENTBYMAIL'; - $paramname='id'; - $mode='emailfromsupplierproposal'; - $trackid='spr'.$object->id; - include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; - - - // Go back to draft if ($action == 'modif' && $user->rights->supplier_proposal->creer) { @@ -876,46 +867,20 @@ if (empty($reshook)) exit(); } - // Generation doc (depuis lien ou depuis cartouche doc) - else if ($action == 'builddoc' && $user->rights->supplier_proposal->creer) { - if (GETPOST('model')) { - $object->setDocModel($user, GETPOST('model')); - } + // Actions to send emails + $trigger_name='SUPPLIER_PROPOSAL_SENTBYMAIL'; + $paramname='id'; + $mode='emailfromsupplierproposal'; + $trackid='spr'.$object->id; + include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; - // Define output language - $outputlangs = $langs; - if (! empty($conf->global->MAIN_MULTILANGS)) { - $outputlangs = new Translate("", $conf); - $newlang = (GETPOST('lang_id','aZ09') ? GETPOST('lang_id','aZ09') : $object->thirdparty->default_lang); - $outputlangs->setDefaultLang($newlang); - } - $ret = $object->fetch($id); // Reload to get new records - $result = $object->generateDocument($object->modelpdf, $outputlangs, $hidedetails, $hidedesc, $hideref); - if ($result <= 0) - { - setEventMessages($object->error, $object->errors, 'errors'); - $action=''; - } - } - - // Remove file in doc form - else if ($action == 'remove_file' && $user->rights->supplier_proposal->creer) { - if ($object->id > 0) { - require_once DOL_DOCUMENT_ROOT . '/core/lib/files.lib.php'; - - $langs->load("other"); - $upload_dir = $conf->supplier_proposal->dir_output; - $file = $upload_dir . '/' . GETPOST('file'); - $ret = dol_delete_file($file, 0, 0, 0, $object); - if ($ret) - setEventMessages($langs->trans("FileWasRemoved", GETPOST('file')), null, 'mesgs'); - else - setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('file')), null, 'errors'); - } - } + // Actions to build doc + $upload_dir = $conf->supplier_proposal->dir_output; + $permissioncreate=$user->rights->supplier_proposal->creer; + include DOL_DOCUMENT_ROOT.'/core/actions_builddoc.inc.php'; // Set project - else if ($action == 'classin' && $user->rights->supplier_proposal->creer) { + if ($action == 'classin' && $user->rights->supplier_proposal->creer) { $object->setProject($_POST['projectid']); } diff --git a/htdocs/user/card.php b/htdocs/user/card.php index 1885740b489..5e83ee81fd0 100644 --- a/htdocs/user/card.php +++ b/htdocs/user/card.php @@ -75,6 +75,9 @@ if (! empty($conf->global->MAIN_USE_ADVANCED_PERMS)) $canreadgroup=(! empty($user->admin) || $user->rights->user->group_advance->read); $caneditgroup=(! empty($user->admin) || $user->rights->user->group_advance->write); } +if(! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { + $caneditgroup = $conf->entity == 1 && ! empty($user->admin) && empty($user->entity); +} // Define value to know what current user can do on properties of edited user if ($id) { @@ -1791,41 +1794,21 @@ else print ''."\n"; print ''."\n"; - if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && ! $user->entity) - { - print ''; - } print ''; - print "'."\n"; @@ -1849,40 +1832,46 @@ else print img_object($langs->trans("ShowGroup"),"group").' '.$group->name; } print ''; - if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE) && $conf->entity == 1 && $user->admin && ! $user->entity) - { - print '\n"; + print ''."\n"; } } else { - print ''; + $colspan = 2; + if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { + $colspan ++; + if ($caneditgroup) $colspan ++; + } + + print ''; } print "
'.$langs->trans("Groups").''.$langs->trans("Entity").''; - if ($caneditgroup) - { - // Users/Groups management only in master entity if transverse mode - if (! empty($conf->multicompany->enabled) && $conf->entity > 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE) - { - // nothing - } - else - { - print $form->select_dolgroups('', 'group', 1, $exclude, 0, '', '', $object->entity); - print '   '; - // Multicompany - if (! empty($conf->multicompany->enabled)) - { - if ($conf->entity == 1 && $conf->global->MULTICOMPANY_TRANSVERSE_MODE) - { - print ''.$langs->trans("Entity").'".$mc->select_entities($conf->entity); - } - else - { - print ''; - } - } - else - { - print ''; - } - print ''; - } + if ($caneditgroup) { + print $form->select_dolgroups('', 'group', 1, $exclude, 0, '', '', $object->entity); + } + + if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { + print '' . $langs->trans("Entity"); + + if ($caneditgroup) { + print '' . $mc->select_entities($conf->entity, 'entity'); + } + } + + if ($caneditgroup) { + print '   '; } print '
'; - if (! empty($group->usergroup_entity)) - { - $nb=0; - foreach($group->usergroup_entity as $group_entity) - { - $mc->getInfo($group_entity); - print ($nb > 0 ? ', ' : '').$mc->label; - print ''; - print img_delete($langs->trans("RemoveFromGroup")); - print ''; - $nb++; - } - } - } print ''; - if ($caneditgroup && empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) - { - print ''; + if (! empty($conf->multicompany->enabled) && ! empty($conf->global->MULTICOMPANY_TRANSVERSE_MODE)) { + print ''; + + if (! empty($group->usergroup_entity)) { + $nb = 0; + foreach ($group->usergroup_entity as $group_entity) { + $mc->getInfo($group_entity); + print ($nb > 0 ? ', ' : '') . $mc->label; + + if ($conf->entity == 1 && ! empty($user->admin) && empty($user->entity)) { + print ''; + print img_delete($langs->trans("RemoveFromGroup")); + print ''; + } + + $nb ++; + } + } + + if ($caneditgroup) { + print ''; + } + } elseif ($caneditgroup) { + print ''; print img_delete($langs->trans("RemoveFromGroup")); print ''; } - else - { - print " "; - } - print "
'.$langs->trans("None").'
' . $langs->trans("None") . '
"; @@ -2001,7 +1990,7 @@ else } else if ($caneditpassword) { - $text=''; + $text=''; if ($dolibarr_main_authentication && $dolibarr_main_authentication == 'http') { $text=$form->textwithpicto($text,$langs->trans("DolibarrInHttpAuthenticationSoPasswordUseless",$dolibarr_main_authentication),1,'warning'); diff --git a/htdocs/variants/ajax/getCombinations.php b/htdocs/variants/ajax/getCombinations.php index 8b7baaee27e..5c57191c3eb 100644 --- a/htdocs/variants/ajax/getCombinations.php +++ b/htdocs/variants/ajax/getCombinations.php @@ -28,7 +28,7 @@ require_once DOL_DOCUMENT_ROOT.'/variants/class/ProductCombination.class.php'; header('Content-Type: application/json'); -$id = GETPOST('id'); +$id = GETPOST('id', 'int'); if (!$id) { print json_encode(array( diff --git a/htdocs/variants/combinations.php b/htdocs/variants/combinations.php index 0ec1bf07b68..ef7dffd9ed0 100644 --- a/htdocs/variants/combinations.php +++ b/htdocs/variants/combinations.php @@ -383,7 +383,7 @@ if (! empty($id) || ! empty($ref)) select.empty().append(''); - jQuery.getJSON("", { + jQuery.getJSON("ajax/get_attribute_values.php", { id: jQuery(this).val() }, function(data) { if (data.error) { @@ -699,8 +699,12 @@ if (! empty($id) || ! empty($ref)) print ''; print ''; } +} else { + llxHeader(); + // not found } + llxFooter(); $db->close(); diff --git a/scripts/product/migrate_picture_path.php b/scripts/product/migrate_picture_path.php index 98a5c4d51bc..d72c60f05e5 100755 --- a/scripts/product/migrate_picture_path.php +++ b/scripts/product/migrate_picture_path.php @@ -104,6 +104,7 @@ function migrate_product_photospath($product) global $conf; $dir = $conf->product->multidir_output[$product->entity]; + $conf->global->PRODUCT_USE_OLD_PATH_FOR_PHOTO = 1; $origin = $dir .'/'. get_exdir($product->id,2,0,0,$product,'product') . $product->id ."/photos"; $destin = $dir.'/'.dol_sanitizeFileName($product->ref);