diff --git a/.gitignore b/.gitignore index 371c8be2f5e..e4790fe7b4e 100644 --- a/.gitignore +++ b/.gitignore @@ -55,3 +55,4 @@ yarn.lock package-lock.json doc/install.lock +/factory/ diff --git a/ChangeLog b/ChangeLog index 2c9e138e1f9..8c52db8af69 100644 --- a/ChangeLog +++ b/ChangeLog @@ -105,6 +105,8 @@ NEW: Use an ajax call for the clicktodial feature instead of href link. NEW: when multiple order linked to facture, show list into note. NEW: when we delete several objects with massaction, if somes object has child we must see which objects are concerned and nevertheless delete objects which can be deleted NEW: Editing a page in website module keep old page with name .back +NEW: External backups can be downloaded from the "About info page". +NEW: Add massaction to switch status on sale / on purchase of a product. For developers: @@ -131,8 +133,9 @@ NEW: printFieldListFrom hook call on several lists NEW: Use lang selector when using a field key 'lang' in modulebuilder NEW: we need to be able to put more filters on deleteByParentField() function NEW: make it easier to set the `keyword`, `keywords` and `description` attributes of an ecm file object - - +NEW: Experimental feature to manage user sessions in database +NEW: Hidden option API_DISABLE_COMPRESSION is now visible in API setup page. +NEW: Add hook printUnderHeaderPDFline on invoice PDF templates (can be used for example to add a barcode or more information on header of invoices). Following changes may create regressions for some external modules, but were necessary to make Dolibarr better: * Update hook 'printOriginObjectLine', removed check on product type and special code. Need now reshook. @@ -140,8 +143,50 @@ Following changes may create regressions for some external modules, but were nec * The method static ActionComm::getActions($db, ...) is no more static. Use $actioncomm->getActions(...) instead (without $db param). * The 'action=delete&file=...' has been replaced with 'action=deletefile&file=...' to avoid confusion with deletion of object lines. * Method getDictvalue has been renamed into getDictionaryValue to match camel case rule. +* To execute shell or command line command, your code must never use method like exec, shell_exec, popen, .. but must use the built-in + method executeCLI() available into core/class/utils.class.php +* Class file expeditionbatch.class.php renamed to expeditionlinebatch.class.php +* ExpeditionLineBatch::fetchAll is not static anymore and first parameter $db is removed +* ExtraFields->showOutputField parameter 4 'extrafieldsobjectkey' is now required +* CommonObject method add_object_linked now sets targettype to 'mymodule_myobject' instead of 'myobject', + you can use hook 'setLinkedObjectSourceTargetType' to set your usual targettype +***** ChangeLog for 14.0.5 compared to 14.0.4 ***** + +FIX: 13.0: printFieldListWhere called twice on same query +FIX: 14.0.4 fatal error on cron list. +FIX: #19476 +FIX: #19564 +FIX: #19651 +FIX: Accountancy - SQL error on subledger account search in journal +FIX: apply eldy's suggestion to not overwrite existing extrafields of $line +FIX: Can't close a down payment if paid with credit notes. +FIX: better compatibility with multicompany +FIX: contact card: bad colspan value for separator extrafield in creation/modification form +FIX: discounts are applied both when fetching the best supplier price and when displaying it +FIX: double display for contact categorie on societe create card +FIX: fatal error on cron list. +FIX: holiday list: only mass delete if leave request is not in draft, canceled or refused, like in card +FIX: holiday mass deletion: correct return of record deleted +FIX: Holiday month report +FIX: info tab on customer invoice record not found +FIX: line extrafields are inoperative in dispatch cards even when they exist +FIX: list of categories in stats of supplier invoices +FIX: missing default value for more comprehensive +FIX: multicurrency: fields in discount unitialized when creating deposit +FIX: Navigation on bank transaction list +FIX: Can't edit a bank transaction due to bad permission check. +FIX: Option MAIN_DIRECT_STATUS_UPDATE broken. Ajax on/off not saving value in DB after updating to version >=12 +FIX: postgresql compatibility, "" as is not authorized +FIX: printFieldListWhere called twice (at different locations) for the same SQL query, can result in syntax errors +FIX: select too large into addrights (pb of missing parenthesis) +FIX: set optional from post, we can't untick boolean field on product card +FIX: Take into consideration work leave over serveral months +FIX: test if method exist on wrong object +FIX: title for nature of third party in company list +FIX: Urgent onglet contact inaccessible depuis une facture +FIX: wrong syntax of sql request ***** ChangeLog for 14.0.4 compared to 14.0.3 ***** @@ -614,7 +659,8 @@ Following changes may create regressions for some external modules, but were nec * Removed deprecated substitution key __REFCLIENT__ (replaced with __REF_CLIENT__) * Removed constant MAIN_COUNTRIES_IN_EEC. You can now set if country is in Europe or not from the dictionary of countries. * v14 seems to work correctly on PHP v8 but it generates a lot of verbose warnings. Currently, v14 i snot yet officialy supported with PHP 8. - +* To execute shell or command line command, your code must never use method like exec, shell_exec, popen, .. but must use the built-in + method executeCLI() available into core/class/utils.class.php ***** ChangeLog for 13.0.5 compared to 13.0.4 ***** diff --git a/dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf b/dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf deleted file mode 100644 index fef9f48f53e..00000000000 Binary files a/dev/resources/iso-normes/Intracommreport-ManuelDebXml.pdf and /dev/null differ diff --git a/dev/resources/iso-normes/QR code for invoices.txt b/dev/resources/iso-normes/QR code for invoices.txt new file mode 100644 index 00000000000..a55c9569297 --- /dev/null +++ b/dev/resources/iso-normes/QR code for invoices.txt @@ -0,0 +1,13 @@ +List of QR Code format we found on some invoices +------------------------------------------------ + + +* For SEPA QR payment Code format (Europe) +------------------------------------------ +https://en.wikipedia.org/wiki/EPC_QR_code#Generators + + + +* For ZATCA QR Code format (Saudi Arabia) +----------------------------------------- +https://www.pwc.com/m1/en/services/tax/me-tax-legal-news/2021/saudi-arabia-guide-to-develop-compliant-qr-code-for-simplified-einvoices.html diff --git a/dev/resources/iso-normes/address_format.txt b/dev/resources/iso-normes/address_format.txt index d87e90e79b5..18069cd89fa 100644 --- a/dev/resources/iso-normes/address_format.txt +++ b/dev/resources/iso-normes/address_format.txt @@ -1,3 +1,5 @@ +Address format + https://bitboost.com/ref/international-address-formats.html#Formats https://www.upu.int/en/Postal-Solutions/Programmes-Services/Addressing-Solutions diff --git a/dev/resources/facturx-zugferd/README.txt b/dev/resources/iso-normes/facturx-zugferd/README.txt similarity index 100% rename from dev/resources/facturx-zugferd/README.txt rename to dev/resources/iso-normes/facturx-zugferd/README.txt diff --git a/dev/resources/iso-normes/14-pourquoi le format PDF A.pdf b/dev/resources/iso-normes/format PDF - PDF A.pdf similarity index 100% rename from dev/resources/iso-normes/14-pourquoi le format PDF A.pdf rename to dev/resources/iso-normes/format PDF - PDF A.pdf diff --git a/dev/resources/iso-normes/format_FEC-Lien_outil_de_test_agréé.pdf b/dev/resources/iso-normes/format_FEC - Lien_outil_de_test_agréé.pdf similarity index 100% rename from dev/resources/iso-normes/format_FEC-Lien_outil_de_test_agréé.pdf rename to dev/resources/iso-normes/format_FEC - Lien_outil_de_test_agréé.pdf diff --git a/dev/resources/iso-normes/sample_FEC_file.txt b/dev/resources/iso-normes/format_FEC - fie example.txt similarity index 100% rename from dev/resources/iso-normes/sample_FEC_file.txt rename to dev/resources/iso-normes/format_FEC - fie example.txt diff --git a/dev/resources/intracommreport/manuelDebXml1.2.pdf b/dev/resources/iso-normes/intracommreport/Intracommreport-ManuelDebXml.pdf similarity index 100% rename from dev/resources/intracommreport/manuelDebXml1.2.pdf rename to dev/resources/iso-normes/intracommreport/Intracommreport-ManuelDebXml.pdf diff --git a/dev/resources/iso-normes/Intracommreport-ManuelDesXML.pdf b/dev/resources/iso-normes/intracommreport/Intracommreport-ManuelDesXML.pdf similarity index 100% rename from dev/resources/iso-normes/Intracommreport-ManuelDesXML.pdf rename to dev/resources/iso-normes/intracommreport/Intracommreport-ManuelDesXML.pdf diff --git a/dev/resources/intracommreport/schema_deb.xsd b/dev/resources/iso-normes/intracommreport/schema_deb.xsd similarity index 100% rename from dev/resources/intracommreport/schema_deb.xsd rename to dev/resources/iso-normes/intracommreport/schema_deb.xsd diff --git a/dev/resources/iso-normes/locales.txt b/dev/resources/iso-normes/locales.txt index 67ea5280342..a4459d2a8b1 100644 --- a/dev/resources/iso-normes/locales.txt +++ b/dev/resources/iso-normes/locales.txt @@ -1,3 +1,5 @@ +Date and number format +---------------------- For languages: https://icu4c-demos.unicode.org/icu-bin/icudemos - Locale Explorer -> Error 404 diff --git a/dev/resources/sepa/pain.001.001.03.xsd b/dev/resources/iso-normes/sepa/pain.001.001.03.xsd similarity index 100% rename from dev/resources/sepa/pain.001.001.03.xsd rename to dev/resources/iso-normes/sepa/pain.001.001.03.xsd diff --git a/dev/resources/sepa/pain.008.001.02.xsd b/dev/resources/iso-normes/sepa/pain.008.001.02.xsd similarity index 100% rename from dev/resources/sepa/pain.008.001.02.xsd rename to dev/resources/iso-normes/sepa/pain.008.001.02.xsd diff --git a/dev/resources/sepa/sample-credit-transfer.xml b/dev/resources/iso-normes/sepa/sample-credit-transfer.xml similarity index 100% rename from dev/resources/sepa/sample-credit-transfer.xml rename to dev/resources/iso-normes/sepa/sample-credit-transfer.xml diff --git a/dev/resources/sepa/sample-direct-debit.xml b/dev/resources/iso-normes/sepa/sample-direct-debit.xml similarity index 100% rename from dev/resources/sepa/sample-direct-debit.xml rename to dev/resources/iso-normes/sepa/sample-direct-debit.xml diff --git a/dev/resources/sepa/text.txt b/dev/resources/iso-normes/sepa/text.txt similarity index 100% rename from dev/resources/sepa/text.txt rename to dev/resources/iso-normes/sepa/text.txt diff --git a/dev/resources/iso-normes/world_tax_rates.txt b/dev/resources/iso-normes/world_tax_rates.txt index c007474e5fd..508446b618a 100644 --- a/dev/resources/iso-normes/world_tax_rates.txt +++ b/dev/resources/iso-normes/world_tax_rates.txt @@ -1,3 +1,6 @@ +VAT Rates +--------- + http://www.taxrates.cc/index.html https://en.wikipedia.org/wiki/List_of_countries_by_tax_rates diff --git a/dev/tools/fixdosfiles.sh b/dev/tools/fixdosfiles.sh index 6fd152127fb..4be867aea98 100755 --- a/dev/tools/fixdosfiles.sh +++ b/dev/tools/fixdosfiles.sh @@ -17,14 +17,14 @@ fi # To detec if [ "x$1" = "xlist" ] then - find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" -o -iname "*.pml" \) -exec file "{}" + | grep -v 'documents\/website' | grep -v 'documents\/mdedias' | grep CRLF -# find . \( -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep -v 'documents\/website' | grep -v 'documents\/mdedias' | grep -v 'htdocs\/includes' | grep CRLF + find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" -o -iname "*.pml" \) -exec file "{}" + | grep -v 'custom\/' | grep -v 'documents\/website' | grep -v 'documents\/medias' | grep -v 'documents\/sellyoursaas' | grep CRLF +# find . \( -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" \) -exec file "{}" + | grep -v 'custom\/' | grep -v 'documents\/website' | grep -v 'documents\/medias' | grep -v 'documents\/sellyoursaas' | grep -v 'htdocs\/includes' | grep CRLF fi # To convert if [ "x$1" = "xfix" ] then - for fic in `find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" -o -iname "*.pml" \) -exec file "{}" + | grep -v 'documents\/website' | grep -v 'documents\/mdedias' | grep CRLF | awk -F':' '{ print $1 }' ` + for fic in `find . \( -iname "functions" -o -iname "*.md" -o -iname "*.html" -o -iname "*.htm" -o -iname "*.php" -o -iname "*.sh" -o -iname "*.cml" -o -iname "*.css" -o -iname "*.js" -o -iname "*.lang" -o -iname "*.pl" -o -iname "*.sql" -o -iname "*.txt" -o -iname "*.xml" -o -iname "*.pml" \) -exec file "{}" + | grep -v 'custom\/' | grep -v 'documents\/website' | grep -v 'documents\/medias' | grep -v 'documents\/sellyoursaas' | grep CRLF | awk -F':' '{ print $1 }' ` do echo "Fix file $fic" dos2unix "$fic" diff --git a/dev/tools/optimize_images.sh b/dev/tools/optimize_images.sh index 2f8a84c57e7..dd538c5e1aa 100755 --- a/dev/tools/optimize_images.sh +++ b/dev/tools/optimize_images.sh @@ -14,7 +14,8 @@ max_output_size=0 usage() { cat <trans("New"), $langs->trans("Addanaccount"), 'fa fa-plus-circle', './card.php?action=create'); include DOL_DOCUMENT_ROOT.'/core/tpl/massactions_pre.tpl.php'; - print_barre_liste($langs->trans('ListAccounts'), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'title_accountancy', 0, $newcardbutton, '', $limit, 0, 0, 1); + print_barre_liste($langs->trans('ListAccounts'), $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, $nbtotalofrecords, 'accounting_account', 0, $newcardbutton, '', $limit, 0, 0, 1); // Box to select active chart of account print $langs->trans("Selectchartofaccounts")." : "; @@ -404,6 +404,11 @@ if ($resql) { $moreforfilter = ''; + $accountstatic = new AccountingAccount($db); + $accountparent = new AccountingAccount($db); + $totalarray = array(); + $totalarray['nbfield'] = 0; + print '
'; print ''."\n"; @@ -466,11 +471,6 @@ if ($resql) { print_liste_field_titre($selectedfields, $_SERVER["PHP_SELF"], "", '', '', '', $sortfield, $sortorder, 'center maxwidthsearch '); print "\n"; - $accountstatic = new AccountingAccount($db); - $accountparent = new AccountingAccount($db); - $totalarray = array(); - $totalarray['nbfield'] = 0; - $i = 0; while ($i < min($num, $limit)) { $obj = $db->fetch_object($resql); @@ -615,8 +615,13 @@ if ($resql) { } if ($num == 0) { - $totalarray['nbfield']++; - print ''; + $colspan = 1; + foreach ($arrayfields as $key => $val) { + if (!empty($val['checked'])) { + $colspan++; + } + } + print ''; } print "
'.$langs->trans("None").'
'.$langs->trans("None").'
"; diff --git a/htdocs/accountancy/admin/card.php b/htdocs/accountancy/admin/card.php index 9430bf33439..91d8257ea7f 100644 --- a/htdocs/accountancy/admin/card.php +++ b/htdocs/accountancy/admin/card.php @@ -417,13 +417,13 @@ if ($action == 'create') { print '
'; if (!empty($user->rights->accounting->chartofaccount)) { - print ''.$langs->trans('Modify').''; + print 'id.'">'.$langs->trans('Modify').''; } else { print ''.$langs->trans('Modify').''; } if (!empty($user->rights->accounting->chartofaccount)) { - print ''.$langs->trans('Delete').''; + print 'id.'">'.$langs->trans('Delete').''; } else { print ''.$langs->trans('Delete').''; } diff --git a/htdocs/accountancy/admin/export.php b/htdocs/accountancy/admin/export.php index 9e393beeacd..8cef3a05cf4 100644 --- a/htdocs/accountancy/admin/export.php +++ b/htdocs/accountancy/admin/export.php @@ -142,7 +142,7 @@ $linkback = ''; print load_fiche_titre($langs->trans('ExportOptions'), $linkback, 'accountancy'); -print "\n".''; print ''; } - print ''; + print ''; print ' '; print ''; print ''; @@ -1663,20 +1663,20 @@ if ($resql) { } } - // Action edit/delete + // Action edit/delete and select print ''; // Transaction reconciliated or edit link if ($objp->conciliated && $bankaccount->canBeConciliated() > 0) { // If line not conciliated and account can be conciliated - print ''; + print ''; print img_edit(); print ''; } else { if ($user->rights->banque->modifier || $user->rights->banque->consolidate) { - print ''; + print ''; print img_edit(); print ''; } else { - print ''; + print ''; print img_view(); print ''; } @@ -1686,24 +1686,19 @@ if ($resql) { } } if ($user->rights->banque->modifier) { - print 'rowid.'&id='.$objp->bankid.'&page='.$page.'">'; + print 'rowid.'&page='.$page.$param.($sortfield ? '&sortfield='.$sortfield : '').($sortorder ? '&sortorder='.$sortorder : '').'">'; print img_delete('', 'class="marginleftonly"'); print ''; } } - print ''; - if (!$i) { - $totalarray['nbfield']++; - } // Action column - print ''; if ($massactionbutton || $massaction) { // If we are in select mode (massactionbutton defined) or if we have already selected and sent an action ($massaction) defined $selected = 0; if (in_array($obj->rowid, $arrayofselected)) { $selected = 1; } - print ''; + print ''; } print ''; if (!$i) { diff --git a/htdocs/compta/bank/card.php b/htdocs/compta/bank/card.php index c543b9edd9b..5d2bb71109b 100644 --- a/htdocs/compta/bank/card.php +++ b/htdocs/compta/bank/card.php @@ -175,7 +175,7 @@ if (empty($reshook)) { } // Fill array 'array_options' with data from add form - $ret = $extrafields->setOptionalsFromPost(null, $object); + $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET'); if (!$error) { $id = $object->create($user); @@ -343,7 +343,7 @@ if ($action == 'create') { print load_fiche_titre($langs->trans("NewFinancialAccount"), '', 'bank_account'); if ($conf->use_javascript_ajax) { - print "\n".''; // This ajax service is called only when a directory $selecteddir is opened but not when closed. - //print ''; } @@ -169,7 +169,7 @@ if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_ if (empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_ECM_DISABLE_JS)) { print '
    '; - // Load full tree from database. We will use it to define nbofsubdir and nboffilesinsubdir + // Load full manual tree from database. We will use it to define nbofsubdir and nboffilesinsubdir if (empty($sqltree)) { $sqltree = $ecmdirstatic->get_full_arbo(0); // Slow } diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php index 05843abed9d..5bac89345ce 100644 --- a/htdocs/core/ajax/objectonoff.php +++ b/htdocs/core/ajax/objectonoff.php @@ -65,9 +65,14 @@ if (!empty($user->socid)) { $socid = $user->socid; } -/*if (empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) { - accessforbidden('Calling this file is allowed only when MAIN_DIRECT_STATUS_UPDATE is set'); -}*/ +if (in_array($field, array('status'))) { + restrictedArea($user, $element, $id); +} elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) { // Special case for products + restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid'); +} else { + accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1); + exit; +} /* @@ -78,15 +83,6 @@ top_httphead(); print ''."\n"; -if (in_array($field, array('status'))) { - restrictedArea($user, $element, $id); -} elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) { // Special case for products - restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid'); -} else { - accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1); - exit; -} - // Registering new values if (($action == 'set') && !empty($id)) { $triggerkey = strtoupper($element).'_UPDATE'; diff --git a/htdocs/core/ajax/onlineSign.php b/htdocs/core/ajax/onlineSign.php index 488b5051ea5..5110918541f 100644 --- a/htdocs/core/ajax/onlineSign.php +++ b/htdocs/core/ajax/onlineSign.php @@ -51,11 +51,30 @@ if (!defined('NOBROWSERNOTIF')) { include '../../main.inc.php'; $action = GETPOST('action', 'aZ09'); + $signature = GETPOST('signaturebase64'); $ref = GETPOST('ref', 'aZ09'); $mode = GETPOST('mode', 'aZ09'); +$SECUREKEY = GETPOST("securekey"); // Secure key + $error = 0; $response = ""; + +$type = $mode; + +// Check securitykey +$securekeyseed = ''; +if ($type == 'proposal') { + $securekeyseed = $conf->global->PROPOSAL_ONLINE_SIGNATURE_SECURITY_TOKEN; +} + +if (!dol_verifyHash($securekeyseed.$type.$ref, $SECUREKEY, '0')) { + http_response_code(403); + print 'Bad value for securitykey. Value provided '.dol_escape_htmltag($SECUREKEY).' does not match expected value for ref='.dol_escape_htmltag($ref); + exit(-1); +} + + /* * Actions */ @@ -71,62 +90,91 @@ if ($action == "importSignature") { if (!empty($signature) && $signature[0] == "image/png;base64") { $signature = $signature[1]; $data = base64_decode($signature); - $upload_dir = DOL_DATA_ROOT."/".$mode."/".$ref."/"; - $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S"); - $filename = "signatures/".$date."_signature.png"; - if (!is_dir($upload_dir."signatures/")) { - if (!mkdir($upload_dir."signatures/")) { - $response ="error mkdir"; - $error++; + + if ($mode == "propale" || $mode == 'proposal') { + require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; + require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; + $object = new Propal($db); + $object->fetch(0, $ref); + + $upload_dir = !empty($conf->propal->multidir_output[$object->entity])?$conf->propal->multidir_output[$object->entity]:$conf->propal->dir_output; + $upload_dir .= '/'.dol_sanitizeFileName($object->ref).'/'; + + $date = dol_print_date(dol_now(), "%Y%m%d%H%M%S"); + $filename = "signatures/".$date."_signature.png"; + if (!is_dir($upload_dir."signatures/")) { + if (!dol_mkdir($upload_dir."signatures/")) { + $response ="Error mkdir. Failed to create dir ".$upload_dir."signatures/"; + $error++; + } } - } - if (!$error) { - $return = file_put_contents($upload_dir.$filename, $data); - if ($return == false) { - $response = 'error file_put_content'; - } else { - if ($mode == "propale") { - require_once DOL_DOCUMENT_ROOT.'/comm/propal/class/propal.class.php'; - require_once DOL_DOCUMENT_ROOT.'/core/lib/pdf.lib.php'; - $object = new Propal($db); - $object->fetch(0, $ref); - $pdf = pdf_getInstance(); - $pdf->Open(); - $pdf->AddPage(); - $pagecount = $pdf->setSourceFile($upload_dir.$ref.".pdf"); + if (!$error) { + $return = file_put_contents($upload_dir.$filename, $data); + if ($return == false) { + $error++; + $response = 'Error file_put_content: failed to create signature file.'; + } + } - $tppl = $pdf->importPage(1); - $pdf->useTemplate($tppl); - $pdf->Image($upload_dir.$filename, 129, 239.6, 60, 15); - $pdf->Close(); - $pdf->Output($upload_dir.$ref."_signed-".$date.".pdf", "F"); + if (!$error) { + $newpdffilename = $upload_dir.$ref."_signed-".$date.".pdf"; - $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; - $sql .= " SET fk_statut = ".((int) $object::STATUS_SIGNED).", note_private = '".$object->note_private."', date_signature='".$db->idate(dol_now())."'"; - $sql .= " WHERE rowid = ".((int) $object->id); + $pdf = pdf_getInstance(); + $pdf->Open(); + $pdf->AddPage(); + $pagecount = $pdf->setSourceFile($upload_dir.$ref.".pdf"); // original PDF - dol_syslog(__METHOD__, LOG_DEBUG); - $resql = $db->query($sql); - if (!$resql) { - $error++; - } else { - $num = $db->affected_rows($resql); - } + $tppl = $pdf->importPage(1); + $pdf->useTemplate($tppl); + $pdf->Image($upload_dir.$filename, 129, 239.6, 60, 15); // FIXME Position will be wrong with non A4 format. Use a value from width and height of page minus relative offset. + $pdf->Close(); + $pdf->Output($newpdffilename, "F"); - if (!$error) { - $db->commit(); - $response = "success"; - setEventMessage("PropalSigned"); - } else { - $db->rollback(); - $response = "error sql"; - } + $db->begin(); + + // Index the new file and update the last_main_doc property of object. + $object->indexFile($newpdffilename, 1); + + $online_sign_ip = getUserRemoteIP(); + $online_sign_name = ''; // TODO Ask name on form to sign + + $sql = "UPDATE ".MAIN_DB_PREFIX."propal"; + $sql .= " SET fk_statut = ".((int) $object::STATUS_SIGNED).", note_private = '".$db->escape($object->note_private)."',"; + $sql .= " date_signature = '".$db->idate(dol_now())."',"; + $sql .= " online_sign_ip = '".$db->escape($online_sign_ip)."'"; + if ($online_sign_name) { + $sql .= ", online_sign_name = '".$db->escape($online_sign_name)."'"; + } + $sql .= " WHERE rowid = ".((int) $object->id); + + dol_syslog(__METHOD__, LOG_DEBUG); + $resql = $db->query($sql); + if (!$resql) { + $error++; + } else { + $num = $db->affected_rows($resql); + } + + if (!$error) { + $db->commit(); + $response = "success"; + setEventMessages("PropalSigned", null, 'warnings'); + } else { + $db->rollback(); + $error++; + $response = "error sql"; } } } } else { + $error++; $response = 'error signature_not_found'; } } + +if ($error) { + http_response_code(501); +} + echo $response; diff --git a/htdocs/core/bookmarks_page.php b/htdocs/core/bookmarks_page.php index 32e2be230b9..dde8df5f82e 100644 --- a/htdocs/core/bookmarks_page.php +++ b/htdocs/core/bookmarks_page.php @@ -55,10 +55,22 @@ $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left'); * View */ +// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access. +if (empty($dolibarr_nocache) && GETPOST('cache', 'int')) { + header('Cache-Control: max-age='.GETPOST('cache', 'int').', public'); + // For a .php, we must set an Expires to avoid to have it forced to an expired value by the web server + header('Expires: '.gmdate('D, d M Y H:i:s', dol_now('gmt') + GETPOST('cache', 'int')).' GMT'); + // HTTP/1.0 + header('Pragma: token=public'); +} else { + // HTTP/1.0 + header('Cache-Control: no-cache'); +} + $title = $langs->trans("Bookmarks"); // URL http://mydolibarr/core/bookmarks_page?dol_use_jmobile=1 can be used for tests -$head = ''."\n"; +$head = ''."\n"; // This is used by DoliDroid to know page is a bookmark selection page $arrayofjs = array(); $arrayofcss = array(); top_htmlhead($head, $title, 0, 0, $arrayofjs, $arrayofcss); @@ -77,7 +89,7 @@ $bookmarkList = ''; $searchForm = ''; -if (empty($conf->bookmarks->enabled)) { +if (empty($conf->bookmark->enabled)) { $langs->load("admin"); $bookmarkList .= '
    '.$langs->trans("WarningModuleNotActive", $langs->transnoentitiesnoconv("Bookmarks")).''; $bookmarkList .= '

    '; @@ -99,12 +111,20 @@ if (empty($conf->bookmarks->enabled)) { if ($i == 0) { $bookmarkList .= '
    '.$langs->trans("NoBookmarks").''; $bookmarkList .= '

    '; - - $newcardbutton = ''; - $newcardbutton .= dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/bookmarks/card.php?action=create&backtopage='.urlencode(DOL_URL_ROOT.'/bookmarks/list.php'), '', !empty($user->rights->bookmark->creer)); - - $bookmarkList .= '
    '.$newcardbutton.'
    '; } + + $newcardbutton = ''; + $newcardbutton .= dolGetButtonTitle($langs->trans('New'), '', 'fa fa-plus-circle', DOL_URL_ROOT.'/bookmarks/card.php?action=create&backtopage='.urlencode(DOL_URL_ROOT.'/bookmarks/list.php'), '', !empty($user->rights->bookmark->creer)); + + // Url to list bookmark + $bookmarkList .= '
    '; + $bookmarkList .= ''; + $bookmarkList .= img_picto('', 'bookmark', 'class="paddingright"').$langs->trans('Bookmarks').''; + $bookmarkList .= '
    '; + $bookmarkList .= '
    '; + + $bookmarkList .= '
    '.$newcardbutton.'
    '; + $bookmarkList .= '
'; diff --git a/htdocs/core/boxes/box_accountancy_last_manual_entries.php b/htdocs/core/boxes/box_accountancy_last_manual_entries.php index b1e4a637046..96abd8699f3 100644 --- a/htdocs/core/boxes/box_accountancy_last_manual_entries.php +++ b/htdocs/core/boxes/box_accountancy_last_manual_entries.php @@ -134,7 +134,7 @@ class box_accountancy_last_manual_entries extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($amount, 0, $langs, 0, -1, -1, $conf->currency), ); diff --git a/htdocs/core/boxes/box_activity.php b/htdocs/core/boxes/box_activity.php index 487c2170a4a..371a7a0dbed 100644 --- a/htdocs/core/boxes/box_activity.php +++ b/htdocs/core/boxes/box_activity.php @@ -174,7 +174,7 @@ class box_activity extends ModeleBoxes $totalnb += $data[$j]->nb; $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), ); $this->info_box_contents[$line][4] = array( @@ -262,7 +262,7 @@ class box_activity extends ModeleBoxes $totalnb += $data[$j]->nb; $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), ); $this->info_box_contents[$line][4] = array( @@ -350,7 +350,7 @@ class box_activity extends ModeleBoxes ); $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency) ); @@ -433,7 +433,7 @@ class box_activity extends ModeleBoxes ); $totalnb += $data[$j]->nb; $this->info_box_contents[$line][3] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($data[$j]->Mnttot, 1, $langs, 0, 0, -1, $conf->currency), ); $this->info_box_contents[$line][4] = array( diff --git a/htdocs/core/boxes/box_commandes.php b/htdocs/core/boxes/box_commandes.php index abf9baf06f3..ae939afe25c 100644 --- a/htdocs/core/boxes/box_commandes.php +++ b/htdocs/core/boxes/box_commandes.php @@ -163,7 +163,7 @@ class box_commandes extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency), ); diff --git a/htdocs/core/boxes/box_comptes.php b/htdocs/core/boxes/box_comptes.php index f42b7a2ef7c..5570051a065 100644 --- a/htdocs/core/boxes/box_comptes.php +++ b/htdocs/core/boxes/box_comptes.php @@ -141,8 +141,11 @@ class box_comptes extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="right nowraponall"', - 'text' => price($solde, 0, $langs, 1, -1, -1, $objp->currency_code) + 'td' => 'class="nowraponall right amount"', + 'text' => '' + .price($solde, 0, $langs, 1, -1, -1, $objp->currency_code) + .'', + 'asis' => 1, ); $line++; @@ -161,7 +164,7 @@ class box_comptes extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="liste_total right nowraponall"', + 'td' => 'class="liste_total nowraponall right amount"', 'text' => price($solde, 0, $langs, 0, -1, -1, $key) ); $line++; diff --git a/htdocs/core/boxes/box_dolibarr_state_board.php b/htdocs/core/boxes/box_dolibarr_state_board.php index 21bf58b859f..0381b493448 100644 --- a/htdocs/core/boxes/box_dolibarr_state_board.php +++ b/htdocs/core/boxes/box_dolibarr_state_board.php @@ -105,7 +105,8 @@ class box_dolibarr_state_board extends ModeleBoxes 'supplier_invoices', 'contracts', 'interventions', - 'ticket' + 'ticket', + 'dolresource' ); $conditions = array( 'users' => $user->rights->user->user->lire, @@ -132,7 +133,8 @@ class box_dolibarr_state_board extends ModeleBoxes 'projects' => !empty($conf->projet->enabled) && $user->rights->projet->lire, 'expensereports' => !empty($conf->expensereport->enabled) && $user->rights->expensereport->lire, 'holidays' => !empty($conf->holiday->enabled) && $user->rights->holiday->read, - 'ticket' => !empty($conf->ticket->enabled) && $user->rights->ticket->read + 'ticket' => !empty($conf->ticket->enabled) && $user->rights->ticket->read, + 'dolresource' => !empty($conf->resource->enabled) && $user->rights->resource->read ); $classes = array( 'users' => 'User', @@ -156,6 +158,7 @@ class box_dolibarr_state_board extends ModeleBoxes 'expensereports' => 'ExpenseReport', 'holidays' => 'Holiday', 'ticket' => 'Ticket', + 'dolresource' => 'Dolresource' ); $includes = array( 'users' => DOL_DOCUMENT_ROOT . "/user/class/user.class.php", @@ -178,7 +181,8 @@ class box_dolibarr_state_board extends ModeleBoxes 'projects' => DOL_DOCUMENT_ROOT . "/projet/class/project.class.php", 'expensereports' => DOL_DOCUMENT_ROOT . "/expensereport/class/expensereport.class.php", 'holidays' => DOL_DOCUMENT_ROOT . "/holiday/class/holiday.class.php", - 'ticket' => DOL_DOCUMENT_ROOT . "/ticket/class/ticket.class.php" + 'ticket' => DOL_DOCUMENT_ROOT . "/ticket/class/ticket.class.php", + 'dolresource' => DOL_DOCUMENT_ROOT . "/resource/class/dolresource.class.php" ); $links = array( 'users' => DOL_URL_ROOT . '/user/list.php', @@ -201,7 +205,8 @@ class box_dolibarr_state_board extends ModeleBoxes 'projects' => DOL_URL_ROOT . '/projet/list.php?mainmenu=project', 'expensereports' => DOL_URL_ROOT . '/expensereport/list.php?mainmenu=hrm&leftmenu=expensereport', 'holidays' => DOL_URL_ROOT . '/holiday/list.php?mainmenu=hrm&leftmenu=holiday', - 'ticket' => DOL_URL_ROOT . '/ticket/list.php?leftmenu=ticket' + 'ticket' => DOL_URL_ROOT . '/ticket/list.php?leftmenu=ticket', + 'dolresource' => DOL_URL_ROOT . '/resource/list.php?mainmenu=tools', ); $titres = array( 'users' => "Users", @@ -225,6 +230,7 @@ class box_dolibarr_state_board extends ModeleBoxes 'expensereports' => "ExpenseReports", 'holidays' => "Holidays", 'ticket' => "Ticket", + 'dolresource' => "Resources", ); $langfile = array( 'customers' => "companies", diff --git a/htdocs/core/boxes/box_factures_fourn.php b/htdocs/core/boxes/box_factures_fourn.php index ae905d5d468..42a945b9289 100644 --- a/htdocs/core/boxes/box_factures_fourn.php +++ b/htdocs/core/boxes/box_factures_fourn.php @@ -183,7 +183,7 @@ class box_factures_fourn extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="right nowraponall"', + 'td' => 'class="nowraponall right amount"', 'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency), ); diff --git a/htdocs/core/boxes/box_factures_fourn_imp.php b/htdocs/core/boxes/box_factures_fourn_imp.php index cfef8801414..a421706e855 100644 --- a/htdocs/core/boxes/box_factures_fourn_imp.php +++ b/htdocs/core/boxes/box_factures_fourn_imp.php @@ -170,7 +170,7 @@ class box_factures_fourn_imp extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="nowraponall right"', + 'td' => 'class="nowraponall right amount"', 'text' => price($objp->total_ht, 0, $langs, 0, -1, -1, $conf->currency), ); diff --git a/htdocs/core/boxes/box_funnel_of_prospection.php b/htdocs/core/boxes/box_funnel_of_prospection.php index fd89e732937..cdaa9298f63 100644 --- a/htdocs/core/boxes/box_funnel_of_prospection.php +++ b/htdocs/core/boxes/box_funnel_of_prospection.php @@ -219,7 +219,7 @@ class box_funnel_of_prospection extends ModeleBoxes if (!$conf->use_javascript_ajax) { $stringtoprint .= ''; $stringtoprint .= ''.$labelStatus.''; - $stringtoprint .= ''.price((isset($valsamount[$status]) ? (float) $valsamount[$status] : 0), 0, '', 1, -1, -1, $conf->currency).''; + $stringtoprint .= ''.price((isset($valsamount[$status]) ? (float) $valsamount[$status] : 0), 0, '', 1, -1, -1, $conf->currency).''; $stringtoprint .= "\n"; } } @@ -237,7 +237,7 @@ class box_funnel_of_prospection extends ModeleBoxes $dolgraph->setBorderColor(array_values($bordercolorseries)); $dolgraph->setShowLegend(2); if (!empty($conf->dol_optimize_smallscreen)) { - $px1->SetWidth(320); + $dolgraph->SetWidth(320); } $dolgraph->setShowPercent(1); $dolgraph->setMirrorGraphValues(true); @@ -277,7 +277,7 @@ class box_funnel_of_prospection extends ModeleBoxes ); $this->info_box_contents[$line][] = array( 'tr' => 'class="oddeven"', - 'td' => 'class="right "', + 'td' => 'class="nowraponall right amount"', 'maxlength' => 500, 'text' => price($totalamount, 0, '', 1, -1, -1, $conf->currency) ); @@ -290,7 +290,7 @@ class box_funnel_of_prospection extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="right "', + 'td' => 'class="nowraponall right amount"', 'maxlength' => 500, 'text' => price(price2num($ponderated_opp_amount, 'MT'), 0, '', 1, -1, -1, $conf->currency) ); diff --git a/htdocs/core/boxes/box_graph_invoices_permonth.php b/htdocs/core/boxes/box_graph_invoices_permonth.php index 65498ab6362..8179e134bcf 100644 --- a/htdocs/core/boxes/box_graph_invoices_permonth.php +++ b/htdocs/core/boxes/box_graph_invoices_permonth.php @@ -227,7 +227,7 @@ class box_graph_invoices_permonth extends ModeleBoxes if (!$mesg) { $stringtoshow = ''; - $stringtoshow .= ''."\n"; } } @@ -244,7 +254,7 @@ class DolEditor $out .= '
'.$titlecontent; $out .= '   -   '.dol_escape_htmltag($langs->trans("ShowMoreLines")).'     '; $out .= '
'; - $out .= ''; @@ -827,6 +844,7 @@ class FormOther $out .= ''; $out .= ''; @@ -905,11 +938,11 @@ class FormOther // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** - * Creation d'un icone de couleur + * Creae an image for color * - * @param string $color Couleur de l'image - * @param string $module Nom du module - * @param string $name Nom de l'image + * @param string $color Color of image + * @param string $module Name of module + * @param string $name Name of image * @param int $x Largeur de l'image en pixels * @param int $y Hauteur de l'image en pixels * @return void @@ -1194,7 +1227,7 @@ class FormOther // Javascript code for dynamic actions if (!empty($conf->use_javascript_ajax)) { - $selectboxlist .= ''; } else { // Default Header Redirect diff --git a/htdocs/core/class/translate.class.php b/htdocs/core/class/translate.class.php index e741adc84b5..f881447cd67 100644 --- a/htdocs/core/class/translate.class.php +++ b/htdocs/core/class/translate.class.php @@ -555,9 +555,9 @@ class Translate * Return translated value of key for special keys ("Currency...", "Civility...", ...). * Search in lang file, then into database. Key must be any complete entry into lang file: CurrencyEUR, ... * If not found, return key. - * The string return is not formated (translated with transnoentitiesnoconv) - * NOTE: To avoid infinite loop (getLabelFromKey->transnoentities->getTradFromKey), if you modify this function, - * check that getLabelFromKey is not called with same value than input. + * The string return is not formated (translated with transnoentitiesnoconv). + * NOTE: To avoid infinite loop (getLabelFromKey->transnoentities->getTradFromKey->getLabelFromKey), if you modify this function, + * check that getLabelFromKey is never called with the same value than $key. * * @param string $key Key to translate * @return string Translated string (translated with transnoentitiesnoconv) @@ -579,13 +579,13 @@ class Translate $newstr = $this->getLabelFromKey($db, $reg[1], 'c_currencies', 'code_iso', 'label'); } elseif (preg_match('/^SendingMethod([0-9A-Z]+)$/i', $key, $reg)) { $newstr = $this->getLabelFromKey($db, $reg[1], 'c_shipment_mode', 'code', 'libelle'); - } elseif (preg_match('/^PaymentTypeShort([0-9A-Z]+)$/i', $key, $reg)) { + } elseif (preg_match('/^PaymentType(?:Short)?([0-9A-Z]+)$/i', $key, $reg)) { $newstr = $this->getLabelFromKey($db, $reg[1], 'c_paiement', 'code', 'libelle', '', 1); } elseif (preg_match('/^OppStatus([0-9A-Z]+)$/i', $key, $reg)) { $newstr = $this->getLabelFromKey($db, $reg[1], 'c_lead_status', 'code', 'label'); } elseif (preg_match('/^OrderSource([0-9A-Z]+)$/i', $key, $reg)) { // TODO OrderSourceX must be replaced with content of table llx_c_input_reason or llx_c_input_method - //$newstr=$this->getLabelFromKey($db,$reg[1],'c_ordersource','code','label'); + //$newstr=$this->getLabelFromKey($db,$reg[1],'llx_c_input_reason','code','label'); } /* Disabled. There is too many cases where translation of $newstr is not defined is normal (like when output with setEventMessage an already translated string) @@ -945,9 +945,9 @@ class Translate * * @param DoliDB $db Database handler * @param string $key Translation key to get label (key in language file) - * @param string $tablename Table name without prefix - * @param string $fieldkey Field for key - * @param string $fieldlabel Field for label + * @param string $tablename Table name without prefix. This value must always be a hardcoded string and not a value coming from user input. + * @param string $fieldkey Field for key. This value must always be a hardcoded string and not a value coming from user input. + * @param string $fieldlabel Field for label. This value must always be a hardcoded string and not a value coming from user input. * @param string $keyforselect Use another value than the translation key for the where into select * @param int $filteronentity Use a filter on entity * @return string Label in UTF8 (but without entities) @@ -959,10 +959,15 @@ class Translate if ($key == '') { return ''; } + // Test should be useless because the 3 variables are never set from user input but we keep it in case of. + if (preg_match('/[^0-9A-Z_]/i', $tablename) || preg_match('/[^0-9A-Z_]/i', $fieldkey) || preg_match('/[^0-9A-Z_]/i', $fieldlabel)) { + $this->error = 'Bad value for parameter tablename, fieldkey or fieldlabel'; + return -1; + } //print 'param: '.$key.'-'.$keydatabase.'-'.$this->trans($key); exit; - // Check if a translation is available (this can call getTradFromKey) + // Check if a translation is available (Note: this can call getTradFromKey that can call getLabelFromKey) $tmp = $this->transnoentitiesnoconv($key); if ($tmp != $key && $tmp != 'ErrorBadValueForParamNotAString') { return $tmp; // Found in language array @@ -973,6 +978,7 @@ class Translate return $this->cache_labels[$tablename][$key]; // Found in cache } + // Not found in loaded language file nor in cache. So we will take the label into database. $sql = "SELECT ".$fieldlabel." as label"; $sql .= " FROM ".MAIN_DB_PREFIX.$tablename; $sql .= " WHERE ".$fieldkey." = '".$db->escape($keyforselect ? $keyforselect : $key)."'"; diff --git a/htdocs/core/class/utils.class.php b/htdocs/core/class/utils.class.php index e7ab489c60d..b408985a92d 100644 --- a/htdocs/core/class/utils.class.php +++ b/htdocs/core/class/utils.class.php @@ -399,21 +399,23 @@ class Utils if ($execmethod == 2) { // With this method, there is no way to get the return code, only output $handlein = popen($fullcommandclear, 'r'); $i = 0; - while (!feof($handlein)) { - $i++; // output line number - $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; + if ($handlein) { + while (!feof($handlein)) { + $i++; // output line number + $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; + } } + pclose($handlein); } - pclose($handlein); } @@ -636,7 +638,6 @@ class Utils $execmethod = 1; } //$execmethod=1; - dol_syslog("Utils::executeCLI execmethod=".$execmethod." system:".$command, LOG_DEBUG); $output_arr = array(); diff --git a/htdocs/core/class/validate.class.php b/htdocs/core/class/validate.class.php index 1b2447dc23a..389bb708e82 100644 --- a/htdocs/core/class/validate.class.php +++ b/htdocs/core/class/validate.class.php @@ -61,6 +61,11 @@ class Validate $this->outputLang = $outputLang; } + if (!is_object($this->outputLang) || !method_exists($outputLang, 'load')) { + return false; + } + + /** @var Translate $outputLang */ $outputLang->load('validate'); $this->db = $db; @@ -212,7 +217,7 @@ class Validate /** * Check Duration validity * - * @param string $duration to validate + * @param mixed $duration to validate * @return boolean Validity is ok or not */ public function isDuration($duration) diff --git a/htdocs/core/customreports.php b/htdocs/core/customreports.php index b7f01de0aeb..e380dea8403 100644 --- a/htdocs/core/customreports.php +++ b/htdocs/core/customreports.php @@ -40,7 +40,6 @@ if (!defined('USE_CUSTOM_REPORT_AS_INCLUDE')) { $objecttype = 'thirdparty'; } - $search_filters = GETPOST('search_filters', 'array'); $search_measures = GETPOST('search_measures', 'array'); //$search_xaxis = GETPOST('search_xaxis', 'array'); @@ -158,6 +157,7 @@ $extrafields->fetch_name_optionals_label($object->table_element); $search_array_options = $extrafields->getOptionalsFromPost($object->table_element, '', 'search_'); $search_component_params = array(''); +$search_component_params_hidden = GETPOST('search_component_params_hidden', 'alphanohtml'); $MAXUNIQUEVALFORGROUP = 20; $MAXMEASURESINBARGRAPH = 20; @@ -175,14 +175,16 @@ $arrayofgroupby = array(); $arrayofyaxis = array(); $arrayofvaluesforgroupby = array(); -$result = restrictedArea($user, $object->element, 0, ''); +restrictedArea($user, $object->element, 0, ''); + +$error = 0; /* * Actions */ - +// None @@ -245,8 +247,19 @@ if (is_array($search_groupby) && count($search_groupby)) { } else { $sql .= ' FROM '.MAIN_DB_PREFIX.$object->table_element.' as t'; } - // TODO Add the where here - // ... + + // Add the where here + /* + $sqlfilters = GETPOST('search_component_params_hidden', 'alphanohtml'); + if ($sqlfilters) { + $errormessage = ''; + if (dolCheckFilters($sqlfilters, $errormessage)) { + $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; + $sql .= " WHERE (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")"; + } else { + print $errormessage; + } + }*/ $sql .= ' LIMIT '.($MAXUNIQUEVALFORGROUP + 1); @@ -333,6 +346,24 @@ print ''; print ''; print ''; +$viewmode = ''; + +$viewmode .= '
'; +$arrayofgraphs = array('bars' => 'Bars', 'lines' => 'Lines'); // also 'pies' +$viewmode .= '
'.$langs->trans("Graph").'
'; +$viewmode .= $form->selectarray('search_graph', $arrayofgraphs, $search_graph, 0, 0, 0, 'minwidth100', 1); +$viewmode .= '
'; + +$num = 0; +$massactionbutton = ''; +$nav = ''; +$newcardbutton = ''; +$limit = 0; + +print_barre_liste('', $page, $_SERVER["PHP_SELF"], $param, $sortfield, $sortorder, $massactionbutton, $num, -1, 'object_action', 0, $nav.''.$newcardbutton, '', $limit, 1, 0, 1, $viewmode); + + + print '
'; // Select object @@ -349,22 +380,23 @@ foreach ($arrayoftype as $key => $val) { } print $form->selectarray('objecttype', $newarrayoftype, $objecttype, 0, 0, 0, '', 1, 0, 0, '', 'minwidth200', 1); if (empty($conf->use_javascript_ajax)) { - print ''; + print ''; } else { - print ''; } print '
'; -// Add Filter +// Add Filter (you can use param &show_search_component_params_hidden=1 for debug) print '
'; -print $form->searchComponent(array($object->element => $object->fields), $search_component_params); +print $form->searchComponent(array($object->element => $object->fields), $search_component_params, array(), $search_component_params_hidden); print '
'; // Add measures into array @@ -393,13 +425,6 @@ print $form->multiselectarray('search_measures', $arrayofmesures, $search_measur print '
'; -// Group by -print '
'; -print '
'.$langs->trans("GroupBy").'
'; -print $formother->selectGroupByField($object, $search_groupby, $arrayofgroupby); -print '
'; - - // XAxis print '
'; print '
'.$langs->trans("XAxis").'
'; @@ -407,6 +432,13 @@ print $formother->selectXAxisField($object, $search_xaxis, $arrayofxaxis); print '
'; +// Group by +print '
'; +print '
'.$langs->trans("GroupBy").'
'; +print $formother->selectGroupByField($object, $search_groupby, $arrayofgroupby); +print '
'; + + if ($mode == 'grid') { // YAxis print '
'; @@ -449,14 +481,11 @@ if ($mode == 'grid') { } if ($mode == 'graph') { - print '
'; - $arrayofgraphs = array('bars' => 'Bars', 'lines' => 'Lines'); // also 'pies' - print '
'.$langs->trans("Graph").'
'; - print $form->selectarray('search_graph', $arrayofgraphs, $search_graph, 0, 0, 0, 'minwidth100', 1); - print '
'; + // } + print '
'; -print ''; +print ''; print '
'; print '
'; print ''; @@ -531,8 +560,16 @@ if (!empty($search_measures) && !empty($search_xaxis)) { if ($object->ismultientitymanaged == 1) { $sql .= ' AND entity IN ('.getEntity($object->element).')'; } - foreach ($search_filters as $key => $val) { - // TODO Add the where here + // Add the where here + $sqlfilters = GETPOST('search_component_params_hidden', 'alphanohtml'); + if ($sqlfilters) { + $errormessage = ''; + if (dolCheckFilters($sqlfilters, $errormessage)) { + $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; + $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'dolForgeCriteriaCallback', $sqlfilters).")"; + } else { + print $errormessage; + } } $sql .= ' GROUP BY '; foreach ($search_xaxis as $key => $val) { diff --git a/htdocs/core/db/Database.interface.php b/htdocs/core/db/Database.interface.php index c6769ad0619..e349072ddec 100644 --- a/htdocs/core/db/Database.interface.php +++ b/htdocs/core/db/Database.interface.php @@ -227,7 +227,7 @@ interface Database * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param int $result_mode Result mode - * @return resource Resultset of answer + * @return bool|resource Resultset of answer or false */ public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0); diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php index 7cf0a5d905a..74abf7a1e36 100644 --- a/htdocs/core/db/pgsql.class.php +++ b/htdocs/core/db/pgsql.class.php @@ -495,7 +495,7 @@ class DoliDBPgsql extends DoliDB * @param int $usesavepoint 0=Default mode, 1=Run a savepoint before and a rollback to savepoint if error (this allow to have some request with errors inside global transactions). * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param int $result_mode Result mode (not used with pgsql) - * @return false|resource Resultset of answer + * @return bool|resource Resultset of answer */ public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0) { diff --git a/htdocs/core/db/sqlite3.class.php b/htdocs/core/db/sqlite3.class.php index d1d6a4b680a..10f9c021c0d 100644 --- a/htdocs/core/db/sqlite3.class.php +++ b/htdocs/core/db/sqlite3.class.php @@ -394,7 +394,7 @@ class DoliDBSqlite3 extends DoliDB * Note that with Mysql, this parameter is not used as Myssql can already commit a transaction even if one request is in error, without using savepoints. * @param string $type Type of SQL order ('ddl' for insert, update, select, delete or 'dml' for create, alter...) * @param int $result_mode Result mode (not used with sqlite) - * @return SQLite3Result Resultset of answer + * @return bool|SQLite3Result Resultset of answer */ public function query($query, $usesavepoint = 0, $type = 'auto', $result_mode = 0) { @@ -407,6 +407,7 @@ class DoliDBSqlite3 extends DoliDB $this->error = ''; // Convert MySQL syntax to SQLite syntax + $reg = array(); if (preg_match('/ALTER\s+TABLE\s*(.*)\s*ADD\s+CONSTRAINT\s+(.*)\s*FOREIGN\s+KEY\s*\(([\w,\s]+)\)\s*REFERENCES\s+(\w+)\s*\(([\w,\s]+)\)/i', $query, $reg)) { // Ajout d'une clef étrangère à la table // procédure de remplacement de la table pour ajouter la contrainte diff --git a/htdocs/core/get_info.php b/htdocs/core/get_info.php index d5e79f21e01..067372c26ff 100644 --- a/htdocs/core/get_info.php +++ b/htdocs/core/get_info.php @@ -33,7 +33,7 @@ if (!defined('NOCSRFCHECK')) { if (!defined('NOTOKENRENEWAL')) { define('NOTOKENRENEWAL', 1); } -//if (! defined('NOLOGIN')) define('NOLOGIN',1); // Not disabled cause need to load personalized language +//if (! defined('NOLOGIN')) define('NOLOGIN',1); // Not disabled cause need to load personalized language and need security layer if (!defined('NOREQUIREMENU')) { define('NOREQUIREMENU', 1); } @@ -56,8 +56,8 @@ $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left'); $title = $langs->trans("Info"); -// URL http://mydolibarr/core/search_page?dol_use_jmobile=1 can be used for tests -$head = ''."\n"; +// URL http://mydolibarr/core/get_info.php?dol_use_jmobile=1 can be used for tests +$head = ''."\n"; $arrayofjs = array(); $arrayofcss = array(); top_htmlhead($head, $title, 0, 0, $arrayofjs, $arrayofcss); @@ -93,7 +93,7 @@ if (empty($conf->global->MAIN_OPTIMIZEFORTEXTBROWSER)) { if ($_SESSION["dol_authmode"] != 'forceuser' && $_SESSION["dol_authmode"] != 'http') { $logouthtmltext .= $langs->trans("Logout").'
'; - $logouttext .= ''; + $logouttext .= ''; //$logouttext .= img_picto($langs->trans('Logout').":".$langs->trans('Logout'), 'logout_top.png', 'class="login"', 0, 0, 1); $logouttext .= ''; $logouttext .= ''; diff --git a/htdocs/core/get_menudiv.php b/htdocs/core/get_menudiv.php index 84be9ff8e0f..77b0416956b 100644 --- a/htdocs/core/get_menudiv.php +++ b/htdocs/core/get_menudiv.php @@ -81,10 +81,22 @@ $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left'); * View */ +// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access. +if (empty($dolibarr_nocache) && GETPOST('cache', 'int')) { + header('Cache-Control: max-age='.GETPOST('cache', 'int').', public, must-revalidate'); + // For a .php, we must set an Expires to avoid to have it forced to an expired value by the web server + header('Expires: '.gmdate('D, d M Y H:i:s', dol_now('gmt') + GETPOST('cache', 'int')).' GMT'); + // HTTP/1.0 + header('Pragma: token=public'); +} else { + // HTTP/1.0 + header('Cache-Control: no-cache'); +} + $title = $langs->trans("Menu"); // URL http://mydolibarr/core/get_menudiv.php?dol_use_jmobile=1 can be used for tests -$head = ''."\n"; +$head = ''."\n"; // This is used by DoliDroid to know page is a menu page $arrayofjs = array(); $arrayofcss = array(); top_htmlhead($head, $title, 0, 0, $arrayofjs, $arrayofcss); diff --git a/htdocs/core/js/lib_notification.js.php b/htdocs/core/js/lib_notification.js.php index ee41555119a..f4a4e59526a 100644 --- a/htdocs/core/js/lib_notification.js.php +++ b/htdocs/core/js/lib_notification.js.php @@ -68,22 +68,27 @@ print ' var time_auto_update = '.$conf->global->MAIN_BROWSER_NOTIFICATION_FREQUE print ' var time_js_next_test;'."\n"; ?> -/* Check if permission ok */ -if (Notification.permission !== "granted") { - console.log("Ask Notification.permission"); - Notification.requestPermission() +/* Check if Notification is supported */ +if ("Notification" in window) { + /* Check if permission ok */ + if (Notification.permission !== "granted") { + console.log("Ask Notification.permission"); + Notification.requestPermission() + } + + /* Launch timer */ + + // We set a delay before launching first test so next check will arrive after the time_auto_update compared to previous one. + //var time_first_execution = (time_auto_update + (time_js_next_test - nowtime)) * 1000; //need milliseconds + var time_first_execution = global->MAIN_BROWSER_NOTIFICATION_CHECK_FIRST_EXECUTION) ? 0 : $conf->global->MAIN_BROWSER_NOTIFICATION_CHECK_FIRST_EXECUTION); ?>; + + setTimeout(first_execution, time_first_execution * 1000); + time_js_next_test = nowtime + time_first_execution; + console.log("Launch browser notif check: setTimeout is set to launch 'first_execution' function after a wait of time_first_execution="+time_first_execution+". nowtime (time php page generation) = "+nowtime+" time_js_next_check = "+time_js_next_test); +} else { + console.log("This browser in this context does not support Notification."); } -/* Launch timer */ - -// We set a delay before launching first test so next check will arrive after the time_auto_update compared to previous one. -//var time_first_execution = (time_auto_update + (time_js_next_test - nowtime)) * 1000; //need milliseconds -var time_first_execution = global->MAIN_BROWSER_NOTIFICATION_CHECK_FIRST_EXECUTION) ? 0 : $conf->global->MAIN_BROWSER_NOTIFICATION_CHECK_FIRST_EXECUTION); ?>; - -setTimeout(first_execution, time_first_execution * 1000); -time_js_next_test = nowtime + time_first_execution; -console.log("Launch browser notif check: setTimeout is set to launch 'first_execution' function after a wait of time_first_execution="+time_first_execution+". nowtime (time php page generation) = "+nowtime+" time_js_next_check = "+time_js_next_test); - function first_execution() { console.log("Call first_execution then set repeat time to time_auto_update = MAIN_BROWSER_NOTIFICATION_FREQUENCY = "+time_auto_update); diff --git a/htdocs/core/js/lib_photosresize.js b/htdocs/core/js/lib_photosresize.js index 99c7c36c29e..38c508f90b3 100644 --- a/htdocs/core/js/lib_photosresize.js +++ b/htdocs/core/js/lib_photosresize.js @@ -32,12 +32,40 @@ function updateCoords(c) { //alert(parseInt(jQuery("#ratioforcrop").val())); ratio=1; - if (parseInt(jQuery("#ratioforcrop").val()) > 0) ratio = parseInt(jQuery("#ratioforcrop").val()); + imagewidth=0; + imageheight=0; + + console.log(c); + + if (parseInt(jQuery("#ratioforcrop").val()) > 1) { + ratio = parseInt(jQuery("#ratioforcrop").val()); + if (parseInt(jQuery("#imagewidth").val()) > 0) imagewidth = parseInt(jQuery("#imagewidth").val()); + if (parseInt(jQuery("#imageheight").val()) > 0) imageheight = parseInt(jQuery("#imageheight").val()); + } + + x = Math.floor(c.x * ratio); + y = Math.floor(c.y * ratio); + x2 = Math.ceil(c.x2 * ratio); + y2 = Math.ceil(c.y2 * ratio); + console.log("x="+x+" y="+y+" x2="+x2+" y2="+y2+" imageheight="+imageheight+" ratio="+ratio); + if (imagewidth > 0 && x > imagewidth) { + x = imagewidth; + } + if (imageheight > 0 && y > imageheight) { + y = imageheight; + } + if (imagewidth > 0 && x2 > imagewidth) { + x2 = imagewidth; + } + if (imageheight > 0 && y2 > imageheight) { + y2 = imageheight; + } + //console.log(ratio); - jQuery('#x').val(Math.ceil(c.x * ratio)); - jQuery('#y').val(Math.ceil(c.y * ratio)); - jQuery('#x2').val(Math.ceil(c.x2 * ratio)); - jQuery('#y2').val(Math.ceil(c.y2 * ratio)); - jQuery('#w').val(Math.ceil(c.w * ratio)); - jQuery('#h').val(Math.ceil(c.h * ratio)); + jQuery('#x').val(x); + jQuery('#y').val(y); + jQuery('#x2').val(x2); + jQuery('#y2').val(y2); + jQuery('#w').val(x2-x); + jQuery('#h').val(y2-y); }; diff --git a/htdocs/core/lib/admin.lib.php b/htdocs/core/lib/admin.lib.php index 842d7333bbd..e806d9b5957 100644 --- a/htdocs/core/lib/admin.lib.php +++ b/htdocs/core/lib/admin.lib.php @@ -451,7 +451,7 @@ function run_sql($sqlfile, $silent = 1, $entity = '', $usesavepoint = 1, $handle } //if (!empty($conf->use_javascript_ajax)) { // use_javascript_ajax is not defined - print ''; @@ -2010,7 +2021,7 @@ if ($action == 'create') { $morehtmlref .= '
'; $morehtmlref .= ''; $morehtmlref .= ''; - $morehtmlref .= $formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, 'projectid', 0, 0, 1, 0, 1, 0, 0, '', 1, 0, 'maxwidth500'); + $morehtmlref .= $formproject->select_projects((empty($conf->global->PROJECT_CAN_ALWAYS_LINK_TO_ALL_SUPPLIERS) ? $object->socid : -1), $object->fk_project, 'projectid', 0, 0, 1, 1, 1, 0, 0, '', 1, 0, 'maxwidth500'); $morehtmlref .= ''; $morehtmlref .= '
'; } else { @@ -2513,7 +2524,7 @@ if ($action == 'create') { } if (in_array($object->statut, array(3, 4, 5))) { - if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled)) && $usercanreceived) { + if (((!empty($conf->fournisseur->enabled) && empty($conf->global->MAIN_USE_NEW_SUPPLIERMOD)) || !empty($conf->supplier_order->enabled)) && $usercanreceive) { print '
'.$labelofbutton.'
'; } else { print '
'.$labelofbutton.'
'; @@ -2531,7 +2542,7 @@ if ($action == 'create') { // Classify received (this does not record reception) if ($object->statut == CommandeFournisseur::STATUS_ORDERSENT || $object->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY) { - if ($usercanreceived) { + if ($usercanreceive) { print '
'.$langs->trans("ClassifyReception").'
'; } } @@ -2650,7 +2661,7 @@ if ($action == 'create') { print '
'; if ($action == 'classifyreception') { - if ($usercanreceived && ($object->statut == CommandeFournisseur::STATUS_ORDERSENT || $object->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY)) { + if ($usercanreceive && ($object->statut == CommandeFournisseur::STATUS_ORDERSENT || $object->statut == CommandeFournisseur::STATUS_RECEIVED_PARTIALLY)) { // Set status to received (action=livraison) print ''."\n"; print '
'; diff --git a/htdocs/fourn/commande/dispatch.php b/htdocs/fourn/commande/dispatch.php index 311cbd5f022..abeee1a9e26 100644 --- a/htdocs/fourn/commande/dispatch.php +++ b/htdocs/fourn/commande/dispatch.php @@ -788,6 +788,8 @@ if ($id > 0 || !empty($ref)) { $nbproduct = 0; // Nb of predefined product lines to dispatch (already done or not) if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is off (default) // or nb of line that remain to dispatch if SUPPLIER_ORDER_DISABLE_STOCK_DISPATCH_WHEN_TOTAL_REACHED is on. + $conf->cache['product'] = array(); + while ($i < $num) { $objp = $db->fetch_object($resql); @@ -815,11 +817,20 @@ if ($id > 0 || !empty($ref)) { print ''; print ''; - $linktoprod = ''.img_object($langs->trans("ShowProduct"), 'product').' '.$objp->ref.''; + if (empty($conf->cache['product'][$objp->fk_product])) { + $tmpproduct = new Product($db); + $tmpproduct->fetch($objp->fk_product); + $conf->cache['product'][$objp->fk_product] = $tmpproduct; + } else { + $tmpproduct = $conf->cache['product'][$objp->fk_product]; + } + + $linktoprod = $tmpproduct->getNomUrl(1); $linktoprod .= ' - '.$objp->label."\n"; if (!empty($conf->productbatch->enabled)) { if ($objp->tobatch) { + // Product print ''; print $linktoprod; print ""; @@ -831,6 +842,7 @@ if ($id > 0 || !empty($ref)) { print ''; } } else { + // Product print ''; print $linktoprod; print ""; @@ -1150,10 +1162,11 @@ if ($id > 0 || !empty($ref)) { print ''; print ''; + // Reception ref if ($conf->reception->enabled) { print ''; } - + // Product print ''; print ''; print ''; @@ -1181,9 +1194,14 @@ if ($id > 0 || !empty($ref)) { print "\n"; + while ($i < $num) { $objp = $db->fetch_object($resql); + $tmpproduct->id = $objp->fk_product; + $tmpproduct->ref = $objp->ref; + $tmpproduct->label = $objp->label; + if ($action == 'editline' && $lineid == $objp->dispatchlineid) { print ' @@ -1194,6 +1212,7 @@ if ($id > 0 || !empty($ref)) { print ''; + // Reception ref if (!empty($conf->reception->enabled)) { print '"; } + // Product print '\n"; print ''; diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 419e75b55aa..6470dc62bcd 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -765,7 +765,7 @@ $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_country as country on (country.rowid = s $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_typent as typent on (typent.id = s.fk_typent)"; $sql .= " LEFT JOIN ".MAIN_DB_PREFIX."c_departements as state on (state.rowid = s.fk_departement)"; $sql .= ", ".MAIN_DB_PREFIX."commande_fournisseur as cf"; -if (is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { +if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) { $sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (cf.rowid = ef.fk_object)"; } if ($sall || $search_product_category > 0) { @@ -1200,14 +1200,14 @@ if ($resql) { $langs->load("commercial"); $moreforfilter .= '
'; $tmptitle = $langs->trans('ThirdPartiesOfSaleRepresentative'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$formother->select_salesrepresentatives($search_sale, 'search_sale', $user, 0, $tmptitle, 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
'; } // If the user can view other users if ($user->rights->user->user->lire) { $moreforfilter .= '
'; $tmptitle = $langs->trans('LinkedToSpecificUsers'); - $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250'); + $moreforfilter .= img_picto($tmptitle, 'user', 'class="pictofixedwidth"').$form->select_dolusers($search_user, 'search_user', $tmptitle, '', 0, '', '', 0, 0, 0, '', 0, '', 'maxwidth250 widthcentpercentminusx'); $moreforfilter .= '
'; } // If the user can view prospects other than his' @@ -1216,7 +1216,7 @@ if ($resql) { $moreforfilter .= '
'; $tmptitle = $langs->trans('IncludingProductWithTag'); $cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, null, 'parent', null, null, 1); - $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$form->selectarray('search_product_category', $cate_arbo, $search_product_category, $tmptitle, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1); + $moreforfilter .= img_picto($tmptitle, 'category', 'class="pictofixedwidth"').$form->selectarray('search_product_category', $cate_arbo, $search_product_category, $tmptitle, 0, 0, '', 0, 0, 0, 0, 'maxwidth300 widthcentpercentminusx', 1); $moreforfilter .= '
'; } $parameters = array(); diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php old mode 100755 new mode 100644 index cb3b1bcd5e9..17ebd6efcb5 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -1299,7 +1299,7 @@ if (empty($reshook)) { $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $object->thirdparty); $remise_percent = price2num(GETPOST('remise_percent'), '', 2); - $pu_ht_devise = price2num(GETPOST('multicurrency_subprice'), 'MU', 2); + $pu_devise = price2num(GETPOST('multicurrency_subprice'), 'MU', 2); // Extrafields Lines $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line); @@ -1311,7 +1311,7 @@ if (empty($reshook)) { } } - $result = $object->updateline(GETPOST('lineid', 'int'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, price2num(GETPOST('qty'), 'MS'), GETPOST('productid', 'int'), $price_base_type, $info_bits, $type, $remise_percent, 0, $date_start, $date_end, $array_options, GETPOST('units'), $pu_ht_devise, GETPOST('fourn_ref', 'alpha')); + $result = $object->updateline(GETPOST('lineid', 'int'), $label, $up, $tva_tx, $localtax1_tx, $localtax2_tx, price2num(GETPOST('qty'), 'MS'), GETPOST('productid', 'int'), $price_base_type, $info_bits, $type, $remise_percent, 0, $date_start, $date_end, $array_options, GETPOST('units'), $pu_devise, GETPOST('fourn_ref', 'alpha')); if ($result >= 0) { unset($_POST['label']); unset($_POST['fourn_ref']); @@ -1327,6 +1327,8 @@ if (empty($reshook)) { unset($_POST['date_endday']); unset($_POST['date_endmonth']); unset($_POST['date_endyear']); + unset($_POST['price_ttc']); + unset($_POST['price_ht']); $db->commit(); } else { @@ -1355,17 +1357,18 @@ if (empty($reshook)) { $prod_entry_mode = GETPOST('prod_entry_mode'); if ($prod_entry_mode == 'free') { $idprod = 0; - $price_ht = price2num(GETPOST('price_ht'), 'MU', 2); - $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); } else { $idprod = GETPOST('idprod', 'int'); - $price_ht = price2num(GETPOST('price_ht'), 'MU', 2); - $tva_tx = ''; } + $tva_tx = (GETPOST('tva_tx') ? GETPOST('tva_tx') : 0); // Can be '1.2' or '1.2 (CODE)' + + $price_ht = price2num(GETPOST('price_ht'), 'MU', 2); + $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'CU', 2); + $price_ttc = price2num(GETPOST('price_ttc'), 'MU', 2); + $price_ttc_devise = price2num(GETPOST('multicurrency_price_ttc'), 'CU', 2); $qty = price2num(GETPOST('qty'.$predef, 'alpha'), 'MS'); $remise_percent = price2num(GETPOST('remise_percent'.$predef), 2); - $price_ht_devise = price2num(GETPOST('multicurrency_price_ht'), 'MU', 2); // Extrafields $extralabelsline = $extrafields->fetch_name_optionals_label($object->table_element_line); @@ -1455,8 +1458,8 @@ if (empty($reshook)) { } //If text set in desc is the same as product descpription (as now it's preloaded) whe add it only one time - if ($product_desc==$desc && !empty($conf->global->PRODUIT_AUTOFILL_DESC)) { - $product_desc=''; + if (trim($product_desc) == trim($desc) && !empty($conf->global->PRODUIT_AUTOFILL_DESC)) { + $product_desc = ''; } if (!empty($product_desc) && !empty($conf->global->MAIN_NO_CONCAT_DESCRIPTION)) { $desc = $product_desc; @@ -1465,32 +1468,39 @@ if (empty($reshook)) { $desc = dol_concatdesc($desc, $product_desc, '', !empty($conf->global->MAIN_CHANGE_ORDER_CONCAT_DESCRIPTION)); } - $type = $productsupplier->type; - if (GETPOST('price_ht') != '' || GETPOST('price_ht_devise') != '') { - $price_base_type = 'HT'; - $pu = price2num($price_ht, 'MU'); - $pu_ht_devise = price2num($price_ht_devise, 'CU'); - } else { - $price_base_type = ($productsupplier->fourn_price_base_type ? $productsupplier->fourn_price_base_type : 'HT'); - if (empty($object->multicurrency_code) || ($productsupplier->fourn_multicurrency_code != $object->multicurrency_code)) { // If object is in a different currency and price not in this currency - $pu = $productsupplier->fourn_pu; - $pu_ht_devise = 0; - } else { - $pu = $productsupplier->fourn_pu; - $pu_ht_devise = $productsupplier->fourn_multicurrency_unitprice; - } - } - $ref_supplier = $productsupplier->ref_supplier; - $tva_tx = get_default_tva($object->thirdparty, $mysoc, $productsupplier->id, GETPOST('idprodfournprice', 'alpha')); - $tva_npr = get_default_npr($object->thirdparty, $mysoc, $productsupplier->id, GETPOST('idprodfournprice', 'alpha')); + // Get vat rate + if (!GETPOSTISSET('tva_tx')) { // If vat rate not provided from the form (the form has the priority) + $tva_tx = get_default_tva($object->thirdparty, $mysoc, $productsupplier->id, GETPOST('idprodfournprice', 'alpha')); + $tva_npr = get_default_npr($object->thirdparty, $mysoc, $productsupplier->id, GETPOST('idprodfournprice', 'alpha')); + } if (empty($tva_tx)) { $tva_npr = 0; } $localtax1_tx = get_localtax($tva_tx, 1, $mysoc, $object->thirdparty, $tva_npr); $localtax2_tx = get_localtax($tva_tx, 2, $mysoc, $object->thirdparty, $tva_npr); + $type = $productsupplier->type; + if (GETPOST('price_ht') != '' || GETPOST('price_ht_devise') != '') { + $price_base_type = 'HT'; + $pu = price2num($price_ht, 'MU'); + $pu_devise = price2num($price_ht_devise, 'CU'); + } elseif (GETPOST('price_ttc') != '' || GETPOST('price_ttc_devise') != '') { + $price_base_type = 'TTC'; + $pu = price2num($price_ttc, 'MU'); + $pu_devise = price2num($price_ttc_devise, 'CU'); + } else { + $price_base_type = ($productsupplier->fourn_price_base_type ? $productsupplier->fourn_price_base_type : 'HT'); + if (empty($object->multicurrency_code) || ($productsupplier->fourn_multicurrency_code != $object->multicurrency_code)) { // If object is in a different currency and price not in this currency + $pu = $productsupplier->fourn_pu; + $pu_devise = 0; + } else { + $pu = $productsupplier->fourn_pu; + $pu_devise = $productsupplier->fourn_multicurrency_unitprice; + } + } + if (empty($pu)) { $pu = 0; // If pu is '' or null, we force to have a numeric value } @@ -1515,7 +1525,7 @@ if (empty($reshook)) { $array_options, $productsupplier->fk_unit, 0, - $pu_ht_devise, + $pu_devise, $ref_supplier, '' ); @@ -1557,9 +1567,9 @@ if (empty($reshook)) { $pu_ht = price2num($pu_ttc / (1 + ($tva_tx / 100)), 'MU'); // $pu_ht must be rounded according to settings } $price_base_type = 'HT'; - $pu_ht_devise = price2num($price_ht_devise, 'CU'); + $pu_devise = price2num($price_devise, 'CU'); - $result = $object->addline($product_desc, $pu_ht, $tva_tx, $localtax1_tx, $localtax2_tx, $qty, 0, $remise_percent, $date_start, $date_end, 0, $tva_npr, $price_base_type, $type, -1, 0, $array_options, $fk_unit, 0, $pu_ht_devise, $ref_supplier); + $result = $object->addline($product_desc, $pu_ht, $tva_tx, $localtax1_tx, $localtax2_tx, $qty, 0, $remise_percent, $date_start, $date_end, 0, $tva_npr, $price_base_type, $type, -1, 0, $array_options, $fk_unit, 0, $pu_devise, $ref_supplier); } //print "xx".$tva_tx; exit; @@ -1956,7 +1966,7 @@ if ($action == 'create') { print $societe->getNomUrl(1, 'supplier'); print ''; } else { - print img_picto('', 'company').$form->select_company($societe->id, 'socid', 's.fournisseur=1', 'SelectThirdParty', 0, 0, null, 0, 'minwidth300 widthcentpercentminusxx'); + print img_picto('', 'company').$form->select_company($societe->id, 'socid', 's.fournisseur=1', 'SelectThirdParty', 0, 0, null, 0, 'minwidth300 widthcentpercentminusxx maxwidth500'); // reload page to retrieve supplier informations if (!empty($conf->global->RELOAD_PAGE_ON_SUPPLIER_CHANGE)) { print ''; + } } return $ret; diff --git a/htdocs/hrm/skill_agenda.php b/htdocs/hrm/skill_agenda.php index 9c1821fb8d7..a352988c297 100644 --- a/htdocs/hrm/skill_agenda.php +++ b/htdocs/hrm/skill_agenda.php @@ -147,7 +147,7 @@ if ($object->id > 0) { // Object card // ------------------------------------------------------------ - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; $morehtmlref.= $object->label; diff --git a/htdocs/hrm/skill_card.php b/htdocs/hrm/skill_card.php index 3c72b5478ce..6fa601249db 100644 --- a/htdocs/hrm/skill_card.php +++ b/htdocs/hrm/skill_card.php @@ -21,8 +21,8 @@ /** * \file skill_card.php - * \ingroup hrm - * \brief Page to create/edit/view skill + * \ingroup hrm + * \brief Page to create/edit/view skill */ @@ -84,6 +84,8 @@ $upload_dir = $conf->hrm->multidir_output[isset($object->entity) ? $object->enti if (empty($conf->hrm->enabled)) accessforbidden(); if (!$permissiontoread || ($action === 'create' && !$permissiontoadd)) accessforbidden(); +$MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; + /* * Actions @@ -98,14 +100,14 @@ if ($reshook < 0) { if (empty($reshook)) { $error = 0; - $backurlforlist = dol_buildpath('/hrm/skill_list.php', 1); + $backurlforlist = DOL_URL_ROOT.'/hrm/skill_list.php'; if (empty($backtopage) || ($cancel && empty($id))) { if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { $backtopage = $backurlforlist; } else { - $backtopage = dol_buildpath('/hrm/skill_card.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + $backtopage = DOL_URL_ROOT.'/hrm/skill_card.php?id=' . ($id > 0 ? $id : '__ID__'); } } } @@ -166,8 +168,6 @@ if (empty($reshook)) { /* * View - * - * Put here all code to build page */ $form = new Form($db); @@ -186,9 +186,9 @@ if ($action == 'create') { print ''; print ''; print ''; - $backtopage .= "&objecttype=job"; + $backtopage .= (strpos($backtopage, '?') > 0 ? '&' : '?' ) ."objecttype=job"; if ($backtopage) { - print ''; + print ''; } if ($backtopageforcancel) { print ''; @@ -254,11 +254,16 @@ if (($id || $ref) && $action == 'edit') { // SKILLDET print dol_get_fiche_head(array(), ''); + $SkilldetRecords = $object->fetchLines(); + + if (is_array($SkilldetRecords) && count($SkilldetRecords) == 0) { + $object->createSkills(1); + } + if (is_array($SkilldetRecords) && count($SkilldetRecords) > 0) { print '
'.$langs->trans("Reception").''.$langs->trans("Product").''.$langs->trans("DateCreation").''.$langs->trans("DateDeliveryPlanned").'
'; if (!empty($objp->fk_reception)) { @@ -1205,8 +1224,16 @@ if ($id > 0 || !empty($ref)) { print "'; - print ''.img_object($langs->trans("ShowProduct"), 'product').' '.$objp->ref.''; + if (empty($conf->cache['product'][$objp->fk_product])) { + $tmpproduct = new Product($db); + $tmpproduct->fetch($objp->fk_product); + $conf->cache['product'][$objp->fk_product] = $tmpproduct; + } else { + $tmpproduct = $conf->cache['product'][$objp->fk_product]; + } + print $tmpproduct->getNomUrl(1); print ' - '.$objp->label; print "'.dol_print_date($db->jdate($objp->datec), 'day').'
'; foreach ($SkilldetRecords as $sk) { - $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; if ($sk->rank > $MaxNumberSkill) { continue; } @@ -397,7 +402,7 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea // Object card // ------------------------------------------------------------ - $linkback = '' . $langs->trans("BackToList") . ''; + $linkback = '' . $langs->trans("BackToList") . ''; $morehtmlref = '
'; @@ -691,7 +696,6 @@ if ($action != "create" && $action != "edit") { break; // Should not happen } - $MaxNumberSkill = isset($conf->global->HRM_MAXRANK) ? $conf->global->HRM_MAXRANK : Skill::DEFAULT_MAX_RANK_PER_SKILL; if ($obj->rank > $MaxNumberSkill) { continue; } diff --git a/htdocs/hrm/skill_contact.php b/htdocs/hrm/skill_contact.php index f8ea2a04a9f..d8fecd74610 100644 --- a/htdocs/hrm/skill_contact.php +++ b/htdocs/hrm/skill_contact.php @@ -129,7 +129,7 @@ if ($object->id) { print dol_get_fiche_head($head, 'contact', '', -1, $object->picto); - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; /* diff --git a/htdocs/hrm/skill_document.php b/htdocs/hrm/skill_document.php index 77f3325de15..65549dbfe7a 100644 --- a/htdocs/hrm/skill_document.php +++ b/htdocs/hrm/skill_document.php @@ -127,7 +127,7 @@ if ($object->id) { // Object card // ------------------------------------------------------------ - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; $morehtmlref.= $object->label; diff --git a/htdocs/hrm/skill_note.php b/htdocs/hrm/skill_note.php index 1510f746e5e..45a0690f176 100644 --- a/htdocs/hrm/skill_note.php +++ b/htdocs/hrm/skill_note.php @@ -100,7 +100,7 @@ if ($id > 0 || !empty($ref)) { // Object card // ------------------------------------------------------------ - $linkback = ''.$langs->trans("BackToList").''; + $linkback = ''.$langs->trans("BackToList").''; $morehtmlref = '
'; $morehtmlref.= $object->label; diff --git a/htdocs/hrm/skill_tab.php b/htdocs/hrm/skill_tab.php index 9a9ea39e31d..e7c6798bbec 100644 --- a/htdocs/hrm/skill_tab.php +++ b/htdocs/hrm/skill_tab.php @@ -93,14 +93,14 @@ if ($reshook < 0) { if (empty($reshook)) { $error = 0; - $backurlforlist = dol_buildpath('/hrm/skill_list.php', 1); + $backurlforlist = DOL_URL_ROOT.'/hrm/skill_list.php'; if (empty($backtopage) || ($cancel && empty($id))) { if (empty($backtopage) || ($cancel && strpos($backtopage, '__ID__'))) { if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) { $backtopage = $backurlforlist; } else { - $backtopage = dol_buildpath('/hrm/skill_list.php', 1) . '?id=' . ($id > 0 ? $id : '__ID__'); + $backtopage = DOL_URL_ROOT.'/hrm/skill_list.php?id=' . ($id > 0 ? $id : '__ID__'); } } } diff --git a/htdocs/imports/import.php b/htdocs/imports/import.php index d516a67278c..41059a45e92 100644 --- a/htdocs/imports/import.php +++ b/htdocs/imports/import.php @@ -1178,7 +1178,7 @@ if ($step == 4 && $datatoimport) { if ($conf->use_javascript_ajax) { - print ''."\n"; print "\n"; diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php index 84562bf95a4..32c4c83378c 100644 --- a/htdocs/product/ajax/products.php +++ b/htdocs/product/ajax/products.php @@ -47,7 +47,7 @@ if (empty($_GET['keysearch']) && !defined('NOREQUIREHTML')) { require '../../main.inc.php'; -$htmlname = GETPOST('htmlname', 'alpha'); +$htmlname = GETPOST('htmlname', 'aZ09'); $socid = GETPOST('socid', 'int'); $type = GETPOST('type', 'int'); $mode = GETPOST('mode', 'int'); @@ -73,7 +73,7 @@ restrictedArea($user, 'produit|service', 0, 'product&product'); // print ''."\n"; // print_r($_GET); -if (!empty($action) && $action == 'fetch' && !empty($id)) { +if ($action == 'fetch' && !empty($id)) { // action='fetch' is used to get product information on a product. So when action='fetch', id must be the product id. require_once DOL_DOCUMENT_ROOT.'/product/class/product.class.php'; require_once DOL_DOCUMENT_ROOT.'/societe/class/societe.class.php'; @@ -85,10 +85,15 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { if ($ret > 0) { $outref = $object->ref; $outlabel = $object->label; - $outlabel_trans =''; + $outlabel_trans = ''; $outdesc = $object->description; - $outdesc_trans =''; + $outdesc_trans = ''; $outtype = $object->type; + $outprice_ht = null; + $outprice_ttc = null; + $outpricebasetype = null; + $outtva_tx = 0; + $outdefault_vat_code = ''; $outqty = 1; $outdiscount = 0; $mandatory_period = $object->mandatory_period; @@ -132,17 +137,21 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { $found = true; $outprice_ht = price($objp->unitprice); $outprice_ttc = price($objp->unitprice * (1 + ($object->tva_tx / 100))); + $outpricebasetype = $object->price_base_type; $outtva_tx = $object->tva_tx; + $outdefault_vat_code = $object->default_vat_code; + $outqty = $objp->quantity; $outdiscount = $objp->remise_percent; } } } - // Multiprice + // Multiprice (1 price per level) if (!$found && isset($price_level) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) { // If we need a particular price level (from 1 to 6) - $sql = "SELECT price, price_ttc, price_base_type, tva_tx"; + $sql = "SELECT price, price_ttc, price_base_type,"; + $sql .= " tva_tx, default_vat_code"; // Vat rate and code will be used if PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL is on. $sql .= " FROM ".MAIN_DB_PREFIX."product_price "; $sql .= " WHERE fk_product = ".((int) $id); $sql .= " AND entity IN (".getEntity('productprice').")"; @@ -158,7 +167,14 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { $outprice_ht = price($objp->price); $outprice_ttc = price($objp->price_ttc); $outpricebasetype = $objp->price_base_type; - $outtva_tx = $objp->tva_tx; + if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) { + $outtva_tx = $objp->tva_tx; + $outdefault_vat_code = $objp->default_vat_code; + } else { + // The common and default behaviour. + $outtva_tx = $object->tva_tx; + $outdefault_vat_code = $object->default_vat_code; + } } } } @@ -175,10 +191,11 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { if ($result) { if (count($prodcustprice->lines) > 0) { $found = true; - $outprice_ht = price($prodcustprice->lines [0]->price); - $outprice_ttc = price($prodcustprice->lines [0]->price_ttc); - $outpricebasetype = $prodcustprice->lines [0]->price_base_type; - $outtva_tx = $prodcustprice->lines [0]->tva_tx; + $outprice_ht = price($prodcustprice->lines[0]->price); + $outprice_ttc = price($prodcustprice->lines[0]->price_ttc); + $outpricebasetype = $prodcustprice->lines[0]->price_base_type; + $outtva_tx = $prodcustprice->lines[0]->tva_tx; + $outdefault_vat_code = $prodcustprice->lines[0]->default_vat_code; } } } @@ -188,6 +205,7 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { $outprice_ttc = price($object->price_ttc); $outpricebasetype = $object->price_base_type; $outtva_tx = $object->tva_tx; + $outdefault_vat_code = $object->default_vat_code; } $outjson = array( @@ -201,6 +219,7 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { 'price_ttc' => $outprice_ttc, 'pricebasetype' => $outpricebasetype, 'tva_tx' => $outtva_tx, + 'default_vat_code' => $outdefault_vat_code, 'qty' => $outqty, 'discount' => $outdiscount, 'mandatory_period' => $mandatory_period, @@ -223,7 +242,7 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) { // Filter on the product to search can be: // Into an array with key $htmlname123 (we take first one found). Which page use this ? // Into a var with name $htmlname can be 'prodid', 'productid', ... - $match = preg_grep('/('.$htmlname.'[0-9]+)/', array_keys($_GET)); + $match = preg_grep('/('.preg_quote($htmlname, '/').'[0-9]+)/', array_keys($_GET)); sort($match); $idprod = (empty($match[0]) ? '' : $match[0]); // Take first key found into GET array with matching $htmlname123 diff --git a/htdocs/product/canvas/service/actions_card_service.class.php b/htdocs/product/canvas/service/actions_card_service.class.php index c4296dc63a8..b07c3d96a52 100644 --- a/htdocs/product/canvas/service/actions_card_service.class.php +++ b/htdocs/product/canvas/service/actions_card_service.class.php @@ -39,6 +39,13 @@ class ActionsCardService public $field_list = array(); public $list_datas = array(); + public $id; + public $ref; + public $description; + public $note; + public $price; + public $price_min; + /** * Constructor @@ -196,6 +203,7 @@ class ActionsCardService } // Duration + $dur = array(); if ($this->object->duration_value > 1) { $dur = array("h"=>$langs->trans("Hours"), "d"=>$langs->trans("Days"), "w"=>$langs->trans("Weeks"), "m"=>$langs->trans("Months"), "y"=>$langs->trans("Years")); } elseif ($this->object->duration_value > 0) { @@ -286,6 +294,7 @@ class ActionsCardService if ($search_categ) { $sql .= ", ".MAIN_DB_PREFIX."categorie_product as cp"; } + $fourn_id = 0; if (GETPOST("fourn_id", 'int') > 0) { $fourn_id = GETPOST("fourn_id", 'int'); $sql .= ", ".MAIN_DB_PREFIX."product_fournisseur_price as pfp"; diff --git a/htdocs/product/class/api_products.class.php b/htdocs/product/class/api_products.class.php index 6283b692a28..91edbe5eaff 100644 --- a/htdocs/product/class/api_products.class.php +++ b/htdocs/product/class/api_products.class.php @@ -172,9 +172,10 @@ class Products extends DolibarrApi * @param bool $ids_only Return only IDs of product instead of all properties (faster, above all if list is long) * @param int $variant_filter Use this param to filter list (0 = all, 1=products without variants, 2=parent of variants, 3=variants only) * @param bool $pagination_data If this parameter is set to true the response will include pagination data. Default value is false. Page starts from 0 + * @param int $includestockdata Load also information about stock (slower) * @return array Array of product objects */ - public function index($sortfield = "t.ref", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false) + public function index($sortfield = "t.ref", $sortorder = 'ASC', $limit = 100, $page = 0, $mode = 0, $category = 0, $sqlfilters = '', $ids_only = false, $variant_filter = 0, $pagination_data = false, $includestockdata = 0) { global $db, $conf; @@ -218,8 +219,9 @@ class Products extends DolibarrApi } // Add sql filters if ($sqlfilters) { - if (!DolibarrApi::_checkFilters($sqlfilters)) { - throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + $errormessage = ''; + if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) { + throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage); } //var_dump($sqlfilters);exit; $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; // We must accept datc:<:2020-01-01 10:10:10 @@ -249,6 +251,21 @@ class Products extends DolibarrApi if (!$ids_only) { $product_static = new Product($this->db); if ($product_static->fetch($obj->rowid)) { + if ($includestockdata && DolibarrApiAccess::$user->rights->stock->lire) { + $product_static->load_stock(); + + if (is_array($product_static->stock_warehouse)) { + foreach ($product_static->stock_warehouse as $keytmp => $valtmp) { + if (is_array($product_static->stock_warehouse[$keytmp]->detail_batch)) { + foreach ($product_static->stock_warehouse[$keytmp]->detail_batch as $keytmp2 => $valtmp2) { + unset($product_static->stock_warehouse[$keytmp]->detail_batch[$keytmp2]->db); + } + } + } + } + } + + $obj_ret[] = $this->_cleanObjectDatas($product_static); } } else { @@ -873,8 +890,9 @@ class Products extends DolibarrApi } // Add sql filters if ($sqlfilters) { - if (!DolibarrApi::_checkFilters($sqlfilters)) { - throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + $errormessage = ''; + if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) { + throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage); } $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; @@ -1000,8 +1018,9 @@ class Products extends DolibarrApi // Add sql filters if ($sqlfilters) { - if (!DolibarrApi::_checkFilters($sqlfilters)) { - throw new RestException(503, 'Error when validating parameter sqlfilters '.$sqlfilters); + $errormessage = ''; + if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) { + throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage); } $regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)'; $sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")"; @@ -1948,6 +1967,7 @@ class Products extends DolibarrApi if (empty(DolibarrApiAccess::$user->rights->stock->lire)) { unset($object->stock_reel); unset($object->stock_theorique); + unset($object->stock_warehouse); } return $object; diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php index 1d4a5926b6e..27b2bdaff2c 100644 --- a/htdocs/product/class/product.class.php +++ b/htdocs/product/class/product.class.php @@ -2037,7 +2037,7 @@ class Product extends CommonObject /** - * Modify customer price of a product/Service + * Modify customer price of a product/Service * * @param double $newprice New price * @param string $newpricebase HT or TTC @@ -4800,9 +4800,10 @@ class Product extends CommonObject if (!empty($this->entity)) { $tmpphoto = $this->show_photos('product', $conf->product->multidir_output[$this->entity], 1, 1, 0, 0, 0, 80); if ($this->nbphoto > 0) { - $label .= '
'; + $label .= '
'; $label .= $tmpphoto; - $label .= '
'; + $label .= '
'; + //$label .= '
'; } } diff --git a/htdocs/product/class/productcustomerprice.class.php b/htdocs/product/class/productcustomerprice.class.php index 407eac7c30a..a9444d1c569 100644 --- a/htdocs/product/class/productcustomerprice.class.php +++ b/htdocs/product/class/productcustomerprice.class.php @@ -392,9 +392,9 @@ class Productcustomerprice extends CommonObject $sql .= " t.import_key,"; $sql .= " soc.nom as socname,"; $sql .= " prod.ref as prodref"; - $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price as t "; - $sql .= " ,".MAIN_DB_PREFIX."product as prod "; - $sql .= " ,".MAIN_DB_PREFIX."societe as soc "; + $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price as t,"; + $sql .= " ".MAIN_DB_PREFIX."product as prod,"; + $sql .= " ".MAIN_DB_PREFIX."societe as soc"; $sql .= " WHERE soc.rowid=t.fk_soc "; $sql .= " AND prod.rowid=t.fk_product "; $sql .= " AND prod.entity IN (".getEntity('product').")"; diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php index 02e0211c01d..d521f3b5eae 100644 --- a/htdocs/product/fournisseurs.php +++ b/htdocs/product/fournisseurs.php @@ -63,10 +63,9 @@ $error = 0; $extrafields = new ExtraFields($db); // If socid provided by ajax company selector -if (!empty($_REQUEST['search_fourn_id'])) { +if (GETPOST('search_fourn_id', 'int')) { $_GET['id_fourn'] = GETPOST('search_fourn_id', 'int'); $_POST['id_fourn'] = GETPOST('search_fourn_id', 'int'); - $_REQUEST['id_fourn'] = GETPOST('search_fourn_id', 'int'); } // Security check @@ -518,7 +517,7 @@ if ($id > 0 || $ref) { } else { $events = array(); $events[] = array('method' => 'getVatRates', 'url' => dol_buildpath('/core/ajax/vatrates.php', 1), 'htmlname' => 'tva_tx', 'params' => array()); - print $form->select_company(GETPOST("id_fourn", 'alpha'), 'id_fourn', 'fournisseur=1', 'SelectThirdParty', 0, 0, $events); + print img_picto('', 'company', 'class="pictofixedwidth"').$form->select_company(GETPOST("id_fourn", 'alpha'), 'id_fourn', 'fournisseur=1', 'SelectThirdParty', 0, 0, $events); $parameters = array('filtre'=>"fournisseur=1", 'html_name'=>'id_fourn', 'selected'=>GETPOST("id_fourn"), 'showempty'=>1, 'prod_id'=>$object->id); $reshook = $hookmanager->executeHooks('formCreateThirdpartyOptions', $parameters, $object, $action); @@ -1211,7 +1210,7 @@ END; $obj = $db->fetch_object($resql); foreach ($extralabels as $key => $value) { if (!empty($arrayfields['ef.'.$key]['checked']) && !empty($extrafields->attributes["product_fournisseur_price"]['list'][$key]) && $extrafields->attributes["product_fournisseur_price"]['list'][$key] != 3) { - print '
"; + print '"; } } } diff --git a/htdocs/product/index.php b/htdocs/product/index.php index 082e8a4d8d2..e4a0bfc7421 100644 --- a/htdocs/product/index.php +++ b/htdocs/product/index.php @@ -225,6 +225,7 @@ if (!empty($conf->categorie->enabled) && !empty($conf->global->CATEGORY_GRAPHSTA $sql .= " WHERE c.type = 0"; $sql .= " AND c.entity IN (".getEntity('category').")"; $sql .= " GROUP BY c.label"; + $sql .= " ORDER BY nb desc"; $total = 0; $result = $db->query($sql); if ($result) { @@ -341,8 +342,8 @@ if ((!empty($conf->product->enabled) || !empty($conf->service->enabled)) && ($us if (!empty($conf->global->MAIN_MULTILANGS)) { $sql = "SELECT label"; $sql .= " FROM ".MAIN_DB_PREFIX."product_lang"; - $sql .= " WHERE fk_product=".((int) $objp->rowid); - $sql .= " AND lang='".$db->escape($langs->getDefaultLang())."'"; + $sql .= " WHERE fk_product = ".((int) $objp->rowid); + $sql .= " AND lang = '".$db->escape($langs->getDefaultLang())."'"; $resultd = $db->query($sql); if ($resultd) { diff --git a/htdocs/product/inventory/ajax/ajax.inventory.php b/htdocs/product/inventory/ajax/ajax.inventory.php deleted file mode 100644 index 920607f4c1e..00000000000 --- a/htdocs/product/inventory/ajax/ajax.inventory.php +++ /dev/null @@ -1,47 +0,0 @@ -rights->stock->creer)) { - echo -1; exit; - } - - $fk_det_inventory = GETPOST('fk_det_inventory'); - - $det = new InventoryLine($db); - if ($det->fetch($fk_det_inventory)) { - $det->qty_view += GETPOST('qty'); - $res = $det->update($user); - - echo $det->qty_view; - } else { - echo -2; - } - - break; - - case 'pmp': - if (empty($user->rights->stock->creer) || empty($user->rights->stock->changePMP)) { - echo -1; exit; - } - - $fk_det_inventory = GETPOST('fk_det_inventory'); - - $det = new InventoryLine($db); - if ($det->fetch($fk_det_inventory)) { - $det->new_pmp = price2num(GETPOST('pmp')); - $det->update($user); - - echo $det->new_pmp; - } else { - echo -2; - } - - break; -} diff --git a/htdocs/product/inventory/ajax/searchfrombarcode.php b/htdocs/product/inventory/ajax/searchfrombarcode.php new file mode 100644 index 00000000000..68ffee43c23 --- /dev/null +++ b/htdocs/product/inventory/ajax/searchfrombarcode.php @@ -0,0 +1,135 @@ +. + */ + +/** + * \file /htdocs/product/inventory/ajax/searchfrombarcode.php + * \brief File to make Ajax action on product and stock + */ + +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', 1); // Disables token renewal +} +if (!defined('NOREQUIREMENU')) { + define('NOREQUIREMENU', '1'); +} +if (!defined('NOREQUIREHTML')) { + define('NOREQUIREHTML', '1'); +} +if (!defined('NOREQUIREAJAX')) { + define('NOREQUIREAJAX', '1'); +} +if (!defined('NOREQUIRESOC')) { + define('NOREQUIRESOC', '1'); +} +if (!defined('NOCSRFCHECK')) { + define('NOCSRFCHECK', '1'); +} +require '../../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT."/product/stock/class/entrepot.class.php"; +$warehouse = new Entrepot($db); + +$action = GETPOST("action", "alpha"); +$barcode = GETPOST("barcode", "aZ09"); +$product = GETPOST("product"); +$response = ""; + +$fk_entrepot = GETPOST("fk_entrepot", "int"); +$fk_inventory = GETPOST("fk_inventory", "int"); +$fk_product = GETPOST("fk_product", "int"); +$reelqty = GETPOST("reelqty", "int"); +$batch = GETPOST("batch", "int"); +$mode = GETPOST("mode", "aZ"); + +$warehousefound = 0; +$warehouseid = 0; +$objectreturn = array(); + +if ($action == "existbarcode" && !empty($barcode)) { + if (!empty($mode) && $mode == "lotserial") { + $sql = "SELECT ps.fk_entrepot, ps.fk_product, p.barcode, ps.reel, pb.batch"; + $sql .= " FROM ".MAIN_DB_PREFIX."product_batch as pb"; + $sql .= " JOIN ".MAIN_DB_PREFIX."product_stock as ps ON pb.fk_product_stock = ps.rowid JOIN ".MAIN_DB_PREFIX."product as p ON ps.fk_product = p.rowid"; + $sql .= " WHERE pb.batch = '".$db->escape($barcode)."'"; + } else { + $sql = "SELECT ps.fk_entrepot, ps.fk_product, p.barcode,ps.reel"; + $sql .= " FROM ".MAIN_DB_PREFIX."product_stock as ps JOIN ".MAIN_DB_PREFIX."product as p ON ps.fk_product = p.rowid"; + $sql .= " WHERE p.barcode = '".$db->escape($barcode)."'"; + } + if (!empty($fk_entrepot)) { + $sql .= " AND ps.fk_entrepot = '".$db->escape($fk_entrepot)."'"; + } + if (!empty($fk_product)) { + $sql .= " AND ps.fk_product = '".$db->escape($fk_product)."'"; + } + $result = $db->query($sql); + if ($result) { + $nbline = $db->num_rows($result); + for ($i=0; $i < $nbline; $i++) { + $object = $db->fetch_object($result); + if (($mode == "barcode" && $barcode == $object->barcode) || ($mode == "lotserial" && $barcode == $object->batch)) { + $warehouse->fetch(0, $product["Warehouse"]); + if (!empty($object->fk_entrepot) && $warehouse->id == $object->fk_entrepot) { + $warehousefound++; + $warehouseid = $object->fk_entrepot; + $fk_product = $object->fk_product; + $reelqty = $object->reel; + + $objectreturn = array('fk_warehouse'=>$warehouseid,'fk_product'=>$fk_product,'reelqty'=>$reelqty); + } + } + } + if ($warehousefound < 1) { + $response = array('status'=>'error','errorcode'=>'NotFound','message'=>'No warehouse found for barcode'.$barcode); + } elseif ($warehousefound > 1) { + $response = array('status'=>'error','errorcode'=>'TooManyWarehouse','message'=>'Too many warehouse found'); + } else { + $response = array('status'=>'success','message'=>'Warehouse found','object'=>$objectreturn); + } + } else { + $response = array('status'=>'error','errorcode'=>'NotFound','message'=>"No results found for barcode"); + } +} else { + $response = array('status'=>'error','errorcode'=>'ActionError','message'=>"Error on action"); +} + +if ($action == "addnewlineproduct") { + require_once DOL_DOCUMENT_ROOT."/product/inventory/class/inventory.class.php"; + $inventoryline = new InventoryLine($db); + if (!empty($fk_inventory)) { + $inventoryline->fk_inventory = $fk_inventory; + + $inventoryline->fk_warehouse = $fk_entrepot; + $inventoryline->fk_product = $fk_product; + $inventoryline->qty_stock = $reelqty; + if (!empty($batch)) { + $inventoryline->batch = $batch; + } + $inventoryline->datec = dol_now(); + + $result = $inventoryline->create($user); + if ($result > 0) { + $response = array('status'=>'success','message'=>'Success on creating line','id_line'=>$result); + } else { + $response = array('status'=>'error','errorcode'=>'ErrorCreation','message'=>"Error on line creation"); + } + } else { + $response = array('status'=>'error','errorcode'=>'NoIdForInventory','message'=>"No id for inventory"); + } +} + +$response = json_encode($response); +echo $response; diff --git a/htdocs/product/inventory/card.php b/htdocs/product/inventory/card.php index 1f036e1fa3c..23473545b11 100644 --- a/htdocs/product/inventory/card.php +++ b/htdocs/product/inventory/card.php @@ -207,6 +207,8 @@ if ($action == 'create') { // Other attributes include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; + //print ''; + print '
'.$extrafields->showOutputField($key, $obj->{$key})."'.$extrafields->showOutputField($key, $obj->{$key}, '', 'product_fournisseur_price')."
'.$langs->trans("InventoryCode").'INV'.$object->id.'
'."\n"; print dol_get_fiche_end(); @@ -462,7 +464,8 @@ if ($object->id > 0 && (empty($action) || ($action != 'edit' && $action != 'crea $MAXEVENT = 10; - $morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/product/inventory/inventory_info.php?id='.$object->id); + //$morehtmlcenter = dolGetButtonTitle($langs->trans('SeeAll'), '', 'fa fa-list-alt imgforviewmode', DOL_URL_ROOT.'/product/inventory/inventory_info.php?id='.$object->id); + $morehtmlcenter = ''; // List of actions on element include_once DOL_DOCUMENT_ROOT.'/core/class/html.formactions.class.php'; diff --git a/htdocs/product/inventory/class/inventory.class.php b/htdocs/product/inventory/class/inventory.class.php index b972e44245b..bb55bc1b143 100644 --- a/htdocs/product/inventory/class/inventory.class.php +++ b/htdocs/product/inventory/class/inventory.class.php @@ -26,6 +26,7 @@ // Put here all includes required by your class file require_once DOL_DOCUMENT_ROOT.'/core/class/commonobject.class.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/commonobjectline.class.php'; //require_once DOL_DOCUMENT_ROOT . '/societe/class/societe.class.php'; //require_once DOL_DOCUMENT_ROOT . '/product/class/product.class.php'; @@ -110,7 +111,7 @@ class Inventory extends CommonObject 'fk_user_valid' => array('type'=>'integer:User:user/class/user.class.php', 'label'=>'UserValidation', 'visible'=>-2, 'enabled'=>1, 'position'=>512, 'csslist'=>'tdoverflowmax200'), 'import_key' => array('type'=>'varchar(14)', 'label'=>'ImportId', 'enabled'=>1, 'visible'=>-2, 'notnull'=>-1, 'index'=>0, 'position'=>1000), - 'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>4, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>1, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 2=>'Recorded', 9=>'Canceled')) + 'status' => array('type'=>'integer', 'label'=>'Status', 'visible'=>4, 'enabled'=>1, 'position'=>1000, 'notnull'=>1, 'default'=>0, 'index'=>1, 'arrayofkeyval'=>array(0=>'Draft', 1=>'Validated', 2=>'Closed', 9=>'Canceled')) ); /** @@ -625,7 +626,7 @@ class Inventory extends CommonObject $statusType = 'status'.$status; if ($status == self::STATUS_RECORDED) { - $statusType = 'status5'; + $statusType = 'status6'; } return dolGetStatus($labelStatus[$status], $labelStatusShort[$status], '', $statusType, $mode); diff --git a/htdocs/product/inventory/inventory.php b/htdocs/product/inventory/inventory.php index ce657f1c9d6..82747fb8360 100644 --- a/htdocs/product/inventory/inventory.php +++ b/htdocs/product/inventory/inventory.php @@ -103,122 +103,6 @@ if ($cancel) { $action = ''; } -if ($action == 'cancel_record' && $permissiontoadd) { - $object->setCanceled($user); -} - -if ($action == 'update' && !empty($user->rights->stock->mouvement->creer)) { - $stockmovment = new MouvementStock($db); - $stockmovment->setOrigin($object->element, $object->id); - - $db->begin(); - - $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; - $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; - $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; - $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); - - $resql = $db->query($sql); - if ($resql) { - $num = $db->num_rows($resql); - $i = 0; - $totalarray = array(); - while ($i < $num) { - $line = $db->fetch_object($resql); - $qty_stock = $line->qty_stock; - $qty_view = $line->qty_view; // The quantity viewed by inventorier, the qty we target - - if (!is_null($qty_view)) { - $stock_movement_qty = price2num($qty_view - $qty_stock, 'MS'); - if ($stock_movement_qty != 0) { - if ($stock_movement_qty < 0) { - $movement_type = 1; - } else { - $movement_type = 0; - } - - $datemovement = ''; - - $idstockmove = $stockmovment->_create($user, $line->fk_product, $line->fk_warehouse, $stock_movement_qty, $movement_type, 0, $langs->trans('LabelOfInventoryMovemement', $object->id), 'INV'.$object->id, $datemovement, '', '', $line->batch); - if ($idstockmove < 0) { - $error++; - setEventMessages($stockmovment->error, $stockmovment->errors, 'errors'); - break; - } - } - } - $i++; - } - - if (!$error) { - $object->setRecorded($user); - } - } else { - setEventMessages($db->lasterror, null, 'errors'); - $error++; - } - - if (! $error) { - $db->commit(); - } else { - $db->rollback(); - } -} - -if ($action =='updateinventorylines' && $permissiontoadd) { - $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; - $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; - $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; - $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); - - $db->begin(); - - $resql = $db->query($sql); - if ($resql) { - $num = $db->num_rows($resql); - $i = 0; - $totalarray = array(); - $inventoryline = new InventoryLine($db); - - while ($i < $num) { - $line = $db->fetch_object($resql); - $lineid = $line->rowid; - - if (GETPOST("id_".$lineid, 'alpha') != '') { // If a value was set ('0' or something else) - $qtytoupdate = price2num(GETPOST("id_".$lineid, 'alpha'), 'MS'); - $result = $inventoryline->fetch($lineid); - if ($qtytoupdate < 0) { - $result = -1; - setEventMessages($langs->trans("FieldCannotBeNegative", $langs->transnoentitiesnoconv("RealQty")), null, 'errors'); - } - if ($result > 0) { - $inventoryline->qty_view = $qtytoupdate; - $resultupdate = $inventoryline->update($user); - } - } else { - // Delete record - $result = $inventoryline->fetch($lineid); - if ($result > 0) { - $inventoryline->qty_view = null; - $resultupdate = $inventoryline->update($user); - } - } - - if ($result < 0 || $resultupdate < 0) { - $error++; - } - - $i++; - } - } - - if (!$error) { - $db->commit(); - } else { - $db->rollback(); - } -} - $parameters = array(); $reshook = $hookmanager->executeHooks('doActions', $parameters, $object, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) { @@ -228,6 +112,179 @@ if ($reshook < 0) { if (empty($reshook)) { $error = 0; + if ($action == 'cancel_record' && $permissiontoadd) { + $object->setCanceled($user); + } + + // Close inventory by recording the stock movements + if ($action == 'update' && !empty($user->rights->stock->mouvement->creer)) { + $stockmovment = new MouvementStock($db); + $stockmovment->setOrigin($object->element, $object->id); + + $cacheOfProducts = array(); + + $db->begin(); + + $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; + $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; + $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + $totalarray = array(); + while ($i < $num) { + $line = $db->fetch_object($resql); + + $qty_stock = $line->qty_stock; + $qty_view = $line->qty_view; // The quantity viewed by inventorier, the qty we target + + + // Load real stock we have now. + if (isset($cacheOfProducts[$line->fk_product])) { + $product_static = $cacheOfProducts[$line->fk_product]; + } else { + $product_static = new Product($db); + $result = $product_static->fetch($line->fk_product, '', '', '', 1, 1, 1); + + //$option = 'nobatch'; + $option .= ',novirtual'; + $product_static->load_stock($option); // Load stock_reel + stock_warehouse. + + $cacheOfProducts[$product_static->id] = $product_static; + } + + // Get the real quantity in stock now, but before the stock move for inventory. + $realqtynow = $product_static->stock_warehouse[$line->fk_warehouse]->real; + if ($conf->productbatch->enabled && $product_static->hasbatch()) { + $realqtynow = $product_static->stock_warehouse[$line->fk_warehouse]->detail_batch[$line->batch]->qty; + } + + + if (!is_null($qty_view)) { + $stock_movement_qty = price2num($qty_view - $realqtynow, 'MS'); + if ($stock_movement_qty != 0) { + if ($stock_movement_qty < 0) { + $movement_type = 1; + } else { + $movement_type = 0; + } + + $datemovement = ''; + //$inventorycode = 'INV'.$object->id; + $inventorycode = 'INV-'.$object->ref; + + $idstockmove = $stockmovment->_create($user, $line->fk_product, $line->fk_warehouse, $stock_movement_qty, $movement_type, 0, $langs->trans('LabelOfInventoryMovemement', $object->ref), $inventorycode, $datemovement, '', '', $line->batch); + if ($idstockmove < 0) { + $error++; + setEventMessages($stockmovment->error, $stockmovment->errors, 'errors'); + break; + } + + // Update line with id of stock movement (and the start quantity if it has changed this last recording) + $sqlupdate = "UPDATE ".MAIN_DB_PREFIX."inventorydet"; + $sqlupdate .= " SET fk_movement = ".((int) $idstockmove); + if ($qty_stock != $realqtynow) { + $sqlupdate .= ", qty_stock = ".((float) $realqtynow); + } + $sqlupdate .= " WHERE rowid = ".((int) $line->rowid); + $resqlupdate = $db->query($sqlupdate); + if (! $resqlupdate) { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + break; + } + } + } + $i++; + } + + if (!$error) { + $object->setRecorded($user); + } + } else { + setEventMessages($db->lasterror, null, 'errors'); + $error++; + } + + if (! $error) { + $db->commit(); + } else { + $db->rollback(); + } + } + + // Save quantity found during inventory + if ($action =='updateinventorylines' && $permissiontoadd) { + $sql = 'SELECT id.rowid, id.datec as date_creation, id.tms as date_modification, id.fk_inventory, id.fk_warehouse,'; + $sql .= ' id.fk_product, id.batch, id.qty_stock, id.qty_view, id.qty_regulated'; + $sql .= ' FROM '.MAIN_DB_PREFIX.'inventorydet as id'; + $sql .= ' WHERE id.fk_inventory = '.((int) $object->id); + + $db->begin(); + + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); + $i = 0; + $totalarray = array(); + $inventoryline = new InventoryLine($db); + + while ($i < $num) { + $line = $db->fetch_object($resql); + $lineid = $line->rowid; + + if (GETPOST("id_".$lineid, 'alpha') != '') { // If a value was set ('0' or something else) + $qtytoupdate = price2num(GETPOST("id_".$lineid, 'alpha'), 'MS'); + $result = $inventoryline->fetch($lineid); + if ($qtytoupdate < 0) { + $result = -1; + setEventMessages($langs->trans("FieldCannotBeNegative", $langs->transnoentitiesnoconv("RealQty")), null, 'errors'); + } + if ($result > 0) { + $inventoryline->qty_stock = price2num(GETPOST('stock_qty_'.$lineid, 'alpha'), 'MS'); // The new value that was set in as hidden field + $inventoryline->qty_view = $qtytoupdate; // The new value we want + $resultupdate = $inventoryline->update($user); + } + } else { + // Delete record + $result = $inventoryline->fetch($lineid); + if ($result > 0) { + $inventoryline->qty_view = null; // The new value we want + $resultupdate = $inventoryline->update($user); + } + } + + if ($result < 0 || $resultupdate < 0) { + $error++; + } + + $i++; + } + } + + // Update line with id of stock movement (and the start quantity if it has changed this last recording) + if (! $error) { + $sqlupdate = "UPDATE ".MAIN_DB_PREFIX."inventory"; + $sqlupdate .= " SET fk_user_modif = ".((int) $user->id); + $sqlupdate .= " WHERE rowid = ".((int) $object->id); + $resqlupdate = $db->query($sqlupdate); + if (! $resqlupdate) { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + } + } + + if (!$error) { + $db->commit(); + } else { + $db->rollback(); + } + } + + $backurlforlist = DOL_URL_ROOT.'/product/inventory/list.php'; $backtopage = DOL_URL_ROOT.'/product/inventory/inventory.php?id='.$object->id; @@ -286,10 +343,15 @@ if (empty($reshook)) { $result = $tmp->create($user); if ($result < 0) { if ($db->lasterrno() == 'DB_ERROR_RECORD_ALREADY_EXISTS') { - setEventMessages($langs->trans("DuplicateRecord"), null, 'errors'); + $langs->load("errors"); + setEventMessages($langs->trans("ErrorRecordAlreadyExists"), null, 'errors'); } else { dol_print_error($db, $tmp->error, $tmp->errors); } + } else { + // Clear var + $_POST['batch'] = ''; + $_POST['qtytoadd'] = ''; } } } @@ -311,7 +373,7 @@ llxHeader('', $langs->trans('Inventory'), $help_url); // Disable button Generate movement if data were modified and not saved -print ''; + // Link to autofill + print ''.img_picto('', 'autofill', 'class="paddingrightonly"').$langs->trans('AutofillWithExpected').''; + print ''; + + // Link to reset qty + print ''.img_picto('', 'eraser', 'class="paddingrightonly"').$langs->trans("ClearQtys").''; + } else { + print ''.$langs->trans("Save").''."\n"; + } } print '
'; print '
'; @@ -540,17 +606,34 @@ if ($object->id > 0) { // Popup for mass barcode scanning if ($action == 'updatebyscaning') { if ($permissiontoadd) { + // Output the javascript to manage the scanner tool. print ''; } include DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; $formother = new FormOther($db); - print $formother->getHTMLScannerForm(); + print $formother->getHTMLScannerForm("barcodescannerjs", 'all'); } //Call method to undo changes in real qty print ' '; } else { - if ($object->status == $object::STATUS_SIGNED) { - print '
'; - if ($message == 'signed') { - print ''.$langs->trans("PropalSigned").''; + if ($source == 'proposal') { + if ($object->status == $object::STATUS_SIGNED) { + print '
'; + if ($message == 'signed') { + print ''.$langs->trans("PropalSigned").''; + } else { + print ''.$langs->trans("PropalAlreadySigned").''; + } + } elseif ($object->status == $object::STATUS_NOTSIGNED) { + print '
'; + if ($message == 'refused') { + print ''.$langs->trans("PropalRefused").''; + } else { + print ''.$langs->trans("PropalAlreadyRefused").''; + } } else { - print ''.$langs->trans("PropalAlreadySigned").''; + print ''; + print ''; } - } elseif ($object->status == $object::STATUS_NOTSIGNED) { - print '
'; - if ($message == 'refused') { - print ''.$langs->trans("PropalRefused").''; - } else { - print ''.$langs->trans("PropalAlreadyRefused").''; - } - } else { - print ''; - print ''; } } print ''."\n"; diff --git a/htdocs/public/payment/newpayment.php b/htdocs/public/payment/newpayment.php index 8eefd77e746..5158e294fb2 100644 --- a/htdocs/public/payment/newpayment.php +++ b/htdocs/public/payment/newpayment.php @@ -184,11 +184,12 @@ if ($source == 'organizedeventregistration') { } -$paymentmethod = GETPOST('paymentmethod', 'alphanohtml') ?GETPOST('paymentmethod', 'alphanohtml') : ''; // Empty in most cases. Defined when a payment mode is forced +$paymentmethod = GETPOST('paymentmethod', 'alphanohtml') ? GETPOST('paymentmethod', 'alphanohtml') : ''; // Empty in most cases. Defined when a payment mode is forced $validpaymentmethod = array(); // Detect $paymentmethod foreach ($_POST as $key => $val) { + $reg = array(); if (preg_match('/^dopayment_(.*)$/', $key, $reg)) { $paymentmethod = $reg[1]; break; @@ -246,7 +247,6 @@ $urlok = preg_replace('/&$/', '', $urlok); // Remove last & $urlko = preg_replace('/&$/', '', $urlko); // Remove last & - // Make special controls if ((empty($paymentmethod) || $paymentmethod == 'paypal') && !empty($conf->paypal->enabled)) { @@ -299,21 +299,23 @@ if ($tmpsource == 'membersubscription') { } $valid = true; if (!empty($conf->global->PAYMENT_SECURITY_TOKEN)) { - $token = ''; - $tokenoldcompat = ''; + $tokenisok = false; if (!empty($conf->global->PAYMENT_SECURITY_TOKEN_UNIQUE)) { if ($tmpsource && $REF) { - $token = dol_hash($conf->global->PAYMENT_SECURITY_TOKEN.$tmpsource.$REF, 2); // Use the source in the hash to avoid duplicates if the references are identical + // Use the source in the hash to avoid duplicates if the references are identical + $tokenisok = dol_verifyHash($conf->global->PAYMENT_SECURITY_TOKEN.$tmpsource.$REF, $SECUREKEY, '2'); + // Do a second test for retro-compatibility (token may have been hashed with membersubscription in external module) if ($tmpsource != $source) { - $tokenoldcompat = dol_hash($conf->global->PAYMENT_SECURITY_TOKEN.$source.$REF, 2); // for retro-compatibility (token may have been hashed with membersubscription in external module) + $tokenisok = dol_verifyHash($conf->global->PAYMENT_SECURITY_TOKEN.$source.$REF, $SECUREKEY, '2'); } } else { - $token = dol_hash($conf->global->PAYMENT_SECURITY_TOKEN, 2); + $tokenisok = dol_verifyHash($conf->global->PAYMENT_SECURITY_TOKEN, $SECUREKEY, '2'); } } else { - $token = $conf->global->PAYMENT_SECURITY_TOKEN; + $tokenisok = ($conf->global->PAYMENT_SECURITY_TOKEN == $SECUREKEY); } - if ($SECUREKEY != $token && (empty($tokenoldcompat) || $SECUREKEY != $tokenoldcompat)) { + + if (! $tokenisok) { if (empty($conf->global->PAYMENT_SECURITY_ACCEPT_ANY_TOKEN)) { $valid = false; // PAYMENT_SECURITY_ACCEPT_ANY_TOKEN is for backward compatibility } else { @@ -323,7 +325,7 @@ if (!empty($conf->global->PAYMENT_SECURITY_TOKEN)) { if (!$valid) { print '
Bad value for key.
'; - //print 'SECUREKEY='.$SECUREKEY.' token='.$token.' valid='.$valid; + //print 'SECUREKEY='.$SECUREKEY.' valid='.$valid; exit; } } @@ -439,21 +441,21 @@ if ($action == 'dopayment') { $origfulltag = GETPOST("fulltag", 'alpha'); // Securekey into back url useless for back url and we need an url lower than 150. - $urlok = preg_replace('/securekey=[^&]+/', '', $urlok); - $urlko = preg_replace('/securekey=[^&]+/', '', $urlko); + $urlok = preg_replace('/securekey=[^&]+&?/', '', $urlok); + $urlko = preg_replace('/securekey=[^&]+&?/', '', $urlko); if (empty($PRICE) || !is_numeric($PRICE)) { $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("Amount")); } elseif (empty($email)) { - $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("YourEMail")); + $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("ONLINE_PAYMENT_SENDEMAIL")); } elseif (!isValidEMail($email)) { $mesg = $langs->trans("ErrorBadEMail", $email); } elseif (!$origfulltag) { $mesg = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("PaymentCode")); } elseif (dol_strlen($urlok) > 150) { - $mesg = 'Error urlok too long '.$urlok.'( Paybox requires 150, found '.strlen($urlok).')'; + $mesg = 'Error urlok too long '.$urlok.' (Paybox requires 150, found '.strlen($urlok).')'; } elseif (dol_strlen($urlko) > 150) { - $mesg = 'Error urlko too long '.$urlko.'( Paybox requires 150, found '.strlen($urlok).')'; + $mesg = 'Error urlko too long '.$urlko.' (Paybox requires 150, found '.strlen($urlok).')'; } if (empty($mesg)) { @@ -480,7 +482,7 @@ if ($action == 'dopayment') { // Called when choosing Stripe mode. // When using the Charge API architecture, this code is called after clicking the 'dopayment' with the Charge API architecture. -// When using the PaymentIntent API architecture, the Stripe customer is already created when creating PaymentIntent when showing payment page and the payment is already ok. +// When using the PaymentIntent API architecture, the Stripe customer was already created when creating PaymentIntent when showing payment page, and the payment is already ok when action=charge. if ($action == 'charge' && !empty($conf->stripe->enabled)) { $amountstripe = $amount; @@ -767,9 +769,23 @@ if ($action == 'charge' && !empty($conf->stripe->enabled)) { setEventMessages($paymentintent->status, null, 'errors'); $action = ''; } else { - // TODO We can alse record the payment mode into llx_societe_rib with stripe $paymentintent->payment_method + // TODO We can also record the payment mode into llx_societe_rib with stripe $paymentintent->payment_method // Note that with other old Stripe architecture (using Charge API), the payment mode was not recorded, so it is not mandatory to do it here. //dol_syslog("Create payment_method for ".$paymentintent->payment_method, LOG_DEBUG, 0, '_stripe'); + + // Get here amount and currency used for payment and force value into $amount and $currency so the real amount is saved into session instead + // of the amount and currency retreived from the POST. + if (!empty($paymentintent->currency) && !empty($paymentintent->amount)) { + $currency = strtoupper($paymentintent->currency); + $amount = $paymentintent->amount; + + // Correct the amount according to unit of currency + // See https://support.stripe.com/questions/which-zero-decimal-currencies-does-stripe-support + $arrayzerounitcurrency = array('BIF', 'CLP', 'DJF', 'GNF', 'JPY', 'KMF', 'KRW', 'MGA', 'PYG', 'RWF', 'VND', 'VUV', 'XAF', 'XOF', 'XPF'); + if (!in_array($currency, $arrayzerounitcurrency)) { + $amount = $amount / 100; + } + } } } @@ -911,7 +927,8 @@ print ''."\n"; print ''."\n"; print "\n"; -print ''."\n"; +// Section with payment informationsummary +print '
'."\n"; // Output introduction text $text = ''; @@ -968,13 +985,13 @@ if (!$source) { if (empty($amount) || !is_numeric($amount)) { print ''; print ''; + // Currency + print ' '.$langs->trans("Currency".$currency).''; } else { - print ''.price($amount).''; + print ''.price($amount, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print ''."\n"; @@ -1067,13 +1084,13 @@ if ($source == 'order') { if (empty($amount) || !is_numeric($amount)) { print ''; print ''; + // Currency + print ' '.$langs->trans("Currency".$currency).''; } else { - print ''.price($amount).''; + print ''.price($amount, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print ''."\n"; @@ -1198,18 +1215,16 @@ if ($source == 'invoice') { if (empty($amount) || !is_numeric($amount)) { print ''; print ''; + print ' '.$langs->trans("Currency".$currency).''; } else { - print ''.price($amount).''; + print ''.price($amount, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - print ' '.$langs->trans("Currency".$currency).''; - print ''; } else { - print ''.price($object->total_ttc, 1, $langs).''; - print ' '.$langs->trans("Currency".$currency).''; - print ''; + print ''.price($object->total_ttc, 1, $langs, 1, -1, -1, $currency).''; // Price with currency } + print ''; print ''."\n"; // Tag @@ -1325,7 +1340,7 @@ if ($source == 'contractline') { $qty = 1; if (GETPOST('qty')) { - $qty = GETPOST('qty'); + $qty = price2num(GETPOST('qty', 'alpha'), 'MS'); } // Creditor @@ -1402,13 +1417,13 @@ if ($source == 'contractline') { if (empty($amount) || !is_numeric($amount)) { print ''; print ''; + // Currency + print ' '.$langs->trans("Currency".$currency).''; } else { - print ''.price($amount).''; + print ''.price($amount, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print ''."\n"; @@ -1460,9 +1475,12 @@ if ($source == 'member' || $source == 'membersubscription') { $langs->load("members"); require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent.class.php'; + require_once DOL_DOCUMENT_ROOT.'/adherents/class/adherent_type.class.php'; require_once DOL_DOCUMENT_ROOT.'/adherents/class/subscription.class.php'; $member = new Adherent($db); + $adht = new AdherentType($db); + $result = $member->fetch('', $ref); if ($result <= 0) { $mesg = $member->error; @@ -1470,6 +1488,8 @@ if ($source == 'member' || $source == 'membersubscription') { } else { $member->fetch_thirdparty(); $subscription = new Subscription($db); + + $adht->fetch($member->typeid); } $object = $member; @@ -1478,6 +1498,11 @@ if ($source == 'member' || $source == 'membersubscription') { if (GETPOST("amount", 'alpha')) { $amount = GETPOST("amount", 'alpha'); } + // If amount still not defined, we take amount of the type of member + if (empty($amount)) { + $amount = $adht->amount; + } + $amount = price2num($amount, 'MT'); } @@ -1499,10 +1524,13 @@ if ($source == 'member' || $source == 'membersubscription') { // Debitor print ''."\n"; @@ -1782,18 +1809,18 @@ if ($source == 'donation') { } print ''; print ''; + // Currency + print ' '.$langs->trans("Currency".$currency).''; } else { $valtoshow = $amount; if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) { $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow); $amount = $valtoshow; } - print ''.price($valtoshow).''; + print ''.price($valtoshow, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print ''."\n"; @@ -1882,12 +1909,9 @@ if ($source == 'organizedeventregistration') { print ''."\n"; @@ -1968,12 +1992,9 @@ if ($source == 'boothlocation') { print ''."\n"; @@ -2286,7 +2307,7 @@ if (preg_match('/^dopayment/', $action)) { // If we choosed/click on the payme print ''."\n"; // Code to ask the credit card. This use the default "API version". No way to force API version when using JS code. - print ' + + + + + + diff --git a/htdocs/public/test/test_exec.php b/htdocs/public/test/test_exec.php new file mode 100644 index 00000000000..732bfefa824 --- /dev/null +++ b/htdocs/public/test/test_exec.php @@ -0,0 +1,91 @@ +\n"; +print 'PHP_SESSION_DISABLED='.PHP_SESSION_DISABLED."
\n"; +print 'PHP_SESSION_NONE='.PHP_SESSION_NONE."
\n"; +print 'PHP_SESSION_ACTIVE='.PHP_SESSION_ACTIVE."
\n"; +print '
'; + +print 'session_status='.session_status().' (before main.inc.php)'; +print '
'; + +require '../../main.inc.php'; + +// Security +if ($dolibarr_main_prod) { + accessforbidden('Access forbidden when $dolibarr_main_prod is set to 1'); +} + + +/* + * View + */ + +echo "Test
\n"; +$out=''; +$ret=0; + +$file = '/tmp/test.txt'; +$f=fopen($file, 'r'); +if ($f) { + $s=fread($f, 4096); + print $s; + fclose($f); +} else { + print "Failed to open file ".$file."
\n"; +} + +print '

'."\n"; + +exec('cat /test.txt; ls /dev/std*; sleep 1;', $out, $ret); +print $ret."
\n"; +print_r($out); + +print '

'."\n"; + +$ret = 0; +$out = null; +exec('/usr/bin/clamdscan --fdpass filethatdoesnotexists.php', $out, $ret); +print $ret."
\n"; +print_r($out); diff --git a/htdocs/public/test/test_forms.php b/htdocs/public/test/test_forms.php index d89e04e12a6..47d827cbaf5 100644 --- a/htdocs/public/test/test_forms.php +++ b/htdocs/public/test/test_forms.php @@ -8,10 +8,16 @@ if (!defined('NOSESSION')) { require '../../main.inc.php'; include_once DOL_DOCUMENT_ROOT.'/core/lib/date.lib.php'; +// Security if ($dolibarr_main_prod) { - accessforbidden(); + accessforbidden('Access forbidden when $dolibarr_main_prod is set to 1'); } + +/* + * View + */ + llxHeader(); ?> diff --git a/htdocs/public/test/test_sessionlock.php b/htdocs/public/test/test_sessionlock.php index 18a1ef73d08..8464ba2eb4f 100644 --- a/htdocs/public/test/test_sessionlock.php +++ b/htdocs/public/test/test_sessionlock.php @@ -52,11 +52,15 @@ print '
'; require '../../main.inc.php'; -/* No need for this. +// Security if ($dolibarr_main_prod) { accessforbidden(); } -*/ + + +/* + * View + */ print 'session_status='.session_status().' (after main.inc.php)'; print '
'; diff --git a/htdocs/public/ticket/create_ticket.php b/htdocs/public/ticket/create_ticket.php index 00eff71da78..9efa561341e 100644 --- a/htdocs/public/ticket/create_ticket.php +++ b/htdocs/public/ticket/create_ticket.php @@ -47,6 +47,12 @@ if (!defined('NOBROWSERNOTIF')) { define('NOBROWSERNOTIF', '1'); } +// For MultiCompany module. +// Do not use GETPOST here, function is not defined and define must be done before including main.inc.php +$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); +if (is_numeric($entity)) { + define("DOLENTITY", $entity); +} require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/ticket/class/actions_ticket.class.php'; @@ -297,7 +303,7 @@ if (empty($reshook) && $action == 'create_ticket' && GETPOST('save', 'alpha')) { if (is_array($object->array_options) && count($object->array_options) > 0) { foreach ($object->array_options as $key => $value) { $key = substr($key, 8); // remove "options_" - $message_admin .= '
  • '.$langs->trans($extrafields->attributes[$object->element]['label'][$key]).' : '.$extrafields->showOutputField($key, $value).'
  • '; + $message_admin .= '
  • '.$langs->trans($extrafields->attributes[$object->table_element]['label'][$key]).' : '.$extrafields->showOutputField($key, $value, '', $object->table_element).'
  • '; } } $message_admin .= ''; @@ -342,7 +348,7 @@ if (empty($reshook) && $action == 'create_ticket' && GETPOST('save', 'alpha')) { $messagetoshow = str_replace(array('{s1}', '{s2}'), array(''.$object->track_id.'', ''.$object->ref.''), $messagetoshow); setEventMessages($messagetoshow, null, 'warnings'); setEventMessages($langs->trans('PleaseRememberThisId'), null, 'warnings'); - header("Location: index.php"); + header("Location: index.php".(!empty($entity) && !empty($conf->multicompany->enabled)?'?entity='.$entity:'')); exit; } } else { diff --git a/htdocs/public/ticket/index.php b/htdocs/public/ticket/index.php index 6abeb5f8b12..227dcf3867b 100644 --- a/htdocs/public/ticket/index.php +++ b/htdocs/public/ticket/index.php @@ -40,7 +40,6 @@ if (!defined('NOBROWSERNOTIF')) { // For MultiCompany module. // Do not use GETPOST here, function is not defined and define must be done before including main.inc.php -// TODO This should be useless. Because entity must be retrieve from object ref and not from url. $entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); if (is_numeric($entity)) { define("DOLENTITY", $entity); @@ -77,7 +76,6 @@ if (empty($conf->global->TICKET_ENABLE_PUBLIC_INTERFACE)) { print $langs->trans('TicketPublicInterfaceForbidden'); exit; } - $arrayofjs = array(); $arrayofcss = array('/ticket/css/styles.css.php'); @@ -86,9 +84,9 @@ llxHeaderTicket($langs->trans("Tickets"), "", 0, 0, $arrayofjs, $arrayofcss); print ''; diff --git a/htdocs/public/ticket/list.php b/htdocs/public/ticket/list.php index db5f5d8d754..ef16b716db2 100644 --- a/htdocs/public/ticket/list.php +++ b/htdocs/public/ticket/list.php @@ -40,6 +40,13 @@ if (!defined('NOBROWSERNOTIF')) { } // If this page is public (can be called outside logged session) +// For MultiCompany module. +// Do not use GETPOST here, function is not defined and define must be done before including main.inc.php +$entity = (!empty($_GET['entity']) ? (int) $_GET['entity'] : (!empty($_POST['entity']) ? (int) $_POST['entity'] : 1)); +if (is_numeric($entity)) { + define("DOLENTITY", $entity); +} + require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT.'/ticket/class/actions_ticket.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formticket.class.php'; @@ -154,10 +161,6 @@ if ($action == "view_ticketlist") { } } -//$object->doActions($action); - - - /* * View */ @@ -215,6 +218,9 @@ if ($action == "view_ticketlist") { $filter = array(); $param = 'action=view_ticketlist'; + if (!empty($entity) && !empty($conf->multicompany->enabled)) { + $param .= '&entity='.$entity; + } // Definition of fields for list $arrayfields = array( @@ -392,7 +398,7 @@ if ($action == "view_ticketlist") { print_barre_liste($langs->trans('TicketList'), $page, 'public/list.php', $param, $sortfield, $sortorder, '', $num, $num_total, 'ticket'); // Search bar - print ''."\n"; + print ''."\n"; print ''; print ''; print ''; @@ -651,7 +657,7 @@ if ($action == "view_ticketlist") { } print '>'; $tmpkey = 'options_'.$key; - print $extrafields->showOutputField($key, $obj->$tmpkey, '', 1); + print $extrafields->showOutputField($key, $obj->$tmpkey, '', $object->table_element); print ''; } } @@ -674,7 +680,7 @@ if ($action == "view_ticketlist") { print '
    '.$langs->trans("Member"); - print ''; - if ($member->morphy == 'mor' && !empty($member->societe)) { - print $member->societe; + print ''; + print ''; + if ($member->morphy == 'mor' && !empty($member->company)) { + print img_picto('', 'company', 'class="pictofixedwidth"'); + print $member->company; } else { + print img_picto('', 'member', 'class="pictofixedwidth"'); print $member->getFullName($langs); } print ''; @@ -1621,23 +1649,22 @@ if ($source == 'member' || $source == 'membersubscription') { } print ''; if (empty($conf->global->MEMBER_NEWFORM_EDITAMOUNT)) { - print ''; + print ''; print ''; } else { print ''; } + print ' '.$langs->trans("Currency".$currency).''; } else { $valtoshow = $amount; if (!empty($conf->global->MEMBER_MIN_AMOUNT) && $valtoshow) { $valtoshow = max($conf->global->MEMBER_MIN_AMOUNT, $valtoshow); $amount = $valtoshow; } - print ''.price($valtoshow).''; + print ''.price($valtoshow, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; } - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print '
    '.$langs->trans("Amount"); print ''; $valtoshow = $amount; - print ''.price($valtoshow).''; + print ''.price($valtoshow, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; - - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print '
    '.$langs->trans("Amount"); print ''; $valtoshow = $amount; - print ''.price($valtoshow).''; + print ''.price($valtoshow, 1, $langs, 1, -1, -1, $currency).''; // Price with currency print ''; print ''; - - // Currency - print ' '.$langs->trans("Currency".$currency).''; print ''; print '
    '; print ''; - print '