From 46b235c139709fd1e2410da5f60b8f5c4a4892e4 Mon Sep 17 00:00:00 2001 From: John Date: Tue, 20 Feb 2018 15:08:57 +0100 Subject: [PATCH 01/36] add auto select model when select type on create invoice --- htdocs/admin/facture.php | 70 ++++++++++++++++++- htdocs/compta/facture/card.php | 63 +++++++++++++---- htdocs/compta/facture/class/facture.class.php | 17 +++-- htdocs/langs/en_US/admin.lang | 1 + 4 files changed, 131 insertions(+), 20 deletions(-) diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 1f574175898..ae3b0a66ed5 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -240,6 +240,32 @@ if ($action == 'setforcedate') } } +if ($action == 'setDefaultPDFModulesByType') +{ + $invoicetypemodels = GETPOST('invoicetypemodels'); + + if(!empty($invoicetypemodels) && is_array($invoicetypemodels)) + { + $error = 0; + + foreach ($invoicetypemodels as $type => $value) + { + $res = dolibarr_set_const($db, 'FACTURE_ADDON_PDF_'.intval($type) ,$value,'chaine',0,'',$conf->entity); + if (! $res > 0) $error++; + } + + if (! $error) + { + setEventMessages($langs->trans("SetupSaved"), null, 'mesgs'); + } + else + { + setEventMessages($langs->trans("Error"), null, 'errors'); + } + } + + +} /* @@ -469,7 +495,7 @@ print ''.$langs->trans("Preview").''; print "\n"; clearstatcache(); - +$activatedModels = array(); $var=true; foreach ($dirmodels as $reldir) { @@ -588,6 +614,48 @@ foreach ($dirmodels as $reldir) print ''; + + +/* + * Document templates generators + */ +print '
'; +print load_fiche_titre($langs->trans("BillsPDFModulesAccordindToInvoiceType"),'',''); +print '
'; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print ''; +print "\n"; + +$listtype=array( + Facture::TYPE_STANDARD=>$langs->trans("InvoiceStandard"), + Facture::TYPE_REPLACEMENT=>$langs->trans("InvoiceReplacement"), + Facture::TYPE_CREDIT_NOTE=>$langs->trans("InvoiceAvoir"), + Facture::TYPE_DEPOSIT=>$langs->trans("InvoiceDeposit"), +); +if (! empty($conf->global->INVOICE_USE_SITUATION)) +{ + $listtype[Facture::TYPE_SITUATION] = $langs->trans("InvoiceSituation"); +} + +foreach ($listtype as $type => $trans) +{ + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; + $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; + print ''; + print ''; + print ''; + print "\n"; +} + +print '
'.$langs->trans("Type").''.$langs->trans("Name").'
'.$trans.''.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db) , $curent ,0,0, 0).'
'; +print "
"; + + /* * Modes de reglement */ diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 19612349214..277a3bc9697 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -2505,7 +2505,8 @@ if ($action == 'create') // Standard invoice print '
'; $tmp=' '; - $desc = $form->textwithpicto($tmp.$langs->trans("InvoiceStandardAsk"), $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', '', 0, 3); + $tmp = $tmp.''; + $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceStandardDesc"), 1, 'help', '', 0, 3); print $desc; print '
'; @@ -2524,7 +2525,8 @@ if ($action == 'create') }); '; - $desc = $form->textwithpicto($tmp.$langs->trans("InvoiceDeposit"), $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3); + $tmp = $tmp.''; + $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceDepositDesc"), 1, 'help', '', 0, 3); print ''; @@ -2548,8 +2550,9 @@ if ($action == 'create') { // First situation invoice print '
'; - $tmp=' '; - $desc = $form->textwithpicto($tmp.$langs->trans("InvoiceFirstSituationAsk"), $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3); + $tmp=' '; + $tmp = $tmp.''; + $desc = $form->textwithpicto($tmp, $langs->transnoentities("InvoiceFirstSituationDesc"), 1, 'help', '', 0, 3); print $desc; print '
'; @@ -2559,7 +2562,7 @@ if ($action == 'create') $tmp='' . $langs->trans('NoSituations') . '') || (GETPOST('origin') && GETPOST('origin') != 'facture' && GETPOST('origin') != 'commande')) $tmp.=' disabled'; $tmp.= '> '; - $text = $tmp.$langs->trans("InvoiceSituationAsk") . ' '; + $text = ' '; $text .= ''; @@ -2583,7 +2586,7 @@ if ($action == 'create') }); }); '; - $text = $tmp.$langs->trans("InvoiceReplacementAsk") . ' '; + $text = ''; $text .= ' '; - $text = $tmp.$langs->trans("InvoiceReplacement") . ' '; + $text = ' '; $text.= '('.$langs->trans("YouMustCreateInvoiceFromThird").') '; $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceReplacementDesc"), 1, 'help', '', 0, 3); print $desc; print ''; } - + + if (empty($origin)) { if ($socid > 0) @@ -2637,7 +2641,7 @@ if ($action == 'create') }); }); '; - $text = $tmp.$langs->transnoentities("InvoiceAvoirAsk") . ' '; + $text = ' '; // $text.=''; $text .= ' '; else $tmp=' '; - $text = $tmp.$langs->trans("InvoiceAvoir") . ' '; + $text = ' '; $text.= '('.$langs->trans("YouMustCreateInvoiceFromThird").') '; $desc = $form->textwithpicto($text, $langs->transnoentities("InvoiceAvoirDesc"), 1, 'help', '', 0, 3); print $desc; @@ -2677,7 +2681,7 @@ if ($action == 'create') // Template invoice print '
'; $tmp=' '; - $text = $tmp.$langs->trans("RepeatableInvoice") . ' '; + $text = ' '; //$text.= '('.$langs->trans("YouMustCreateStandardInvoiceFirst").') '; $desc = $form->textwithpicto($text, $langs->transnoentities("YouMustCreateStandardInvoiceFirstDesc"), 1, 'help', '', 0, 3); print $desc; @@ -2685,6 +2689,40 @@ if ($action == 'create') print '
'; + + + // Add auto select default document model + $listtType=array(Facture::TYPE_STANDARD,Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE,Facture::TYPE_DEPOSIT,Facture::TYPE_SITUATION); + $jsListType=''; + foreach ($listtType as $type) + { + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; + $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; + $jsListType.=(!empty($jsListType)?',':'').'"'.$type.'":"'.$curent.'"'; + } + + print ''; + + + + print '
'; if ($socid > 0) @@ -2782,7 +2820,8 @@ if ($action == 'create') print '"; // Multicurrency diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 7edc3b65b41..91e05827032 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4023,13 +4023,16 @@ class Facture extends CommonInvoice if (! dol_strlen($modele)) { - $modele = 'crabe'; - - if ($this->modelpdf) { - $modele = $this->modelpdf; - } elseif (! empty($conf->global->FACTURE_ADDON_PDF)) { - $modele = $conf->global->FACTURE_ADDON_PDF; - } + $modele = 'crabe'; + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; + + if ($this->modelpdf) { + $modele = $this->modelpdf; + }elseif (! empty($conf->global->{'FACTURE_ADDON_PDF_'.$this->type})){ + $modele = $conf->global->{'FACTURE_ADDON_PDF_'.$this->type} ; + }elseif (! empty($conf->global->FACTURE_ADDON_PDF)) { + $modele = $conf->global->FACTURE_ADDON_PDF; + } } $modelpath = "core/modules/facture/doc/"; diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 91a503ba6a6..005b77bd5c2 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1204,6 +1204,7 @@ WebCalUrlForVCalExport=An export link to %s format is available at follow BillsSetup=Invoices module setup BillsNumberingModule=Invoices and credit notes numbering model BillsPDFModules=Invoice documents models +BillsPDFModulesAccordindToInvoiceType=Invoice documents models according to invoice type PaymentsPDFModules=Payment documents models CreditNote=Credit note CreditNotes=Credit notes From d0ef8fe75a0b783b4c93c9b15a21fe81776ae94c Mon Sep 17 00:00:00 2001 From: John Date: Thu, 22 Feb 2018 09:54:36 +0100 Subject: [PATCH 02/36] fix travis errors --- htdocs/admin/facture.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index ae3b0a66ed5..0db1ffc72db 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -250,7 +250,7 @@ if ($action == 'setDefaultPDFModulesByType') foreach ($invoicetypemodels as $type => $value) { - $res = dolibarr_set_const($db, 'FACTURE_ADDON_PDF_'.intval($type) ,$value,'chaine',0,'',$conf->entity); + $res = dolibarr_set_const($db, 'FACTURE_ADDON_PDF_'.intval($type),$value,'chaine',0,'',$conf->entity); if (! $res > 0) $error++; } @@ -645,10 +645,10 @@ if (! empty($conf->global->INVOICE_USE_SITUATION)) foreach ($listtype as $type => $trans) { $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; - $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; + $current = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; print ''; print ''; - print ''; + print ''; print "\n"; } From 227e4ef9a662ed739779a3635792a545dc277d9b Mon Sep 17 00:00:00 2001 From: John Date: Tue, 3 Apr 2018 10:50:15 +0200 Subject: [PATCH 03/36] fix php compatibility --- htdocs/compta/facture/card.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index 04217fee7cd..9d2205fc98e 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -2820,7 +2820,8 @@ if ($action == 'create') print '"; From 5ac0f77d0e0acae668eade5d9efe03be1d73c0b3 Mon Sep 17 00:00:00 2001 From: BENKE Charlene Date: Wed, 2 May 2018 17:29:31 +0200 Subject: [PATCH 04/36] Add trigger for virtual stock Allow to add/sustract some qty for GPAO OF running --- htdocs/product/class/product.class.php | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 2f36fd59035..2fa802a532c 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3925,7 +3925,7 @@ class Product extends CommonObject */ function load_virtual_stock() { - global $conf; + global $conf, $user, $langs; $stock_commande_client=0; $stock_commande_fournisseur=0; @@ -3975,6 +3975,16 @@ class Product extends CommonObject if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; } + + // Call triggers + include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; + $interface=new Interfaces($this->db); + $result=$interface->run_triggers('LOAD_VIRTUAL_STOCK', $this, $user, $langs, $conf); + if ($result < 0) { + $this->errors=$interface->errors; + return -1; + } + } From 70c9ed960d67f1ff14023d32dcec069dec1fd6bb Mon Sep 17 00:00:00 2001 From: BENKE Charlene Date: Sun, 6 May 2018 22:11:24 +0200 Subject: [PATCH 05/36] let's play with hook --- htdocs/product/class/product.class.php | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 2fa802a532c..9bdb286db25 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3976,14 +3976,15 @@ class Product extends CommonObject $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; } - // Call triggers - include_once DOL_DOCUMENT_ROOT . '/core/class/interfaces.class.php'; - $interface=new Interfaces($this->db); - $result=$interface->run_triggers('LOAD_VIRTUAL_STOCK', $this, $user, $langs, $conf); - if ($result < 0) { - $this->errors=$interface->errors; - return -1; + if (! is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); } + $hookmanager->initHooks(array('productdao')); + $parameters=array('id'=>$this->id); + // Note that $action and $object may have been modified by some hooks + $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); + if ($reshook > 0) $this->stock_theorique+= $hookmanager->resPrint; } From 8ed3b3e49c9e230592c43283b74cbf03e20e3a7b Mon Sep 17 00:00:00 2001 From: BENKE Charlene Date: Sun, 6 May 2018 22:12:43 +0200 Subject: [PATCH 06/36] Update product.class.php --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 9bdb286db25..06ff0bd3ee6 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -3925,7 +3925,7 @@ class Product extends CommonObject */ function load_virtual_stock() { - global $conf, $user, $langs; + global $conf, $action; $stock_commande_client=0; $stock_commande_fournisseur=0; From af66a8971a323ba43448a1d01b747e9a7bea9ba5 Mon Sep 17 00:00:00 2001 From: John BOTELLA Date: Tue, 2 Oct 2018 15:51:17 +0200 Subject: [PATCH 07/36] NEW Hidden conf INVOICE_USE_DEFAULT_DOCUMENT --- htdocs/admin/facture.php | 75 +++++++++++++++++----------------- htdocs/compta/facture/card.php | 66 ++++++++++++++++-------------- 2 files changed, 74 insertions(+), 67 deletions(-) diff --git a/htdocs/admin/facture.php b/htdocs/admin/facture.php index 71fa035ee00..6e0f4bf681d 100644 --- a/htdocs/admin/facture.php +++ b/htdocs/admin/facture.php @@ -610,47 +610,48 @@ foreach ($dirmodels as $reldir) } print '
'; print $desc; print '
'; include_once DOL_DOCUMENT_ROOT . '/core/modules/facture/modules_facture.php'; $liste = ModelePDFFactures::liste_modeles($db); - print $form->selectarray('model', $liste, $conf->global->FACTURE_ADDON_PDF); + $curent = !empty($conf->global->{'FACTURE_ADDON_PDF_'.$object->type})?$conf->global->{'FACTURE_ADDON_PDF_'.$object->type}:$conf->global->FACTURE_ADDON_PDF; + print $form->selectarray('model', $liste, $curent); print "
'.$trans.''.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db) , $curent ,0,0, 0).''.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db), $current,0,0, 0).'
'; include_once DOL_DOCUMENT_ROOT . '/core/modules/facture/modules_facture.php'; $liste = ModelePDFFactures::liste_modeles($db); - $curent = !empty($conf->global->{'FACTURE_ADDON_PDF_'.$object->type})?$conf->global->{'FACTURE_ADDON_PDF_'.$object->type}:$conf->global->FACTURE_ADDON_PDF; + $paramkey='FACTURE_ADDON_PDF_'.$object->type; + $curent = !empty($conf->global->$paramkey)?$conf->global->$paramkey:$conf->global->FACTURE_ADDON_PDF; print $form->selectarray('model', $liste, $curent); print "
'; - -/* - * Document templates generators - */ -print '
'; -print load_fiche_titre($langs->trans("BillsPDFModulesAccordindToInvoiceType"),'',''); -print '
'; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print ''; -print "\n"; - -$listtype=array( - Facture::TYPE_STANDARD=>$langs->trans("InvoiceStandard"), - Facture::TYPE_REPLACEMENT=>$langs->trans("InvoiceReplacement"), - Facture::TYPE_CREDIT_NOTE=>$langs->trans("InvoiceAvoir"), - Facture::TYPE_DEPOSIT=>$langs->trans("InvoiceDeposit"), -); -if (! empty($conf->global->INVOICE_USE_SITUATION)) +if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf { - $listtype[Facture::TYPE_SITUATION] = $langs->trans("InvoiceSituation"); -} - -foreach ($listtype as $type => $trans) -{ - $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; - $current = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; - print ''; - print ''; - print ''; + /* + * Document templates generators + */ + print '
'; + print load_fiche_titre($langs->trans("BillsPDFModulesAccordindToInvoiceType"),'',''); + print ''; + print ''; + print ''; + print '
'.$langs->trans("Type").''.$langs->trans("Name").'
'.$trans.''.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db), $current,0,0, 0).'
'; + print ''; + print ''; + print ''; + print ''; print "\n"; + + $listtype=array( + Facture::TYPE_STANDARD=>$langs->trans("InvoiceStandard"), + Facture::TYPE_REPLACEMENT=>$langs->trans("InvoiceReplacement"), + Facture::TYPE_CREDIT_NOTE=>$langs->trans("InvoiceAvoir"), + Facture::TYPE_DEPOSIT=>$langs->trans("InvoiceDeposit"), + ); + if (! empty($conf->global->INVOICE_USE_SITUATION)) + { + $listtype[Facture::TYPE_SITUATION] = $langs->trans("InvoiceSituation"); + } + + foreach ($listtype as $type => $trans) + { + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; + $current = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; + print ''; + print ''; + print ''; + print "\n"; + } + + print '
'.$langs->trans("Type").''.$langs->trans("Name").'
'.$trans.''.$form->selectarray('invoicetypemodels['.$type.']', ModelePDFFactures::liste_modeles($db), $current,0,0, 0).'
'; + print "
"; } -print ''; -print ""; - - /* * Modes de reglement */ diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index ecd9ad09bbf..074558fd4ac 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -2779,37 +2779,38 @@ if ($action == 'create') print ''; - - // Add auto select default document model - $listtType=array(Facture::TYPE_STANDARD,Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE,Facture::TYPE_DEPOSIT,Facture::TYPE_SITUATION); - $jsListType=''; - foreach ($listtType as $type) + if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)) // Hidden conf { - $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; - $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; - $jsListType.=(!empty($jsListType)?',':'').'"'.$type.'":"'.$curent.'"'; + // Add auto select default document model + $listtType=array(Facture::TYPE_STANDARD,Facture::TYPE_REPLACEMENT,Facture::TYPE_CREDIT_NOTE,Facture::TYPE_DEPOSIT,Facture::TYPE_SITUATION); + $jsListType=''; + foreach ($listtType as $type) + { + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; + $curent = !empty($conf->global->{$thisTypeConfName})?$conf->global->{$thisTypeConfName}:$conf->global->FACTURE_ADDON_PDF; + $jsListType.=(!empty($jsListType)?',':'').'"'.$type.'":"'.$curent.'"'; + } + + print ''; } - print ''; - - print ''; @@ -2902,8 +2903,13 @@ if ($action == 'create') print ''; include_once DOL_DOCUMENT_ROOT . '/core/modules/facture/modules_facture.php'; $liste = ModelePDFFactures::liste_modeles($db); - $paramkey='FACTURE_ADDON_PDF_'.$object->type; - $curent = !empty($conf->global->$paramkey)?$conf->global->$paramkey:$conf->global->FACTURE_ADDON_PDF; + if(!empty($conf->global->INVOICE_USE_DEFAULT_DOCUMENT)){ // Hidden conf + $paramkey='FACTURE_ADDON_PDF_'.$object->type; + $curent = !empty($conf->global->$paramkey)?$conf->global->$paramkey:$conf->global->FACTURE_ADDON_PDF; + } + else{ + $curent = $conf->global->FACTURE_ADDON_PDF; + } print $form->selectarray('model', $liste, $curent); print ""; From d9e13129240303fec9572816454a899c3361bb5c Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Sun, 14 Oct 2018 06:16:14 +0200 Subject: [PATCH 08/36] Debug FEC model export --- .../class/accountancyexport.class.php | 30 +++++++++++++++---- htdocs/accountancy/tpl/export_journal.tpl.php | 16 ++++++++-- 2 files changed, 38 insertions(+), 8 deletions(-) diff --git a/htdocs/accountancy/class/accountancyexport.class.php b/htdocs/accountancy/class/accountancyexport.class.php index 060efab591c..13fec3cf388 100644 --- a/htdocs/accountancy/class/accountancyexport.class.php +++ b/htdocs/accountancy/class/accountancyexport.class.php @@ -651,19 +651,39 @@ class AccountancyExport */ public function exportFEC($objectLines) { - $separator = ';'; + $separator = "\t"; $end_line = "\n"; + print "JournalCode" . $separator; + print "JournalLib" . $separator; + print "EcritureNum" . $separator; + print "EcritureDate" . $separator; + print "CompteNum" . $separator; + print "CompteLib" . $separator; + print "CompAuxNum" . $separator; + print "CompAuxLib" . $separator; + print "PieceRef" . $separator; + print "PieceDate" . $separator; + print "EcritureLib" . $separator; + print "Debit" . $separator; + print "Credit" . $separator; + print "EcritureLet" . $separator; + print "DateLet" . $separator; + print "ValidDate" . $separator; + print "Montantdevise" . $separator; + print "Idevise"; + print $end_line; + foreach ( $objectLines as $line ) { $date_creation = dol_print_date($line->date_creation, '%d%m%Y'); $date_doc = dol_print_date($line->doc_date, '%d%m%Y'); $date_valid = dol_print_date($line->date_validated, '%d%m%Y'); // FEC:JournalCode - print $line->code_journal; + print $line->code_journal . $separator; // FEC:JournalLib - print $line->journal_label; + print $line->journal_label . $separator; // FEC:EcritureNum print $line->piece_num . $separator; @@ -693,10 +713,10 @@ class AccountancyExport print $line->label_operation . $separator; // FEC:Debit - print price($line->debit) . $separator; + print price2num($line->debit) . $separator; // FEC:Credit - print price($line->credit) . $separator; + print price2num($line->credit) . $separator; // FEC:EcritureLet print $line->lettering_code . $separator; diff --git a/htdocs/accountancy/tpl/export_journal.tpl.php b/htdocs/accountancy/tpl/export_journal.tpl.php index 773f7a7ff68..1d7e7fd6f54 100644 --- a/htdocs/accountancy/tpl/export_journal.tpl.php +++ b/htdocs/accountancy/tpl/export_journal.tpl.php @@ -1,6 +1,6 @@ - * Copyright (C) 2016 Charlie Benke +/* Copyright (C) 2015-2018 Alexandre Spangaro + * Copyright (C) 2016 Charlie Benke * * 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 @@ -27,11 +27,21 @@ $code = $conf->global->MAIN_INFO_ACCOUNTANT_CODE; $prefix = $conf->global->ACCOUNTING_EXPORT_PREFIX_SPEC; $format = $conf->global->ACCOUNTING_EXPORT_FORMAT; $nodateexport = $conf->global->ACCOUNTING_EXPORT_NO_DATE_IN_FILENAME; +$siren = $conf->global->MAIN_INFO_SIREN; $date_export = "_" . dol_print_date(dol_now(), '%Y%m%d%H%M%S'); +$endaccountingperiod = dol_print_date(dol_now(), '%Y%m%d'); header('Content-Type: text/csv'); -$completefilename = ($code?$code . "_":"") . ($prefix?$prefix . "_":"") . $filename . ($nodateexport?"":$date_export) . "." . $format; + +if ($conf->global->ACCOUNTING_EXPORT_MODELCSV == "11") // Specific filename for FEC model export +{ + $completefilename = $siren . "FEC" . $search_date_end . $endaccountingperiod . "." . $format; +} +else +{ + $completefilename = ($code?$code . "_":"") . ($prefix?$prefix . "_":"") . $filename . ($nodateexport?"":$date_export) . "." . $format; +} header('Content-Disposition: attachment;filename=' . $completefilename); From 65c69c4564826669dd239698c22777734de9105d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fr=C3=A9d=C3=A9ric=20FRANCE?= Date: Sun, 14 Oct 2018 10:57:27 +0200 Subject: [PATCH 09/36] fix standard prepare_head --- htdocs/asset/admin/assets_extrafields.php | 2 +- htdocs/asset/admin/assets_type_extrafields.php | 2 +- htdocs/asset/admin/setup.php | 2 +- htdocs/asset/card.php | 2 +- htdocs/asset/document.php | 2 +- htdocs/asset/info.php | 2 +- htdocs/asset/note.php | 2 +- htdocs/core/lib/asset.lib.php | 4 ++-- 8 files changed, 9 insertions(+), 9 deletions(-) diff --git a/htdocs/asset/admin/assets_extrafields.php b/htdocs/asset/admin/assets_extrafields.php index 109b0f1e94f..f220d5cb849 100644 --- a/htdocs/asset/admin/assets_extrafields.php +++ b/htdocs/asset/admin/assets_extrafields.php @@ -64,7 +64,7 @@ $linkback=''.$langs->trans("BackToM print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup'); -$head = AssetsAdminPrepareHead(); +$head = asset_admin_prepare_head(); dol_fiche_head($head, 'attributes', $langs->trans("Assets"), -1, 'generic'); diff --git a/htdocs/asset/admin/assets_type_extrafields.php b/htdocs/asset/admin/assets_type_extrafields.php index e8f1d71370b..a791078f37b 100644 --- a/htdocs/asset/admin/assets_type_extrafields.php +++ b/htdocs/asset/admin/assets_type_extrafields.php @@ -63,7 +63,7 @@ $linkback=''.$langs->trans("BackToM print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup'); -$head = AssetsAdminPrepareHead(); +$head = asset_admin_prepare_head(); dol_fiche_head($head, 'attributes_type', $langs->trans("Assets"), -1, 'generic'); diff --git a/htdocs/asset/admin/setup.php b/htdocs/asset/admin/setup.php index 1168fd3ada3..57738309abd 100644 --- a/htdocs/asset/admin/setup.php +++ b/htdocs/asset/admin/setup.php @@ -58,7 +58,7 @@ $linkback=''.$langs->trans("BackToM print load_fiche_titre($langs->trans("AssetsSetup"),$linkback,'title_setup'); -$head = AssetsAdminPrepareHead(); +$head = asset_admin_prepare_head(); dol_fiche_head($head, 'settings', $langs->trans("Assets"), -1, 'generic'); diff --git a/htdocs/asset/card.php b/htdocs/asset/card.php index 9af7638316f..4f7061aed20 100644 --- a/htdocs/asset/card.php +++ b/htdocs/asset/card.php @@ -203,7 +203,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea { $res = $object->fetch_optionals($object->id, $extralabels); - $head = AssetsPrepareHead($object); + $head = asset_prepare_head($object); dol_fiche_head($head, 'card', $langs->trans("Asset"), -1, 'generic'); $formconfirm = ''; diff --git a/htdocs/asset/document.php b/htdocs/asset/document.php index 784f65aa220..c1332ed10a2 100644 --- a/htdocs/asset/document.php +++ b/htdocs/asset/document.php @@ -95,7 +95,7 @@ if ($object->id) * Show tabs */ if (! empty($conf->notification->enabled)) $langs->load("mails"); - $head = AssetsPrepareHead($object); + $head = asset_prepare_head($object); dol_fiche_head($head, 'document', $langs->trans("Asset"), -1, 'generic'); diff --git a/htdocs/asset/info.php b/htdocs/asset/info.php index 9cc9495c1b9..e01316ae685 100644 --- a/htdocs/asset/info.php +++ b/htdocs/asset/info.php @@ -55,7 +55,7 @@ $form = new Form($db); $object->info($id); -$head = AssetsPrepareHead($object); +$head = asset_prepare_head($object); dol_fiche_head($head, 'info', $langs->trans("Asset"), -1, 'generic'); diff --git a/htdocs/asset/note.php b/htdocs/asset/note.php index e95e62aeaa4..f76c6ea028f 100644 --- a/htdocs/asset/note.php +++ b/htdocs/asset/note.php @@ -78,7 +78,7 @@ if ($id > 0 || ! empty($ref)) { $object->fetch_thirdparty(); - $head = AssetsPrepareHead($object); + $head = asset_prepare_head($object); dol_fiche_head($head, 'note', $langs->trans("Asset"), -1, 'generic'); diff --git a/htdocs/core/lib/asset.lib.php b/htdocs/core/lib/asset.lib.php index 7a4fd80158c..b0a4a6b81a9 100644 --- a/htdocs/core/lib/asset.lib.php +++ b/htdocs/core/lib/asset.lib.php @@ -26,7 +26,7 @@ * * @return array head array with tabs */ -function AssetsAdminPrepareHead() +function asset_admin_prepare_head() { global $langs, $conf; @@ -70,7 +70,7 @@ function AssetsAdminPrepareHead() * * @return array head array with tabs */ -function AssetsPrepareHead() +function asset_prepare_head() { global $langs, $conf; From 26c9158ed7e0aa6872125b8871e6a680d982695f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 14:20:28 +0200 Subject: [PATCH 10/36] Label of DPO --- htdocs/langs/en_US/admin.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 93a48d763cd..724dbf61659 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -1802,7 +1802,7 @@ EnterCalculationRuleIfPreviousFieldIsYes=Enter calculation rule if previous fiel SeveralLangugeVariatFound=Several language variants found COMPANY_AQUARIUM_REMOVE_SPECIAL=Remove special characters COMPANY_AQUARIUM_CLEAN_REGEX=Regex filter to clean value (COMPANY_AQUARIUM_CLEAN_REGEX) -GDPRContact=Privacy Policies or GDPR contact +GDPRContact=Data Protection Officer (DPO, Data Privacy or GDPR contact) GDPRContactDesc=If you store data about European companies/citizen, you can store the contact who is responsible for the General Data Protection Regulation here HelpOnTooltip=Help text to show on tooltip HelpOnTooltipDesc=Put text or a translation key here for the text to show on a tooltip when this field appears in a form From 278910b66b70f60e0f60010cc0288a55cbd5ffeb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 14:26:18 +0200 Subject: [PATCH 11/36] Fix website --- htdocs/website/index.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 1d277c32ed7..0cf6380d1b8 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -1943,6 +1943,7 @@ if (count($object->records) > 0) // There is at least one web site print ''; + print ''."\n"; print ''; From 96d2950051829cae69591e19f2ecf82a27edeb21 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 16:10:02 +0200 Subject: [PATCH 12/36] Better tooltip --- htdocs/website/index.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 0cf6380d1b8..65a17be6281 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -1749,7 +1749,7 @@ if (count($object->records) > 0) // There is at least one web site $htmltext = $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $urlint, $dataroot); $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT); - $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT); + $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website
'.DOL_DATA_ROOT.'/medias'); print ''; print $form->textwithpicto('', $htmltext, 1, 'preview'); print ''; @@ -1760,7 +1760,7 @@ if (count($object->records) > 0) // There is at least one web site $htmltext =$langs->trans("SetHereVirtualHost", $dataroot); $htmltext.='
'; $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT); - $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT); + $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website
'.DOL_DATA_ROOT.'/medias'); $htmltext.='
'; $htmltext.='
'; $htmltext.=$langs->trans("YouCanAlsoTestWithPHPS", $dataroot); @@ -1782,7 +1782,7 @@ if (count($object->records) > 0) // There is at least one web site $htmltext = $langs->trans("PreviewSiteServedByWebServer", $langs->transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext?$urlext:''.$langs->trans("VirtualHostUrlNotDefined").''); $htmltext.='
'; $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT); - $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT); + $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website
'.DOL_DATA_ROOT.'/medias'); print 'transnoentitiesnoconv("Site"), $langs->transnoentitiesnoconv("Site"), $dataroot, $urlext)).'">'; print $form->textwithpicto('', $htmltext, 1, 'preview_ext'); print ''; @@ -2003,7 +2003,7 @@ if (count($object->records) > 0) // There is at least one web site $htmltext = $langs->trans("PreviewSiteServedByDolibarr", $langs->transnoentitiesnoconv("Page"), $langs->transnoentitiesnoconv("Page"), $realpage, $dataroot); $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT); - $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT); + $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website
'.DOL_DATA_ROOT.'/medias'); print ''; print $form->textwithpicto('', $htmltext, 1, 'preview'); @@ -2321,7 +2321,7 @@ if ($action == 'createsite') $htmltext = $langs->trans("SetHereVirtualHost", DOL_DATA_ROOT.'/website/websiteref'); $htmltext.='
'; $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("ReadPerm"), DOL_DOCUMENT_ROOT); - $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT); + $htmltext.='
'.$langs->trans("CheckVirtualHostPerms", $langs->transnoentitiesnoconv("WritePerm"), DOL_DATA_ROOT.'/website
'.DOL_DATA_ROOT.'/medias'); print $form->textwithpicto($langs->trans('Virtualhost'), $htmltext, 1, 'help', '', 0, 2, 'tooltipvirtual'); print ''; From 5654492ba88ca74ea46559f2f26ff2c702c67f75 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 16:45:45 +0200 Subject: [PATCH 13/36] Update product.class.php --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index cdef8e18db7..3ed33ef5235 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4085,7 +4085,7 @@ class Product extends CommonObject function load_virtual_stock() { // phpcs:enable - global $conf, $action; + global $conf, $hookmanager, $action; $stock_commande_client=0; $stock_commande_fournisseur=0; From 7e68d8df1b7ad8a8ed4e2ea9326820e4431db376 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 16:47:30 +0200 Subject: [PATCH 14/36] Update product.class.php --- htdocs/product/class/product.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 3ed33ef5235..5bf2f45d31c 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4144,7 +4144,7 @@ class Product extends CommonObject $parameters=array('id'=>$this->id); // Note that $action and $object may have been modified by some hooks $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); - if ($reshook > 0) $this->stock_theorique+= $hookmanager->resPrint; + if ($reshook > 0) $this->stock_theorique = $hookmanager->resArray['stock_theorique']; } From b0569de1660fba102e01856006175e1069624e28 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 18:44:29 +0200 Subject: [PATCH 15/36] Work on multilang support --- htdocs/core/website.inc.php | 31 ++++ htdocs/langs/en_US/website.lang | 2 + htdocs/public/website/index.php | 158 +++++++++++---------- htdocs/website/class/websitepage.class.php | 3 + htdocs/website/index.php | 50 ++++++- 5 files changed, 165 insertions(+), 79 deletions(-) diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index ac4d6b35988..43c9116cea5 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -19,6 +19,7 @@ /** * \file htdocs/core/website.inc.php * \brief Common file loaded by all website pages (after master.inc.php). It set the new object $weblangs, using parameter 'l'. + * This file is included in top of all container pages. * The global variable $websitekey must be defined. */ @@ -34,6 +35,36 @@ if (! is_object($weblangs)) { $weblangs = dol_clone($langs); } + +// A lang was forced, so we change weblangs init if (GETPOST('l','aZ09')) $weblangs->setDefaultLang(GETPOST('l','aZ09')); +// A lang was forced, so we check to find if we must make a redirect on translation page +if (! defined('USEDOLIBARREDITOR')) +{ + if (GETPOST('l','aZ09')) + { + $sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page"; + $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp, ".MAIN_DB_PREFIX."website as w"; + $sql.=" WHERE w.rowid = wp.fk_website AND w.ref = '".$db->escape($websitekey)."' AND fk_page = '".$db->escape($pageid)."' AND lang = '".$db->escape(GETPOST('l','aZ09'))."'"; + $resql = $db->query($sql); + if ($resql) + { + $obj = $db->fetch_object($resql); + if ($obj) + { + //$pageid = $obj->rowid; + //$pageref = $obj->pageurl; + if (! defined('USEDOLIBARRSERVER')) { + // TODO Redirect + } + else + { + // TODO Redirect + } + } + } + } +} + // Load websitepage class include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; diff --git a/htdocs/langs/en_US/website.lang b/htdocs/langs/en_US/website.lang index 55db08c3785..a14d05132cd 100644 --- a/htdocs/langs/en_US/website.lang +++ b/htdocs/langs/en_US/website.lang @@ -91,3 +91,5 @@ ExternalURLMustStartWithHttp=External URL must start with http:// or https:// ZipOfWebsitePackageToImport=Zip file of website package ShowSubcontainers=Show included containers InternalURLOfPage=Internal URL of page +ThisPageIsTranslationOf=This page/container is translation of +ThisPageHasTranslationPages=This page/container has translation \ No newline at end of file diff --git a/htdocs/public/website/index.php b/htdocs/public/website/index.php index 862d8ada71a..19abc48094b 100644 --- a/htdocs/public/website/index.php +++ b/htdocs/public/website/index.php @@ -18,8 +18,7 @@ /** * \file htdocs/public/website/index.php * \ingroup website - * \brief Page to output pages - * \author Laurent Destailleur + * \brief Wrapper to output pages when website is powered by Dolibarr instead of a native web server */ if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL',1); // Disables token renewal @@ -59,88 +58,91 @@ $accessallowed = 1; $type=''; -/* - * View - */ +if (empty($pageid)) +{ + require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php'; + require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; + + $object=new Website($db); + $object->fetch(0, $websitekey); + + if (empty($object->id)) + { + if (empty($pageid)) + { + // Return header 404 + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); + + include DOL_DOCUMENT_ROOT.'/public/error-404.php'; + exit; + } + } + + $objectpage=new WebsitePage($db); + + if ($pageref) + { + $result=$objectpage->fetch(0, $object->id, $pageref); + if ($result > 0) + { + $pageid = $objectpage->id; + } + elseif($result == 0) + { + // Page not found from ref=pageurl, we try using alternative alias + $result=$objectpage->fetch(0, $object->id, null, $pageref); + if ($result > 0) + { + $pageid = $objectpage->id; + } + } + } + else + { + if ($object->fk_default_home > 0) + { + $result=$objectpage->fetch($object->fk_default_home); + if ($result > 0) + { + $pageid = $objectpage->id; + } + } + + if (empty($pageid)) + { + $array=$objectpage->fetchAll($object->id); + if (is_array($array) && count($array) > 0) + { + $firstrep=reset($array); + $pageid=$firstrep->id; + } + } + } +} +if (empty($pageid)) +{ + // Return header 404 + header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); + + $langs->load("website"); + + if (! GETPOSTISSET('pageref')) print $langs->trans("PreviewOfSiteNotYetAvailable", $websitekey); + + include DOL_DOCUMENT_ROOT.'/public/error-404.php'; + exit; +} $appli=constant('DOL_APPLICATION_TITLE'); if (!empty($conf->global->MAIN_APPLICATION_TITLE)) $appli=$conf->global->MAIN_APPLICATION_TITLE; + + +/* + * View + */ + //print 'Directory with '.$appli.' websites.
'; -if (empty($pageid)) -{ - require_once DOL_DOCUMENT_ROOT.'/website/class/website.class.php'; - require_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; - - $object=new Website($db); - $object->fetch(0, $websitekey); - - if (empty($object->id)) - { - if (empty($pageid)) - { - // Return header 404 - header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); - - include DOL_DOCUMENT_ROOT.'/public/error-404.php'; - exit; - } - } - - $objectpage=new WebsitePage($db); - - if ($pageref) - { - $result=$objectpage->fetch(0, $object->id, $pageref); - if ($result > 0) - { - $pageid = $objectpage->id; - } - elseif($result == 0) - { - // Page not found from ref=pageurl, we try using alternative alias - $result=$objectpage->fetch(0, $object->id, null, $pageref); - if ($result > 0) - { - $pageid = $objectpage->id; - } - } - } - else - { - if ($object->fk_default_home > 0) - { - $result=$objectpage->fetch($object->fk_default_home); - if ($result > 0) - { - $pageid = $objectpage->id; - } - } - - if (empty($pageid)) - { - $array=$objectpage->fetchAll($object->id); - if (is_array($array) && count($array) > 0) - { - $firstrep=reset($array); - $pageid=$firstrep->id; - } - } - } -} -if (empty($pageid)) -{ - // Return header 404 - header($_SERVER["SERVER_PROTOCOL"]." 404 Not Found", true, 404); - - $langs->load("website"); - - if (! GETPOSTISSET('pageref')) print $langs->trans("PreviewOfSiteNotYetAvailable", $websitekey); - - include DOL_DOCUMENT_ROOT.'/public/error-404.php'; - exit; -} // Security: Delete string ../ into $original_file global $dolibarr_main_data_root; diff --git a/htdocs/website/class/websitepage.class.php b/htdocs/website/class/websitepage.class.php index 4277a03167d..79ff3bc789d 100644 --- a/htdocs/website/class/websitepage.class.php +++ b/htdocs/website/class/websitepage.class.php @@ -193,8 +193,11 @@ class WebsitePage extends CommonObject $this->fk_website = $obj->fk_website; $this->type_container = $obj->type_container; + $this->pageurl = $obj->pageurl; + $this->ref = $obj->pageurl; $this->aliasalt = preg_replace('/,+$/', '', preg_replace('/^,+/', '', $obj->aliasalt)); + $this->title = $obj->title; $this->description = $obj->description; $this->keywords = $obj->keywords; diff --git a/htdocs/website/index.php b/htdocs/website/index.php index 65a17be6281..e9e14c4f888 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -1926,10 +1926,11 @@ if (count($object->records) > 0) // There is at least one web site // Create an array for form $preselectedlanguage = GETPOST('newlang', 'az09') ? GETPOST('newlang', 'az09') : ($objectpage->lang ? $objectpage->lang : $langs->defaultlang); $formquestion = array( - array('type' => 'text', 'tdclass'=>'maxwidth200', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME"), 'value'=> 'copy_of_'.$objectpage->pageurl), + array('type' => 'hidden', 'name' => 'sourcepageurl', 'value'=> $objectpage->pageurl), array('type' => 'checkbox', 'tdclass'=>'maxwidth200', 'name' => 'is_a_translation', 'label' => $langs->trans("PageIsANewTranslation"), 'value' => 0), array('type' => 'other','name' => 'newlang', 'label' => $langs->trans("Language"), 'value' => $formadmin->select_language($preselectedlanguage, 'newlang', 0, null, 1, 0, 0, 'minwidth200', 0, 1)), array('type' => 'other','name' => 'newwebsite', 'label' => $langs->trans("WebSite"), 'value' => $formwebsite->selectWebsite($object->id, 'newwebsite', 0)), + array('type' => 'text', 'tdclass'=>'maxwidth200 fieldrequired', 'name' => 'pageurl', 'label'=> $langs->trans("WEBSITE_PAGENAME"), 'value'=> 'copy_of_'.$objectpage->pageurl), ); $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"] . '?website='.$object->ref.'&pageid=' . $pageid, $langs->trans('ClonePage'), '', 'confirm_createpagefromclone', $formquestion, 0, 1, 300, 550); @@ -2518,6 +2519,53 @@ if ($action == 'editmeta' || $action == 'createcontainer') print $formadmin->select_language($pagelang?$pagelang:$langs->defaultlang, 'WEBSITE_LANG', 0, null, '1'); print ''; + if ($action != 'createcontainer') + { + // Translation of + if ($objectpage->fk_page > 0) + { + print ''; + print $langs->trans('ThisPageIsTranslationOf'); + print ''; + $sourcepage=new WebsitePage($db); + $result = $sourcepage->fetch($objectpage->fk_page); + if ($result == 0) // not found, we can reset value + { + + } + elseif ($result > 0) + { + print $sourcepage->getNomUrl(1); + } + print ''; + } + + // Has translation pages + $sql='SELECT rowid, lang from '.MAIN_DB_PREFIX.'website_page where fk_page = '.$objectpage->id; + $resql = $db->query($sql); + if ($resql) + { + $num_rows = $db->num_rows($resql); + if ($num_rows > 0) + { + print ''; + print $langs->trans('ThisPageHasTranslationPages'); + print ''; + $i=0; + while ($obj = $db->fetch_object($resql)) + { + $tmppage=new WebsitePage($db); + $tmppage->fetch($obj->rowid); + if ($i > 0) print ' - '; + print $tmppage->getNomUrl(1).' ('.$tmppage->lang.')'; + $i++; + } + print ''; + } + } + else dol_print_error($db); + } + print ''; $htmlhelp=$langs->trans("WEBSITE_ALIASALTDesc"); print $form->textwithpicto($langs->trans('WEBSITE_ALIASALT'), $htmlhelp, 1, 'help', '', 0, 2, 'htmlheadertooltip'); From 45860b24948d71bc96084d15fe9814f258228028 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 20:04:25 +0200 Subject: [PATCH 16/36] Work on multilang --- htdocs/core/lib/website.lib.php | 6 ++-- htdocs/core/website.inc.php | 47 +++++++++++++++++--------- htdocs/website/class/website.class.php | 18 +++++++++- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index 9f848fb68ee..ab0cbbdbdfb 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -307,7 +307,7 @@ function includeContainer($containerref) { global $conf, $db, $hookmanager, $langs, $mysoc, $user, $website, $weblangs; // Very important. Required to have var available when running inluded containers. global $includehtmlcontentopened; - global $websitekey; + global $websitekey, $websitepagefile; $MAXLEVEL=20; @@ -607,7 +607,7 @@ function dolSavePageContent($filetpl, $object, $objectpage) $tplcontent =''; $tplcontent.= "setDefaultLang(GETPOST('l','aZ09')); // A lang was forced, so we check to find if we must make a redirect on translation page -if (! defined('USEDOLIBARREDITOR')) +if ($_SERVER['PHP_SELF'] != DOL_URL_ROOT.'/website/index.php') // If we browsing page using Dolibarr server or a Native web server { + //print_r(get_defined_constants(true));exit; if (GETPOST('l','aZ09')) { - $sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page"; - $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp, ".MAIN_DB_PREFIX."website as w"; - $sql.=" WHERE w.rowid = wp.fk_website AND w.ref = '".$db->escape($websitekey)."' AND fk_page = '".$db->escape($pageid)."' AND lang = '".$db->escape(GETPOST('l','aZ09'))."'"; - $resql = $db->query($sql); - if ($resql) + if (! $pageid && ! empty($websitepagefile)) { - $obj = $db->fetch_object($resql); - if ($obj) + $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile)); + } + if ($pageid > 0) + { + $sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page"; + $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp, ".MAIN_DB_PREFIX."website as w"; + $sql.=" WHERE w.rowid = wp.fk_website AND w.ref = '".$db->escape($websitekey)."' AND wp.lang = '".$db->escape(GETPOST('l','aZ09'))."'"; + $sql.=" AND wp.fk_page = ".$db->escape($pageid); + //var_dump($sql);exit; + $resql = $db->query($sql); + if ($resql) { - //$pageid = $obj->rowid; - //$pageref = $obj->pageurl; - if (! defined('USEDOLIBARRSERVER')) { - // TODO Redirect - } - else + $obj = $db->fetch_object($resql); + if ($obj) { - // TODO Redirect + $newpageid = $obj->rowid; + if ($newpageid != $pageid) // To avoid to make a redirect on same page (infinite loop) + { + if (defined('USEDOLIBARRSERVER')) { + header("Location: ".DOL_URL_ROOT.'/public/website/index.php?website='.$websitekey.'&pageid='.$newpageid.'.php&l='.GETPOST('l','aZ09')); + exit; + } + else + { + $newpageref = $obj->pageurl; + header("Location: ".$newpageref.'.php?l='.GETPOST('l','aZ09')); + exit; + } + } } } } diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 843304fbe45..658e35edcd9 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -1089,10 +1089,26 @@ class Website extends CommonObject */ public function componentSelectLang($languagecodes, $weblangs, $morecss='', $htmlname='') { + global $websitepagefile; + if (! is_object($weblangs)) return 'ERROR componentSelectLang called with parameter $weblangs not defined'; - $languagecodeselected = $weblangs->defaultlang; + $languagecodeselected= $weblangs->defaultlang; // Becasue we must init with a value, but real value is the lang of main parent container + if (! empty($websitepagefile)) + { + $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile)); + if ($pageid > 0) + { + $tmppage=new WebsitePage($this->db); + $tmppage->fetch($pageid); + + $languagecodeselected=$tmppage->lang; + $languagecodes[]=$tmppage->lang; // We add language code of page into combo list + } + } + $weblangs->load('languages'); + //var_dump($weblangs->defaultlang); $url = $_SERVER["REQUEST_URI"]; $url = preg_replace('/(\?|&)l=([a-zA-Z_]*)/', '', $url); // We remove param l from url From ac143b28aeb9c8249746f2c3b65e50b9202ac6cb Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 20:54:28 +0200 Subject: [PATCH 17/36] Work on multilang --- htdocs/core/lib/website.lib.php | 4 +- htdocs/website/class/website.class.php | 56 +++++++++++++++++++++----- 2 files changed, 48 insertions(+), 12 deletions(-) diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php index ab0cbbdbdfb..fc2a90bbeb1 100644 --- a/htdocs/core/lib/website.lib.php +++ b/htdocs/core/lib/website.lib.php @@ -607,7 +607,7 @@ function dolSavePageContent($filetpl, $object, $objectpage) $tplcontent =''; $tplcontent.= "defaultlang; // Becasue we must init with a value, but real value is the lang of main parent container + // Load tmppage if we have $websitepagefile defined + $tmppage=new WebsitePage($this->db); + + $pageid = 0; if (! empty($websitepagefile)) { $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile)); if ($pageid > 0) { - $tmppage=new WebsitePage($this->db); $tmppage->fetch($pageid); + } + } + + // Fill with existing translation, nothing if none + if (! is_array($languagecodes) && $pageid > 0) + { + $languagecodes = array(); + + $sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page"; + $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp"; + $sql.=" WHERE wp.fk_website = ".$website->id; + $sql.=" AND (wp.fk_page = ".$pageid." OR wp.rowid = ".$pageid; + if ($tmppage->fk_page > 0) $sql.=" OR wp.fk_page = ".$tmppage->fk_page." OR wp.rowid = ".$tmppage->fk_page; + $sql.=")"; + + $resql = $this->db->query($sql); + if ($resql) + { + while ($obj = $this->db->fetch_object($resql)) + { + $newlang = $obj->lang; + if ($obj->rowid == $pageid) $newlang = $obj->lang; + if (! in_array($newlang, $languagecodes)) $languagecodes[]=$newlang; + } + } + } + // Now $languagecodes is always an array + + $languagecodeselected= $weblangs->defaultlang; // Because we must init with a value, but real value is the lang of main parent container + if (! empty($websitepagefile)) + { + $pageid = str_replace(array('.tpl.php', 'page'), array('', ''), basename($websitepagefile)); + if ($pageid > 0) + { $languagecodeselected=$tmppage->lang; - $languagecodes[]=$tmppage->lang; // We add language code of page into combo list + if (! in_array($tmppage->lang, $languagecodes)) $languagecodes[]=$tmppage->lang; // We add language code of page into combo list } } From ab807ada07717dc3e316f204b5df650dc424b316 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 23:26:57 +0200 Subject: [PATCH 18/36] Work on translation --- htdocs/core/website.inc.php | 16 ++++++++++++---- htdocs/website/class/website.class.php | 2 +- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/htdocs/core/website.inc.php b/htdocs/core/website.inc.php index 7ce4af6c9b2..4e382088da5 100644 --- a/htdocs/core/website.inc.php +++ b/htdocs/core/website.inc.php @@ -50,11 +50,19 @@ if ($_SERVER['PHP_SELF'] != DOL_URL_ROOT.'/website/index.php') // If we browsing } if ($pageid > 0) { + // Load tmppage if we have $websitepagefile defined + include_once DOL_DOCUMENT_ROOT.'/website/class/websitepage.class.php'; + $tmppage=new WebsitePage($db); + $tmppage->fetch($pageid); + $sql ="SELECT wp.rowid, wp.lang, wp.pageurl, wp.fk_page"; - $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp, ".MAIN_DB_PREFIX."website as w"; - $sql.=" WHERE w.rowid = wp.fk_website AND w.ref = '".$db->escape($websitekey)."' AND wp.lang = '".$db->escape(GETPOST('l','aZ09'))."'"; - $sql.=" AND wp.fk_page = ".$db->escape($pageid); - //var_dump($sql);exit; + $sql.=" FROM ".MAIN_DB_PREFIX."website_page as wp"; + $sql.=" WHERE wp.fk_website = ".$website->id; + $sql.=" AND (wp.fk_page = ".$pageid." OR wp.rowid = ".$pageid; + if ($tmppage->fk_page > 0) $sql.=" OR wp.fk_page = ".$tmppage->fk_page." OR wp.rowid = ".$tmppage->fk_page; + $sql.=")"; + $sql.= " AND wp.lang = '".$db->escape(GETPOST('l','aZ09'))."'"; + $resql = $db->query($sql); if ($resql) { diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index 04bad804678..b9be32bcafa 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -1081,7 +1081,7 @@ class Website extends CommonObject /** * Component to select language inside a container (Full CSS Only) * - * @param array|string $languagecodes 'auto' to show all languages available for page or language codes array like array('en_US','fr_FR','de_DE','es_ES') + * @param array|string $languagecodes 'auto' to show all languages available for page, or language codes array like array('en_US','fr_FR','de_DE','es_ES') * @param Translate $weblangs Language Object * @param string $morecss More CSS class on component * @param string $htmlname Suffix for HTML name From 8fc73d1b1be00a477ffe5856a8c12861879c380b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 23:47:38 +0200 Subject: [PATCH 19/36] Fix pagination show two times the same account on balance of accounts --- htdocs/accountancy/bookkeeping/balance.php | 23 ++++++++++++------- .../accountancy/class/bookkeeping.class.php | 9 ++++++-- 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index 2b263ca166c..bfd65ee1be7 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -42,6 +42,21 @@ $page = GETPOST("page"); $sortorder = GETPOST("sortorder", 'alpha'); $sortfield = GETPOST("sortfield", 'alpha'); $action = GETPOST('action', 'alpha'); +if (GETPOST("exportcsv",'alpha')) $action = 'export_csv'; + +// Load variable for pagination +$limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; +$sortfield = GETPOST('sortfield','alpha'); +$sortorder = GETPOST('sortorder','alpha'); +$page = GETPOST('page','int'); +if (empty($page) || $page == -1 || GETPOST('button_search','alpha') || GETPOST('button_removefilter','alpha') || (empty($toselect) && $massaction === '0')) { $page = 0; } // If $page is not defined, or '' or -1 or if we click on clear filters or if we select empty mass action +$offset = $limit * $page; +$pageprev = $page - 1; +$pagenext = $page + 1; +//if (! $sortfield) $sortfield="p.date_fin"; +//if (! $sortorder) $sortorder="DESC"; + + $search_date_start = dol_mktime(0, 0, 0, GETPOST('date_startmonth', 'int'), GETPOST('date_startday', 'int'), GETPOST('date_startyear', 'int')); $search_date_end = dol_mktime(0, 0, 0, GETPOST('date_endmonth', 'int'), GETPOST('date_endday', 'int'), GETPOST('date_endyear', 'int')); @@ -54,14 +69,6 @@ if ($search_accountancy_code_end == - 1) { $search_accountancy_code_end = ''; } -if (GETPOST("exportcsv",'alpha')) $action = 'export_csv'; - - -$limit = GETPOST('limit','int')?GETPOST('limit', 'int'):$conf->liste_limit; -if (empty($page) || $page < 0) { $page = 0; } - -$offset = $limit * $page; - $object = new BookKeeping($db); $formaccounting = new FormAccounting($db); diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 5e9350b0366..a9bfcce027a 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -1016,16 +1016,21 @@ class BookKeeping extends CommonObject } $resql = $this->db->query($sql); - if ($resql) { + if ($resql) + { $num = $this->db->num_rows($resql); - while ( $obj = $this->db->fetch_object($resql) ) { + $i = 0; + while ($obj = $this->db->fetch_object($resql) && $i < $num) + { $line = new BookKeepingLine(); $line->numero_compte = $obj->numero_compte; $line->debit = $obj->debit; $line->credit = $obj->credit; $this->lines[] = $line; + + $i++; } $this->db->free($resql); From 995f4fa35fa3e4038ed4fabf33ff2e5b2595815b Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sun, 14 Oct 2018 23:57:07 +0200 Subject: [PATCH 20/36] Fix limit --- htdocs/accountancy/class/bookkeeping.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index a9bfcce027a..b228588b90f 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -1021,7 +1021,7 @@ class BookKeeping extends CommonObject $num = $this->db->num_rows($resql); $i = 0; - while ($obj = $this->db->fetch_object($resql) && $i < $num) + while (($obj = $this->db->fetch_object($resql)) && ($i < min($limit, $num))) { $line = new BookKeepingLine(); From b13d9650f29a9515a25f83123dab4b83881ed193 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 00:06:16 +0200 Subject: [PATCH 21/36] Fix pagination --- htdocs/accountancy/bookkeeping/balance.php | 33 +++++++++++++--------- 1 file changed, 19 insertions(+), 14 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index bfd65ee1be7..21ae4759447 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -104,23 +104,27 @@ if ($sortorder == "") if ($sortfield == "") $sortfield = "t.numero_compte"; -$options = ''; + +$param=''; +if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); +if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); + $filter = array (); if (! empty($search_date_start)) { $filter['t.doc_date>='] = $search_date_start; - $options .= '&date_startmonth=' . GETPOST('date_startmonth', 'int') . '&date_startday=' . GETPOST('date_startday', 'int') . '&date_startyear=' . GETPOST('date_startyear', 'int'); + $param .= '&date_startmonth=' . GETPOST('date_startmonth', 'int') . '&date_startday=' . GETPOST('date_startday', 'int') . '&date_startyear=' . GETPOST('date_startyear', 'int'); } if (! empty($search_date_end)) { $filter['t.doc_date<='] = $search_date_end; - $options .= '&date_endmonth=' . GETPOST('date_endmonth', 'int') . '&date_endday=' . GETPOST('date_endday', 'int') . '&date_endyear=' . GETPOST('date_endyear', 'int'); + $param .= '&date_endmonth=' . GETPOST('date_endmonth', 'int') . '&date_endday=' . GETPOST('date_endday', 'int') . '&date_endyear=' . GETPOST('date_endyear', 'int'); } if (! empty($search_accountancy_code_start)) { $filter['t.numero_compte>='] = $search_accountancy_code_start; - $options .= '&search_accountancy_code_start=' . $search_accountancy_code_start; + $param .= '&search_accountancy_code_start=' . $search_accountancy_code_start; } if (! empty($search_accountancy_code_end)) { $filter['t.numero_compte<='] = $search_accountancy_code_end; - $options .= '&search_accountancy_code_end=' . $search_accountancy_code_end; + $param .= '&search_accountancy_code_end=' . $search_accountancy_code_end; } @@ -137,8 +141,8 @@ if (GETPOST('button_removefilter_x','alpha') || GETPOST('button_removefilter.x', $filter = array(); } -if ($action == 'export_csv') { - +if ($action == 'export_csv') +{ $sep = $conf->global->ACCOUNTING_EXPORT_SEPARATORCSV; $filename = 'balance'; @@ -200,7 +204,8 @@ if ($action != 'export_csv') print ''; $button = 'global->ACCOUNTING_EXPORT_FORMAT.')" />'; - print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $options, $sortfield, $sortorder, $button, $result, $result, 'title_accountancy', 0); + + print_barre_liste($title_page, $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $button, $result, $nbtotalofrecords, 'title_accountancy', 0, '', '', $limit); $moreforfilter = ''; @@ -238,12 +243,12 @@ if ($action != 'export_csv') print ''; print ''; - print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $options, "", $sortfield, $sortorder); - print_liste_field_titre("Label", $_SERVER['PHP_SELF'], "t.label_operation", "", $options, "", $sortfield, $sortorder); - print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $options, 'align="right"', $sortfield, $sortorder); - print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $options, 'align="right"', $sortfield, $sortorder); - print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $options, "", 'align="right"', $sortfield, $sortorder); - print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $options, "", 'width="60" align="center"', $sortfield, $sortorder); + print_liste_field_titre("AccountAccounting", $_SERVER['PHP_SELF'], "t.numero_compte", "", $param, "", $sortfield, $sortorder); + print_liste_field_titre("Label", $_SERVER['PHP_SELF'], "t.label_operation", "", $param, "", $sortfield, $sortorder); + print_liste_field_titre("Debit", $_SERVER['PHP_SELF'], "t.debit", "", $param, 'align="right"', $sortfield, $sortorder); + print_liste_field_titre("Credit", $_SERVER['PHP_SELF'], "t.credit", "", $param, 'align="right"', $sortfield, $sortorder); + print_liste_field_titre("Balance", $_SERVER["PHP_SELF"], "", $param, "", 'align="right"', $sortfield, $sortorder); + print_liste_field_titre('', $_SERVER["PHP_SELF"], "", $param, "", 'width="60" align="center"', $sortfield, $sortorder); print "\n"; $total_debit = 0; From 35eeb32f5d87621819cd58dac2ba6815c1624584 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 00:08:28 +0200 Subject: [PATCH 22/36] Fix pagination --- htdocs/accountancy/bookkeeping/balance.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/balance.php b/htdocs/accountancy/bookkeeping/balance.php index 21ae4759447..fe797cc3e06 100644 --- a/htdocs/accountancy/bookkeeping/balance.php +++ b/htdocs/accountancy/bookkeeping/balance.php @@ -274,7 +274,7 @@ if ($action != 'export_csv') { // Affiche un Sous-Total par compte comptable if ($displayed_account != "") { - print '' . $langs->trans("SubTotal") . ':' . price($sous_total_debit) . '' . price($sous_total_credit) . '' . price($sous_total_credit - $sous_total_debit) . ''; + print '' . $langs->trans("SubTotal") . ':' . price($sous_total_debit) . '' . price($sous_total_credit) . '' . price(price2num($sous_total_credit - $sous_total_debit)) . ''; print " \n"; print ''; } @@ -305,11 +305,11 @@ if ($action != 'export_csv') $sous_total_credit += $line->credit; } - print '' . $langs->trans("SubTotal") . ':' . price($sous_total_debit) . '' . price($sous_total_credit) . '' . price($sous_total_credit - $sous_total_debit) . ''; + print '' . $langs->trans("SubTotal") . ':' . price($sous_total_debit) . '' . price($sous_total_credit) . '' . price(price2num($sous_total_credit - $sous_total_debit)) . ''; print " \n"; print ''; - print '' . $langs->trans("AccountBalance") . ':' . price($total_debit) . '' . price($total_credit) . '' . price($total_credit - $total_debit) . ''; + print '' . $langs->trans("AccountBalance") . ':' . price($total_debit) . '' . price($total_credit) . '' . price(price2num($total_credit - $total_debit)) . ''; print " \n"; print ''; From c881be847d6093c3770ef58046f0b67e15345357 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 01:47:44 +0200 Subject: [PATCH 23/36] Fix remove step in accountancy if module expense report not used --- htdocs/accountancy/index.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/htdocs/accountancy/index.php b/htdocs/accountancy/index.php index ac674eb95e0..4dec253cb90 100644 --- a/htdocs/accountancy/index.php +++ b/htdocs/accountancy/index.php @@ -146,9 +146,12 @@ if ($conf->accounting->enabled) print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("BillsSuppliers"), ''.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("SuppliersVentilation").'')."\n"; print "
\n"; - $step++; - print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("ExpenseReports"), ''.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'')."\n"; - print "
\n"; + if (! empty($conf->expensereport->enabled) || ! empty($conf->deplacement->enabled)) + { + $step++; + print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescBind", chr(64+$step), $langs->transnoentitiesnoconv("ExpenseReports"), ''.$langs->transnoentitiesnoconv("MenuAccountancy")."-".$langs->transnoentitiesnoconv("ExpenseReportsVentilation").'')."\n"; + print "
\n"; + } $step++; print img_picto('', 'puce').' '.$langs->trans("AccountancyAreaDescWriteRecords", chr(64+$step), $langs->transnoentitiesnoconv("Journalization"), $langs->transnoentitiesnoconv("WriteBookKeeping"))."\n"; From 0a8f3051510d36cdd53ec7b0d1e2197655e1431a Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 02:40:49 +0200 Subject: [PATCH 24/36] Trans --- htdocs/langs/en_US/admin.lang | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 6b18dab5848..4630757dbad 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -229,7 +229,7 @@ DoNotStoreClearPassword=Do no store clear passwords in database but store only e MainDbPasswordFileConfEncrypted=Database password encrypted in conf.php (Activated recommended) InstrucToEncodePass=To have password encoded into the conf.php file, replace the line
$dolibarr_main_db_pass="...";
by
$dolibarr_main_db_pass="crypted:%s"; InstrucToClearPass=To have password decoded (clear) into the conf.php file, replace the line
$dolibarr_main_db_pass="crypted:...";
by
$dolibarr_main_db_pass="%s"; -ProtectAndEncryptPdfFiles=Protection of generated PDF files NOT recommended, breaks mass PDF generation) +ProtectAndEncryptPdfFiles=Protection of generated PDF files NOT recommended (breaks mass PDF generation) ProtectAndEncryptPdfFilesDesc=Protection of a PDF document keeps it available to read and print with any PDF browser. However, editing and copying is not possible anymore. Note that using this feature makes building of a global merged PDFs not working. Feature=Feature DolibarrLicense=License From 30072a98e96e2fc82244052ee97b303de50ca1ee Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 11:04:29 +0200 Subject: [PATCH 25/36] FIX content lost when editing a label with " --- htdocs/projet/card.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/projet/card.php b/htdocs/projet/card.php index dd18a115ab6..e2632fe244e 100644 --- a/htdocs/projet/card.php +++ b/htdocs/projet/card.php @@ -765,7 +765,7 @@ elseif ($object->id > 0) // Label print ''.$langs->trans("Label").''; - print ''; + print ''; // Status print ''.$langs->trans("Status").''; From f59dba66e7b571b974fa58ac2dbb4131e4afbca3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:23:35 +0200 Subject: [PATCH 26/36] Fix phpcs --- htdocs/product/class/product.class.php | 92 +++++++++++++------------- 1 file changed, 46 insertions(+), 46 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 5bf2f45d31c..5326fadd556 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4750,51 +4750,51 @@ class Product extends CommonObject } } - /** - * Load information for tab info - * - * @param int $id Id of thirdparty to load - * @return void - */ - function info($id) - { - $sql = "SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,"; - $sql.= " p.fk_user_author, p.fk_user_modif"; - $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p"; - $sql.= " WHERE p.rowid = ".$id; + /** + * Load information for tab info + * + * @param int $id Id of thirdparty to load + * @return void + */ + function info($id) + { + $sql = "SELECT p.rowid, p.ref, p.datec as date_creation, p.tms as date_modification,"; + $sql.= " p.fk_user_author, p.fk_user_modif"; + $sql.= " FROM ".MAIN_DB_PREFIX.$this->table_element." as p"; + $sql.= " WHERE p.rowid = ".$id; - $result=$this->db->query($sql); - if ($result) - { - if ($this->db->num_rows($result)) - { - $obj = $this->db->fetch_object($result); - - $this->id = $obj->rowid; - - if ($obj->fk_user_author) { - $cuser = new User($this->db); - $cuser->fetch($obj->fk_user_author); - $this->user_creation = $cuser; - } - - if ($obj->fk_user_modif) { - $muser = new User($this->db); - $muser->fetch($obj->fk_user_modif); - $this->user_modification = $muser; - } - - $this->ref = $obj->ref; - $this->date_creation = $this->db->jdate($obj->date_creation); - $this->date_modification = $this->db->jdate($obj->date_modification); - } - - $this->db->free($result); - - } - else + $result=$this->db->query($sql); + if ($result) { - dol_print_error($this->db); - } - } -} + if ($this->db->num_rows($result)) + { + $obj = $this->db->fetch_object($result); + + $this->id = $obj->rowid; + + if ($obj->fk_user_author) { + $cuser = new User($this->db); + $cuser->fetch($obj->fk_user_author); + $this->user_creation = $cuser; + } + + if ($obj->fk_user_modif) { + $muser = new User($this->db); + $muser->fetch($obj->fk_user_modif); + $this->user_modification = $muser; + } + + $this->ref = $obj->ref; + $this->date_creation = $this->db->jdate($obj->date_creation); + $this->date_modification = $this->db->jdate($obj->date_modification); + } + + $this->db->free($result); + + } + else + { + dol_print_error($this->db); + } + } +} \ No newline at end of file From 6ab037c766c7c7a6e9b0e05c5385103bf8b2644f Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:26:18 +0200 Subject: [PATCH 27/36] Fix code comment --- htdocs/product/class/product.class.php | 127 +++++++++++++------------ 1 file changed, 64 insertions(+), 63 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 5326fadd556..db367301120 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -4005,7 +4005,7 @@ class Product extends CommonObject * 'warehouseclosed' = Load stock from closed warehouses only, * 'warehouseinternal' = Load stock from warehouses for internal correction/transfer only * @return int < 0 if KO, > 0 if OK - * @see load_virtual_stock, getBatchInfo + * @see load_virtual_stock(), loadBatchInfo() */ function load_stock($option='') { @@ -4074,79 +4074,80 @@ class Product extends CommonObject } } - // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps + // phpcs:disable PEAR.NamingConventions.ValidFunctionName.NotCamelCaps /** * Load value ->stock_theorique of a product. Property this->id must be defined. * This function need a lot of load. If you use it on list, use a cache to execute it one for each product id. * * @return int < 0 if KO, > 0 if OK - * @see load_stock, getBatchInfo + * @see load_stock(), loadBatchInfo() */ - function load_virtual_stock() - { - // phpcs:enable - global $conf, $hookmanager, $action; + function load_virtual_stock() + { + // phpcs:enable + global $conf, $hookmanager, $action; - $stock_commande_client=0; - $stock_commande_fournisseur=0; - $stock_sending_client=0; - $stock_reception_fournisseur=0; + $stock_commande_client=0; + $stock_commande_fournisseur=0; + $stock_sending_client=0; + $stock_reception_fournisseur=0; - if (! empty($conf->commande->enabled)) - { - $result=$this->load_stats_commande(0,'1,2', 1); - if ($result < 0) dol_print_error($this->db,$this->error); - $stock_commande_client=$this->stats_commande['qty']; - } - if (! empty($conf->expedition->enabled)) - { - $result=$this->load_stats_sending(0,'1,2', 1); - if ($result < 0) dol_print_error($this->db,$this->error); - $stock_sending_client=$this->stats_expedition['qty']; - } - if (! empty($conf->fournisseur->enabled)) - { - $result=$this->load_stats_commande_fournisseur(0,'1,2,3,4', 1); - if ($result < 0) dol_print_error($this->db,$this->error); - $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty']; + if (! empty($conf->commande->enabled)) + { + $result=$this->load_stats_commande(0,'1,2', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_commande_client=$this->stats_commande['qty']; + } + if (! empty($conf->expedition->enabled)) + { + $result=$this->load_stats_sending(0,'1,2', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_sending_client=$this->stats_expedition['qty']; + } + if (! empty($conf->fournisseur->enabled)) + { + $result=$this->load_stats_commande_fournisseur(0,'1,2,3,4', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_commande_fournisseur=$this->stats_commande_fournisseur['qty']; - $result=$this->load_stats_reception(0,'4', 1); - if ($result < 0) dol_print_error($this->db,$this->error); - $stock_reception_fournisseur=$this->stats_reception['qty']; - } + $result=$this->load_stats_reception(0,'4', 1); + if ($result < 0) dol_print_error($this->db,$this->error); + $stock_reception_fournisseur=$this->stats_reception['qty']; + } - // Stock decrease mode - if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { - $this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) { - $this->stock_theorique=$this->stock_reel; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) { - $this->stock_theorique=$this->stock_reel-$stock_commande_client; - } - // Stock Increase mode - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { - $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) { - $this->stock_theorique-=$stock_reception_fournisseur; - } - if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { - $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; - } + // Stock decrease mode + if (! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT) || ! empty($conf->global->STOCK_CALCULATE_ON_SHIPMENT_CLOSE)) { + $this->stock_theorique=$this->stock_reel-$stock_commande_client+$stock_sending_client; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_VALIDATE_ORDER)) { + $this->stock_theorique=$this->stock_reel; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_BILL)) { + $this->stock_theorique=$this->stock_reel-$stock_commande_client; + } + // Stock Increase mode + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_DISPATCH_ORDER)) { + $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_VALIDATE_ORDER)) { + $this->stock_theorique-=$stock_reception_fournisseur; + } + if (! empty($conf->global->STOCK_CALCULATE_ON_SUPPLIER_BILL)) { + $this->stock_theorique+=$stock_commande_fournisseur-$stock_reception_fournisseur; + } - if (! is_object($hookmanager)) { - include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; - $hookmanager=new HookManager($this->db); + if (! is_object($hookmanager)) { + include_once DOL_DOCUMENT_ROOT.'/core/class/hookmanager.class.php'; + $hookmanager=new HookManager($this->db); + } + $hookmanager->initHooks(array('productdao')); + $parameters=array('id'=>$this->id); + // Note that $action and $object may have been modified by some hooks + $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); + if ($reshook > 0) $this->stock_theorique = $hookmanager->resArray['stock_theorique']; + + return 1; } - $hookmanager->initHooks(array('productdao')); - $parameters=array('id'=>$this->id); - // Note that $action and $object may have been modified by some hooks - $reshook=$hookmanager->executeHooks('loadvirtualstock', $parameters, $this, $action); - if ($reshook > 0) $this->stock_theorique = $hookmanager->resArray['stock_theorique']; - - } /** @@ -4154,7 +4155,7 @@ class Product extends CommonObject * * @param string $batch Lot/serial number * @return array Array with record into product_batch - * @see load_stock, load_virtual_stock + * @see load_stock(), load_virtual_stock() */ function loadBatchInfo($batch) { From cca87f3d5af853117b00d3582e0f88655c610bb4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:27:17 +0200 Subject: [PATCH 28/36] Fix phpcs --- htdocs/product/class/product.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index db367301120..fe0e9c3733c 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -299,7 +299,7 @@ class Product extends CommonObject /** * @deprecated - * @see ref_supplier + * @see $ref_supplier */ public $ref_fourn; public $ref_supplier; @@ -3282,7 +3282,7 @@ class Product extends CommonObject * * @param int $fromId Id product source * @param int $toId Id product target - * @return nt < 0 if KO, > 0 if OK + * @return int < 0 if KO, > 0 if OK */ function clone_price($fromId, $toId) { From df4b3b09d2f5abfeadc8bf9e659a90d4715708ab Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:30:07 +0200 Subject: [PATCH 29/36] Fix var not defined --- htdocs/compta/facture/class/facture.class.php | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index e9cb7aa214e..9fa7fc988e2 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4116,18 +4116,18 @@ class Facture extends CommonInvoice $langs->load("bills"); - if (! dol_strlen($modele)) { + if (! dol_strlen($modele)) + { + $modele = 'crabe'; + $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$this->type; - $modele = 'crabe'; - $thisTypeConfName = 'FACTURE_ADDON_PDF_'.$type; - - if ($this->modelpdf) { - $modele = $this->modelpdf; - }elseif (! empty($conf->global->{'FACTURE_ADDON_PDF_'.$this->type})){ - $modele = $conf->global->{'FACTURE_ADDON_PDF_'.$this->type} ; - }elseif (! empty($conf->global->FACTURE_ADDON_PDF)) { - $modele = $conf->global->FACTURE_ADDON_PDF; - } + if ($this->modelpdf) { + $modele = $this->modelpdf; + } elseif (! empty($conf->global->$thisTypeConfName)) { + $modele = $conf->global->$thisTypeConfName; + } elseif (! empty($conf->global->FACTURE_ADDON_PDF)) { + $modele = $conf->global->FACTURE_ADDON_PDF; + } } $modelpath = "core/modules/facture/doc/"; From 5d9b77051186d918e9dc2429a2475d4179809fad Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:30:25 +0200 Subject: [PATCH 30/36] phpcs --- htdocs/compta/facture/class/facture.class.php | 2 +- htdocs/core/class/utils.class.php | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/facture/class/facture.class.php b/htdocs/compta/facture/class/facture.class.php index 9fa7fc988e2..e225d1468c4 100644 --- a/htdocs/compta/facture/class/facture.class.php +++ b/htdocs/compta/facture/class/facture.class.php @@ -4107,7 +4107,7 @@ class Facture extends CommonInvoice * @param int $hidedetails Hide details of lines * @param int $hidedesc Hide description * @param int $hideref Hide ref - * @param null|array $moreparams Array to provide more information + * @param null|array $moreparams Array to provide more information * @return int <0 if KO, >0 if OK */ public function generateDocument($modele, $outputlangs, $hidedetails=0, $hidedesc=0, $hideref=0, $moreparams=null) diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index 9f680ef4990..7904f485d6a 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -284,8 +284,9 @@ class Utils } $errormsg=''; + $handle = ''; - // Debut appel methode execution + // Start call method to execute dump $fullcommandcrypted=$command." ".$paramcrypted." 2>&1"; $fullcommandclear=$command." ".$paramclear." 2>&1"; if ($compression == 'none') $handle = fopen($outputfile, 'w'); From 4cd7119d1c91d5755d796c7f21d17584950a69da Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:38:50 +0200 Subject: [PATCH 31/36] Not used var --- htdocs/datapolicies/class/datapolicies.class.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/htdocs/datapolicies/class/datapolicies.class.php b/htdocs/datapolicies/class/datapolicies.class.php index df818db6f5e..e6b3af3bf25 100644 --- a/htdocs/datapolicies/class/datapolicies.class.php +++ b/htdocs/datapolicies/class/datapolicies.class.php @@ -149,7 +149,7 @@ Class DataPolicies extends Contact $error = 0; $from = $user->getFullName($langs) . ' <' . $user->email . '>'; - $replyto = $from; + $sendto = $contact->email; $code= md5($contact->email); if (!empty($contact->default_lang)) { @@ -225,7 +225,7 @@ Class DataPolicies extends Contact $error = 0; $from = $user->getFullName($langs) . ' <' . $user->email . '>'; - $replyto = $from; + $sendto = $societe->email; $code= md5($societe->email); @@ -297,7 +297,7 @@ Class DataPolicies extends Contact $error = 0; $from = $user->getFullName($langs) . ' <' . $user->email . '>'; - $replyto = $from; + $sendto = $adherent->email; $code= md5($adherent->email); From a20498126aabeece85bf30cf953ec9dd2943c0d3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 15 Oct 2018 13:40:22 +0200 Subject: [PATCH 32/36] Fix init var --- htdocs/website/class/website.class.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/htdocs/website/class/website.class.php b/htdocs/website/class/website.class.php index b9be32bcafa..3f51f669829 100644 --- a/htdocs/website/class/website.class.php +++ b/htdocs/website/class/website.class.php @@ -1155,7 +1155,8 @@ class Website extends CommonObject $MAXHEIGHT = 4 * $HEIGHTOPTION; $nboflanguage = count($languagecodes); - $out.=''."\n"; + $out =''."\n"; + $out.= '