From 34e434a17e8751f6e76ab20d8f7a6053dbc48fc8 Mon Sep 17 00:00:00 2001 From: Regis Houssin Date: Mon, 6 Apr 2020 16:36:11 +0200 Subject: [PATCH 01/58] FIX missing member entity --- htdocs/societe/class/societe.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 87c4956e48e..5ea844a7320 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -3275,6 +3275,7 @@ class Societe extends CommonObject $this->phone=$member->phone; // Prof phone $this->email=$member->email; $this->skype=$member->skype; + $this->entity=$member->entity; $this->client = 1; // A member is a customer by default $this->code_client = ($customercode?$customercode:-1); @@ -3778,7 +3779,7 @@ class Societe extends CommonObject $outstandingOpened+=$obj->total_ttc - $paiement - $creditnotes - $deposits; } - + //if credit note is converted but not used if($mode == 'supplier' && $obj->type == FactureFournisseur::TYPE_CREDIT_NOTE && $tmpobject->isCreditNoteUsed())$outstandingOpened-=$tmpobject->getSumFromThisCreditNotesNotUsed(); From 3327f1c0742bf9a08eed8d77f206c3ae700f23e9 Mon Sep 17 00:00:00 2001 From: gauthier Date: Thu, 9 Apr 2020 11:53:03 +0200 Subject: [PATCH 02/58] FIX : IHM, unexpected quote --- htdocs/langs/fr_FR/exports.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/fr_FR/exports.lang b/htdocs/langs/fr_FR/exports.lang index 58242dfaa1a..b76d78ea09d 100644 --- a/htdocs/langs/fr_FR/exports.lang +++ b/htdocs/langs/fr_FR/exports.lang @@ -109,7 +109,7 @@ Separator=Séparateur de champs Enclosure=Encadrement des chaînes de textes SpecialCode=Code spécial ExportStringFilter=%% permet de remplacer 1 ou plusieurs caractères dans le texte -ExportDateFilter=AAAA, AAAAMM, AAAAMMJJ: filtre pour une année/mois/jour
AAAA+AAAA, AAAAMM+AAAAMM, AAAAMMJJ+AAAAMMJJ: filtre pour une plage année/mois/jour
> AAAA, > AAAAMM, > AAAAMMJJ': filtre pour une date supérieure à une année/mois/jour donné
< AAAA, < AAAAMM, < AAAAMMJJ: filtre pour une date inférieure à une année/mois/jour donné +ExportDateFilter=AAAA, AAAAMM, AAAAMMJJ: filtre pour une année/mois/jour
AAAA+AAAA, AAAAMM+AAAAMM, AAAAMMJJ+AAAAMMJJ: filtre pour une plage année/mois/jour
> AAAA, > AAAAMM, > AAAAMMJJ: filtre pour une date supérieure à une année/mois/jour donné
< AAAA, < AAAAMM, < AAAAMMJJ: filtre pour une date inférieure à une année/mois/jour donné ExportNumericFilter=NNNNN filtre une seule valeur
NNNNN+NNNNN filtre une plage de valeurs
< NNNNN filtre les valeurs inférieures
> NNNNN filtre les valeurs supérieures ImportFromLine=Début d'import à la ligne numéro EndAtLineNb=Fin à la ligne numéro From 1f471d46eb6445d3a736773e019716523b14a9cc Mon Sep 17 00:00:00 2001 From: gauthier Date: Fri, 10 Apr 2020 15:51:51 +0200 Subject: [PATCH 03/58] FIX : some others modules (like subtotal) use other product_type than 0 or 1 AND must not be considered in this report --- htdocs/compta/stats/cabyprodserv.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/compta/stats/cabyprodserv.php b/htdocs/compta/stats/cabyprodserv.php index 786521c0511..f9057e1066c 100644 --- a/htdocs/compta/stats/cabyprodserv.php +++ b/htdocs/compta/stats/cabyprodserv.php @@ -243,6 +243,7 @@ if ($modecompta == 'CREANCES-DETTES') } $sql.= " WHERE l.fk_facture = f.rowid"; $sql.= " AND f.fk_statut in (1,2)"; + $sql.= " AND l.product_type in (0,1)"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { $sql.= " AND f.type IN (0,1,2,5)"; } else { From f5ab957faff92e6574e73d99bbdc82131aa77bdb Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sat, 11 Apr 2020 17:55:07 +0200 Subject: [PATCH 04/58] FIX #13535 : state in italian address --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 9c9bf505b05..1f7c08c8d7a 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -1651,7 +1651,7 @@ function dol_format_address($object, $withcountry = 0, $sep = "\n", $outputlangs { $ret .= ($ret ? $sep : '' ).$object->zip; $ret .= ($object->town?(($object->zip?' ':'').$object->town):''); - $ret .= ($object->state_id?(' ('.($object->state_id).')'):''); + $ret .= ($object->state_code?(' ('.($object->state_code).')'):''); } else // Other: title firstname name \n address lines \n zip town \n country { From e2660fd31c7c14bb5344a77ed14880ef598d85a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sat, 11 Apr 2020 22:38:28 +0200 Subject: [PATCH 05/58] Update actioncomm.class.php --- htdocs/comm/action/class/actioncomm.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 392cd9255d9..98b910fdfca 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -774,7 +774,7 @@ class ActionComm extends CommonObject dol_syslog(get_class($this)."::delete", LOG_DEBUG); $res=$this->db->query($sql); - if ($res < 0) { + if (!$res) { $this->error=$this->db->lasterror(); $error++; } @@ -785,7 +785,7 @@ class ActionComm extends CommonObject dol_syslog(get_class($this)."::delete", LOG_DEBUG); $res=$this->db->query($sql); - if ($res < 0) { + if (!$res) { $this->error=$this->db->lasterror(); $error++; } From 3ca0d48b37a50a0e7afe961017c6346ac9da193f Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sun, 12 Apr 2020 10:45:30 +0200 Subject: [PATCH 06/58] Fix warning on shipment because of count func --- htdocs/expedition/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/expedition/card.php b/htdocs/expedition/card.php index c6b172a5366..236534fa35d 100644 --- a/htdocs/expedition/card.php +++ b/htdocs/expedition/card.php @@ -2544,7 +2544,7 @@ else if ($id || $ref) // This is just to generate a delivery receipt //var_dump($object->linkedObjectsIds['delivery']); - if ($conf->livraison_bon->enabled && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED) && $user->rights->expedition->livraison->creer && count($object->linkedObjectsIds['delivery']) == 0) + if ($conf->livraison_bon->enabled && ($object->statut == Expedition::STATUS_VALIDATED || $object->statut == Expedition::STATUS_CLOSED) && $user->rights->expedition->livraison->creer && empty($object->linkedObjectsIds['delivery'])) { print ''.$langs->trans("CreateDeliveryOrder").''; } From b72651fdfdae61724fcb8832979a12ead6264f1f Mon Sep 17 00:00:00 2001 From: gauthier Date: Mon, 20 Apr 2020 15:59:44 +0200 Subject: [PATCH 07/58] FIX : we must export company mail address on contact vcard only if contact email address is empty --- htdocs/contact/vcard.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/contact/vcard.php b/htdocs/contact/vcard.php index ebfdfecd6a7..8536c4ebe33 100644 --- a/htdocs/contact/vcard.php +++ b/htdocs/contact/vcard.php @@ -79,7 +79,7 @@ if ($company->id) if (! $contact->phone_pro) $v->setPhoneNumber($company->phone, "TYPE=WORK;VOICE"); if (! $contact->fax) $v->setPhoneNumber($company->fax, "TYPE=WORK;FAX"); if (! $contact->zip) $v->setAddress("", "", $company->address, $company->town, "", $company->zip, $company->country, "TYPE=WORK;POSTAL"); - if ($company->email != $contact->email) $v->setEmail($company->email, 'TYPE=PREF,INTERNET'); + if (empty($contact->email)) $v->setEmail($company->email, 'TYPE=PREF,INTERNET'); // Si contact lie a un tiers non de type "particulier" if ($contact->typent_code != 'TE_PRIVATE') $v->setOrg($company->name); } From 536ab9520745218532e7bdb901750a1eb3c26a17 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 5 Apr 2020 00:29:34 +0200 Subject: [PATCH 08/58] FIX: The "test smtp connectivity" failed on page to setup mass emailing Conflicts: htdocs/admin/mails.php --- htdocs/admin/mails.php | 5 +++-- htdocs/admin/mails_emailing.php | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index dd67b138da5..d41cb687446 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -99,6 +99,7 @@ $trigger_name=''; // Disable triggers $paramname='id'; $mode='emailfortest'; $trackid=(($action == 'testhtml')?"testhtml":"test"); +$sendcontext=''; include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; if ($action == 'presend' && GETPOST('trackid', 'alphanohtml') == 'test') $action='test'; @@ -791,8 +792,8 @@ else print load_fiche_titre($langs->trans("DoTestServerAvailability")); include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mail = new CMailFile('', '', '', ''); - $result=$mail->check_server_port($server, $port); + $mail = new CMailFile('', '', '', '', array(), array(), array(), '', '', 0, '', '', '', '', $trackid, $sendcontext); + $result = $mail->check_server_port($server, $port); if ($result) print '
'.$langs->trans("ServerAvailableOnIPOrPort", $server, $port).'
'; else { diff --git a/htdocs/admin/mails_emailing.php b/htdocs/admin/mails_emailing.php index 12076a00579..5a15be94bc4 100644 --- a/htdocs/admin/mails_emailing.php +++ b/htdocs/admin/mails_emailing.php @@ -536,8 +536,9 @@ else print load_fiche_titre($langs->trans("DoTestServerAvailability")); include_once DOL_DOCUMENT_ROOT.'/core/class/CMailFile.class.php'; - $mail = new CMailFile('', '', '', ''); - $result=$mail->check_server_port($server, $port); + $mail = new CMailFile('', '', '', '', array(), array(), array(), '', '', 0, '', '', '', '', $trackid, $sendcontext); + + $result = $mail->check_server_port($server, $port); if ($result) print '
'.$langs->trans("ServerAvailableOnIPOrPort", $server, $port).'
'; else { From f6735ce8f20577241ba6f64065d506e0398fb9c1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 21 Apr 2020 14:28:52 +0200 Subject: [PATCH 09/58] Update repair.sql script --- htdocs/install/mysql/migration/repair.sql | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 73cb1e6592d..64e81e30329 100755 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -337,9 +337,14 @@ UPDATE llx_c_lead_status set code = 'WON' where code = 'WIN'; -- To replace amount on all invoice and lines when forgetting to apply a 20% vat -- update llx_facturedet set tva_tx = 20 where tva_tx = 0; -- update llx_facturedet set total_ht = round(total_ttc / 1.2, 5) where total_ht = total_ttc; --- update llx_facturedet set total_tva = total_ttc - total_ht where total_vat = 0; -- update llx_facture set total = round(total_ttc / 1.2, 5) where total_ht = total_ttc; --- update llx_facture set tva = total_ttc - total where tva = 0; + +-- To fix bad total of price excluding tax, vat and price tax including tax. +-- select * from llx_facture where tva <> (total_ttc - total - localtax1 - localtax2 - revenuestamp); +-- update llx_facture set tva = (total_ttc - total - localtax1 - localtax2 - revenuestamp) where tva <> (total_ttc - total - localtax1 - localtax2 - revenuestamp); +-- select * from llx_facturedet where total_tva <> (total_ttc - total_ht - total_localtax1 - total_localtax2); +-- update llx_facturedet set total_tva = (total_ttc - total_ht - total_localtax1 - total_localtax2) where total_tva <> (total_ttc - total_ht - total_localtax1 - total_localtax2); + -- To insert elements into a category -- Search idcategory: select rowid from llx_categorie where type=0 and ref like '%xxx%' From 43f4c5ac962d3a99b33f9cab2410c6d323a8a411 Mon Sep 17 00:00:00 2001 From: gauthier Date: Wed, 22 Apr 2020 15:29:54 +0200 Subject: [PATCH 10/58] FIX : model export list must be sorted by label --- htdocs/core/class/html.formother.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index 9556fd6c423..cf3cd58355c 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -75,7 +75,7 @@ class FormOther $sql.= " FROM ".MAIN_DB_PREFIX."export_model"; $sql.= " WHERE type = '".$type."'"; if (!empty($fk_user)) $sql.=" AND fk_user IN (0, ".$fk_user.")"; // An export model - $sql.= " ORDER BY rowid"; + $sql.= " ORDER BY label"; $result = $this->db->query($sql); if ($result) { From cd1368cb71202231393aeb207ddd9fcd3cdfdf72 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 23 Apr 2020 17:10:40 +0200 Subject: [PATCH 11/58] Fix dispatch in ledger for various payment done in same account when there is 2 different transaction in 2 different account (backport v12) --- htdocs/accountancy/journal/bankjournal.php | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index e9be75990dc..06f5a56f943 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -666,7 +666,7 @@ if (! $error && $action == 'writebookkeeping') { } elseif ($tabtype[$key] == 'payment_various') { $bookkeeping->subledger_account = $k; $bookkeeping->subledger_label = $tabcompany[$key]['name']; - $bookkeeping->numero_compte = $tabpay[$obj->rowid]["account_various"]; + $bookkeeping->numero_compte = $tabpay[$key]["account_various"]; $accountingaccount->fetch(null, $bookkeeping->numero_compte, true); $bookkeeping->label_compte = $accountingaccount->label; @@ -1174,7 +1174,11 @@ if (empty($action) || $action == 'view') { //print ''.$langs->trans("ThirdpartyAccountNotDefined").''; if (! empty($tabcompany[$key]['code_compta'])) { - print ''.$langs->trans("ThirdpartyAccountNotDefinedOrThirdPartyUnknown", $tabcompany[$key]['code_compta']).''; + if (in_array($tabtype[$key], array('payment_various'))) { + // For such case, if subledger is not defined, we won't use subledger accounts. + print ''.$langs->trans("ThirdpartyAccountNotDefinedOrThirdPartyUnknownSubledgerIgnored").''; + } else { + print ''.$langs->trans("ThirdpartyAccountNotDefinedOrThirdPartyUnknown", $tabcompany[$key]['code_compta']).''; } else { From f7d4d78008b132574dc81f6e358bd498b4863f7b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 23 Apr 2020 17:55:55 +0200 Subject: [PATCH 12/58] Fix error 500 --- htdocs/accountancy/journal/bankjournal.php | 1 + 1 file changed, 1 insertion(+) diff --git a/htdocs/accountancy/journal/bankjournal.php b/htdocs/accountancy/journal/bankjournal.php index 06f5a56f943..d2ad7a0503e 100644 --- a/htdocs/accountancy/journal/bankjournal.php +++ b/htdocs/accountancy/journal/bankjournal.php @@ -1179,6 +1179,7 @@ if (empty($action) || $action == 'view') { print ''.$langs->trans("ThirdpartyAccountNotDefinedOrThirdPartyUnknownSubledgerIgnored").''; } else { print ''.$langs->trans("ThirdpartyAccountNotDefinedOrThirdPartyUnknown", $tabcompany[$key]['code_compta']).''; + } } else { From 1101c4e587232905e2caa9c61545c47a8503e888 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 23 Apr 2020 18:01:04 +0200 Subject: [PATCH 13/58] Fix trans --- htdocs/langs/en_US/accountancy.lang | 1 + htdocs/langs/fr_FR/accountancy.lang | 1 + 2 files changed, 2 insertions(+) diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang index 4b22f512826..9b80eae930c 100644 --- a/htdocs/langs/en_US/accountancy.lang +++ b/htdocs/langs/en_US/accountancy.lang @@ -218,6 +218,7 @@ ListAccounts=List of the accounting accounts UnknownAccountForThirdparty=Unknown third-party account. We will use %s UnknownAccountForThirdpartyBlocking=Unknown third-party account. Blocking error ThirdpartyAccountNotDefinedOrThirdPartyUnknown=Third-party account not defined or third party unknown. We will use %s +ThirdpartyAccountNotDefinedOrThirdPartyUnknownSubledgerIgnored=Third-party unknown and subledger not defined on the payment. We will keep the subledger account value empty. ThirdpartyAccountNotDefinedOrThirdPartyUnknownBlocking=Third-party account not defined or third party unknown. Blocking error. UnknownAccountForThirdpartyAndWaitingAccountNotDefinedBlocking=Unknown third-party account and waiting account not defined. Blocking error PaymentsNotLinkedToProduct=Payment not linked to any product / service diff --git a/htdocs/langs/fr_FR/accountancy.lang b/htdocs/langs/fr_FR/accountancy.lang index 0150ff7d017..7c0602332f3 100644 --- a/htdocs/langs/fr_FR/accountancy.lang +++ b/htdocs/langs/fr_FR/accountancy.lang @@ -218,6 +218,7 @@ ListAccounts=Liste des comptes comptables UnknownAccountForThirdparty=Compte de tiers inconnu. %s sera utilisé UnknownAccountForThirdpartyBlocking=Compte de tiers inconnu. Erreur bloquante. ThirdpartyAccountNotDefinedOrThirdPartyUnknown=Code comptable du tiers non défini ou tiers inconnu. On utilisera %s. +ThirdpartyAccountNotDefinedOrThirdPartyUnknownSubledgerIgnored=Tiers inconnu et code comptable auxiliaire non défini sur le paiement. Nous conserverons la valeur du compte auxiliaire vide. ThirdpartyAccountNotDefinedOrThirdPartyUnknownBlocking=Compte tiers non défini ou inconnu. Erreur bloquante. UnknownAccountForThirdpartyAndWaitingAccountNotDefinedBlocking=Compte tiers inconnu et compte d'attente non défini. Erreur blocante. PaymentsNotLinkedToProduct=Paiement non lié à un produit / service From 1aafd4667b70148265d79ef44731e659c9b1cc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Fri, 24 Apr 2020 11:57:23 +0200 Subject: [PATCH 14/58] fix countable php7 warning --- htdocs/core/lib/sendings.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/sendings.lib.php b/htdocs/core/lib/sendings.lib.php index 6dc78611c26..96a51815b09 100644 --- a/htdocs/core/lib/sendings.lib.php +++ b/htdocs/core/lib/sendings.lib.php @@ -388,7 +388,7 @@ function show_list_sending_receive($origin,$origin_id,$filter='') //var_dump($expedition->linkedObjects); $receiving=''; - if (count($expedition->linkedObjects['delivery']) > 0) $receiving=reset($expedition->linkedObjects['delivery']); // Take first link + if (!empty($expedition->linkedObjects['delivery'])) $receiving=reset($expedition->linkedObjects['delivery']); // Take first link if (! empty($receiving)) { From 42ee9845ad33dfa9a7a623102357c4e13e3ee0cc Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 24 Apr 2020 15:21:02 +0200 Subject: [PATCH 15/58] Report error --- htdocs/compta/facture/class/facture.class.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 05661fb01cc..1558b6cbfab 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -5013,8 +5013,7 @@ class FactureLigne extends CommonInvoiceLine $returnPercent = floatval($res['situation_percent']); - if($include_credit_note) { - + if ($include_credit_note) { $sql = 'SELECT fd.situation_percent FROM ' . MAIN_DB_PREFIX . 'facturedet fd'; $sql.= ' JOIN ' . MAIN_DB_PREFIX . 'facture f ON (f.rowid = fd.fk_facture) '; $sql.= ' WHERE fd.fk_prev_id =' . $this->fk_prev_id; @@ -5026,6 +5025,8 @@ class FactureLigne extends CommonInvoiceLine while($obj = $this->db->fetch_object($res)) { $returnPercent = $returnPercent + floatval($obj->situation_percent); } + } else { + dol_print_error($this->db); } } From df917805525cbd22453c9b05c68d4b2785f2290a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 24 Apr 2020 15:57:08 +0200 Subject: [PATCH 16/58] FIX Situation invoice take into account the credit notes. --- htdocs/compta/facture/card.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index d83e13da433..934916fa31e 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -1590,6 +1590,8 @@ if (empty($reshook)) if (!empty($origin) && !empty($originid)) { + include_once DOL_DOCUMENT_ROOT.'/core/lib/price.lib.php'; + $object->origin = $origin; $object->origin_id = $originid; @@ -1601,6 +1603,17 @@ if (empty($reshook)) $line->fetch_optionals($line->id); $line->situation_percent = $line->get_prev_progress($object->id); // get good progress including credit note + // The $line->situation_percent has been modified, so we must recalculate all amounts + $tabprice = calcul_price_total($line->qty, $line->subprice, $line->remise_percent, $line->tva_tx, $line->localtax1_tx, $line->localtax2_tx, 0, 'HT', 0, $line->product_type, $mysoc, '', $line->situation_percent); + $line->total_ht = $tabprice[0]; + $line->total_tva = $tabprice[1]; + $line->total_ttc = $tabprice[2]; + $line->total_localtax1 = $tabprice[9]; + $line->total_localtax2 = $tabprice[10]; + $line->multicurrency_total_ht = $tabprice[16]; + $line->multicurrency_total_tva = $tabprice[17]; + $line->multicurrency_total_ttc = $tabprice[18]; + // Si fk_remise_except defini on vérifie si la réduction à déjà été appliquée if ($line->fk_remise_except) { @@ -1644,6 +1657,7 @@ if (empty($reshook)) { $nextSituationInvoice = new Facture($db); $nextSituationInvoice->fetch($id); + // create extrafields with data from create form $extralabels = $extrafields->fetch_name_optionals_label($nextSituationInvoice->table_element); $ret = $extrafields->setOptionalsFromPost($extralabels, $nextSituationInvoice); From df10b86d1fbe6a613160ea8922d617cde6d62faf Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 24 Apr 2020 19:52:34 +0200 Subject: [PATCH 17/58] FIX consistency of price w/wo vat wrong when price entered with tax --- htdocs/core/class/commonobject.class.php | 25 ++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index d4735e4ba8d..157fc718700 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -2807,8 +2807,8 @@ abstract class CommonObject $sql = 'SELECT rowid, qty, '.$fieldup.' as up, remise_percent, total_ht, '.$fieldtva.' as total_tva, total_ttc, '.$fieldlocaltax1.' as total_localtax1, '.$fieldlocaltax2.' as total_localtax2,'; $sql.= ' tva_tx as vatrate, localtax1_tx, localtax2_tx, localtax1_type, localtax2_type, info_bits, product_type'; - if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent'; - $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; + if ($this->table_element_line == 'facturedet') $sql.= ', situation_percent'; + $sql.= ', multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc'; $sql.= ' FROM '.MAIN_DB_PREFIX.$this->table_element_line; $sql.= ' WHERE '.$this->fk_element.' = '.$this->id; if ($exclspec) @@ -2847,18 +2847,23 @@ abstract class CommonObject if (empty($reshook) && $forcedroundingmode == '0') // Check if data on line are consistent. This may solve lines that were not consistent because set with $forcedroundingmode='auto' { + // This part of code is to fix data. We should not call it too often. $localtax_array=array($obj->localtax1_type,$obj->localtax1_tx,$obj->localtax2_type,$obj->localtax2_tx); $tmpcal=calcul_price_total($obj->qty, $obj->up, $obj->remise_percent, $obj->vatrate, $obj->localtax1_tx, $obj->localtax2_tx, 0, 'HT', $obj->info_bits, $obj->product_type, $seller, $localtax_array, (isset($obj->situation_percent) ? $obj->situation_percent : 100), $multicurrency_tx); - $diff=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1); - if ($diff) + + $diff_when_using_price_ht=price2num($tmpcal[1] - $obj->total_tva, 'MT', 1); // If price was set with tax price adn unit price HT has a low number of digits, then we may have a diff on recalculation from unit price HT. + $diff_on_current_total=price2num($obj->total_ttc - $obj->total_ht - $obj->total_tva - $obj->total_localtax1 - $obj->total_localtax2, 'MT', 1); + //var_dump($obj->total_ht.' '.$obj->total_tva.' '.$obj->total_localtax1.' '.$obj->total_localtax2.' =? '.$obj->total_ttc); + //var_dump($diff_when_using_price_ht.' '.$diff_on_current_total); + + if ($diff_when_using_price_ht && $diff_on_current_total) { $sqlfix="UPDATE ".MAIN_DB_PREFIX.$this->table_element_line." SET ".$fieldtva." = ".$tmpcal[1].", total_ttc = ".$tmpcal[2]." WHERE rowid = ".$obj->rowid; - dol_syslog('We found unconsistent data into detailed line (difference of '.$diff.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix); - $resqlfix=$this->db->query($sqlfix); - if (! $resqlfix) dol_print_error($this->db, 'Failed to update line'); - $obj->total_tva = $tmpcal[1]; - $obj->total_ttc = $tmpcal[2]; - // + dol_syslog('We found unconsistent data into detailed line (diff_when_using_price_ht = '.$diff_when_using_price_ht.' and diff_on_current_total = '.$diff_on_current_total.') for line rowid = '.$obj->rowid." (total vat of line calculated=".$tmpcal[1].", database=".$obj->total_tva."). We fix the total_vat and total_ttc of line by running sqlfix = ".$sqlfix, LOG_WARNING); + $resqlfix=$this->db->query($sqlfix); + if (! $resqlfix) dol_print_error($this->db, 'Failed to update line'); + $obj->total_tva = $tmpcal[1]; + $obj->total_ttc = $tmpcal[2]; } } From 6798e9e6f5ab8862450ee9745b0017e8f08a5c68 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 24 Apr 2020 19:52:54 +0200 Subject: [PATCH 18/58] Fix remove warning missing the seller in update_price --- htdocs/fourn/class/fournisseur.facture.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.facture.class.php b/htdocs/fourn/class/fournisseur.facture.class.php index b62190686b3..e20a3f9e7de 100644 --- a/htdocs/fourn/class/fournisseur.facture.class.php +++ b/htdocs/fourn/class/fournisseur.facture.class.php @@ -1967,7 +1967,7 @@ class FactureFournisseur extends CommonInvoice $this->errors[] = $line->error; } else { // Update total price into invoice record - $res = $this->update_price('', 'auto'); + $res = $this->update_price('', 'auto', 0, $this->thirdparty); } return $res; From b90a6024f57097830be749a5eee755cc45b603af Mon Sep 17 00:00:00 2001 From: Ferran Marcet Date: Mon, 27 Apr 2020 10:15:47 +0200 Subject: [PATCH 19/58] FIX: Wrong Sql on getListOfTowns api method --- htdocs/api/class/api_setup.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/api/class/api_setup.class.php b/htdocs/api/class/api_setup.class.php index 5174aae7221..1e1ab2f8307 100644 --- a/htdocs/api/class/api_setup.class.php +++ b/htdocs/api/class/api_setup.class.php @@ -603,7 +603,7 @@ class Setup extends DolibarrApi $sql = "SELECT rowid AS id, zip, town, fk_county, fk_pays AS fk_country"; $sql.= " FROM ".MAIN_DB_PREFIX."c_ziptown as t"; - $sql.= " AND t.active = ".$active; + $sql.= " WHERE t.active = ".$active; if ($zipcode) $sql.=" AND t.zip LIKE '%" . $this->db->escape($zipcode) . "%'"; if ($town) $sql.=" AND t.town LIKE '%" . $this->db->escape($town) . "%'"; // Add sql filters From a0c013d87bfc61db04b84ae33990d6b14112724e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 27 Apr 2020 17:13:23 +0200 Subject: [PATCH 20/58] Fix missing link Conflicts: htdocs/core/class/notify.class.php --- htdocs/core/class/notify.class.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 59d523b6b44..99910e82ecc 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -314,6 +314,7 @@ class Notify global $user,$conf,$langs,$mysoc; global $hookmanager; global $dolibarr_main_url_root; + global $action; if (! in_array($notifcode, $this->arrayofnotifsupported)) return 0; @@ -524,8 +525,10 @@ class Notify $message.= $mesg; if ($link) $message.= "\n" . $urlwithroot . $link; - $parameters=array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); - $reshook=$hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks + $parameters = array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); + if (!isset($action)) $action = ''; + + $reshook = $hookmanager->executeHooks('formatNotificationMessage', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if (empty($reshook)) { if (! empty($hookmanager->resArray['subject'])) $subject.=$hookmanager->resArray['subject']; @@ -694,21 +697,25 @@ class Notify $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); break; case 'EXPENSE_REPORT_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); break; case 'EXPENSE_REPORT_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); break; case 'HOLIDAY_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); break; case 'HOLIDAY_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); From 84bca036c9eb20c073b1a6549d090deed4a808a6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 29 Apr 2020 18:03:28 +0200 Subject: [PATCH 21/58] FIX Link missing into email of some notification --- htdocs/core/class/notify.class.php | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 99910e82ecc..db0e490a6c6 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -482,26 +482,31 @@ class Notify $mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'SHIPPING_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; - $object_type = 'order_supplier'; + $object_type = 'expedition'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); break; case 'EXPENSE_REPORT_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); break; case 'EXPENSE_REPORT_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); break; case 'HOLIDAY_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); break; case 'HOLIDAY_APPROVE': + $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); @@ -692,6 +697,7 @@ class Notify $mesg.= "\n\n".$langs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'SHIPPING_VALIDATE': + $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; $object_type = 'order_supplier'; $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); From 82ace4b4ef6f8fd63ec4f6d73df641fb7362c129 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Tue, 3 Sep 2019 22:39:24 +0200 Subject: [PATCH 22/58] FIX Several pb in export of documents FIX Must escape shell FIX Must exclude logs and some dirs for compressed backup FIX gzip and bzip2 must use option -f --- htdocs/admin/tools/dolibarr_export.php | 74 ++-- htdocs/admin/tools/export_files.php | 49 +- htdocs/core/class/utils.class.php | 178 +++++--- htdocs/core/lib/files.lib.php | 591 +++++++++++++++---------- 4 files changed, 520 insertions(+), 372 deletions(-) diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index d04840e2d71..0bef19dde56 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -29,15 +29,15 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; $langs->load("admin"); -$action=GETPOST('action','alpha'); +$action=GETPOST('action', 'alpha'); -$sortfield = GETPOST('sortfield','alpha'); -$sortorder = GETPOST('sortorder','alpha'); -$page = GETPOST('page','int'); +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOST('page', 'int'); if (! $sortorder) $sortorder="DESC"; if (! $sortfield) $sortfield="date"; if (empty($page) || $page == -1) { $page = 0; } -$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; $offset = $limit * $page; if (! $user->admin) @@ -50,10 +50,20 @@ if (! $user->admin) if ($action == 'delete') { - $file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha')); - $ret=dol_delete_file($file, 1); - if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); - else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + if (preg_match('/^backup\//', GETPOST('urlfile', 'alpha'))) + { + $file=$conf->admin->dir_output.'/backup/'.basename(GETPOST('urlfile', 'alpha')); + $ret=dol_delete_file($file, 1); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } + else + { + $file=$conf->admin->dir_output.'/documents/'.basename(GETPOST('urlfile', 'alpha')); + $ret=dol_delete_file($file, 1); + if ($ret) setEventMessages($langs->trans("FileWasRemoved", GETPOST('urlfile')), null, 'mesgs'); + else setEventMessages($langs->trans("ErrorFailToDeleteFile", GETPOST('urlfile')), null, 'errors'); + } $action=''; } @@ -70,7 +80,7 @@ $type=$db->type; //var_dump($db); $help_url='EN:Backups|FR:Sauvegardes|ES:Copias_de_seguridad'; -llxHeader('','',$help_url); +llxHeader('', '', $help_url); ?> trans("Backup"),'','title_setup'); +print load_fiche_titre($langs->trans("Backup"), '', 'title_setup'); //print_barre_liste($langs->trans("Backup"), '', '', '', '', '', $langs->trans("BackupDesc",DOL_DATA_ROOT), 0, 0, 'title_setup'); -print '
'; -print $langs->trans("BackupDesc",DOL_DATA_ROOT); +print '
'; +print $langs->trans("BackupDesc", DOL_DATA_ROOT); print '
'; print '
'; @@ -128,7 +138,7 @@ print '
';
1 trans("BackupDesc3",$dolibarr_main_db_name).'
'; +print $langs->trans("BackupDesc3", $dolibarr_main_db_name).'
'; //print $langs->trans("BackupDescY").'
'; print '
'; ?> @@ -166,7 +176,7 @@ print '';
@@ -211,6 +221,7 @@ print '';
+
global->MYSQL_OLD_OPTION_DISABLE_FK)) { ?> @@ -233,14 +244,6 @@ print '';
- - -
@@ -453,8 +456,10 @@ print "\n";
-
" id="buttonGo" />
+
+ " id="buttonGo"> + +

'.$langs->trans("BackupResult").': '; print $_SESSION["commandbackupresult"]; @@ -476,7 +481,7 @@ if (! empty($_SESSION["commandbackuplastdone"])) } if (! empty($_SESSION["commandbackuptorun"])) { - print '
'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser",$dolibarr_main_db_user,$dolibarr_main_db_user).':
'."\n"; + print '
'.$langs->trans("YouMustRunCommandFromCommandLineAfterLoginToUser", $dolibarr_main_db_user, $dolibarr_main_db_user).':
'."\n"; print '
'."\n"; print ajax_autoselect("commandbackuptoruntext", 0); print '
'; @@ -505,8 +510,8 @@ print '';
admin->dir_output.'/backup','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); -$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'backup/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); +$filearray=dol_dir_list($conf->admin->dir_output.'/backup', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1); +$result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'backup/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles")); print '
'; ?> @@ -526,7 +531,7 @@ print '
';
2 trans("BackupDesc2",DOL_DATA_ROOT).'
'; +print $langs->trans("BackupDesc2", DOL_DATA_ROOT).'
'; print $langs->trans("BackupDescX").'

'; ?> @@ -582,7 +587,7 @@ print "\n"; ?>
-
" id="buttonGo" />

@@ -593,8 +598,8 @@ print "\n";
admin->dir_output.'/documents','files',0,'','',$sortfield,(strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC),1); -$result=$formfile->list_of_documents($filearray,null,'systemtools','',1,'documents/',1,0,$langs->trans("NoBackupFileAvailable"),0,$langs->trans("PreviousDumpFiles")); +$filearray=dol_dir_list($conf->admin->dir_output.'/documents', 'files', 0, '', '', $sortfield, (strtolower($sortorder)=='asc'?SORT_ASC:SORT_DESC), 1); +$result=$formfile->list_of_documents($filearray, null, 'systemtools', '', 1, 'documents/', 1, 0, $langs->trans("NoBackupFileAvailable"), 0, $langs->trans("PreviousDumpFiles")); print '
'; ?> @@ -605,9 +610,6 @@ print '
';
- - - load("admin"); -$action=GETPOST('action','alpha'); -$what=GETPOST('what','alpha'); -$export_type=GETPOST('export_type','alpha'); -$file=GETPOST('zipfilename_template','alpha'); +$action=GETPOST('action', 'alpha'); +$what=GETPOST('what', 'alpha'); +$export_type=GETPOST('export_type', 'alpha'); +$file=GETPOST('zipfilename_template', 'alpha'); $compression = GETPOST('compression'); $file = dol_sanitizeFileName($file); -$sortfield = GETPOST('sortfield','alpha'); -$sortorder = GETPOST('sortorder','alpha'); -$page = GETPOST("page",'int'); +$sortfield = GETPOST('sortfield', 'alpha'); +$sortorder = GETPOST('sortorder', 'alpha'); +$page = GETPOST("page", 'int'); if (! $sortorder) $sortorder="DESC"; if (! $sortfield) $sortfield="date"; if ($page < 0) { $page = 0; } elseif (empty($page)) $page = 0; -$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; $offset = $limit * $page; if (! $user->admin) accessforbidden(); @@ -112,21 +112,27 @@ $utils = new Utils($db); if ($compression == 'zip') { - $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression); + $ret = dol_compress_dir(DOL_DATA_ROOT, $outputdir."/".$file, $compression, '/(\.log|\/temp\/|documents\/admin\/documents\/)/'); if ($ret < 0) { - $errormsg = $langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg = $langs->trans("ErrorFailedToWriteInDir", $outputdir); } } elseif (in_array($compression, array('gz', 'bz'))) { - $file = substr($file, 0, strrpos($file, '.')); - $file .= '.tar'; - $cmd = 'tar -cf '.$outputdir."/".$file." --exclude=documents/admin/documents -C ".DOL_DATA_ROOT." ".DOL_DATA_ROOT."/../documents/"; - exec($cmd, $out, $retval); - //var_dump($cmd, DOL_DATA_ROOT);exit; + $userlogin = ($user->login ? $user->login : 'unknown'); - if ($retval != 0) + $outputfile = $conf->admin->dir_temp.'/export_files.'.$userlogin.'.out'; // File used with popen method + + $file = substr($file, 0, strrpos($file, '.')); + $file .= '.tar'; + // We also exclude '/temp/' dir and 'documents/admin/documents' + $cmd = "tar -cf ".$outputdir."/".$file." --exclude-vcs --exclude 'temp' --exclude 'dolibarr.log' --exclude='documents/admin/documents' -C ".dirname(DOL_DATA_ROOT)." ".basename(DOL_DATA_ROOT); + + $result = $utils->executeCLI($cmd, $outputfile); + + $retval = $result['error']; + if ($result['result'] || ! empty($retval)) { $langs->load("errors"); dol_syslog("Documents tar retval after exec=".$retval, LOG_ERR); @@ -136,15 +142,17 @@ elseif (in_array($compression, array('gz', 'bz'))) { if ($compression == 'gz') { - $cmd = "gzip " . $outputdir."/".$file; + $cmd = "gzip -f " . $outputdir."/".$file; } if ($compression == 'bz') { - $cmd = "bzip2 " . $outputdir."/".$file; + $cmd = "bzip2 -f " . $outputdir."/".$file; } - exec($cmd, $out, $retval); - if ($retval != 0) + $result = $utils->executeCLI($cmd, $outputfile); + + $retval = $result['error']; + if ($result['result'] || ! empty($retval)) { $errormsg = 'Error '.$compression.' generation return '.$retval; unlink($outputdir."/".$file); @@ -166,4 +174,3 @@ header("Location: dolibarr_export.php"); $time_end = time(); $db->close(); - diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 5007e642300..86eff6613c1 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -32,15 +32,15 @@ class Utils */ public $db; - var $output; // Used by Cron method to return message - var $result; // Used by Cron method to return data + public $output; // Used by Cron method to return message + public $result; // Used by Cron method to return data /** * Constructor * * @param DoliDB $db Database handler */ - function __construct($db) + public function __construct($db) { $this->db = $db; } @@ -54,7 +54,7 @@ class Utils * @param int $nbsecondsold Nb of seconds old to accept deletion of a directory if $choice is 'tempfilesold' * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ - function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400) + public function purgeFiles($choice = 'tempfilesold', $nbsecondsold = 86400) { global $conf, $langs, $dolibarr_main_data_root; @@ -106,7 +106,7 @@ class Utils if (! empty($conf->syslog->enabled)) { $filelog=$conf->global->SYSLOG_FILE; - $filelog=preg_replace('/DOL_DATA_ROOT/i',DOL_DATA_ROOT,$filelog); + $filelog=preg_replace('/DOL_DATA_ROOT/i', DOL_DATA_ROOT, $filelog); $alreadyincluded=false; foreach ($filesarray as $tmpcursor) @@ -193,7 +193,7 @@ class Utils * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @return int 0 if OK, < 0 if KO (this function is used also by cron so only 0 is OK) */ - function dumpDatabase($compression='none', $type='auto', $usedefault=1, $file='auto', $keeplastnfiles=0, $execmethod=0) + public function dumpDatabase($compression = 'none', $type = 'auto', $usedefault = 1, $file = 'auto', $keeplastnfiles = 0, $execmethod = 0) { global $db, $conf, $langs, $dolibarr_main_data_root; global $dolibarr_main_db_name, $dolibarr_main_db_host, $dolibarr_main_db_user, $dolibarr_main_db_port, $dolibarr_main_db_pass; @@ -251,8 +251,8 @@ class Utils // Parameteres execution $command = $cmddump; - $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. - if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters + $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. + if (preg_match("/\s/", $command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters //$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=$dolibarr_main_db_name." -h ".$dolibarr_main_db_host; @@ -262,7 +262,6 @@ class Utils if (GETPOST("disable_fk", "alpha") || $usedefault) $param.=" -K"; if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha")); if (GETPOST("drop_database", "alpha")) $param.=" --add-drop-database"; - if (GETPOST("use_mysql_quick_param", "alpha"))$param.=" --quick"; if (GETPOST("sql_structure", "alpha") || $usedefault) { if (GETPOST("drop", "alpha") || $usedefault) $param.=" --add-drop-table=TRUE"; @@ -292,8 +291,8 @@ class Utils $paramclear=$param; if (! empty($dolibarr_main_db_pass)) { - $paramcrypted.=' -p"'.preg_replace('/./i','*',$dolibarr_main_db_pass).'"'; - $paramclear.=' -p"'.str_replace(array('"','`'),array('\"','\`'),$dolibarr_main_db_pass).'"'; + $paramcrypted.=' -p"'.preg_replace('/./i', '*', $dolibarr_main_db_pass).'"'; + $paramclear.=' -p"'.str_replace(array('"','`'), array('\"','\`'), $dolibarr_main_db_pass).'"'; } $errormsg=''; @@ -317,27 +316,29 @@ class Utils // TODO Replace with executeCLI function if ($execmethod == 1) { - exec($fullcommandclear, $readt, $retval); - $result = $retval; + $output_arr = array(); $retval = null; + exec($fullcommandclear, $output_arr, $retval); if ($retval != 0) { $langs->load("errors"); dol_syslog("Datadump retval after exec=".$retval, LOG_ERR); - $error = 'Error '.$retval; + $errormsg = 'Error '.$retval; $ok=0; } else { $i=0; - if (!empty($readt)) - foreach($readt as $key=>$read) + if (!empty($output_arr)) { - $i++; // output line number - if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; - fwrite($handle, $read.($execmethod == 2 ? '' : "\n")); - if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; - elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; + foreach($output_arr as $key => $read) + { + $i++; // output line number + if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; + fwrite($handle, $read.($execmethod == 2 ? '' : "\n")); + if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1; + elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1; + } } } } @@ -351,9 +352,9 @@ class Utils $read = fgets($handlein); // Exclude warning line we don't want if ($i == 1 && preg_match('/Warning.*Using a password/i', $read)) continue; - fwrite($handle,$read); - if (preg_match('/'.preg_quote('-- Dump completed').'/i',$read)) $ok=1; - elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i',$read)) $ok=1; + fwrite($handle, $read); + if (preg_match('/'.preg_quote('-- Dump completed').'/i', $read)) $ok=1; + elseif (preg_match('/'.preg_quote('SET SQL_NOTES=@OLD_SQL_NOTES').'/i', $read)) $ok=1; } pclose($handlein); } @@ -369,7 +370,7 @@ class Utils else { $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); } @@ -380,18 +381,18 @@ class Utils if ($handle) { // Get 2048 first chars of error message. - $errormsg = fgets($handle,2048); + $errormsg = fgets($handle, 2048); // Close file if ($compression == 'none') fclose($handle); if ($compression == 'gz') gzclose($handle); if ($compression == 'bz') bzclose($handle); - if ($ok && preg_match('/^-- MySql/i',$errormsg)) $errormsg=''; // Pas erreur + if ($ok && preg_match('/^-- MySql/i', $errormsg)) $errormsg=''; // Pas erreur else { // Renommer fichier sortie en fichier erreur //print "$outputfile -> $outputerror"; @dol_delete_file($outputerror, 1, 0, 0, null, false, 0); - @rename($outputfile,$outputerror); + @rename($outputfile, $outputerror); // Si safe_mode on et command hors du parametre exec, on a un fichier out vide donc errormsg vide if (! $errormsg) { @@ -450,8 +451,8 @@ class Utils // Parameteres execution $command = $cmddump; - $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. - if (preg_match("/\s/",$command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters + $command = preg_replace('/(\$|%)/', '', $command); // We removed chars that can be used to inject vars that contains space inside path of command without seeing there is a space to bypass the escapeshellarg. + if (preg_match("/\s/", $command)) $command=escapeshellarg($command); // If there is spaces, we add quotes on command to be sure $command is only a program and not a program+parameters //$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"; @@ -515,7 +516,7 @@ class Utils * @param int $execmethod 0=Use default method (that is 1 by default), 1=Use the PHP 'exec', 2=Use the 'popen' method * @return array array('result'=>...,'output'=>...,'error'=>...). result = 0 means OK. */ - function executeCLI($command, $outputfile, $execmethod=0) + public function executeCLI($command, $outputfile, $execmethod = 0) { global $conf, $langs; @@ -535,6 +536,7 @@ class Utils if ($execmethod == 1) { + $retval = null; exec($command, $output_arr, $retval); $result = $retval; if ($retval != 0) @@ -546,7 +548,6 @@ class Utils } if ($execmethod == 2) // With this method, there is no way to get the return code, only output { - $ok=0; $handle = fopen($outputfile, 'w+b'); if ($handle) { @@ -555,7 +556,7 @@ class Utils while (!feof($handlein)) { $read = fgets($handlein); - fwrite($handle,$read); + fwrite($handle, $read); $output_arr[]=$read; } pclose($handlein); @@ -584,14 +585,15 @@ class Utils * @param string $module Module name * @return int <0 if KO, >0 if OK */ - function generateDoc($module) + public function generateDoc($module) { - global $conf, $langs; + global $conf, $langs, $user, $mysoc; global $dirins; $error = 0; $modulelowercase=strtolower($module); + $now=dol_now(); // Dir for module $dir = $dirins.'/'.$modulelowercase; @@ -621,11 +623,12 @@ class Utils exit; } - $arrayversion=explode('.',$moduleobj->version,3); + $arrayversion=explode('.', $moduleobj->version, 3); if (count($arrayversion)) { $FILENAMEASCII=strtolower($module).'.asciidoc'; - $FILENAMEDOC=strtolower($module).'.html'; // TODO Use/text PDF + $FILENAMEDOC=strtolower($module).'.html'; + $FILENAMEDOCPDF=strtolower($module).'.pdf'; $dirofmodule = dol_buildpath(strtolower($module), 0); $dirofmoduledoc = dol_buildpath(strtolower($module), 0).'/doc'; @@ -641,13 +644,25 @@ class Utils return -1; } - $conf->global->MODULEBUILDER_ASCIIDOCTOR='asciidoctor'; - if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR)) + if (empty($conf->global->MODULEBUILDER_ASCIIDOCTOR) && empty($conf->global->MODULEBUILDER_ASCIIDOCTORPDF)) { $this->error = 'Setup of module ModuleBuilder not complete'; return -1; } + // Copy some files into temp directory, so instruction include::ChangeLog.md[] will works inside the asciidoc file. + dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1); + dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1); + + // Replace into README.md and ChangeLog.md (in case they are included into documentation with tag __README__ or __CHANGELOG__) + $arrayreplacement=array(); + $arrayreplacement['/^#\s.*/m']=''; // Remove first level of title into .md files + $arrayreplacement['/^#/m']='##'; // Add on # to increase level + + dolReplaceInFile($dirofmoduletmp.'/README.md', $arrayreplacement, '', 0, 0, 1); + dolReplaceInFile($dirofmoduletmp.'/ChangeLog.md', $arrayreplacement, '', 0, 0, 1); + + $destfile=$dirofmoduletmp.'/'.$FILENAMEASCII; $fhandle = fopen($destfile, 'w+'); @@ -680,35 +695,48 @@ class Utils $i++; } - fwrite($fhandle, "\n\n\n== DATA SPECIFICATIONS...\n\n"); - - // TODO - fwrite($fhandle, "TODO..."); - - - fwrite($fhandle, "\n\n\n== CHANGELOG...\n\n"); - - // TODO - fwrite($fhandle, "TODO..."); - - - fclose($fhandle); - } - // Copy some files into temp directory - dol_copy($dirofmodule.'/README.md', $dirofmoduletmp.'/README.md', 0, 1); - dol_copy($dirofmodule.'/ChangeLog.md', $dirofmoduletmp.'/ChangeLog.md', 0, 1); + $contentreadme=file_get_contents($dirofmoduletmp.'/README.md'); + $contentchangelog=file_get_contents($dirofmoduletmp.'/ChangeLog.md'); + + include DOL_DOCUMENT_ROOT.'/core/lib/parsemd.lib.php'; + + //var_dump($phpfileval['fullname']); + $arrayreplacement=array( + 'mymodule'=>strtolower($module), + 'MyModule'=>$module, + 'MYMODULE'=>strtoupper($module), + 'My module'=>$module, + 'my module'=>$module, + 'Mon module'=>$module, + 'mon module'=>$module, + 'htdocs/modulebuilder/template'=>strtolower($module), + '__MYCOMPANY_NAME__'=>$mysoc->name, + '__KEYWORDS__'=>$module, + '__USER_FULLNAME__'=>$user->getFullName($langs), + '__USER_EMAIL__'=>$user->email, + '__YYYY-MM-DD__'=>dol_print_date($now, 'dayrfc'), + '---Put here your own copyright and developer email---'=>dol_print_date($now, 'dayrfc').' '.$user->getFullName($langs).($user->email?' <'.$user->email.'>':''), + '__DATA_SPECIFICATION__'=>'Not yet available', + '__README__'=>dolMd2Asciidoc($contentreadme), + '__CHANGELOG__'=>dolMd2Asciidoc($contentchangelog), + ); + + dolReplaceInFile($destfile, $arrayreplacement); + } // Launch doc generation $currentdir = getcwd(); chdir($dirofmodule); + require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; + $utils = new Utils($db); + + // Build HTML doc $command=$conf->global->MODULEBUILDER_ASCIIDOCTOR.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOC; $outfile=$dirofmoduletmp.'/out.tmp'; - require_once DOL_DOCUMENT_ROOT.'/core/class/utils.class.php'; - $utils = new Utils($this->db); $resarray = $utils->executeCLI($command, $outfile); if ($resarray['result'] != '0') { @@ -716,6 +744,16 @@ class Utils } $result = ($resarray['result'] == 0) ? 1 : 0; + // Build PDF doc + $command=$conf->global->MODULEBUILDER_ASCIIDOCTORPDF.' '.$destfile.' -n -o '.$dirofmoduledoc.'/'.$FILENAMEDOCPDF; + $outfile=$dirofmoduletmp.'/outpdf.tmp'; + $resarray = $utils->executeCLI($command, $outfile); + if ($resarray['result'] != '0') + { + $this->error = $resarray['error'].' '.$resarray['output']; + } + $result = ($resarray['result'] == 0) ? 1 : 0; + chdir($currentdir); } else @@ -751,7 +789,7 @@ class Utils * * @return int 0 if OK, < 0 if KO */ - function compressSyslogs() + public function compressSyslogs() { global $conf; @@ -857,7 +895,7 @@ class Utils $this->output = 'Archive log files (keeping last SYSLOG_FILE_SAVES='.$nbSaves.' files) done.'; return 0; - } + } /** Backup the db OR just a table without mysqldump binary, with PHP only (does not require any exec permission) * Author: David Walsh (http://davidwalsh.name/backup-mysql-database-php) @@ -869,7 +907,7 @@ class Utils * @param string $tables Table name or '*' for all * @return int <0 if KO, >0 if OK */ - function backupTables($outputfile, $tables='*') + public function backupTables($outputfile, $tables = '*') { global $db, $langs; global $errormsg; @@ -896,7 +934,7 @@ class Utils } else { - $tables = is_array($tables) ? $tables : explode(',',$tables); + $tables = is_array($tables) ? $tables : explode(',', $tables); } //cycle through @@ -904,7 +942,7 @@ class Utils if (fwrite($handle, '') === false) { $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); return -1; } @@ -947,9 +985,9 @@ class Utils // Saving the table structure fwrite($handle, "\n--\n-- Table structure for table `".$table."`\n--\n"); - if (GETPOST("nobin_drop")) fwrite($handle,"DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it - fwrite($handle,"/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); - fwrite($handle,"/*!40101 SET character_set_client = utf8 */;\n"); + if (GETPOST("nobin_drop")) fwrite($handle, "DROP TABLE IF EXISTS `".$table."`;\n"); // Dropping table if exists prior to re create it + fwrite($handle, "/*!40101 SET @saved_cs_client = @@character_set_client */;\n"); + fwrite($handle, "/*!40101 SET character_set_client = utf8 */;\n"); $resqldrop=$db->query('SHOW CREATE TABLE '.$table); $row2 = $db->fetch_row($resqldrop); if (empty($row2[1])) @@ -958,7 +996,7 @@ class Utils } else { - fwrite($handle,$row2[1].";\n"); + fwrite($handle, $row2[1].";\n"); //fwrite($handle,"/*!40101 SET character_set_client = @saved_cs_client */;\n\n"); // Dumping the data (locking the table and disabling the keys check while doing the process) @@ -972,7 +1010,7 @@ class Utils while($row = $db->fetch_row($result)) { // For each row of data we print a line of INSERT - fwrite($handle,'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES ('); + fwrite($handle, 'INSERT '.$delayed.$ignore.'INTO `'.$table.'` VALUES ('); $columns = count($row); for($j=0; $j<$columns; $j++) { // Processing each columns of the row to ensure that we correctly save the value (eg: add quotes for string - in fact we add quotes for everything, it's easier) @@ -991,11 +1029,11 @@ class Utils $row[$j] = "'".$row[$j]."'"; } } - fwrite($handle,implode(',', $row).");\n"); + fwrite($handle, implode(',', $row).");\n"); } if (GETPOST("nobin_disable_fk")) fwrite($handle, "ALTER TABLE `".$table."` ENABLE KEYS;\n"); // Enabling back the keys/index checking if (!GETPOST("nobin_nolocks")) fwrite($handle, "UNLOCK TABLES;\n"); // Unlocking the table - fwrite($handle,"\n\n\n"); + fwrite($handle, "\n\n\n"); } } diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php index 295bda85d53..d2aee3e6a30 100644 --- a/htdocs/core/lib/files.lib.php +++ b/htdocs/core/lib/files.lib.php @@ -4,6 +4,7 @@ * Copyright (C) 2012-2016 Juanjo Menent * Copyright (C) 2015 Marcos García * Copyright (C) 2016 Raphaël Doursenaud + * Copyright (C) 2019 Frédéric France * * 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 @@ -34,7 +35,7 @@ */ function dol_basename($pathfile) { - return preg_replace('/^.*\/([^\/]+)$/','$1',rtrim($pathfile,'/')); + return preg_replace('/^.*\/([^\/]+)$/', '$1', rtrim($pathfile, '/')); } /** @@ -54,9 +55,9 @@ function dol_basename($pathfile) * @param string $relativename For recursive purpose only. Must be "" at first call. * @param string $donotfollowsymlinks Do not follow symbolic links * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','date'=>'yyy','size'=>99,'type'=>'dir|file',...) - * @see dol_dir_list_indatabase + * @see dol_dir_list_in_database() */ -function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0, $nohook=0, $relativename="", $donotfollowsymlinks=0) +function dol_dir_list($path, $types = "all", $recursive = 0, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0, $nohook = 0, $relativename = "", $donotfollowsymlinks = 0) { global $db, $hookmanager; global $object; @@ -68,7 +69,7 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil $loadsize=($mode==1||$mode==3)?true:false; // Clean parameters - $path=preg_replace('/([\\/]+)$/i','',$path); + $path=preg_replace('/([\\/]+)$/i', '', $path); $newpath=dol_osencode($path); $reshook = 0; @@ -116,9 +117,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil $excludefilterarray=array('^\.'); if (is_array($excludefilter)) { - $excludefilterarray=array_merge($excludefilterarray,$excludefilter); + $excludefilterarray=array_merge($excludefilterarray, $excludefilter); } - else if ($excludefilter) $excludefilterarray[]=$excludefilter; + elseif ($excludefilter) $excludefilterarray[]=$excludefilter; // Check if file is qualified foreach($excludefilterarray as $filt) { @@ -140,9 +141,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file); if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file); - if (! $filter || preg_match('/'.$filter.'/i',$file)) // We do not search key $filter into all $path, only into $file part + if (! $filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into all $path, only into $file part { - preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "name" => $file, @@ -167,15 +168,15 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil } } } - else if (! $isdir && (($types == "files") || ($types == "all"))) + elseif (! $isdir && (($types == "files") || ($types == "all"))) { // Add file into file_list array if ($loaddate || $sortcriteria == 'date') $filedate=dol_filemtime($path."/".$file); if ($loadsize || $sortcriteria == 'size') $filesize=dol_filesize($path."/".$file); - if (! $filter || preg_match('/'.$filter.'/i',$file)) // We do not search key $filter into $path, only into $file + if (! $filter || preg_match('/'.$filter.'/i', $file)) // We do not search key $filter into $path, only into $file { - preg_match('/([^\/]+)\/[^\/]+$/',$path.'/'.$file,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', $path.'/'.$file, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "name" => $file, @@ -194,15 +195,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil closedir($dir); // Obtain a list of columns - if (! empty($sortcriteria)) + if (! empty($sortcriteria) && $sortorder) { - $myarray=array(); - foreach ($file_list as $key => $row) - { - $myarray[$key] = (isset($row[$sortcriteria])?$row[$sortcriteria]:''); - } - // Sort the data - if ($sortorder) array_multisort($myarray, $sortorder, $file_list); + $file_list = dol_sort_array($file_list, $sortcriteria, ($sortorder == SORT_ASC ? 'asc' : 'desc')); } } } @@ -224,9 +219,9 @@ function dol_dir_list($path, $types="all", $recursive=0, $filter="", $excludefil * @param string $sortorder Sort order (SORT_ASC, SORT_DESC) * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like description * @return array Array of array('name'=>'xxx','fullname'=>'/abc/xxx','type'=>'dir|file',...) - * @see dol_dir_list + * @see dol_dir_list() */ -function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortcriteria="name", $sortorder=SORT_ASC, $mode=0) +function dol_dir_list_in_database($path, $filter = "", $excludefilter = null, $sortcriteria = "name", $sortorder = SORT_ASC, $mode = 0) { global $conf, $db; @@ -248,7 +243,7 @@ function dol_dir_list_in_database($path, $filter="", $excludefilter=null, $sortc $obj = $db->fetch_object($resql); if ($obj) { - preg_match('/([^\/]+)\/[^\/]+$/',DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename,$reg); + preg_match('/([^\/]+)\/[^\/]+$/', DOL_DATA_ROOT.'/'.$obj->filepath.'/'.$obj->filename, $reg); $level1name=(isset($reg[1])?$reg[1]:''); $file_list[] = array( "rowid" => $obj->rowid, @@ -313,11 +308,11 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) global $object; if (! empty($object->id)) { - if (! empty($conf->product->enabled)) $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos"; - else $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2),1,1).'/'.substr(substr("000".$object->id, -2),0,1).'/'.$object->id."/photos"; + if (! empty($conf->product->enabled)) $upload_dirold = $conf->product->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos"; + else $upload_dirold = $conf->service->multidir_output[$object->entity].'/'.substr(substr("000".$object->id, -2), 1, 1).'/'.substr(substr("000".$object->id, -2), 0, 1).'/'.$object->id."/photos"; - $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $upload_dirold); - $relativedirold = preg_replace('/^[\\/]/','',$relativedirold); + $relativedirold = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $upload_dirold); + $relativedirold = preg_replace('/^[\\/]/', '', $relativedirold); $filearrayindatabase = array_merge($filearrayindatabase, dol_dir_list_in_database($relativedirold, '', null, 'name', SORT_ASC)); } @@ -353,7 +348,7 @@ function completeFileArrayWithDatabaseInfo(&$filearray, $relativedir) $filearray[$key]['cover']=0; $filearray[$key]['acl']=''; - $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filearray[$key]['fullname']); + $rel_filename = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filearray[$key]['fullname']); if (! preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) // If not a tmp file { dol_syslog("list_of_documents We found a file called '".$filearray[$key]['name']."' not indexed into database. We add it"); @@ -442,6 +437,18 @@ function dol_is_dir($folder) else return false; } +/** + * Return if path is empty + * + * @param string $dir Path of Directory + * @return boolean True or false + */ +function dol_is_dir_empty($dir) +{ + if (!is_readable($dir)) return false; + return (count(scandir($dir)) == 2); +} + /** * Return if path is a file * @@ -477,7 +484,7 @@ function dol_is_url($url) $tmpprot=array('file','http','https','ftp','zlib','data','ssh','ssh2','ogg','expect'); foreach($tmpprot as $prot) { - if (preg_match('/^'.$prot.':/i',$url)) return true; + if (preg_match('/^'.$prot.':/i', $url)) return true; } return false; } @@ -515,7 +522,7 @@ function dol_dir_is_emtpy($folder) * * @param string $file Filename * @return int <0 if KO, Number of lines in files if OK - * @see dol_nboflines + * @see dol_nboflines() */ function dol_count_nb_of_line($file) { @@ -523,7 +530,7 @@ function dol_count_nb_of_line($file) $newfile=dol_osencode($file); //print 'x'.$file; - $fp=fopen($newfile,'r'); + $fp=fopen($newfile, 'r'); if ($fp) { while (!feof($fp)) @@ -570,19 +577,20 @@ function dol_filemtime($pathoffile) /** * Make replacement of strings into a file. * - * @param string $srcfile Source file (can't be a directory) - * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) - * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. - * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' - * @param int $indexdatabase 1=index new file into database. - * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK - * @see dol_copy dolReplaceRegExInFile + * @param string $srcfile Source file (can't be a directory) + * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) + * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. + * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' + * @param int $indexdatabase 1=index new file into database. + * @param int $arrayreplacementisregex 1=Array of replacement is regex + * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK + * @see dol_copy() */ -function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0) +function dolReplaceInFile($srcfile, $arrayreplacement, $destfile = '', $newmask = 0, $indexdatabase = 0, $arrayreplacementisregex = 0) { global $conf; - dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase); + dol_syslog("files.lib.php::dolReplaceInFile srcfile=".$srcfile." destfile=".$destfile." newmask=".$newmask." indexdatabase=".$indexdatabase." arrayreplacementisregex=".$arrayreplacementisregex); if (empty($srcfile)) return -1; if (empty($destfile)) $destfile=$srcfile; @@ -613,7 +621,17 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, // Create $newpathoftmpdestfile from $newpathofsrcfile $content = file_get_contents($newpathofsrcfile, 'r'); - $content = make_substitutions($content, $arrayreplacement, null); + if (empty($arrayreplacementisregex)) + { + $content = make_substitutions($content, $arrayreplacement, null); + } + else + { + foreach ($arrayreplacement as $key => $value) + { + $content = preg_replace($key, $value, $content); + } + } file_put_contents($newpathoftmpdestfile, $content); @chmod($newpathoftmpdestfile, octdec($newmask)); @@ -637,21 +655,6 @@ function dolReplaceInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, return 1; } -/** - * Make replacement of strings into a file. - * - * @param string $srcfile Source file (can't be a directory) - * @param array $arrayreplacement Array with strings to replace. Example: array('valuebefore'=>'valueafter', ...) - * @param string $destfile Destination file (can't be a directory). If empty, will be same than source file. - * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' - * @param int $indexdatabase Index new file into database. - * @return int <0 if error, 0 if nothing done (dest file already exists), >0 if OK - * @see dol_copy dolReplaceInFile - */ -function dolReplaceRegExInFile($srcfile, $arrayreplacement, $destfile='', $newmask=0, $indexdatabase=0) -{ - // TODO -} /** * Copy a file to another file. @@ -661,9 +664,9 @@ function dolReplaceRegExInFile($srcfile, $arrayreplacement, $destfile='', $newma * @param int $newmask Mask for new file (0 by default means $conf->global->MAIN_UMASK). Example: '0666' * @param int $overwriteifexists Overwrite file if exists (1 by default) * @return int <0 if error, 0 if nothing done (dest file already exists and overwriteifexists=0), >0 if OK - * @see dol_delete_file + * @see dol_delete_file() dolCopyDir() */ -function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1) +function dol_copy($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1) { global $conf; @@ -717,9 +720,9 @@ function dol_copy($srcfile, $destfile, $newmask=0, $overwriteifexists=1) * @param int $overwriteifexists Overwrite file if exists (1 by default) * @param array $arrayreplacement Array to use to replace filenames with another one during the copy (works only on file names, not on directory names). * @return int <0 if error, 0 if nothing done (all files already exists and overwriteifexists=0), >0 if OK - * @see dol_copy + * @see dol_copy() */ -function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement=null) +function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayreplacement = null) { global $conf; @@ -809,9 +812,9 @@ function dolCopyDir($srcfile, $destfile, $newmask, $overwriteifexists, $arrayrep * @param int $testvirus Do an antivirus test. Move is canceled if a virus is found. * @param int $indexdatabase Index new file into database. * @return boolean True if OK, false if KO - * @see dol_move_uploaded_file + * @see dol_move_uploaded_file() */ -function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvirus=0, $indexdatabase=1) +function dol_move($srcfile, $destfile, $newmask = 0, $overwriteifexists = 1, $testvirus = 0, $indexdatabase = 1) { global $user, $db, $conf; $result=false; @@ -860,8 +863,8 @@ function dol_move($srcfile, $destfile, $newmask=0, $overwriteifexists=1, $testvi if ($result && $indexdatabase) { // Rename entry into ecm database - $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $srcfile); - $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $destfile); + $rel_filetorenamebefore = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $srcfile); + $rel_filetorenameafter = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $destfile); if (! preg_match('/([\\/]temp[\\/]|[\\/]thumbs|\.meta$)/', $rel_filetorenameafter)) // If not a tmp file { $rel_filetorenamebefore = preg_replace('/^[\\/]/', '', $rel_filetorenamebefore); @@ -956,18 +959,18 @@ function dol_unescapefile($filename) */ function dolCheckVirus($src_file) { - global $conf, $db; + global $conf; if (! empty($conf->global->MAIN_ANTIVIRUS_COMMAND)) { if (! class_exists('AntiVir')) { require_once DOL_DOCUMENT_ROOT.'/core/class/antivir.class.php'; } - $antivir = new AntiVir($db); + $antivir=new AntiVir($db); $result = $antivir->dol_avscan_file($src_file); if ($result < 0) // If virus or error, we stop here { - $reterrors = $antivir->errors; + $reterrors=$antivir->errors; return $reterrors; } } @@ -982,6 +985,7 @@ function dolCheckVirus($src_file) * - This function can be used only into a HTML page context. Use dol_move if you are outside. * - Test on antivirus is always done (if antivirus set). * - Database of files is NOT updated (this is done by dol_add_file_process() that calls this function). + * - Extension .noexe may be added if file is executable and MAIN_DOCUMENT_IS_OUTSIDE_WEBROOT_SO_NOEXE_NOT_REQUIRED is not set. * * @param string $src_file Source full path filename ($_FILES['field']['tmp_name']) * @param string $dest_file Target full path filename ($_FILES['field']['name']) @@ -990,10 +994,10 @@ function dolCheckVirus($src_file) * @param integer $uploaderrorcode Value of PHP upload error code ($_FILES['field']['error']) * @param int $nohook Disable all hooks * @param string $varfiles _FILES var name - * @return int|string >0 if OK, <0 or string if KO - * @see dol_move + * @return int >0 if OK, <0 or string if KO + * @see dol_move() */ -function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan=0, $uploaderrorcode=0, $nohook=0, $varfiles='addedfile') +function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disablevirusscan = 0, $uploaderrorcode = 0, $nohook = 0, $varfiles = 'addedfile') { global $conf, $db, $user, $langs; global $object, $hookmanager; @@ -1045,8 +1049,8 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable $checkvirusarray=dolCheckVirus($src_file); if (count($checkvirusarray)) { - dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: result='.$result.' errors='.join(',',$checkvirusarray), LOG_WARNING); - return 'ErrorFileIsInfectedWithAVirus: '.join(',',$checkvirusarray); + dol_syslog('Files.lib::dol_move_uploaded_file File "'.$src_file.'" (target name "'.$dest_file.'") KO with antivirus: errors='.join(',', $checkvirusarray), LOG_WARNING); + return 'ErrorFileIsInfectedWithAVirus: '.join(',', $checkvirusarray); } } @@ -1060,15 +1064,15 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable // Security: // We refuse cache files/dirs, upload using .. and pipes into filenames. - if (preg_match('/^\./',$src_file) || preg_match('/\.\./',$src_file) || preg_match('/[<>|]/',$src_file)) + if (preg_match('/^\./', basename($src_file)) || preg_match('/\.\./', $src_file) || preg_match('/[<>|]/', $src_file)) { dol_syslog("Refused to deliver file ".$src_file, LOG_WARNING); return -1; } // Security: - // On interdit fichiers caches, remontees de repertoire ainsi que les pipe dans les noms de fichiers. - if (preg_match('/^\./',$dest_file) || preg_match('/\.\./',$dest_file) || preg_match('/[<>|]/',$dest_file)) + // We refuse cache files/dirs, upload using .. and pipes into filenames. + if (preg_match('/^\./', basename($dest_file)) || preg_match('/\.\./', $dest_file) || preg_match('/[<>|]/', $dest_file)) { dol_syslog("Refused to deliver file ".$dest_file, LOG_WARNING); return -2; @@ -1134,9 +1138,9 @@ function dol_move_uploaded_file($src_file, $dest_file, $allowoverwrite, $disable * @param boolean $allowdotdot Allow to delete file path with .. inside. Never use this, it is reserved for migration purpose. * @param int $indexdatabase Try to remove also index entries. * @return boolean True if no error (file is deleted or if glob is used and there's nothing to delete), False if error - * @see dol_delete_dir + * @see dol_delete_dir() */ -function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $object=null, $allowdotdot=false, $indexdatabase=1) +function dol_delete_file($file, $disableglob = 0, $nophperrors = 0, $nohook = 0, $object = null, $allowdotdot = false, $indexdatabase = 1) { global $db, $conf, $user, $langs; global $hookmanager; @@ -1148,7 +1152,7 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje // Security: // We refuse transversal using .. and pipes into filenames. - if ((! $allowdotdot && preg_match('/\.\./',$file)) || preg_match('/[<>|]/',$file)) + if ((! $allowdotdot && preg_match('/\.\./', $file)) || preg_match('/[<>|]/', $file)) { dol_syslog("Refused to delete file ".$file, LOG_WARNING); return false; @@ -1181,8 +1185,8 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje if (empty($disableglob) && ! empty($file_osencoded)) { $ok=true; - $globencoded=str_replace('[','\[',$file_osencoded); - $globencoded=str_replace(']','\]',$globencoded); + $globencoded=str_replace('[', '\[', $file_osencoded); + $globencoded=str_replace(']', '\]', $globencoded); $listofdir=glob($globencoded); if (! empty($listofdir) && is_array($listofdir)) { @@ -1195,7 +1199,7 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje dol_syslog("Removed file ".$filename, LOG_DEBUG); // Delete entry into ecm database - $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $filename); + $rel_filetodelete = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $filename); if (! preg_match('/(\/temp\/|\/thumbs\/|\.meta$)/', $rel_filetodelete)) // If not a tmp file { $rel_filetodelete = preg_replace('/^[\\/]/', '', $rel_filetodelete); @@ -1217,9 +1221,12 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje } } } - 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 it does not exists, we should return true, and we should return false if this is a permission problem + 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 it does not exists, we should return true, and we should return false if this is a permission problem + } } } else dol_syslog("No files to delete found", LOG_DEBUG); @@ -1244,13 +1251,13 @@ function dol_delete_file($file, $disableglob=0, $nophperrors=0, $nohook=0, $obje * @param string $dir Directory to delete * @param int $nophperrors Disable all PHP output errors * @return boolean True if success, false if error - * @see dol_delete_file dol_copy + * @see dol_delete_file() dolCopyDir() */ -function dol_delete_dir($dir,$nophperrors=0) +function dol_delete_dir($dir, $nophperrors = 0) { // Security: // We refuse transversal using .. and pipes into filenames. - if (preg_match('/\.\./',$dir) || preg_match('/[<>|]/',$dir)) + if (preg_match('/\.\./', $dir) || preg_match('/[<>|]/', $dir)) { dol_syslog("Refused to delete dir ".$dir, LOG_WARNING); return false; @@ -1270,9 +1277,9 @@ function dol_delete_dir($dir,$nophperrors=0) * @param int $countdeleted Counter to count nb of elements found really deleted * @return int Number of files and directory we try to remove. NB really removed is returned into var by reference $countdeleted. */ -function dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$countdeleted=0) +function dol_delete_dir_recursive($dir, $count = 0, $nophperrors = 0, $onlysub = 0, &$countdeleted = 0) { - dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir,LOG_DEBUG); + dol_syslog("functions.lib:dol_delete_dir_recursive ".$dir, LOG_DEBUG); if (dol_is_dir($dir)) { $dir_osencoded=dol_osencode($dir); @@ -1319,7 +1326,7 @@ function dol_delete_dir_recursive($dir, $count=0, $nophperrors=0, $onlysub=0, &$ * * @param object $object Object to clean * @return int 0 if error, 1 if OK - * @see dol_convert_file + * @see dol_convert_file() */ function dol_delete_preview($object) { @@ -1347,26 +1354,26 @@ function dol_delete_preview($object) // For new preview files if (file_exists($filepreviewnew) && is_writable($filepreviewnew)) { - if (! dol_delete_file($filepreviewnew,1)) + if (! dol_delete_file($filepreviewnew, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewnew); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewnew); return 0; } } if (file_exists($filepreviewnewbis) && is_writable($filepreviewnewbis)) { - if (! dol_delete_file($filepreviewnewbis,1)) + if (! dol_delete_file($filepreviewnewbis, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewnewbis); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewnewbis); return 0; } } // For old preview files if (file_exists($filepreviewold) && is_writable($filepreviewold)) { - if (! dol_delete_file($filepreviewold,1)) + if (! dol_delete_file($filepreviewold, 1)) { - $object->error=$langs->trans("ErrorFailedToDeleteFile",$filepreviewold); + $object->error=$langs->trans("ErrorFailedToDeleteFile", $filepreviewold); return 0; } } @@ -1379,9 +1386,9 @@ function dol_delete_preview($object) if (file_exists($preview) && is_writable($preview)) { - if ( ! dol_delete_file($preview,1) ) + if ( ! dol_delete_file($preview, 1) ) { - $object->error=$langs->trans("ErrorFailedToOpenFile",$preview); + $object->error=$langs->trans("ErrorFailedToOpenFile", $preview); return 0; } } @@ -1435,7 +1442,7 @@ function dol_meta_create($object) $nblignes = count($object->lines); $client = $object->thirdparty->name . " " . $object->thirdparty->address . " " . $object->thirdparty->zip . " " . $object->thirdparty->town; $meta = "REFERENCE=\"" . $object->ref . "\" - DATE=\"" . dol_print_date($object->date,'') . "\" + DATE=\"" . dol_print_date($object->date, '') . "\" NB_ITEMS=\"" . $nblignes . "\" CLIENT=\"" . $client . "\" AMOUNT_EXCL_TAX=\"" . $object->total_ht . "\" @@ -1447,13 +1454,13 @@ function dol_meta_create($object) $meta .= "ITEM_" . $i . "_QUANTITY=\"" . $object->lines[$i]->qty . "\" ITEM_" . $i . "_AMOUNT_WO_TAX=\"" . $object->lines[$i]->total_ht . "\" ITEM_" . $i . "_VAT=\"" .$object->lines[$i]->tva_tx . "\" - ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n","",nl2br($object->lines[$i]->desc)) . "\" + ITEM_" . $i . "_DESCRIPTION=\"" . str_replace("\r\n", "", nl2br($object->lines[$i]->desc)) . "\" "; } } - $fp = fopen($file,"w"); - fputs($fp,$meta); + $fp = fopen($file, "w"); + fputs($fp, $meta); fclose($fp); if (! empty($conf->global->MAIN_UMASK)) @chmod($file, octdec($conf->global->MAIN_UMASK)); @@ -1478,7 +1485,7 @@ function dol_meta_create($object) * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void */ -function dol_init_file_process($pathtoscan='', $trackid='') +function dol_init_file_process($pathtoscan = '', $trackid = '') { $listofpaths=array(); $listofnames=array(); @@ -1486,7 +1493,7 @@ function dol_init_file_process($pathtoscan='', $trackid='') if ($pathtoscan) { - $listoffiles=dol_dir_list($pathtoscan,'files'); + $listoffiles=dol_dir_list($pathtoscan, 'files'); foreach($listoffiles as $key => $val) { $listofpaths[]=$val['fullname']; @@ -1495,9 +1502,9 @@ function dol_init_file_process($pathtoscan='', $trackid='') } } $keytoavoidconflict = empty($trackid)?'':'-'.$trackid; - $_SESSION["listofpaths".$keytoavoidconflict]=join(';',$listofpaths); - $_SESSION["listofnames".$keytoavoidconflict]=join(';',$listofnames); - $_SESSION["listofmimes".$keytoavoidconflict]=join(';',$listofmimes); + $_SESSION["listofpaths".$keytoavoidconflict]=join(';', $listofpaths); + $_SESSION["listofnames".$keytoavoidconflict]=join(';', $listofnames); + $_SESSION["listofmimes".$keytoavoidconflict]=join(';', $listofmimes); } @@ -1516,7 +1523,7 @@ function dol_init_file_process($pathtoscan='', $trackid='') * @param int $generatethumbs 1=Generate also thumbs for uploaded image files * @return int <=0 if KO, >0 if OK */ -function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesession=0, $varfiles='addedfile', $savingdocmask='', $link=null, $trackid='', $generatethumbs=1) +function dol_add_file_process($upload_dir, $allowoverwrite = 0, $donotupdatesession = 0, $varfiles = 'addedfile', $savingdocmask = '', $link = null, $trackid = '', $generatethumbs = 1) { global $db,$user,$conf,$langs; @@ -1546,8 +1553,8 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio if ($savingdocmask) { - $destfull=$upload_dir . "/" . preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask); - $destfile=preg_replace('/__file__/',$TFile['name'][$i],$savingdocmask); + $destfull=$upload_dir . "/" . preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); + $destfile=preg_replace('/__file__/', $TFile['name'][$i], $savingdocmask); } // dol_sanitizeFileName the file name and lowercase extension @@ -1614,7 +1621,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio { setEventMessages($langs->trans("ErrorFileNotUploaded"), null, 'errors'); } - else if (preg_match('/ErrorFileIsInfectedWithAVirus/',$resupload)) // Files infected by a virus + elseif (preg_match('/ErrorFileIsInfectedWithAVirus/', $resupload)) // Files infected by a virus { setEventMessages($langs->trans("ErrorFileIsInfectedWithAVirus"), null, 'errors'); } @@ -1666,7 +1673,7 @@ function dol_add_file_process($upload_dir, $allowoverwrite=0, $donotupdatesessio * @param string $trackid Track id (used to prefix name of session vars to avoid conflict) * @return void */ -function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile=1,$trackid='') +function dol_remove_file_process($filenb, $donotupdatesession = 0, $donotdeletefile = 1, $trackid = '') { global $db,$user,$conf,$langs,$_FILES; @@ -1677,22 +1684,22 @@ function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile= $listofnames=array(); $listofmimes=array(); $keytoavoidconflict = empty($trackid)?'':'-'.$trackid; - if (! empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths=explode(';',$_SESSION["listofpaths".$keytoavoidconflict]); - if (! empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames=explode(';',$_SESSION["listofnames".$keytoavoidconflict]); - if (! empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes=explode(';',$_SESSION["listofmimes".$keytoavoidconflict]); + if (! empty($_SESSION["listofpaths".$keytoavoidconflict])) $listofpaths=explode(';', $_SESSION["listofpaths".$keytoavoidconflict]); + if (! empty($_SESSION["listofnames".$keytoavoidconflict])) $listofnames=explode(';', $_SESSION["listofnames".$keytoavoidconflict]); + if (! empty($_SESSION["listofmimes".$keytoavoidconflict])) $listofmimes=explode(';', $_SESSION["listofmimes".$keytoavoidconflict]); if ($keytodelete >= 0) { $pathtodelete=$listofpaths[$keytodelete]; $filetodelete=$listofnames[$keytodelete]; - if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete,1); // The delete of ecm database is inside the function dol_delete_file + if (empty($donotdeletefile)) $result = dol_delete_file($pathtodelete, 1); // The delete of ecm database is inside the function dol_delete_file else $result=0; if ($result >= 0) { if (empty($donotdeletefile)) { $langs->load("other"); - setEventMessages($langs->trans("FileWasRemoved",$filetodelete), null, 'mesgs'); + setEventMessages($langs->trans("FileWasRemoved", $filetodelete), null, 'mesgs'); } if (empty($donotupdatesession)) { @@ -1718,13 +1725,13 @@ function dol_remove_file_process($filenb,$donotupdatesession=0,$donotdeletefile= * @param int $setsharekey Set also the share key * @return int <0 if KO, 0 if nothing done, >0 if OK */ -function addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded', $setsharekey=0) +function addFileIntoDatabaseIndex($dir, $file, $fullpathorig = '', $mode = 'uploaded', $setsharekey = 0) { global $db, $user; $result = 0; - $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir); + $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); if (! preg_match('/[\\/]temp[\\/]|[\\/]thumbs|\.meta$/', $rel_dir)) // If not a tmp dir { @@ -1766,7 +1773,7 @@ function addFileIntoDatabaseIndex($dir, $file, $fullpathorig='', $mode='uploaded * @param string $mode How file was created ('uploaded', 'generated', ...) * @return int <0 if KO, 0 if nothing done, >0 if OK */ -function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') +function deleteFilesIntoDatabaseIndex($dir, $file, $mode = 'uploaded') { global $conf, $db, $user; @@ -1780,7 +1787,7 @@ function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') $db->begin(); - $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT,'/').'/', '', $dir); + $rel_dir = preg_replace('/^'.preg_quote(DOL_DATA_ROOT, '/').'/', '', $dir); $filename = basename($file); $rel_dir = preg_replace('/[\\/]$/', '', $rel_dir); @@ -1820,38 +1827,36 @@ function deleteFilesIntoDatabaseIndex($dir, $file, $mode='uploaded') * @param string $fileinput Input file name * @param string $ext Format of target file (It is also extension added to file if fileoutput is not provided). * @param string $fileoutput Output filename + * @param string $page Page number if we convert a PDF into png * @return int <0 if KO, 0=Nothing done, >0 if OK */ -function dol_convert_file($fileinput, $ext='png', $fileoutput='') +function dol_convert_file($fileinput, $ext = 'png', $fileoutput = '', $page = '') { global $langs; - if (class_exists('Imagick')) { - $image=new Imagick(); + $image=new Imagick(); try { - $ret = $image->readImage($fileinput); + $filetoconvert=$fileinput.(($page != '')?'['.$page.']':''); + //var_dump($filetoconvert); + $ret = $image->readImage($filetoconvert); } catch(Exception $e) { - dol_syslog("Failed to read image using Imagick. Try to install package 'apt-get install ghostscript'.", LOG_WARNING); + $ext = pathinfo($fileinput, PATHINFO_EXTENSION); + dol_syslog("Failed to read image using Imagick (Try to install package 'apt-get install php-imagick ghostscript' and check there is no policy to disable ".$ext." convertion in /etc/ImageMagick*/policy.xml): ".$e->getMessage(), LOG_WARNING); return 0; } if ($ret) { - $ret = $image->setImageFormat($ext); + $ret = $image->setImageFormat($ext); if ($ret) { if (empty($fileoutput)) $fileoutput=$fileinput.".".$ext; $count = $image->getNumberImages(); + if (! dol_is_file($fileoutput) || is_writeable($fileoutput)) { - try { - $ret = $image->writeImages($fileoutput, true); - } - catch(Exception $e) - { - dol_syslog($e->getMessage(), LOG_WARNING); - } + $ret = $image->writeImages($fileoutput, true); } else { @@ -1885,26 +1890,89 @@ function dol_convert_file($fileinput, $ext='png', $fileoutput='') * @param string $mode 'gz' or 'bz' or 'zip' * @return int <0 if KO, >0 if OK */ -function dol_compress_file($inputfile, $outputfile, $mode="gz") +function dol_compress_file($inputfile, $outputfile, $mode = "gz") { + global $conf; + $foundhandler=0; try { + dol_syslog("dol_compress_file mode=".$mode." inputfile=".$inputfile." outputfile=".$outputfile); + $data = implode("", file(dol_osencode($inputfile))); if ($mode == 'gz') { $foundhandler=1; $compressdata = gzencode($data, 9); } elseif ($mode == 'bz') { $foundhandler=1; $compressdata = bzcompress($data, 9); } elseif ($mode == 'zip') { + if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) + { + $foundhandler=1; + + $rootPath = realpath($inputfile); + + dol_syslog("Class ZipArchive is set so we zip using ZipArchive to zip into ".$outputfile.' rootPath='.$rootPath); + $zip = new ZipArchive; + + if ($zip->open($outputfile, ZipArchive::CREATE) !== true) { + $errormsg="Failed to open file ".$outputfile."\n"; + dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR); + return -6; + } + + // Create recursive directory iterator + /** @var SplFileInfo[] $files */ + $files = new RecursiveIteratorIterator( + new RecursiveDirectoryIterator($rootPath), + RecursiveIteratorIterator::LEAVES_ONLY + ); + + foreach ($files as $name => $file) + { + // Skip directories (they would be added automatically) + if (!$file->isDir()) + { + // Get real and relative path for current file + $filePath = $file->getRealPath(); + $relativePath = substr($filePath, strlen($rootPath) + 1); + + // Add current file to archive + $zip->addFile($filePath, $relativePath); + } + } + + // Zip archive will be created only after closing object + $zip->close(); + + dol_syslog("dol_compress_file success - ".count($zip->numFiles)." files"); + return 1; + } + if (defined('ODTPHP_PATHTOPCLZIP')) { $foundhandler=1; include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; $archive = new PclZip($outputfile); - $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); - //$archive->add($inputfile); - return 1; + $result = $archive->add($inputfile, PCLZIP_OPT_REMOVE_PATH, dirname($inputfile)); + + if ($result === 0) + { + global $errormsg; + $errormsg=$archive->errorInfo(true); + dol_syslog("dol_compress_file failure - ".$errormsg, LOG_ERR); + if ($archive->errorCode() == PCLZIP_ERR_WRITE_OPEN_FAIL) + { + dol_syslog("dol_compress_file error PCLZIP_ERR_WRITE_OPEN_FAIL", LOG_ERR); + return -4; + } + return -3; + } + else + { + dol_syslog("dol_compress_file success - ".count($result)." files"); + return 1; + } } } @@ -1917,7 +1985,7 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") } else { - dol_syslog("Try to zip with format ".$mode." with no handler for this format",LOG_ERR); + dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR); return -2; } } @@ -1925,7 +1993,7 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") { global $langs, $errormsg; $langs->load("errors"); - dol_syslog("Failed to open file ".$outputfile,LOG_ERR); + dol_syslog("Failed to open file ".$outputfile, LOG_ERR); $errormsg=$langs->trans("ErrorFailedToWriteInDir"); return -1; } @@ -1938,11 +2006,11 @@ function dol_compress_file($inputfile, $outputfile, $mode="gz") * @param string $outputdir Target dir name * @return array array('error'=>'Error code') or array() if no error */ -function dol_uncompress($inputfile,$outputdir) +function dol_uncompress($inputfile, $outputdir) { - global $langs; + global $conf, $langs; - if (defined('ODTPHP_PATHTOPCLZIP')) + if (defined('ODTPHP_PATHTOPCLZIP') && empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_UNCOMPRESS)) { dol_syslog("Constant ODTPHP_PATHTOPCLZIP for pclzip library is set to ".ODTPHP_PATHTOPCLZIP.", so we use Pclzip to unzip into ".$outputdir); include_once ODTPHP_PATHTOPCLZIP.'/pclzip.lib.php'; @@ -1997,9 +2065,10 @@ function dol_uncompress($inputfile,$outputdir) * @param string $inputdir Source dir name * @param string $outputfile Target file name (output directory must exists and be writable) * @param string $mode 'zip' + * @param string $excludefiles A regex pattern. For example: '/\.log$|\/temp\//' * @return int <0 if KO, >0 if OK */ -function dol_compress_dir($inputdir, $outputfile, $mode="zip") +function dol_compress_dir($inputdir, $outputfile, $mode = "zip", $excludefiles = '') { $foundhandler=0; @@ -2009,7 +2078,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") { global $langs, $errormsg; $langs->load("errors"); - $errormsg=$langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg=$langs->trans("ErrorFailedToWriteInDir", $outputfile); return -3; } @@ -2030,6 +2099,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") return 1; } else*/ + //if (class_exists('ZipArchive') && ! empty($conf->global->MAIN_USE_ZIPARCHIVE_FOR_ZIP_COMPRESS)) if (class_exists('ZipArchive')) { $foundhandler=1; @@ -2037,6 +2107,13 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") // Initialize archive object $zip = new ZipArchive(); $result = $zip->open($outputfile, ZipArchive::CREATE | ZipArchive::OVERWRITE); + if (! $result) + { + global $langs, $errormsg; + $langs->load("errors"); + $errormsg=$langs->trans("ErrorFailedToWriteInFile", $outputfile); + return -4; + } // Create recursive directory iterator /** @var SplFileInfo[] $files */ @@ -2053,9 +2130,11 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") // Get real and relative path for current file $filePath = $file->getRealPath(); $relativePath = substr($filePath, strlen($inputdir) + 1); - - // Add current file to archive - $zip->addFile($filePath, $relativePath); + if (empty($excludefiles) || ! preg_match($excludefiles, $filePath)) + { + // Add current file to archive + $zip->addFile($filePath, $relativePath); + } } } @@ -2068,7 +2147,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") if (! $foundhandler) { - dol_syslog("Try to zip with format ".$mode." with no handler for this format",LOG_ERR); + dol_syslog("Try to zip with format ".$mode." with no handler for this format", LOG_ERR); return -2; } else @@ -2082,7 +2161,7 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") $langs->load("errors"); dol_syslog("Failed to open file ".$outputfile, LOG_ERR); dol_syslog($e->getMessage(), LOG_ERR); - $errormsg=$langs->trans("ErrorFailedToWriteInDir",$outputfile); + $errormsg=$langs->trans("ErrorFailedToWriteInDir", $outputfile); return -1; } } @@ -2099,9 +2178,9 @@ function dol_compress_dir($inputdir, $outputfile, $mode="zip") * @param int $mode 0=Return array minimum keys loaded (faster), 1=Force all keys like date and size to be loaded (slower), 2=Force load of date only, 3=Force load of size only * @return string Full path to most recent file */ -function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta|_preview.*\.png)$','^\.'),$nohook=false,$mode='') +function dol_most_recent_file($dir, $regexfilter = '', $excludefilter = array('(\.meta|_preview.*\.png)$','^\.'), $nohook = false, $mode = '') { - $tmparray=dol_dir_list($dir,'files',0,$regexfilter,$excludefilter,'date',SORT_DESC,$mode,$nohook); + $tmparray=dol_dir_list($dir, 'files', 0, $regexfilter, $excludefilter, 'date', SORT_DESC, $mode, $nohook); return $tmparray[0]; } @@ -2115,9 +2194,9 @@ function dol_most_recent_file($dir,$regexfilter='',$excludefilter=array('(\.meta * @param string $refname Ref of object to check permission for external users (autodetect if not provided) * @param string $mode Check permission for 'read' or 'write' * @return mixed Array with access information : 'accessallowed' & 'sqlprotectagainstexternals' & 'original_file' (as a full path name) - * @see restrictedArea + * @see restrictedArea() */ -function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser='', $refname='', $mode='read') +function dol_check_secure_access_document($modulepart, $original_file, $entity, $fuser = '', $refname = '', $mode = 'read') { global $conf, $db, $user; global $dolibarr_main_data_root, $dolibarr_main_document_root_alt; @@ -2134,6 +2213,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, if ($modulepart == 'users') $modulepart='user'; dol_syslog('modulepart='.$modulepart.' original_file='.$original_file.' entity='.$entity); + // We define $accessallowed and $sqlprotectagainstexternals $accessallowed=0; $sqlprotectagainstexternals=''; @@ -2142,8 +2222,6 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Find the subdirectory name as the reference. For exemple original_file='10/myfile.pdf' -> refname='10' if (empty($refname)) $refname=basename(dirname($original_file)."/"); - $relative_original_file = $original_file; - // Define possible keys to use for permission check $lire='lire'; $read='read'; $download='download'; if ($mode == 'write') @@ -2293,7 +2371,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $original_file=$conf->adherent->dir_temp.'/'.$original_file; } // Wrapping pour les images des stats produits - elseif (preg_match('/^productstats_/i',$modulepart) && !empty($conf->product->dir_temp)) + elseif (preg_match('/^productstats_/i', $modulepart) && !empty($conf->product->dir_temp)) { if ($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) $accessallowed=1; $original_file=(!empty($conf->product->multidir_temp[$entity])?$conf->product->multidir_temp[$entity]:$conf->service->multidir_temp[$entity]).'/'.$original_file; @@ -2320,7 +2398,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // Wrapping pour les prelevements elseif ($modulepart == 'prelevement' && !empty($conf->prelevement->dir_output)) { - if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i',$original_file)) $accessallowed=1; + if ($fuser->rights->prelevement->bons->{$lire} || preg_match('/^specimen/i', $original_file)) $accessallowed=1; $original_file=$conf->prelevement->dir_output.'/'.$original_file; } // Wrapping pour les graph energie @@ -2369,11 +2447,11 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for users - else if ($modulepart == 'user' && !empty($conf->user->dir_output)) + elseif ($modulepart == 'user' && !empty($conf->user->dir_output)) { $canreaduser=(! empty($fuser->admin) || $fuser->rights->user->user->{$lire}); if ($fuser->id == (int) $refname) { $canreaduser=1; } // A user can always read its own card - if ($canreaduser || preg_match('/^specimen/i',$original_file)) + if ($canreaduser || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2381,10 +2459,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for third parties - else if (($modulepart == 'company' || $modulepart == 'societe') && !empty($conf->societe->dir_output)) + elseif (($modulepart == 'company' || $modulepart == 'societe' || $modulepart == 'thirdparty') && !empty($conf->societe->dir_output)) { if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->societe->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2393,7 +2471,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for contact - else if ($modulepart == 'contact' && !empty($conf->societe->dir_output)) + elseif ($modulepart == 'contact' && !empty($conf->societe->dir_output)) { if (empty($entity) || empty($conf->societe->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); if ($fuser->rights->societe->{$lire}) @@ -2404,9 +2482,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for invoices - else if (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output)) + elseif (($modulepart == 'facture' || $modulepart == 'invoice') && !empty($conf->facture->dir_output)) { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2414,73 +2492,73 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping for mass actions - else if ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) + elseif ($modulepart == 'massfilesarea_proposals' && !empty($conf->propal->multidir_output[$entity])) { - if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->propal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->propal->multidir_output[$entity].'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_orders') + elseif ($modulepart == 'massfilesarea_orders') { - if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_invoices') + elseif ($modulepart == 'massfilesarea_invoices') { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_expensereport') + elseif ($modulepart == 'massfilesarea_expensereport') { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->expensereport->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_interventions') + elseif ($modulepart == 'massfilesarea_interventions') { - if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->ficheinter->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) + elseif ($modulepart == 'massfilesarea_supplier_proposal' && !empty($conf->supplier_proposal->dir_output)) { - if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->supplier_proposal->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->supplier_proposal->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_order') + elseif ($modulepart == 'massfilesarea_supplier_order') { - if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->commande->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_supplier_invoice') + elseif ($modulepart == 'massfilesarea_supplier_invoice') { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->facture->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; } - else if ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) + elseif ($modulepart == 'massfilesarea_contract' && !empty($conf->contrat->dir_output)) { - if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2488,9 +2566,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for interventions - else if (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) + elseif (($modulepart == 'fichinter' || $modulepart == 'ficheinter') && !empty($conf->ficheinter->dir_output)) { - if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->ficheinter->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2499,9 +2577,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les deplacements et notes de frais - else if ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) + elseif ($modulepart == 'deplacement' && !empty($conf->deplacement->dir_output)) { - if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->deplacement->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2509,9 +2587,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, //$sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."fichinter WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping pour les propales - else if (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity])) + elseif (($modulepart == 'propal' || $modulepart == 'propale') && !empty($conf->propal->multidir_output[$entity])) { - if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->propale->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2520,9 +2598,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les commandes - else if (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output)) + elseif (($modulepart == 'commande' || $modulepart == 'order') && !empty($conf->commande->dir_output)) { - if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2531,18 +2609,18 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les projets - else if ($modulepart == 'project' && !empty($conf->projet->dir_output)) + elseif ($modulepart == 'project' && !empty($conf->projet->dir_output)) { - if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->projet->dir_output.'/'.$original_file; $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."projet WHERE ref='".$db->escape($refname)."' AND entity IN (".getEntity('project').")"; } - else if ($modulepart == 'project_task' && !empty($conf->projet->dir_output)) + elseif ($modulepart == 'project_task' && !empty($conf->projet->dir_output)) { - if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->projet->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2551,9 +2629,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les commandes fournisseurs - else if (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) + elseif (($modulepart == 'commande_fournisseur' || $modulepart == 'order_supplier') && !empty($conf->fournisseur->commande->dir_output)) { - if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->commande->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2562,19 +2640,19 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les factures fournisseurs - else if (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) + elseif (($modulepart == 'facture_fournisseur' || $modulepart == 'invoice_supplier') && !empty($conf->fournisseur->facture->dir_output)) { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->fournisseur->facture->dir_output.'/'.$original_file; - $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE facnumber='".$db->escape($refname)."' AND entity=".$conf->entity; + $sqlprotectagainstexternals = "SELECT fk_soc as fk_soc FROM ".MAIN_DB_PREFIX."facture_fourn WHERE ref='".$db->escape($refname)."' AND entity=".$conf->entity; } // Wrapping pour les rapport de paiements - else if ($modulepart == 'supplier_payment') + elseif ($modulepart == 'supplier_payment') { - if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->fournisseur->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2583,9 +2661,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les rapport de paiements - else if ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) + elseif ($modulepart == 'facture_paiement' && !empty($conf->facture->dir_output)) { - if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->facture->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2594,9 +2672,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for accounting exports - else if ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) + elseif ($modulepart == 'export_compta' && !empty($conf->accounting->dir_output)) { - if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->accounting->bind->write || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2604,18 +2682,18 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les expedition - else if ($modulepart == 'expedition' && !empty($conf->expedition->dir_output)) + elseif ($modulepart == 'expedition' && !empty($conf->expedition->dir_output)) { - if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->expedition->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } $original_file=$conf->expedition->dir_output."/sending/".$original_file; } // Wrapping pour les bons de livraison - else if ($modulepart == 'livraison' && !empty($conf->expedition->dir_output)) + elseif ($modulepart == 'livraison' && !empty($conf->expedition->dir_output)) { - if ($fuser->rights->expedition->livraison->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->expedition->livraison->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2623,9 +2701,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les actions - else if ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) + elseif ($modulepart == 'actions' && !empty($conf->agenda->dir_output)) { - if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->agenda->myactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2633,9 +2711,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les actions - else if ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) + elseif ($modulepart == 'actionsreport' && !empty($conf->agenda->dir_temp)) { - if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->agenda->allactions->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2643,10 +2721,10 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les produits et services - else if ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') + elseif ($modulepart == 'product' || $modulepart == 'produit' || $modulepart == 'service' || $modulepart == 'produit|service') { if (empty($entity) || (empty($conf->product->multidir_output[$entity]) && empty($conf->service->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i',$original_file)) + if (($fuser->rights->produit->{$lire} || $fuser->rights->service->{$lire}) || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2655,20 +2733,31 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les lots produits - else if ($modulepart == 'product_batch' || $modulepart == 'produitlot') + elseif ($modulepart == 'product_batch' || $modulepart == 'produitlot') { if (empty($entity) || (empty($conf->productbatch->multidir_output[$entity]))) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); - if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i',$original_file)) + if (($fuser->rights->produit->{$lire} ) || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } if (! empty($conf->productbatch->enabled)) $original_file=$conf->productbatch->multidir_output[$entity].'/'.$original_file; } - // Wrapping pour les contrats - else if ($modulepart == 'contract' && !empty($conf->contrat->dir_output)) + // Wrapping for stock movements + elseif ($modulepart == 'movement' || $modulepart == 'mouvement') { - if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i',$original_file)) + if (empty($entity) || empty($conf->stock->multidir_output[$entity])) return array('accessallowed'=>0, 'error'=>'Value entity must be provided'); + if (($fuser->rights->stock->{$lire} || $fuser->rights->stock->movement->{$lire} || $fuser->rights->stock->mouvement->{$lire}) || preg_match('/^specimen/i', $original_file)) + { + $accessallowed=1; + } + if (! empty($conf->stock->enabled)) $original_file=$conf->stock->multidir_output[$entity].'/movement/'.$original_file; + } + + // Wrapping pour les contrats + elseif ($modulepart == 'contract' && !empty($conf->contrat->dir_output)) + { + if ($fuser->rights->contrat->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2677,9 +2766,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les dons - else if ($modulepart == 'donation' && !empty($conf->don->dir_output)) + elseif ($modulepart == 'donation' && !empty($conf->don->dir_output)) { - if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->don->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2687,9 +2776,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les dons - else if ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) + elseif ($modulepart == 'dolresource' && !empty($conf->resource->dir_output)) { - if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->resource->{$read} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2697,9 +2786,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour les remises de cheques - else if ($modulepart == 'remisecheque' && !empty($conf->banque->dir_output)) + elseif ($modulepart == 'remisecheque' && !empty($conf->bank->dir_output)) { - if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->banque->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2708,7 +2797,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for bank - else if ($modulepart == 'bank' && !empty($conf->bank->dir_output)) + elseif (($modulepart == 'banque' || $modulepart == 'bank') && !empty($conf->bank->dir_output)) { if ($fuser->rights->banque->{$lire}) { @@ -2718,7 +2807,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for export module - else if ($modulepart == 'export' && !empty($conf->export->dir_temp)) + elseif ($modulepart == 'export' && !empty($conf->export->dir_temp)) { // Aucun test necessaire car on force le rep de download sur // le rep export qui est propre a l'utilisateur @@ -2727,35 +2816,35 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for import module - else if ($modulepart == 'import' && !empty($conf->import->dir_temp)) + elseif ($modulepart == 'import' && !empty($conf->import->dir_temp)) { $accessallowed=1; $original_file=$conf->import->dir_temp.'/'.$original_file; } // Wrapping pour l'editeur wysiwyg - else if ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) + elseif ($modulepart == 'editor' && !empty($conf->fckeditor->dir_output)) { $accessallowed=1; $original_file=$conf->fckeditor->dir_output.'/'.$original_file; } // Wrapping for backups - else if ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) + elseif ($modulepart == 'systemtools' && !empty($conf->admin->dir_output)) { if ($fuser->admin) $accessallowed=1; $original_file=$conf->admin->dir_output.'/'.$original_file; } // Wrapping for upload file test - else if ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) + elseif ($modulepart == 'admin_temp' && !empty($conf->admin->dir_temp)) { if ($fuser->admin) $accessallowed=1; $original_file=$conf->admin->dir_temp.'/'.$original_file; } // Wrapping pour BitTorrent - else if ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) + elseif ($modulepart == 'bittorrent' && !empty($conf->bittorrent->dir_output)) { $accessallowed=1; $dir='files'; @@ -2764,9 +2853,9 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping pour Foundation module - else if ($modulepart == 'member' && !empty($conf->adherent->dir_output)) + elseif ($modulepart == 'member' && !empty($conf->adherent->dir_output)) { - if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i',$original_file)) + if ($fuser->rights->adherent->{$lire} || preg_match('/^specimen/i', $original_file)) { $accessallowed=1; } @@ -2774,7 +2863,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, } // Wrapping for Scanner - else if ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) + elseif ($modulepart == 'scanner_user_temp' && !empty($conf->scanner->dir_temp)) { $accessallowed=1; $original_file=$conf->scanner->dir_temp.'/'.$fuser->id.'/'.$original_file; @@ -2787,45 +2876,58 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity, // If modulepart=module Allows any module to open a file if file is in directory called DOL_DATA_ROOT/modulepart else { - if (preg_match('/^specimen/i',$original_file)) $accessallowed=1; // If link to a file called specimen. Test must be done before changing $original_file int full path. + if (preg_match('/^specimen/i', $original_file)) $accessallowed=1; // If link to a file called specimen. Test must be done before changing $original_file int full path. if ($fuser->admin) $accessallowed=1; // If user is admin // Define $accessallowed - if (preg_match('/^([a-z]+)_user_temp$/i',$modulepart,$reg)) + if (preg_match('/^([a-z]+)_user_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_temp.'/'.$fuser->id.'/'.$original_file; } - else if (preg_match('/^([a-z]+)_temp$/i',$modulepart,$reg)) + elseif (preg_match('/^([a-z]+)_temp$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_temp)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_temp.'/'.$original_file; } - else if (preg_match('/^([a-z]+)_user$/i',$modulepart,$reg)) + elseif (preg_match('/^([a-z]+)_user$/i', $modulepart, $reg)) { if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } if ($fuser->rights->{$reg[1]}->{$lire} || $fuser->rights->{$reg[1]}->{$read} || ($fuser->rights->{$reg[1]}->{$download})) $accessallowed=1; $original_file=$conf->{$reg[1]}->dir_output.'/'.$fuser->id.'/'.$original_file; } + elseif (preg_match('/^massfilesarea_([a-z]+)$/i', $modulepart, $reg)) + { + if (empty($conf->{$reg[1]}->dir_output)) // modulepart not supported + { + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + exit; + } + if ($fuser->rights->{$reg[1]}->{$lire} || preg_match('/^specimen/i', $original_file)) + { + $accessallowed=1; + } + $original_file=$conf->{$reg[1]}->dir_output.'/temp/massgeneration/'.$user->id.'/'.$original_file; + } else { if (empty($conf->$modulepart->dir_output)) // modulepart not supported { - dol_print_error('','Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); + dol_print_error('', 'Error call dol_check_secure_access_document with not supported value for modulepart parameter ('.$modulepart.')'); exit; } @@ -2971,4 +3073,3 @@ function getFilesUpdated(&$file_list, SimpleXMLElement $dir, $path = '', $pathre return $file_list; } - From b1495e12ce4cec42eaca686bc30f12b5be70a869 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 30 Apr 2020 18:45:00 +0200 Subject: [PATCH 23/58] FIX A variable was erased by a temporary variable --- htdocs/compta/facture/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 934916fa31e..9fa696c69b3 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -4202,7 +4202,7 @@ elseif ($id > 0 || ! empty($ref)) $current_situation_counter = array(); foreach ($object->tab_previous_situation_invoice as $prev_invoice) { - $totalpaye = $prev_invoice->getSommePaiement(); + $tmptotalpaidforthisinvoice = $prev_invoice->getSommePaiement(); $total_prev_ht += $prev_invoice->total_ht; $total_prev_ttc += $prev_invoice->total_ttc; $current_situation_counter[] = (($prev_invoice->type == Facture::TYPE_CREDIT_NOTE)?-1:1) * $prev_invoice->situation_counter; @@ -4213,7 +4213,7 @@ elseif ($id > 0 || ! empty($ref)) if (! empty($conf->banque->enabled)) print ''; print '' . price($prev_invoice->total_ht) . ''; print '' . price($prev_invoice->total_ttc) . ''; - print '' . $prev_invoice->getLibStatut(3, $totalpaye) . ''; + print '' . $prev_invoice->getLibStatut(3, $tmptotalpaidforthisinvoice) . ''; print ''; } } From 385f9982540dddf424c9eb35e4c62de0a435408c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Fri, 1 May 2020 21:01:40 +0200 Subject: [PATCH 24/58] Fix restore param --quick --- htdocs/admin/tools/dolibarr_export.php | 8 ++++++++ htdocs/core/class/utils.class.php | 1 + 2 files changed, 9 insertions(+) diff --git a/htdocs/admin/tools/dolibarr_export.php b/htdocs/admin/tools/dolibarr_export.php index 0bef19dde56..ee8594e6bf8 100644 --- a/htdocs/admin/tools/dolibarr_export.php +++ b/htdocs/admin/tools/dolibarr_export.php @@ -244,6 +244,14 @@ print '';
+ + +
diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 86eff6613c1..61fc845d7dc 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -262,6 +262,7 @@ class Utils if (GETPOST("disable_fk", "alpha") || $usedefault) $param.=" -K"; if (GETPOST("sql_compat", "alpha") && GETPOST("sql_compat", "alpha") != 'NONE') $param.=" --compatible=".escapeshellarg(GETPOST("sql_compat", "alpha")); if (GETPOST("drop_database", "alpha")) $param.=" --add-drop-database"; + if (GETPOST("use_mysql_quick_param", "alpha"))$param.=" --quick"; if (GETPOST("sql_structure", "alpha") || $usedefault) { if (GETPOST("drop", "alpha") || $usedefault) $param.=" --add-drop-table=TRUE"; From 6d894b7abd3bd0c7e47a4e98b817b9d954ca0f1b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 4 May 2020 19:08:31 +0200 Subject: [PATCH 25/58] Fix missing link in message --- htdocs/core/class/notify.class.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index db0e490a6c6..6c0ec1ec62b 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -528,7 +528,7 @@ class Notify $message.= $outputlangs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name)."\n"; $message.= "\n"; $message.= $mesg; - if ($link) $message.= "\n" . $urlwithroot . $link; + if ($link) $message.= "\n" . $urlwithroot . $link; // if link is already added around the ref into the translation text, then $link must be set to '' $parameters = array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); if (!isset($action)) $action = ''; @@ -600,6 +600,7 @@ class Notify { foreach($conf->global as $key => $val) { + $reg = array(); if ($val == '' || ! preg_match('/^NOTIFICATION_FIXEDEMAIL_'.$notifcode.'_THRESHOLD_HIGHER_(.*)$/', $key, $reg)) continue; $threshold = (float) $reg[1]; @@ -743,7 +744,7 @@ class Notify $message.= $langs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name)."\n"; $message.= "\n"; $message.= $mesg; - //if ($link) $message.= "\n" . $urlwithroot . $link; // link already added around the ref into the text + if ($link) $message.= "\n" . $urlwithroot . $link; // if link is already added around the ref into the translation text, then $link must be set to '' $message = nl2br($message); From c14b6884e3f71de24cd27dc4da3d1e0db04bb13d Mon Sep 17 00:00:00 2001 From: gauthier Date: Tue, 5 May 2020 10:02:36 +0200 Subject: [PATCH 26/58] FIX : missing hook init + table class + $page not set --- htdocs/compta/prelevement/bons.php | 1 + htdocs/compta/prelevement/list.php | 1 + htdocs/compta/prelevement/rejets.php | 4 +++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/bons.php b/htdocs/compta/prelevement/bons.php index 2b67b73c95b..27654de1ad0 100644 --- a/htdocs/compta/prelevement/bons.php +++ b/htdocs/compta/prelevement/bons.php @@ -53,6 +53,7 @@ $search_ref = GETPOST('search_ref', 'alpha'); $search_amount = GETPOST('search_amount', 'alpha'); $bon=new BonPrelevement($db, ""); +$hookmanager->initHooks(array('withdrawalsreceiptslist')); /* diff --git a/htdocs/compta/prelevement/list.php b/htdocs/compta/prelevement/list.php index 81e58e19cca..eb741b981d9 100644 --- a/htdocs/compta/prelevement/list.php +++ b/htdocs/compta/prelevement/list.php @@ -56,6 +56,7 @@ $search_company = GETPOST('search_company', 'alpha'); $statut = GETPOST('statut', 'int'); $bon=new BonPrelevement($db, ""); +$hookmanager->initHooks(array('withdrawalsreceiptslineslist')); $ligne=new LignePrelevement($db, $user); diff --git a/htdocs/compta/prelevement/rejets.php b/htdocs/compta/prelevement/rejets.php index 333d07a4617..7611945a40d 100644 --- a/htdocs/compta/prelevement/rejets.php +++ b/htdocs/compta/prelevement/rejets.php @@ -40,6 +40,7 @@ $result = restrictedArea($user, 'prelevement', '', '', 'bons'); // Get supervariables $page = GETPOST('page', 'int'); +if (empty($page) || $page == -1) { $page = 0; } // If $page is not defined, or '' or -1 $sortorder = GETPOST('sortorder', 'alpha'); $sortfield = GETPOST('sortfield', 'alpha'); @@ -57,6 +58,7 @@ if ($sortorder == "") $sortorder="DESC"; if ($sortfield == "") $sortfield="p.datec"; $rej = new RejetPrelevement($db, $user); +$hookmanager->initHooks(array('withdrawalsreceiptsrejectedlist')); $ligne = new LignePrelevement($db, $user); /* @@ -85,7 +87,7 @@ if ($result) print_barre_liste($langs->trans("WithdrawsRefused"), $page, $_SERVER["PHP_SELF"], $urladd, $sortfield, $sortorder, '', $num); print"\n\n"; - print ''; + print '
'; print ''; print_liste_field_titre("Line", $_SERVER["PHP_SELF"], "p.ref", '', $urladd); print_liste_field_titre("ThirdParty", $_SERVER["PHP_SELF"], "s.nom", '', $urladd); From d4400cf80fce889f4836338ca40a8bff0080ee2e Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 7 May 2020 11:39:32 +0200 Subject: [PATCH 27/58] FIX links into emails of notifications --- htdocs/core/class/notify.class.php | 56 ++++++++++++++---------------- 1 file changed, 27 insertions(+), 29 deletions(-) diff --git a/htdocs/core/class/notify.class.php b/htdocs/core/class/notify.class.php index 6c0ec1ec62b..8a03196beef 100644 --- a/htdocs/core/class/notify.class.php +++ b/htdocs/core/class/notify.class.php @@ -416,34 +416,34 @@ class Notify switch ($notifcode) { case 'BILL_VALIDATE': - $link='/compta/facture/card.php?facid='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->facture->dir_output; $object_type = 'facture'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoiceValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoiceValidated", $link); break; case 'BILL_PAYED': - $link='/compta/facture/card.php?facid='.$object->id; + $link ='' . $newref . ''; $dir_output = $conf->facture->dir_output; $object_type = 'facture'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoicePayed", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInvoicePayed", $link); break; case 'ORDER_VALIDATE': - $link='/commande/card.php?id='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->commande->dir_output; $object_type = 'order'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextOrderValidated", $link); break; case 'PROPAL_VALIDATE': - $link='/comm/propal/card.php?id='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->propal->multidir_output[$object->entity]; $object_type = 'propal'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalValidated", $link); break; case 'PROPAL_CLOSE_SIGNED': - $link='/comm/propal/card.php?id='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->propal->multidir_output[$object->entity]; $object_type = 'propal'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalClosedSigned", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextProposalClosedSigned", $link); break; case 'FICHINTER_ADD_CONTACT': $link='/fichinter/card.php?id='.$object->id; @@ -452,17 +452,17 @@ class Notify $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionAddedContact", $newref); break; case 'FICHINTER_VALIDATE': - $link='/fichinter/card.php?id='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->ficheinter->dir_output; $object_type = 'ficheinter'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextInterventionValidated", $link); break; case 'ORDER_SUPPLIER_VALIDATE': $link='/fourn/commande/card.php?id='.$object->id; $dir_output = $conf->fournisseur->commande->dir_output; $object_type = 'order_supplier'; $mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n"; - $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderValidatedBy", $newref, $user->getFullName($outputlangs)); + $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderValidatedBy", $link, $user->getFullName($outputlangs)); $mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'ORDER_SUPPLIER_APPROVE': @@ -470,46 +470,46 @@ class Notify $dir_output = $conf->fournisseur->commande->dir_output; $object_type = 'order_supplier'; $mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n"; - $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderApprovedBy", $newref, $user->getFullName($outputlangs)); + $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderApprovedBy", $link, $user->getFullName($outputlangs)); $mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'ORDER_SUPPLIER_REFUSE': - $link='/fourn/commande/card.php?id='.$object->id; + $link = '' . $newref . ''; $dir_output = $conf->fournisseur->commande->dir_output; $object_type = 'order_supplier'; $mesg = $outputlangs->transnoentitiesnoconv("Hello").",\n\n"; - $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderRefusedBy", $newref, $user->getFullName($outputlangs)); + $mesg.= $outputlangs->transnoentitiesnoconv("EMailTextOrderRefusedBy", $link, $user->getFullName($outputlangs)); $mesg.= "\n\n".$outputlangs->transnoentitiesnoconv("Sincerely").".\n\n"; break; case 'SHIPPING_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; $object_type = 'expedition'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpeditionValidated", $link); break; case 'EXPENSE_REPORT_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $link); break; case 'EXPENSE_REPORT_APPROVE': $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $link); break; case 'HOLIDAY_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayValidated", $link); break; case 'HOLIDAY_APPROVE': $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; - $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); + $mesg = $outputlangs->transnoentitiesnoconv("EMailTextHolidayApproved", $link); break; } $ref = dol_sanitizeFileName($newref); @@ -528,7 +528,6 @@ class Notify $message.= $outputlangs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name)."\n"; $message.= "\n"; $message.= $mesg; - if ($link) $message.= "\n" . $urlwithroot . $link; // if link is already added around the ref into the translation text, then $link must be set to '' $parameters = array('notifcode'=>$notifcode, 'sendto'=>$sendto, 'replyto'=>$replyto, 'file'=>$filename_list, 'mimefile'=>$mimetype_list, 'filename'=>$mimefilename_list); if (!isset($action)) $action = ''; @@ -655,7 +654,7 @@ class Notify break; case 'FICHINTER_ADD_CONTACT': $link = '' . $newref . ''; - $dir_output = $conf->facture->dir_output; + $dir_output = $conf->ficheinter->dir_output; $object_type = 'ficheinter'; $mesg = $langs->transnoentitiesnoconv("EMailTextInterventionAddedContact", $link); break; @@ -701,31 +700,31 @@ class Notify $link = ''.$newref.''; $dir_output = $conf->expedition->dir_output.'/sending/'; $object_type = 'order_supplier'; - $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $newref); + $mesg = $langs->transnoentitiesnoconv("EMailTextExpeditionValidated", $link); break; case 'EXPENSE_REPORT_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; - $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $newref); + $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportValidated", $link); break; case 'EXPENSE_REPORT_APPROVE': $link = ''.$newref.''; $dir_output = $conf->expensereport->dir_output; $object_type = 'expensereport'; - $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $newref); + $mesg = $langs->transnoentitiesnoconv("EMailTextExpenseReportApproved", $link); break; case 'HOLIDAY_VALIDATE': $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; - $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $newref); + $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayValidated", $link); break; case 'HOLIDAY_APPROVE': $link = ''.$newref.''; $dir_output = $conf->holiday->dir_output; $object_type = 'holiday'; - $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $newref); + $mesg = $langs->transnoentitiesnoconv("EMailTextHolidayApproved", $link); break; } $ref = dol_sanitizeFileName($newref); @@ -744,7 +743,6 @@ class Notify $message.= $langs->transnoentities("YouReceiveMailBecauseOfNotification2", $application, $mysoc->name)."\n"; $message.= "\n"; $message.= $mesg; - if ($link) $message.= "\n" . $urlwithroot . $link; // if link is already added around the ref into the translation text, then $link must be set to '' $message = nl2br($message); From 4d50ba5e370a57c7168e6f4cd2dd4f336fe3d361 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Mon, 11 May 2020 20:42:47 +0200 Subject: [PATCH 28/58] Fix dolistore search with csrf active --- htdocs/admin/dolistore/ajax/image.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/htdocs/admin/dolistore/ajax/image.php b/htdocs/admin/dolistore/ajax/image.php index c1bb4e997dc..6349c7461b5 100644 --- a/htdocs/admin/dolistore/ajax/image.php +++ b/htdocs/admin/dolistore/ajax/image.php @@ -1,6 +1,7 @@ . * Copyright (C) 2008-2011 Laurent Destailleur + * Copyright (C) 2020 Frédéric France * * This program is free software; you can redistribute it and/or modifyion 2.0 (the "License"); * it under the terms of the GNU General Public License as published bypliance with the License. @@ -17,6 +18,9 @@ */ if (!defined('REQUIRE_JQUERY_BLOCKUI')) define('REQUIRE_JQUERY_BLOCKUI', 1); +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', 1); +} /** From fc2f2c6da71b6c4f7f0b16216f0fba320b52ba1d Mon Sep 17 00:00:00 2001 From: gauthier Date: Tue, 12 May 2020 17:41:21 +0200 Subject: [PATCH 29/58] FIX : wrong url param --- htdocs/compta/facture/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 9fa696c69b3..cb3aa9cd099 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -4837,7 +4837,7 @@ elseif ($id > 0 || ! empty($ref)) { if (! $objectidnext) { - print ''; + print ''; } } From bd3504c4731f68e271ce2de4b4e1183e07b8b8ee Mon Sep 17 00:00:00 2001 From: Florian Mortgat Date: Wed, 13 May 2020 10:26:44 +0200 Subject: [PATCH 30/58] FIX 9.0 - delete unused mandatory argument from migrate_clean_association: argument count mismatch causes a fatal error since php7 --- htdocs/install/upgrade2.php | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/htdocs/install/upgrade2.php b/htdocs/install/upgrade2.php index cf2a0353b4a..58e6bfb3634 100644 --- a/htdocs/install/upgrade2.php +++ b/htdocs/install/upgrade2.php @@ -3605,10 +3605,9 @@ function migrate_mode_reglement($db,$langs,$conf) * @param DoliDB $db Database handler * @param Translate $langs Object langs * @param Conf $conf Object conf - * @param string $versionto Version target * @return void */ -function migrate_clean_association($db,$langs,$conf,$versionto) +function migrate_clean_association($db, $langs, $conf) { $result = $db->DDLDescTable(MAIN_DB_PREFIX."categorie_association"); if ($result) // result defined for version 3.2 or - From 3811586cd0654ef0d99c6369177d7b96cf35b50d Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 14 May 2020 20:34:48 +0200 Subject: [PATCH 31/58] FIX Site ec.europa.eu has moved to https:// --- htdocs/societe/checkvat/checkVatPopup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/societe/checkvat/checkVatPopup.php b/htdocs/societe/checkvat/checkVatPopup.php index 689df14f3d7..e1f940cfab8 100644 --- a/htdocs/societe/checkvat/checkVatPopup.php +++ b/htdocs/societe/checkvat/checkVatPopup.php @@ -28,9 +28,9 @@ require_once NUSOAP_PATH.'/nusoap.php'; $langs->load("companies"); //http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl -$WS_DOL_URL='http://ec.europa.eu/taxation_customs/vies/services/checkVatService'; +$WS_DOL_URL='https://ec.europa.eu/taxation_customs/vies/services/checkVatService'; //$WS_DOL_URL_WSDL=$WS_DOL_URL.'?wsdl'; -$WS_DOL_URL_WSDL='http://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'; +$WS_DOL_URL_WSDL='https://ec.europa.eu/taxation_customs/vies/checkVatService.wsdl'; $WS_METHOD ='checkVat'; From 54af917afb333d91300fc2203914d3231896dd08 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Sat, 16 May 2020 20:04:07 +0200 Subject: [PATCH 32/58] Fix cron globals reload, missing mysoc and langs --- scripts/cron/cron_run_jobs.php | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/cron/cron_run_jobs.php b/scripts/cron/cron_run_jobs.php index 635c128a89f..104443feba1 100755 --- a/scripts/cron/cron_run_jobs.php +++ b/scripts/cron/cron_run_jobs.php @@ -191,11 +191,12 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs)>0)) // Force reload of setup for the current entity if ($line->entity != $conf->entity) { - dol_syslog("cron_run_jobs.php we work on another entity so we reload user and conf", LOG_DEBUG); - echo " -> we change entity so we reload user and conf"; + dol_syslog("cron_run_jobs.php we work on another entity so we reload mysoc, langs, user and conf", LOG_DEBUG); + echo " -> we change entity so we reload mysoc, langs, user and conf"; $conf->entity = (empty($line->entity)?1:$line->entity); $conf->setValues($db); // This make also the $mc->setValues($conf); that reload $mc->sharings + $mysoc->setMysoc($conf); // Force recheck that user is ok for the entity to process and reload permission for entity if ($conf->entity != $user->entity && $user->entity != 0) @@ -218,6 +219,11 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs)>0)) } $user->getrights(); } + + // Reload langs + $langcode = (empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT); + if (! empty($user->conf->MAIN_LANG_DEFAULT)) $langcode = $user->conf->MAIN_LANG_DEFAULT; + if($langs->getDefaultLang() != $langcode) $langs->setDefaultLang($langcode); } //If date_next_jobs is less of current date, execute the program, and store the execution time of the next execution in database From cf96383bf92b93b6492ba89172c00b0f8caf4262 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 18 May 2020 10:44:55 +0200 Subject: [PATCH 33/58] Fix : entity was missing in actioncomm fetch --- htdocs/comm/action/class/actioncomm.class.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 98b910fdfca..1d86f1eba08 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -572,6 +572,7 @@ class ActionComm extends CommonObject $sql = "SELECT a.id,"; $sql.= " a.id as ref,"; + $sql.= " a.entity,"; $sql.= " a.ref_ext,"; $sql.= " a.datep,"; $sql.= " a.datep2,"; @@ -608,6 +609,7 @@ class ActionComm extends CommonObject $obj = $this->db->fetch_object($resql); $this->id = $obj->id; + $this->entity = $obj->entity; $this->ref = $obj->ref; $this->ref_ext = $obj->ref_ext; From 3d9d5d0ad522a76a65d8a9daaf35b2b693c5a138 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 18 May 2020 11:03:32 +0200 Subject: [PATCH 34/58] Fix : entity was missing in expedition fetch --- htdocs/expedition/class/expedition.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/expedition/class/expedition.class.php b/htdocs/expedition/class/expedition.class.php index 70e3683b22c..838cbd87152 100644 --- a/htdocs/expedition/class/expedition.class.php +++ b/htdocs/expedition/class/expedition.class.php @@ -527,7 +527,7 @@ class Expedition extends CommonObject // Check parameters if (empty($id) && empty($ref) && empty($ref_ext) && empty($ref_int)) return -1; - $sql = "SELECT e.rowid, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut, e.fk_projet, e.billed"; + $sql = "SELECT e.rowid, e.entity, e.ref, e.fk_soc as socid, e.date_creation, e.ref_customer, e.ref_ext, e.ref_int, e.fk_user_author, e.fk_statut, e.fk_projet, e.billed"; $sql.= ", e.weight, e.weight_units, e.size, e.size_units, e.width, e.height"; $sql.= ", e.date_expedition as date_expedition, e.model_pdf, e.fk_address, e.date_delivery"; $sql.= ", e.fk_shipping_method, e.tracking_number"; @@ -555,6 +555,7 @@ class Expedition extends CommonObject $obj = $this->db->fetch_object($result); $this->id = $obj->rowid; + $this->entity = $obj->entity; $this->ref = $obj->ref; $this->socid = $obj->socid; $this->ref_customer = $obj->ref_customer; From a9d1519f966163a092a6d994fe6cbb13f472090d Mon Sep 17 00:00:00 2001 From: ptibogxiv Date: Mon, 18 May 2020 14:52:33 +0200 Subject: [PATCH 35/58] FIX php error if multicompany disabled --- htdocs/compta/paiement/card.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/paiement/card.php b/htdocs/compta/paiement/card.php index 848cc20d483..27086713b07 100644 --- a/htdocs/compta/paiement/card.php +++ b/htdocs/compta/paiement/card.php @@ -342,7 +342,7 @@ if ($resql) print ''; print ''; print ''; - if($conf->global->MULTICOMPANY_INVOICE_SHARING_ENABLED )print ''; + if (!empty($conf->multicompany->enabled) && $conf->global->MULTICOMPANY_INVOICE_SHARING_ENABLED ) print ''; print ''; print ''; print ''; @@ -379,7 +379,7 @@ if ($resql) print ''; // Expected to pay - if($conf->global->MULTICOMPANY_INVOICE_SHARING_ENABLED ){ + if(!empty($conf->multicompany->enabled) && $conf->global->MULTICOMPANY_INVOICE_SHARING_ENABLED ){ print 'situation_cycle_ref) { print ''; - print ''; + print ''; } if ($usemargins && ! empty($conf->margin->enabled) && empty($user->societe_id)) diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 64e81e30329..fe0eaff767a 100755 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -475,6 +475,11 @@ UPDATE llx_accounting_bookkeeping set date_creation = tms where date_creation IS -- UPDATE llx_facturedet_rec set label = NULL WHERE label IS NOT NULL; +-- Test inconsistency of data into situation invoices: If it differs, it may be the total_ht that is wrong and situation_percent that is good. +-- select f.rowid, f.type, qty, subprice, situation_percent, total_ht, total_ttc, total_tva, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, (situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) +-- from llx_facturedet as fd, llx_facture as f where fd.fk_facture = f.rowid AND (total_ht - situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) > 0.01 and f.type = 5; + + -- Note to migrate from old counter aquarium to new one -- drop table tmp; diff --git a/htdocs/langs/en_US/bills.lang b/htdocs/langs/en_US/bills.lang index ddef01b17c1..3f6dc358d2f 100644 --- a/htdocs/langs/en_US/bills.lang +++ b/htdocs/langs/en_US/bills.lang @@ -554,4 +554,5 @@ AutoFillDateFromShort=Set start date AutoFillDateTo=Set end date for service line with next invoice date AutoFillDateToShort=Set end date MaxNumberOfGenerationReached=Max number of gen. reached -BILL_DELETEInDolibarr=Invoice deleted \ No newline at end of file +BILL_DELETEInDolibarr=Invoice deleted +UnitPriceXQtyLessDiscount=Unit price x Qty - Discount \ No newline at end of file From f89195e39fe015adc14bdcd9aa61414fd75babf4 Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Thu, 21 May 2020 23:23:59 +0200 Subject: [PATCH 39/58] Fix SQL IF for PGSQL --- htdocs/margin/tabs/productMargins.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/margin/tabs/productMargins.php b/htdocs/margin/tabs/productMargins.php index 57eef531342..4551557e95a 100644 --- a/htdocs/margin/tabs/productMargins.php +++ b/htdocs/margin/tabs/productMargins.php @@ -136,9 +136,9 @@ if ($id > 0 || ! empty($ref)) $sql.= " f.datef, f.paye, f.fk_statut as statut, f.type,"; if (!$user->rights->societe->client->voir && !$socid) $sql.= " sc.fk_soc, sc.fk_user,"; $sql.= " sum(d.total_ht) as selling_price,"; // may be negative or positive - $sql.= " IF(f.type = 2, -1, 1) * sum(d.qty) as qty,"; // not always positive in case of Credit note - $sql.= " IF(f.type = 2, -1, 1) * sum(d.qty * d.buy_price_ht) as buying_price,"; // not always positive in case of Credit note - $sql.= " IF(f.type = 2, -1, 1) * sum(abs(d.total_ht) - (d.buy_price_ht * d.qty)) as marge" ; // not always positive in case of Credit note + $sql.= " ".$db->ifsql('f.type = 2', -1, 1)." * sum(d.qty) as qty,"; // not always positive in case of Credit note + $sql.= " ".$db->ifsql('f.type = 2', -1, 1)." * sum(d.qty * d.buy_price_ht) as buying_price,"; // not always positive in case of Credit note + $sql.= " ".$db->ifsql('f.type = 2', -1, 1)." * sum(abs(d.total_ht) - (d.buy_price_ht * d.qty)) as marge" ; // not always positive in case of Credit note $sql.= " FROM ".MAIN_DB_PREFIX."societe as s"; $sql.= ", ".MAIN_DB_PREFIX."facture as f"; $sql.= ", ".MAIN_DB_PREFIX."facturedet as d"; From 6434f255c32d444c744bb5fba96f547d85e73f0c Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Fri, 22 May 2020 00:32:55 +0200 Subject: [PATCH 40/58] Fix load_state_board doesn't take parameters --- htdocs/index.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/index.php b/htdocs/index.php index 5eee02efa1e..944701fe0d1 100644 --- a/htdocs/index.php +++ b/htdocs/index.php @@ -324,7 +324,7 @@ if (empty($user->societe_id)) include_once $includes[$key]; // Loading a class cost around 1Mb $board=new $classe($db); - $board->load_state_board($user); + $board->load_state_board(); $boardloaded[$classe]=$board; } else From fb0f31c142cad7df1da3fc85190aab10c274e14d Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Fri, 22 May 2020 00:33:30 +0200 Subject: [PATCH 41/58] Fix board filters for expense report and holiday --- .../class/expensereport.class.php | 20 +++++++++++++------ htdocs/holiday/class/holiday.class.php | 18 +++++++++++++---- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/htdocs/expensereport/class/expensereport.class.php b/htdocs/expensereport/class/expensereport.class.php index 2dddac4dbab..bb543642733 100644 --- a/htdocs/expensereport/class/expensereport.class.php +++ b/htdocs/expensereport/class/expensereport.class.php @@ -970,7 +970,7 @@ class ExpenseReport extends CommonObject { // phpcs:enable global $conf; - + $this->lines=array(); $sql = ' SELECT de.rowid, de.comments, de.qty, de.value_unit, de.date, de.rang,'; @@ -2274,7 +2274,7 @@ class ExpenseReport extends CommonObject public function load_state_board() { // phpcs:enable - global $conf; + global $conf, $user; $this->nb=array(); @@ -2282,6 +2282,12 @@ class ExpenseReport extends CommonObject $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex"; $sql.= " WHERE ex.fk_statut > 0"; $sql.= " AND ex.entity IN (".getEntity('expensereport').")"; + if(!$user->rights->expensereport->readall) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; + $sql.= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + } $resql=$this->db->query($sql); if ($resql) { @@ -2316,15 +2322,17 @@ class ExpenseReport extends CommonObject $now=dol_now(); - $userchildids = $user->getAllChildIds(1); - $sql = "SELECT ex.rowid, ex.date_valid"; $sql.= " FROM ".MAIN_DB_PREFIX."expensereport as ex"; if ($option == 'toapprove') $sql.= " WHERE ex.fk_statut = 2"; else $sql.= " WHERE ex.fk_statut = 5"; $sql.= " AND ex.entity IN (".getEntity('expensereport').")"; - $sql.= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; - $sql.= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + if(!$user->rights->expensereport->readall) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (ex.fk_user_author IN (".join(',', $userchildids).")"; + $sql.= " OR ex.fk_user_validator IN (".join(',', $userchildids)."))"; + } $resql=$this->db->query($sql); if ($resql) diff --git a/htdocs/holiday/class/holiday.class.php b/htdocs/holiday/class/holiday.class.php index 25f1d9675bb..1d818d33c1f 100644 --- a/htdocs/holiday/class/holiday.class.php +++ b/htdocs/holiday/class/holiday.class.php @@ -2182,12 +2182,20 @@ class Holiday extends CommonObject public function load_state_board() { // phpcs:enable + global $user; + $this->nb=array(); $sql = "SELECT count(h.rowid) as nb"; $sql.= " FROM ".MAIN_DB_PREFIX."holiday as h"; $sql.= " WHERE h.statut > 1"; $sql.= " AND h.entity IN (".getEntity('holiday').")"; + if(!$user->rights->expensereport->read_all) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; + $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + } $resql=$this->db->query($sql); if ($resql) { @@ -2221,14 +2229,16 @@ class Holiday extends CommonObject $now=dol_now(); - $userchildids = $user->getAllChildIds(1); - $sql = "SELECT h.rowid, h.date_debut"; $sql.= " FROM ".MAIN_DB_PREFIX."holiday as h"; $sql.= " WHERE h.statut = 2"; $sql.= " AND h.entity IN (".getEntity('holiday').")"; - $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; - $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + if(!$user->rights->expensereport->read_all) + { + $userchildids = $user->getAllChildIds(1); + $sql.= " AND (h.fk_user IN (".join(',', $userchildids).")"; + $sql.= " OR h.fk_validator IN (".join(',', $userchildids)."))"; + } $resql=$this->db->query($sql); if ($resql) From 2595f571c74ef424add3c3ca687b769f90df3cb0 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 25 May 2020 00:21:09 +0200 Subject: [PATCH 42/58] Fix exclude credit note when searching situation invoice to use for next --- htdocs/core/class/html.form.class.php | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index acbd15712e5..ec7bfeab7c4 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -3582,10 +3582,11 @@ class Form $opt = ''; $sql = 'SELECT rowid, ref, situation_cycle_ref, situation_counter, situation_final, fk_soc'; - $sql.= ' FROM ' . MAIN_DB_PREFIX . 'facture'; - $sql.= ' WHERE entity IN ('.getEntity('invoice').')'; - $sql.= ' AND situation_counter>=1'; - $sql.= ' ORDER by situation_cycle_ref, situation_counter desc'; + $sql .= ' FROM ' . MAIN_DB_PREFIX . 'facture'; + $sql .= ' WHERE entity IN ('.getEntity('invoice').')'; + $sql .= ' AND situation_counter>=1'; + $sql .= ' AND type <> 2'; + $sql .= ' ORDER by situation_cycle_ref, situation_counter desc'; $resql = $this->db->query($sql); if ($resql && $this->db->num_rows($resql) > 0) { // Last seen cycle From 954c29786e7102c7cf3bf771e42d00d5eb81933d Mon Sep 17 00:00:00 2001 From: Florian Mortgat Date: Wed, 27 May 2020 12:15:42 +0200 Subject: [PATCH 43/58] FIX 10.0 - pagination in prelevement/bons.php --- htdocs/compta/prelevement/bons.php | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/prelevement/bons.php b/htdocs/compta/prelevement/bons.php index 27654de1ad0..b5610b81f68 100644 --- a/htdocs/compta/prelevement/bons.php +++ b/htdocs/compta/prelevement/bons.php @@ -36,7 +36,10 @@ $socid = GETPOST('socid', 'int'); if ($user->societe_id) $socid=$user->societe_id; $result = restrictedArea($user, 'prelevement', '', '', 'bons'); +$urladd = ''; $limit = GETPOST('limit', 'int')?GETPOST('limit', 'int'):$conf->liste_limit; +if ($limit != $conf->liste_limit) $urladd .= '&limit=' . $limit; + $sortfield = GETPOST('sortfield', 'alpha'); $sortorder = GETPOST('sortorder', 'alpha'); $page = GETPOST('page', 'int'); @@ -102,7 +105,7 @@ if ($result) $num = $db->num_rows($result); $i = 0; - $urladd= "&statut=".$statut; + $urladd .= "&statut=" . $statut; $selectedfields=''; From 1e208e537f12cf9be59655c728a64ab38df9e39a Mon Sep 17 00:00:00 2001 From: kamel Date: Fri, 29 May 2020 16:24:07 +0200 Subject: [PATCH 44/58] FIX: Fix link of the button to create a credit note and fix the awareness of a error happen when to create a credit note --- htdocs/compta/facture/card.php | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index cb3aa9cd099..b97d22631a1 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -1106,12 +1106,12 @@ if (empty($reshook)) } // Add link between credit note and origin - if(! empty($object->fk_facture_source)) { + if(! empty($object->fk_facture_source) && $id>0) { $facture_source->fetch($object->fk_facture_source); $facture_source->fetchObjectLinked(); - if(! empty($facture_source->linkedObjectsIds)) { - foreach($facture_source->linkedObjectsIds as $sourcetype => $TIds) { + if (!empty($facture_source->linkedObjectsIds)) { + foreach ($facture_source->linkedObjectsIds as $sourcetype => $TIds) { $object->add_object_linked($sourcetype, current($TIds)); } } @@ -4835,9 +4835,8 @@ elseif ($id > 0 || ! empty($ref)) // Create a credit note if (($object->type == Facture::TYPE_STANDARD || $object->type == Facture::TYPE_DEPOSIT || $object->type == Facture::TYPE_PROFORMA) && $object->statut > 0 && $usercancreate) { - if (! $objectidnext) - { - print ''; + if (! $objectidnext) { + print ''; } } From 68bb552dcceb7570c9c23d4208c932eb67161970 Mon Sep 17 00:00:00 2001 From: gauthier Date: Tue, 2 Jun 2020 17:06:49 +0200 Subject: [PATCH 45/58] FIX : Tickets mail models doesn't work --- htdocs/admin/mails_templates.php | 1 + htdocs/core/class/html.formticket.class.php | 4 +--- htdocs/langs/en_US/admin.lang | 3 ++- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index b5f22376c16..85cb5971652 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -166,6 +166,7 @@ if ($conf->societe->enabled) $elementList['thirdparty']=$langs->trans( if ($conf->adherent->enabled) $elementList['member']=$langs->trans('MailToMember'); if ($conf->contrat->enabled) $elementList['contract']=$langs->trans('MailToSendContract'); if ($conf->projet->enabled) $elementList['project']=$langs->trans('MailToProject'); +if ($conf->ticket->enabled) $elementList['ticket_send']=$langs->trans('MailToTicket'); $elementList['user']=$langs->trans('MailToUser'); $parameters=array('elementList'=>$elementList); diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 1e51d54f37e..72673abb323 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -991,9 +991,7 @@ class FormTicket // MESSAGE $defaultmessage=""; - if (is_array($arraydefaultmessage) && count($arraydefaultmessage) > 0 && $arraydefaultmessage->content) { - $defaultmessage=$arraydefaultmessage->content; - } + if ($arraydefaultmessage && $arraydefaultmessage->content) $defaultmessage = $arraydefaultmessage->content; $defaultmessage=str_replace('\n', "\n", $defaultmessage); // Deal with format differences between message and signature (text / HTML) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 64dac1f39e5..5378ef5729d 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1792,6 +1792,7 @@ MailToThirdparty=Third parties MailToMember=Members MailToUser=Users MailToProject=Projects page +MailToTicket=Tickets ByDefaultInList=Show by default on list view YouUseLastStableVersion=You use the latest stable version TitleExampleForMajorRelease=Example of message you can use to announce this major release (feel free to use it on your web sites) @@ -1923,4 +1924,4 @@ DeleteEmailCollector=Delete email collector ConfirmDeleteEmailCollector=Are you sure you want to delete this email collector? RecipientEmailsWillBeReplacedWithThisValue=Recipient emails will be always replaced with this value AtLeastOneDefaultBankAccountMandatory=At least 1 default bank account must be defined -FeatureNotAvailableWithReceptionModule=Feature not available when module Reception is enabled \ No newline at end of file +FeatureNotAvailableWithReceptionModule=Feature not available when module Reception is enabled From 9e5c7d0acf2c39788fdd90fd5dc8dce8d87cf12f Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Wed, 3 Jun 2020 23:00:53 +0200 Subject: [PATCH 46/58] FIX: Show ref_customer, amount on contract link object --- htdocs/core/class/html.form.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index ec7bfeab7c4..e25f3099ad1 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6671,7 +6671,7 @@ class Form 'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande').')'), 'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'), 'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'), - 'contrat'=>array('enabled'=>$conf->contrat->enabled , 'perms'=>1, 'label'=>'LinkToContract', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, '' as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'), + 'contrat'=>array('enabled'=>$conf->contrat->enabled , 'perms'=>1, 'label'=>'LinkToContract', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, td.total_ht as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_DB_PREFIX."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'), 'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('intervention').')'), 'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled , 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('supplier_proposal').')'), 'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled , 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande_fournisseur').')'), From ede084a1117c0aca753db35da0ec505cc346ba25 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 4 Jun 2020 05:11:00 +0200 Subject: [PATCH 47/58] Fix stickler --- htdocs/core/class/html.form.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index e25f3099ad1..627e5ee8a2b 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -6671,7 +6671,8 @@ class Form 'order'=>array('enabled'=>$conf->commande->enabled, 'perms'=>1, 'label'=>'LinkToOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande').')'), 'invoice'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_client, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'), 'invoice_template'=>array('enabled'=>$conf->facture->enabled, 'perms'=>1, 'label'=>'LinkToTemplateInvoice', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.titre as ref, t.total as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."facture_rec as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('invoice').')'), - 'contrat'=>array('enabled'=>$conf->contrat->enabled , 'perms'=>1, 'label'=>'LinkToContract', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, td.total_ht as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_DB_PREFIX."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'), + 'contrat'=>array('enabled'=>$conf->contrat->enabled , 'perms'=>1, 'label'=>'LinkToContract', + 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_customer as ref_client, t.ref_supplier, td.total_ht as total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as t, ".MAIN_DB_PREFIX."contratdet as td WHERE t.fk_soc = s.rowid AND td.fk_contrat = t.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('contract').')'), 'fichinter'=>array('enabled'=>$conf->ficheinter->enabled, 'perms'=>1, 'label'=>'LinkToIntervention', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('intervention').')'), 'supplier_proposal'=>array('enabled'=>$conf->supplier_proposal->enabled , 'perms'=>1, 'label'=>'LinkToSupplierProposal', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, '' as ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."supplier_proposal as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('supplier_proposal').')'), 'order_supplier'=>array('enabled'=>$conf->supplier_order->enabled , 'perms'=>1, 'label'=>'LinkToSupplierOrder', 'sql'=>"SELECT s.rowid as socid, s.nom as name, s.client, t.rowid, t.ref, t.ref_supplier, t.total_ht FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."commande_fournisseur as t WHERE t.fk_soc = s.rowid AND t.fk_soc IN (".$listofidcompanytoscan.') AND t.entity IN ('.getEntity('commande_fournisseur').')'), From c393f8149c27a437d7c963d9a5d140a024556a8f Mon Sep 17 00:00:00 2001 From: Florian Mortgat Date: Thu, 4 Jun 2020 11:29:51 +0200 Subject: [PATCH 48/58] FIX: when creating a VariousPayment, the value date is not copied onto the AccountLine that gets created at the same time, so the bank transaction's value date will be the payment date instead of the payment's value date --- htdocs/compta/bank/class/paymentvarious.class.php | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/bank/class/paymentvarious.class.php b/htdocs/compta/bank/class/paymentvarious.class.php index aea51e1a544..9a98ed3fc73 100644 --- a/htdocs/compta/bank/class/paymentvarious.class.php +++ b/htdocs/compta/bank/class/paymentvarious.class.php @@ -422,7 +422,11 @@ class PaymentVarious extends CommonObject $sign * abs($this->amount), $this->num_payment, ($this->category_transaction > 0 ? $this->category_transaction : 0), - $user + $user, + '', + '', + '', + $this->datev ); // Update fk_bank into llx_paiement. From ded7b79a6f69544cbf7b1fe4ab09b83246012191 Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Fri, 5 Jun 2020 12:10:03 +0200 Subject: [PATCH 49/58] FIX free text on cash desk --- htdocs/takepos/admin/setup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/takepos/admin/setup.php b/htdocs/takepos/admin/setup.php index f331587723b..e6db38716bc 100644 --- a/htdocs/takepos/admin/setup.php +++ b/htdocs/takepos/admin/setup.php @@ -74,8 +74,8 @@ if (GETPOST('action', 'alpha') == 'set') $res = dolibarr_set_const($db, "TAKEPOS_ORDER_PRINTERS", GETPOST('TAKEPOS_ORDER_PRINTERS', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_ORDER_NOTES", GETPOST('TAKEPOS_ORDER_NOTES', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_AUTO_PRINT_TICKETS", GETPOST('TAKEPOS_AUTO_PRINT_TICKETS', 'int'), 'int', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'alpha'), 'chaine', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'alpha'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'none'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'none'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUMPAD", GETPOST('TAKEPOS_NUMPAD', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUM_TERMINALS", GETPOST('TAKEPOS_NUM_TERMINALS', 'alpha'), 'chaine', 0, '', $conf->entity); From e5f8f38fbf374085c0ac3e0582b253bc51db5fda Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Fri, 5 Jun 2020 17:24:59 +0200 Subject: [PATCH 50/58] FIX: Accountancy - Binding index - Add a filter on sql request for module Subtotal & Jalon --- htdocs/accountancy/customer/index.php | 4 ++++ htdocs/accountancy/supplier/index.php | 3 +++ 2 files changed, 7 insertions(+) diff --git a/htdocs/accountancy/customer/index.php b/htdocs/accountancy/customer/index.php index ab2c00d13b0..b38606dc787 100644 --- a/htdocs/accountancy/customer/index.php +++ b/htdocs/accountancy/customer/index.php @@ -252,6 +252,7 @@ $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'"; $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND f.fk_statut > 0"; +$sql .= " AND fd.product_type <= 2"; $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy $sql .= " AND aa.account_number IS NULL"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { @@ -329,6 +330,7 @@ $sql .= " WHERE f.datef >= '" . $db->idate($search_date_start) . "'"; $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy $sql .= " AND f.fk_statut > 0"; +$sql .= " AND fd.product_type <= 2"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; } else { @@ -406,6 +408,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL > 0) // This part of code looks strange. $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy $sql .= " AND f.fk_statut > 0"; + $sql .= " AND fd.product_type <= 2"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; } else { @@ -458,6 +461,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL > 0) // This part of code looks strange. $sql .= " AND f.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND f.entity IN (" . getEntity('invoice', 0) . ")"; // We don't share object for accountancy $sql .= " AND f.fk_statut > 0"; + $sql .= " AND fd.product_type <= 2"; if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; } else { diff --git a/htdocs/accountancy/supplier/index.php b/htdocs/accountancy/supplier/index.php index eb81e4909d9..9ce820deff9 100644 --- a/htdocs/accountancy/supplier/index.php +++ b/htdocs/accountancy/supplier/index.php @@ -250,6 +250,7 @@ $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid $sql .= " WHERE ff.datef >= '" . $db->idate($search_date_start) . "'"; $sql .= " AND ff.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND ff.fk_statut > 0"; +$sql .= " AND ffd.product_type <= 2"; $sql .= " AND ff.entity IN (" . getEntity('facture_fourn', 0) . ")"; // We don't share object for accountancy $sql .= " AND aa.account_number IS NULL"; $sql .= " GROUP BY ffd.fk_code_ventilation,aa.account_number,aa.label"; @@ -321,6 +322,7 @@ $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON aa.rowid $sql .= " WHERE ff.datef >= '" . $db->idate($search_date_start) . "'"; $sql .= " AND ff.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND ff.fk_statut > 0"; +$sql .= " AND ffd.product_type <= 2"; $sql .= " AND ff.entity IN (" . getEntity('facture_fourn', 0) . ")"; // We don't share object for accountancy $sql .= " AND aa.account_number IS NOT NULL"; $sql .= " GROUP BY ffd.fk_code_ventilation,aa.account_number,aa.label"; @@ -392,6 +394,7 @@ if ($conf->global->MAIN_FEATURES_LEVEL > 0) // This part of code looks strange. $sql .= " WHERE ff.datef >= '" . $db->idate($search_date_start) . "'"; $sql .= " AND ff.datef <= '" . $db->idate($search_date_end) . "'"; $sql .= " AND ff.fk_statut > 0"; + $sql .= " AND ffd.product_type <= 2"; $sql .= " AND ff.entity IN (" . getEntity('facture_fourn', 0) . ")"; // We don't share object for accountancy dol_syslog('htdocs/accountancy/supplier/index.php'); From 30c6ae394b9d4d1bb6ce3c1405e91d94fba77bdb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 6 Jun 2020 21:23:35 +0200 Subject: [PATCH 51/58] Update html.formticket.class.php --- htdocs/core/class/html.formticket.class.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 72673abb323..7a6b4ec38a2 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -991,7 +991,9 @@ class FormTicket // MESSAGE $defaultmessage=""; - if ($arraydefaultmessage && $arraydefaultmessage->content) $defaultmessage = $arraydefaultmessage->content; + if (is_array($arraydefaultmessage) && count($arraydefaultmessage) > 0 && $arraydefaultmessage->content) { + $defaultmessage=$arraydefaultmessage->content; + } $defaultmessage=str_replace('\n', "\n", $defaultmessage); // Deal with format differences between message and signature (text / HTML) From 180a0a45572b038f4234ac336752d8ffb50a8b56 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 7 Jun 2020 18:30:46 +0200 Subject: [PATCH 52/58] Info for debug --- htdocs/compta/facture/class/facture.class.php | 5 +++-- htdocs/install/mysql/migration/repair.sql | 2 +- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 1558b6cbfab..12d60b067fa 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -1584,7 +1584,8 @@ class Facture extends CommonInvoice } /** - * Fetch previous and next situations invoices + * Fetch previous and next situations invoices. + * Return all previous and next invoices (both standard and credit notes). * * @return void */ @@ -1595,7 +1596,7 @@ class Facture extends CommonInvoice $this->tab_previous_situation_invoice = array(); $this->tab_next_situation_invoice = array(); - $sql = 'SELECT rowid, situation_counter FROM '.MAIN_DB_PREFIX.'facture WHERE rowid <> '.$this->id.' AND entity = '.$conf->entity.' AND situation_cycle_ref = '.(int) $this->situation_cycle_ref.' ORDER BY situation_counter ASC'; + $sql = 'SELECT rowid, type, situation_cycle_ref, situation_counter FROM '.MAIN_DB_PREFIX.'facture WHERE rowid <> '.$this->id.' AND entity = '.$conf->entity.' AND situation_cycle_ref = '.(int) $this->situation_cycle_ref.' ORDER BY situation_counter ASC'; dol_syslog(get_class($this).'::fetchPreviousNextSituationInvoice ', LOG_DEBUG); $result = $this->db->query($sql); diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index fe0eaff767a..86c37198347 100755 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -476,7 +476,7 @@ UPDATE llx_accounting_bookkeeping set date_creation = tms where date_creation IS -- Test inconsistency of data into situation invoices: If it differs, it may be the total_ht that is wrong and situation_percent that is good. --- select f.rowid, f.type, qty, subprice, situation_percent, total_ht, total_ttc, total_tva, multicurrency_total_ht, multicurrency_total_tva, multicurrency_total_ttc, (situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) +-- select f.rowid, f.type, fd.qty, fd.subprice, fd.situation_percent, fd.total_ht, fd.total_ttc, fd.total_tva, fd.multicurrency_total_ht, fd.multicurrency_total_tva, fd.multicurrency_total_ttc, (situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) -- from llx_facturedet as fd, llx_facture as f where fd.fk_facture = f.rowid AND (total_ht - situation_percent / 100 * subprice * qty * (1 - (fd.remise_percent / 100))) > 0.01 and f.type = 5; From 4020d9736206f97ed880fb4737623da5bc87f561 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 7 Jun 2020 18:36:58 +0200 Subject: [PATCH 53/58] FIX Can create a credit note on situation invoice if previous is also credit note --- htdocs/compta/facture/card.php | 63 +++++++++++++++++++++++++++------- 1 file changed, 50 insertions(+), 13 deletions(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index b97d22631a1..a134afba603 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -990,6 +990,11 @@ if (empty($reshook)) } $id = $object->create($user); + // NOTE: Pb with situation invoice + // NOTE: fields total on situation invoice are stored as cumulative values on total of lines (bad) but delta on invoice total + // NOTE: fields total on credit note are stored as delta both on total of lines and on invoice total (good) + // NOTE: fields situation_percent on situation invoice are stored as cumulative values on lines (bad) + // NOTE: fields situation_percent on credit note are stored as delta on lines (good) if (GETPOST('invoiceAvoirWithLines', 'int')==1 && $id>0) { if (!empty($facture_source->lines)) @@ -1010,36 +1015,38 @@ if (empty($reshook)) } - - - if($facture_source->type == Facture::TYPE_SITUATION) + if ($facture_source->type == Facture::TYPE_SITUATION) { $source_fk_prev_id = $line->fk_prev_id; // temporary storing situation invoice fk_prev_id - $line->fk_prev_id = $line->id; // Credit note line need to be linked to the situation invoice it is create from + $line->fk_prev_id = $line->id; // The new line of the new credit note we are creating must be linked to the situation invoice line it is created from - if(!empty($facture_source->tab_previous_situation_invoice)) + if (!empty($facture_source->tab_previous_situation_invoice)) { - // search the last invoice in cycle - $lineIndex = count($facture_source->tab_previous_situation_invoice) - 1; + // search the last standard invoice in cycle and the possible credit note between this last and facture_source + // TODO Move this out of loop of $facture_source->lines + $tab_jumped_credit_notes = array(); + $lineIndex = count($facture_source->tab_previous_situation_invoice) - 1; $searchPreviousInvoice = true; - while( $searchPreviousInvoice ) + while ($searchPreviousInvoice) { - if($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) + if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_SITUATION || $lineIndex < 1) { $searchPreviousInvoice=false; // find, exit; break; } else { + if ($facture_source->tab_previous_situation_invoice[$lineIndex]->type == Facture::TYPE_CREDIT_NOTE) { + $tab_jumped_credit_notes[$lineIndex] = $facture_source->tab_previous_situation_invoice[$lineIndex]->id; + } $lineIndex--; // go to previous invoice in cycle } } - $maxPrevSituationPercent = 0; - foreach($facture_source->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) + foreach ($facture_source->tab_previous_situation_invoice[$lineIndex]->lines as $prevLine) { - if($prevLine->id == $source_fk_prev_id) + if ($prevLine->id == $source_fk_prev_id) { $maxPrevSituationPercent = max($maxPrevSituationPercent, $prevLine->situation_percent); @@ -1059,6 +1066,36 @@ if (empty($reshook)) // prorata $line->situation_percent = $maxPrevSituationPercent - $line->situation_percent; + + //print 'New line based on invoice id '.$facture_source->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'
'; + + // If there is some credit note between last situation invoice and invoice used for credit note generation (note: credit notes are stored as delta) + $maxPrevSituationPercent = 0; + foreach ($tab_jumped_credit_notes as $index => $creditnoteid) { + foreach ($facture_source->tab_previous_situation_invoice[$index]->lines as $prevLine) + { + if ($prevLine->fk_prev_id == $source_fk_prev_id) + { + $maxPrevSituationPercent = $prevLine->situation_percent; + + $line->total_ht -= $prevLine->total_ht; + $line->total_tva -= $prevLine->total_tva; + $line->total_ttc -= $prevLine->total_ttc; + $line->total_localtax1 -= $prevLine->total_localtax1; + $line->total_localtax2 -= $prevLine->total_localtax2; + + $line->multicurrency_subprice -= $prevLine->multicurrency_subprice; + $line->multicurrency_total_ht -= $prevLine->multicurrency_total_ht; + $line->multicurrency_total_tva -= $prevLine->multicurrency_total_tva; + $line->multicurrency_total_ttc -= $prevLine->multicurrency_total_ttc; + } + } + } + + // prorata + $line->situation_percent += $maxPrevSituationPercent; + + //print 'New line based on invoice id '.$facture_source->tab_previous_situation_invoice[$lineIndex]->id.' fk_prev_id='.$source_fk_prev_id.' will be fk_prev_id='.$line->fk_prev_id.' '.$line->total_ht.' '.$line->situation_percent.'
'; } } @@ -1078,7 +1115,7 @@ if (empty($reshook)) $line->multicurrency_total_tva = -$line->multicurrency_total_tva; $line->multicurrency_total_ttc = -$line->multicurrency_total_ttc; - $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount alreayd linked + $result = $line->insert(0, 1); // When creating credit note with same lines than source, we must ignore error if discount already linked $object->lines[] = $line; // insert new line in current object From 7bba9db2f0c5fc514414e269e9c48f920a0189cf Mon Sep 17 00:00:00 2001 From: VESSILLER Date: Mon, 8 Jun 2020 11:28:05 +0200 Subject: [PATCH 54/58] FIX replace filter parameter "none" by "restricthtml" --- htdocs/takepos/admin/setup.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/takepos/admin/setup.php b/htdocs/takepos/admin/setup.php index e6db38716bc..e79faf17de0 100644 --- a/htdocs/takepos/admin/setup.php +++ b/htdocs/takepos/admin/setup.php @@ -74,8 +74,8 @@ if (GETPOST('action', 'alpha') == 'set') $res = dolibarr_set_const($db, "TAKEPOS_ORDER_PRINTERS", GETPOST('TAKEPOS_ORDER_PRINTERS', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_ORDER_NOTES", GETPOST('TAKEPOS_ORDER_NOTES', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_AUTO_PRINT_TICKETS", GETPOST('TAKEPOS_AUTO_PRINT_TICKETS', 'int'), 'int', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'none'), 'chaine', 0, '', $conf->entity); - $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'none'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_HEADER", GETPOST('TAKEPOS_HEADER', 'restricthtml'), 'chaine', 0, '', $conf->entity); + $res = dolibarr_set_const($db, "TAKEPOS_FOOTER", GETPOST('TAKEPOS_FOOTER', 'restricthtml'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUMPAD", GETPOST('TAKEPOS_NUMPAD', 'alpha'), 'chaine', 0, '', $conf->entity); $res = dolibarr_set_const($db, "TAKEPOS_NUM_TERMINALS", GETPOST('TAKEPOS_NUM_TERMINALS', 'alpha'), 'chaine', 0, '', $conf->entity); From 0a2099e0ac22763d9f3f23dba6df03f6b50be7a5 Mon Sep 17 00:00:00 2001 From: Florian Mortgat Date: Tue, 9 Jun 2020 14:22:32 +0200 Subject: [PATCH 55/58] FIX 10.0 - undefined $langs if template file copy fails during activation of modContrat --- htdocs/core/modules/modContrat.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/modContrat.class.php b/htdocs/core/modules/modContrat.class.php index b3053cceae0..e29868e6994 100644 --- a/htdocs/core/modules/modContrat.class.php +++ b/htdocs/core/modules/modContrat.class.php @@ -214,7 +214,7 @@ class modContrat extends DolibarrModules */ public function init($options = '') { - global $conf; + global $conf, $langs; // Nettoyage avant activation $this->remove($options); From 92b89437d1e334ebdc0475b4394e099dc34f669a Mon Sep 17 00:00:00 2001 From: gauthier Date: Tue, 9 Jun 2020 16:02:41 +0200 Subject: [PATCH 56/58] FIX : percent must be displayed on one line --- htdocs/core/modules/facture/doc/pdf_crabe.modules.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php index ed99a04fcc2..d3ffe96d4f5 100644 --- a/htdocs/core/modules/facture/doc/pdf_crabe.modules.php +++ b/htdocs/core/modules/facture/doc/pdf_crabe.modules.php @@ -593,7 +593,7 @@ class pdf_crabe extends ModelePDFFactures { $progress = pdf_getlineprogress($object, $i, $outputlangs, $hidedetails); $pdf->SetXY($this->posxprogress, $curY); - $pdf->MultiCell($this->postotalht-$this->posxprogress-1, 3, $progress, 0, 'R'); + $pdf->MultiCell($this->postotalht-$this->posxprogress+1, 3, $progress, 0, 'R'); } // Total HT line From 58ff96af30546bf37256c5daced837e89a7decf4 Mon Sep 17 00:00:00 2001 From: gauthier Date: Wed, 10 Jun 2020 16:48:02 +0200 Subject: [PATCH 57/58] FIX : $arraydefaultmessage is an object, as well as in /htdocs/core/class/html.formmail.class.php --- htdocs/core/class/html.formticket.class.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 7a6b4ec38a2..72673abb323 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -991,9 +991,7 @@ class FormTicket // MESSAGE $defaultmessage=""; - if (is_array($arraydefaultmessage) && count($arraydefaultmessage) > 0 && $arraydefaultmessage->content) { - $defaultmessage=$arraydefaultmessage->content; - } + if ($arraydefaultmessage && $arraydefaultmessage->content) $defaultmessage = $arraydefaultmessage->content; $defaultmessage=str_replace('\n', "\n", $defaultmessage); // Deal with format differences between message and signature (text / HTML) From b36e658b20195e8797b52f1e25b60c584eb4e587 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Thu, 11 Jun 2020 22:58:58 +0200 Subject: [PATCH 58/58] Update html.formticket.class.php --- htdocs/core/class/html.formticket.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formticket.class.php b/htdocs/core/class/html.formticket.class.php index 72673abb323..60574d12d3c 100644 --- a/htdocs/core/class/html.formticket.class.php +++ b/htdocs/core/class/html.formticket.class.php @@ -991,7 +991,7 @@ class FormTicket // MESSAGE $defaultmessage=""; - if ($arraydefaultmessage && $arraydefaultmessage->content) $defaultmessage = $arraydefaultmessage->content; + if (is_object($arraydefaultmessage) && $arraydefaultmessage->content) $defaultmessage = $arraydefaultmessage->content; $defaultmessage=str_replace('\n', "\n", $defaultmessage); // Deal with format differences between message and signature (text / HTML)
'.$langs->trans('Bill').''.$langs->trans('Company').''.$langs->trans('Entity').''.$langs->trans('Entity').''.$langs->trans('ExpectedToPay').''.$langs->trans('PayedByThisPayment').''.$langs->trans('RemainderToPay').''; $mc->getInfo($objp->entity); print $mc->label; From 18a19dafe513942a8a099cac13e60303a7eb3dc1 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 18 May 2020 15:01:29 +0200 Subject: [PATCH 36/58] Update cron_run_jobs.php --- scripts/cron/cron_run_jobs.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/cron/cron_run_jobs.php b/scripts/cron/cron_run_jobs.php index 104443feba1..6438b13e884 100755 --- a/scripts/cron/cron_run_jobs.php +++ b/scripts/cron/cron_run_jobs.php @@ -223,7 +223,7 @@ if (is_array($qualifiedjobs) && (count($qualifiedjobs)>0)) // Reload langs $langcode = (empty($conf->global->MAIN_LANG_DEFAULT)?'auto':$conf->global->MAIN_LANG_DEFAULT); if (! empty($user->conf->MAIN_LANG_DEFAULT)) $langcode = $user->conf->MAIN_LANG_DEFAULT; - if($langs->getDefaultLang() != $langcode) $langs->setDefaultLang($langcode); + if ($langs->getDefaultLang() != $langcode) $langs->setDefaultLang($langcode); } //If date_next_jobs is less of current date, execute the program, and store the execution time of the next execution in database From 55def0248ce74e462536cdc7ad2b798e2fb1853b Mon Sep 17 00:00:00 2001 From: altairis Date: Wed, 20 May 2020 14:37:35 +0200 Subject: [PATCH 37/58] fix missing rollbacks --- htdocs/fourn/class/fournisseur.commande.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/fourn/class/fournisseur.commande.class.php b/htdocs/fourn/class/fournisseur.commande.class.php index 538af54fe23..092c3df8dc2 100644 --- a/htdocs/fourn/class/fournisseur.commande.class.php +++ b/htdocs/fourn/class/fournisseur.commande.class.php @@ -1815,7 +1815,6 @@ class CommandeFournisseur extends CommonOrder if ($result < 0) { $error++; - return -1; } // End call triggers } @@ -1923,6 +1922,7 @@ class CommandeFournisseur extends CommonOrder { $this->errors[]='ErrorWhenRunningTrigger'; dol_syslog(get_class($this)."::delete ".$this->error, LOG_ERR); + $this->db->rollback(); return -1; } // End call triggers From 434341316bbee837d24e168e7f261f2cff3ac451 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Wed, 20 May 2020 19:51:04 +0200 Subject: [PATCH 38/58] suggest some fix to debug situation invoices --- htdocs/core/tpl/objectline_title.tpl.php | 2 +- htdocs/install/mysql/migration/repair.sql | 5 +++++ htdocs/langs/en_US/bills.lang | 3 ++- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/htdocs/core/tpl/objectline_title.tpl.php b/htdocs/core/tpl/objectline_title.tpl.php index fd848764721..c2f2dbb3d42 100644 --- a/htdocs/core/tpl/objectline_title.tpl.php +++ b/htdocs/core/tpl/objectline_title.tpl.php @@ -83,7 +83,7 @@ print ''.$langs->trans('ReductionShort').'' . $langs->trans('Progress') . '' . $langs->trans('TotalHT100Short') . '' . $form->textwithpicto($langs->trans('TotalHT100Short'), $langs->trans('UnitPriceXQtyLessDiscount')) . '