diff --git a/ChangeLog b/ChangeLog index c6b3ee2d89b..c592a261157 100644 --- a/ChangeLog +++ b/ChangeLog @@ -30,7 +30,7 @@ Following changes may create regressions for some external modules, but were nec ***** ChangeLog for 10.0.3 compared to 10.0.2 ***** IMPORTANT : This version fixes a serious bug in saving the units of weight, size, surface and volume on product card. The unit were not saved correctly in database making calculation on shipments wrong. -Update to this version must be done if you use them and have installed version 10.0.0, 10.0.1 or 10.0.2 and set some products after installing or upgrading to this version. +Update to this version must be done if you use them and have installed version 10.0.0, 10.0.1 or 10.0.2 and set some products after installing or upgrading to one of this version. Once update is done you must then edit (manually) the product that has bad unit to set the correct unit to have features restored. FIX: #11702 @@ -42,6 +42,7 @@ FIX: #12041 FIX: #12054 FIX: #12083 FIX: #12088 +FIX: Clean the + of categories on the product view only in POS module FIX: access to public interface when origin email has an alias. FIX: Alias name is not into the email recipient label. FIX: allow standalone credit note even if no invoice @@ -92,6 +93,9 @@ FIX: Update of leave request when CSRF with token is on FIX: Var not enough sanitized FIX: wrong test FIX: XSS +FIX: Payment from POS ware not recorded. +FIX: Can validate invoice with amount including tax of zero for the case of having a final invoice with + VAT that includes a deposit without vat. ***** ChangeLog for 10.0.2 compared to 10.0.1 ***** FIX: #10460 compatibility with MariaDB 10.4 diff --git a/dev/initdata/generate-invoice.php b/dev/initdata/generate-invoice.php index bfdda2896a1..0c754b1c874 100755 --- a/dev/initdata/generate-invoice.php +++ b/dev/initdata/generate-invoice.php @@ -152,7 +152,7 @@ while ($i < GEN_NUMBER_FACTURE && $result >= 0) $fuser = new User($db); $fuser->fetch(mt_rand(1, 2)); $fuser->getRights(); - + $result=$object->create($fuser); if ($result >= 0) { diff --git a/dev/initdata/generate-proposal.php b/dev/initdata/generate-proposal.php index 30c9471a281..ad8cf6025bb 100755 --- a/dev/initdata/generate-proposal.php +++ b/dev/initdata/generate-proposal.php @@ -176,7 +176,7 @@ while ($i < GEN_NUMBER_PROPAL && $result >= 0) $fuser = new User($db); $fuser->fetch(mt_rand(1, 2)); $fuser->getRights(); - + $object->contactid = $contids[$socids[$socid]][0]; $object->socid = $socids[$socid]; $object->datep = $dates[mt_rand(1, count($dates)-1)]; @@ -200,7 +200,7 @@ while ($i < GEN_NUMBER_PROPAL && $result >= 0) } $xnbp++; } - + $result=$object->valid($fuser); if ($result > 0) { diff --git a/dev/setup/codesniffer/ruleset.xml b/dev/setup/codesniffer/ruleset.xml index 32c44ce91e4..8c01eea6d99 100644 --- a/dev/setup/codesniffer/ruleset.xml +++ b/dev/setup/codesniffer/ruleset.xml @@ -201,7 +201,7 @@ - + diff --git a/htdocs/accountancy/customer/index.php b/htdocs/accountancy/customer/index.php index f43ca801c25..c0e45916922 100644 --- a/htdocs/accountancy/customer/index.php +++ b/htdocs/accountancy/customer/index.php @@ -29,6 +29,7 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT . '/compta/facture/class/facture.class.php'; // Load translation files required by the page @@ -65,6 +66,8 @@ $year_current = $year_start; // Validate History $action = GETPOST('action', 'aZ09'); +$chartaccountcode = dol_getIdFromCode($db, $conf->global->CHARTOFACCOUNTS, 'accounting_system', 'rowid', 'pcg_version'); + /* * Actions @@ -101,7 +104,7 @@ if ($action == 'validatehistory') { $db->begin(); // Now make the binding. Bind automatically only for product with a dedicated account that exists into chart of account, others need a manual bind - if ($db->type == 'pgsql') { + /*if ($db->type == 'pgsql') { $sql1 = "UPDATE " . MAIN_DB_PREFIX . "facturedet"; $sql1 .= " SET fk_code_ventilation = accnt.rowid"; $sql1 .= " FROM " . MAIN_DB_PREFIX . "product as p, " . MAIN_DB_PREFIX . "accounting_account as accnt , " . MAIN_DB_PREFIX . "accounting_system as syst"; @@ -114,16 +117,83 @@ if ($action == 'validatehistory') { $sql1 .= " WHERE fd.fk_product = p.rowid AND accnt.fk_pcg_version = syst.pcg_version AND syst.rowid=" . $conf->global->CHARTOFACCOUNTS.' AND accnt.entity = '.$conf->entity; $sql1 .= " AND accnt.active = 1 AND p.accountancy_code_sell=accnt.account_number"; $sql1 .= " AND fd.fk_code_ventilation = 0"; - } + }*/ + + // Customer Invoice lines (must be same request than into page list.php for manual binding) + $sql = "SELECT f.rowid as facid, f.ref as ref, f.datef, f.type as ftype,"; + $sql.= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, l.vat_src_code,"; + $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_sell as code_sell, p.tva_tx as tva_tx_prod,"; + $sql.= " p.accountancy_code_sell_intra as code_sell_intra, p.accountancy_code_sell_export as code_sell_export,"; + $sql.= " aa.rowid as aarowid, aa2.rowid as aarowid_intra, aa3.rowid as aarowid_export,"; + $sql.= " co.code as country_code, co.label as country_label,"; + $sql.= " s.tva_intra"; + $sql.= " FROM " . MAIN_DB_PREFIX . "facture as f"; + $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc"; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays "; + $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "facturedet as l ON f.rowid = l.fk_facture"; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product"; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_sell = aa.account_number AND aa.active = 1 AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa2 ON p.accountancy_code_sell_intra = aa2.account_number AND aa2.active = 1 AND aa2.fk_pcg_version = '" . $chartaccountcode."' AND aa2.entity = " . $conf->entity; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa3 ON p.accountancy_code_sell_export = aa3.account_number AND aa3.active = 1 AND aa3.fk_pcg_version = '" . $chartaccountcode."' AND aa3.entity = " . $conf->entity; + $sql.= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; + $sql.= " AND l.product_type <= 2"; dol_syslog('htdocs/accountancy/customer/index.php'); - - $resql1 = $db->query($sql1); - if (! $resql1) { - $error ++; - $db->rollback(); + $result = $db->query($sql); + if (! $result) { + $error++; setEventMessages($db->lasterror(), null, 'errors'); } else { + $num_lines = $db->num_rows($result); + + $isSellerInEEC = isInEEC($mysoc); + + $i = 0; + while ($i < min($num_lines, 10000)) { // No more than 10000 at once + $objp = $db->fetch_object($result); + + // Search suggested account for product/service + $suggestedaccountingaccountfor = ''; + if (($objp->country_code == $mysoc->country_code) || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country) + $objp->code_sell_p = $objp->code_sell; + $objp->aarowid_suggest = $objp->aarowid; + $suggestedaccountingaccountfor = ''; + } else { + if ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale + $objp->code_sell_p = $objp->code_sell_intra; + $objp->aarowid_suggest = $objp->aarowid_intra; + $suggestedaccountingaccountfor = 'eec'; + } else { // Foreign sale + $objp->code_sell_p = $objp->code_sell_export; + $objp->aarowid_suggest = $objp->aarowid_export; + $suggestedaccountingaccountfor = 'export'; + } + } + + if ($objp->aarowid_suggest > 0) + { + $sqlupdate = "UPDATE " . MAIN_DB_PREFIX . "facturedet"; + $sqlupdate.= " SET fk_code_ventilation = ".$objp->aarowid_suggest; + $sqlupdate.= " WHERE fk_code_ventilation <= 0 AND product_type <= 2 AND rowid = ".$objp->rowid; + + $resqlupdate = $db->query($sqlupdate); + if (! $resqlupdate) + { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + break; + } + } + + $i++; + } + } + + if ($error) + { + $db->rollback(); + } + else { $db->commit(); setEventMessages($langs->trans('AutomaticBindingDone'), null, 'mesgs'); } diff --git a/htdocs/accountancy/customer/lines.php b/htdocs/accountancy/customer/lines.php index 3385eb99b0e..6a5196288e2 100644 --- a/htdocs/accountancy/customer/lines.php +++ b/htdocs/accountancy/customer/lines.php @@ -358,6 +358,7 @@ if ($result) { // Ref Invoice print '' . $facture_static->getNomUrl(1) . ''; + // Date invoice print '' . dol_print_date($db->jdate($objp->datef), 'day') . ''; // Ref Product @@ -377,7 +378,13 @@ if ($result) { print '' . vatrate($objp->tva_tx.($objp->vat_src_code?' ('.$objp->vat_src_code.')':'')) . ''; - print '' . $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')'; + // Country + print ''; + if ($objp->country_code) + { + print $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')'; + } + print ''; print '' . $objp->tva_intra . ''; diff --git a/htdocs/accountancy/customer/list.php b/htdocs/accountancy/customer/list.php index c15ace96ffc..d4cc5f59388 100644 --- a/htdocs/accountancy/customer/list.php +++ b/htdocs/accountancy/customer/list.php @@ -219,9 +219,9 @@ $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc"; $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays "; $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "facturedet as l ON f.rowid = l.fk_facture"; $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product"; -$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_sell = aa.account_number AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; -$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa2 ON p.accountancy_code_sell_intra = aa2.account_number AND aa2.fk_pcg_version = '" . $chartaccountcode."' AND aa2.entity = " . $conf->entity; -$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa3 ON p.accountancy_code_sell_export = aa3.account_number AND aa3.fk_pcg_version = '" . $chartaccountcode."' AND aa3.entity = " . $conf->entity; +$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_sell = aa.account_number AND aa.active = 1 AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; +$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa2 ON p.accountancy_code_sell_intra = aa2.account_number AND aa2.active = 1 AND aa2.fk_pcg_version = '" . $chartaccountcode."' AND aa2.entity = " . $conf->entity; +$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa3 ON p.accountancy_code_sell_export = aa3.account_number AND aa3.active = 1 AND aa3.fk_pcg_version = '" . $chartaccountcode."' AND aa3.entity = " . $conf->entity; $sql.= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; $sql.= " AND l.product_type <= 2"; // Add search filter like @@ -247,7 +247,7 @@ if (strlen(trim($search_account))) { $sql .= natural_search("aa.account_number", $search_account); } if (strlen(trim($search_vat))) { - $sql .= natural_search("l.tva_tx", $search_vat, 1); + $sql .= natural_search("l.tva_tx", price2num($search_vat), 1); } $sql.=dolSqlDateFilter('f.datef', $search_day, $search_month, $search_year); if (strlen(trim($search_country))) { @@ -406,7 +406,7 @@ if ($result) { $isSellerInEEC = isInEEC($mysoc); - while ( $i < min($num_lines, $limit) ) { + while ($i < min($num_lines, $limit)) { $objp = $db->fetch_object($result); $objp->code_sell_l = ''; @@ -518,6 +518,7 @@ if ($result) { print vatrate($objp->tva_tx_line.($objp->vat_src_code?' ('.$objp->vat_src_code.')':'')); print ''; + // Country print ''; $labelcountry=($objp->country_code && ($langs->trans("Country".$objp->country_code)!="Country".$objp->country_code))?$langs->trans("Country".$objp->country_code):$objp->country_label; print $labelcountry; diff --git a/htdocs/accountancy/supplier/index.php b/htdocs/accountancy/supplier/index.php index faa48ac9176..bfb6e7b02e4 100644 --- a/htdocs/accountancy/supplier/index.php +++ b/htdocs/accountancy/supplier/index.php @@ -27,6 +27,7 @@ require '../../main.inc.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/date.lib.php'; require_once DOL_DOCUMENT_ROOT . '/core/lib/accounting.lib.php'; +require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; require_once DOL_DOCUMENT_ROOT . '/fourn/class/fournisseur.facture.class.php'; // Load translation files required by the page @@ -63,6 +64,7 @@ $year_current = $year_start; // Validate History $action = GETPOST('action', 'aZ09'); +$chartaccountcode = dol_getIdFromCode($db, $conf->global->CHARTOFACCOUNTS, 'accounting_system', 'rowid', 'pcg_version'); /* @@ -99,7 +101,7 @@ if ($action == 'validatehistory') { $db->begin(); // Now make the binding. Bind automatically only for product with a dedicated account that exists into chart of account, others need a manual bind - if ($db->type == 'pgsql') { + /*if ($db->type == 'pgsql') { $sql1 = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn_det"; $sql1 .= " SET fk_code_ventilation = accnt.rowid"; $sql1 .= " FROM " . MAIN_DB_PREFIX . "product as p, " . MAIN_DB_PREFIX . "accounting_account as accnt , " . MAIN_DB_PREFIX . "accounting_system as syst"; @@ -112,16 +114,85 @@ if ($action == 'validatehistory') { $sql1 .= " WHERE fd.fk_product = p.rowid AND accnt.fk_pcg_version = syst.pcg_version AND syst.rowid=" . $conf->global->CHARTOFACCOUNTS.' AND accnt.entity = '.$conf->entity; $sql1 .= " AND accnt.active = 1 AND p.accountancy_code_buy=accnt.account_number"; $sql1 .= " AND fd.fk_code_ventilation = 0"; - } + }*/ + + // Supplier Invoice Lines (must be same request than into page list.php for manual binding) + $sql = "SELECT f.rowid as facid, f.ref, f.ref_supplier, f.libelle as invoice_label, f.datef, f.type as ftype,"; + $sql.= " l.rowid, l.fk_product, l.description, l.total_ht, l.fk_code_ventilation, l.product_type as type_l, l.tva_tx as tva_tx_line, l.vat_src_code,"; + $sql.= " p.rowid as product_id, p.ref as product_ref, p.label as product_label, p.fk_product_type as type, p.accountancy_code_buy as code_buy, p.tva_tx as tva_tx_prod,"; + $sql.= " aa.rowid as aarowid,"; + $sql.= " co.code as country_code, co.label as country_label,"; + $sql.= " s.tva_intra"; + $sql.= " FROM " . MAIN_DB_PREFIX . "facture_fourn as f"; + $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays "; + $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "facture_fourn_det as l ON f.rowid = l.fk_facture_fourn"; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product"; + $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_buy = aa.account_number AND aa.active = 1 AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; + $sql.= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; + $sql.= " AND l.product_type <= 2"; dol_syslog('htdocs/accountancy/supplier/index.php'); - $resql1 = $db->query($sql1); - if (! $resql1) { - $error ++; - $db->rollback(); + $result = $db->query($sql); + if (! $result) { + $error++; setEventMessages($db->lasterror(), null, 'errors'); } else { + $num_lines = $db->num_rows($result); + + $isSellerInEEC = isInEEC($mysoc); + + $i = 0; + while ($i < min($num_lines, 10000)) { // No more than 10000 at once + $objp = $db->fetch_object($result); + + // Search suggested account for product/service + $suggestedaccountingaccountfor = ''; + if (($objp->country_code == $mysoc->country_code) || empty($objp->country_code)) { // If buyer in same country than seller (if not defined, we assume it is same country) + $objp->code_buy_p = $objp->code_buy; + $objp->aarowid_suggest = $objp->aarowid; + $suggestedaccountingaccountfor = ''; + } else { + if ($isSellerInEEC && $isBuyerInEEC) { // European intravat sale + //$objp->code_buy_p = $objp->code_buy_intra; + $objp->code_buy_p = $objp->code_buy; + //$objp->aarowid_suggest = $objp->aarowid_intra; + $objp->aarowid_suggest = $objp->aarowid; + $suggestedaccountingaccountfor = 'eec'; + } else { // Foreign sale + //$objp->code_buy_p = $objp->code_buy_export; + $objp->code_buy_p = $objp->code_buy; + //$objp->aarowid_suggest = $objp->aarowid_export; + $objp->aarowid_suggest = $objp->aarowid; + $suggestedaccountingaccountfor = 'export'; + } + } + + if ($objp->aarowid_suggest > 0) + { + $sqlupdate = "UPDATE " . MAIN_DB_PREFIX . "facture_fourn_det"; + $sqlupdate.= " SET fk_code_ventilation = ".$objp->aarowid_suggest; + $sqlupdate.= " WHERE fk_code_ventilation <= 0 AND product_type <= 2 AND rowid = ".$objp->rowid; + + $resqlupdate = $db->query($sqlupdate); + if (! $resqlupdate) + { + $error++; + setEventMessages($db->lasterror(), null, 'errors'); + break; + } + } + + $i++; + } + } + + if ($error) + { + $db->rollback(); + } + else { $db->commit(); setEventMessages($langs->trans('AutomaticBindingDone'), null, 'mesgs'); } diff --git a/htdocs/accountancy/supplier/lines.php b/htdocs/accountancy/supplier/lines.php index a815e5b858b..730aecf9dc1 100644 --- a/htdocs/accountancy/supplier/lines.php +++ b/htdocs/accountancy/supplier/lines.php @@ -367,6 +367,7 @@ if ($result) { print $objp->invoice_label; print ''; + // Date invoice print '' . dol_print_date($db->jdate($objp->datef), 'day') . ''; // Ref product @@ -387,7 +388,12 @@ if ($result) { print '' . vatrate($objp->tva_tx.($objp->vat_src_code?' ('.$objp->vat_src_code.')':'')) . ''; - print '' . $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')'; + print ''; + if ($objp->country_code) + { + print $langs->trans("Country".$objp->country_code) .' ('.$objp->country_code.')'; + } + print ''; print '' . $objp->tva_intra . ''; diff --git a/htdocs/accountancy/supplier/list.php b/htdocs/accountancy/supplier/list.php index f43749f6958..3c61b7a0608 100644 --- a/htdocs/accountancy/supplier/list.php +++ b/htdocs/accountancy/supplier/list.php @@ -222,7 +222,7 @@ $sql .= " INNER JOIN " . MAIN_DB_PREFIX . "societe as s ON s.rowid = f.fk_soc"; $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "c_country as co ON co.rowid = s.fk_pays "; $sql.= " INNER JOIN " . MAIN_DB_PREFIX . "facture_fourn_det as l ON f.rowid = l.fk_facture_fourn"; $sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "product as p ON p.rowid = l.fk_product"; -$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_buy = aa.account_number AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; +$sql.= " LEFT JOIN " . MAIN_DB_PREFIX . "accounting_account as aa ON p.accountancy_code_buy = aa.account_number AND aa.active = 1 AND aa.fk_pcg_version = '" . $chartaccountcode."' AND aa.entity = " . $conf->entity; $sql.= " WHERE f.fk_statut > 0 AND l.fk_code_ventilation <= 0"; $sql.= " AND l.product_type <= 2"; // Add search filter like @@ -307,8 +307,8 @@ if ($result) { $arrayofselected=is_array($toselect)?$toselect:array(); $param=''; - if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.$contextpage; - if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.$limit; + if (! empty($contextpage) && $contextpage != $_SERVER["PHP_SELF"]) $param.='&contextpage='.urlencode($contextpage); + if ($limit > 0 && $limit != $conf->liste_limit) $param.='&limit='.urlencode($limit); if ($search_lineid) $param.='&search_lineid='.urlencode($search_lineid); if ($search_day) $param.='&search_day='.urlencode($search_day); if ($search_month) $param.='&search_month='.urlencode($search_month); @@ -463,7 +463,7 @@ if ($result) { print '' . dol_print_date($db->jdate($objp->datef), 'day') . ''; - // Ref product + // Ref Product print ''; if ($product_static->id > 0) print $product_static->getNomUrl(1); @@ -471,7 +471,7 @@ if ($result) { print ''; // Description - print ''; + print ''; $text = dolGetFirstLineOfText(dol_string_nohtmltag($objp->description)); $trunclength = empty($conf->global->ACCOUNTING_LENGTH_DESCRIPTION) ? 32 : $conf->global->ACCOUNTING_LENGTH_DESCRIPTION; print $form->textwithtooltip(dol_trunc($text, $trunclength), $objp->description); diff --git a/htdocs/admin/company.php b/htdocs/admin/company.php index 912995d7817..09a4e95c0ae 100644 --- a/htdocs/admin/company.php +++ b/htdocs/admin/company.php @@ -476,7 +476,7 @@ if (! empty($conf->barcode->enabled)) { } // Logo -print ''; +print ''; print '
'; print ''; print ''; @@ -493,7 +493,7 @@ print '
'; print ''; // Logo (squarred) -print ''; +print ''; print '
'; print ''; print ''; diff --git a/htdocs/admin/mails.php b/htdocs/admin/mails.php index 79d152fb7bf..61fb0448c8b 100644 --- a/htdocs/admin/mails.php +++ b/htdocs/admin/mails.php @@ -65,27 +65,27 @@ complete_substitutions_array($substitutionarrayfortest, $langs); if ($action == 'update' && empty($_POST["cancel"])) { - dolibarr_set_const($db, "MAIN_DISABLE_ALL_MAILS", GETPOST("MAIN_DISABLE_ALL_MAILS"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_FORCE_SENDTO", GETPOST("MAIN_MAIL_FORCE_SENDTO"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_ENABLED_USER_DEST_SELECT", GETPOST("MAIN_MAIL_ENABLED_USER_DEST_SELECT"), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_DISABLE_ALL_MAILS", GETPOST("MAIN_DISABLE_ALL_MAILS", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_FORCE_SENDTO", GETPOST("MAIN_MAIL_FORCE_SENDTO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_ENABLED_USER_DEST_SELECT", GETPOST("MAIN_MAIL_ENABLED_USER_DEST_SELECT", 'int'), 'chaine', 0, '', $conf->entity); // Send mode parameters - dolibarr_set_const($db, "MAIN_MAIL_SENDMODE", GETPOST("MAIN_MAIL_SENDMODE"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTP_PORT", GETPOST("MAIN_MAIL_SMTP_PORT"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTP_SERVER", GETPOST("MAIN_MAIL_SMTP_SERVER"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTPS_ID", GETPOST("MAIN_MAIL_SMTPS_ID"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_SMTPS_PW", GETPOST("MAIN_MAIL_SMTPS_PW"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_TLS", GETPOST("MAIN_MAIL_EMAIL_TLS"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_STARTTLS", GETPOST("MAIN_MAIL_EMAIL_STARTTLS"), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SENDMODE", GETPOST("MAIN_MAIL_SENDMODE", 'aZ09'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTP_PORT", GETPOST("MAIN_MAIL_SMTP_PORT", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTP_SERVER", GETPOST("MAIN_MAIL_SMTP_SERVER", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_ID", GETPOST("MAIN_MAIL_SMTPS_ID", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_SMTPS_PW", GETPOST("MAIN_MAIL_SMTPS_PW", 'none'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_TLS", GETPOST("MAIN_MAIL_EMAIL_TLS", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_STARTTLS", GETPOST("MAIN_MAIL_EMAIL_STARTTLS", 'int'), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_ENABLED", GETPOST("MAIN_MAIL_EMAIL_DKIM_ENABLED"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_DOMAIN", GETPOST("MAIN_MAIL_EMAIL_DKIM_DOMAIN"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_SELECTOR", GETPOST("MAIN_MAIL_EMAIL_DKIM_SELECTOR"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", GETPOST("MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY"), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_ENABLED", GETPOST("MAIN_MAIL_EMAIL_DKIM_ENABLED", 'int'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_DOMAIN", GETPOST("MAIN_MAIL_EMAIL_DKIM_DOMAIN", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_SELECTOR", GETPOST("MAIN_MAIL_EMAIL_DKIM_SELECTOR", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", GETPOST("MAIN_MAIL_EMAIL_DKIM_PRIVATE_KEY", 'alphanohtml'), 'chaine', 0, '', $conf->entity); // Content parameters - dolibarr_set_const($db, "MAIN_MAIL_EMAIL_FROM", GETPOST("MAIN_MAIL_EMAIL_FROM"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_ERRORS_TO", GETPOST("MAIN_MAIL_ERRORS_TO"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, "MAIN_MAIL_AUTOCOPY_TO", GETPOST("MAIN_MAIL_AUTOCOPY_TO"), 'chaine', 0, '', $conf->entity); - dolibarr_set_const($db, 'MAIN_MAIL_DEFAULT_FROMTYPE', GETPOST('MAIN_MAIL_DEFAULT_FROMTYPE'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_EMAIL_FROM", GETPOST("MAIN_MAIL_EMAIL_FROM", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_ERRORS_TO", GETPOST("MAIN_MAIL_ERRORS_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, "MAIN_MAIL_AUTOCOPY_TO", GETPOST("MAIN_MAIL_AUTOCOPY_TO", 'alphanohtml'), 'chaine', 0, '', $conf->entity); + dolibarr_set_const($db, 'MAIN_MAIL_DEFAULT_FROMTYPE', GETPOST('MAIN_MAIL_DEFAULT_FROMTYPE', 'alphanohtml'), 'chaine', 0, '', $conf->entity); header("Location: ".$_SERVER["PHP_SELF"]."?mainmenu=home&leftmenu=setup"); exit; @@ -101,8 +101,8 @@ $mode='emailfortest'; $trackid=(($action == 'testhtml')?"testhtml":"test"); include DOL_DOCUMENT_ROOT.'/core/actions_sendmails.inc.php'; -if ($action == 'presend' && GETPOST('trackid') == 'test') $action='test'; -if ($action == 'presend' && GETPOST('trackid') == 'testhtml') $action='testhtml'; +if ($action == 'presend' && GETPOST('trackid', 'alphanohtml') == 'test') $action='test'; +if ($action == 'presend' && GETPOST('trackid', 'alphanohtml') == 'testhtml') $action='testhtml'; @@ -821,7 +821,7 @@ else $formmail->frommail = (isset($_POST['frommail'])?$_POST['frommail']:$conf->global->MAIN_MAIL_EMAIL_FROM); $formmail->fromid=$user->id; $formmail->fromalsorobot=1; - $formmail->fromtype=(GETPOST('fromtype')?GETPOST('fromtype'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user')); + $formmail->fromtype=(GETPOSTISSET('fromtype')?GETPOST('fromtype', 'aZ09'):(!empty($conf->global->MAIN_MAIL_DEFAULT_FROMTYPE)?$conf->global->MAIN_MAIL_DEFAULT_FROMTYPE:'user')); $formmail->withfromreadonly=1; $formmail->withsubstit=1; $formmail->withfrom=1; @@ -847,7 +847,7 @@ else $formmail->param["returnurl"]=$_SERVER["PHP_SELF"]; // Init list of files - if (GETPOST("mode")=='init') + if (GETPOST("mode", "aZ09")=='init') { $formmail->clear_attached_files(); } diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index 7660144f7ca..0247514b2a4 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -290,6 +290,7 @@ class DolibarrApi if (count($tmp) < 3) return ''; $tmpescaped=$tmp[2]; + $regbis = array(); if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) { $tmpescaped = "'".$db->escape($regbis[1])."'"; diff --git a/htdocs/bom/bom_card.php b/htdocs/bom/bom_card.php index 0949fa1a334..17fae31ef7d 100644 --- a/htdocs/bom/bom_card.php +++ b/htdocs/bom/bom_card.php @@ -79,6 +79,7 @@ $permissionnote=$user->rights->bom->write; // Used by the include of actions_set $permissiondellink=$user->rights->bom->write; // Used by the include of actions_dellink.inc.php $permissionedit=$user->rights->bom->write; // Used by the include of actions_lineupdown.inc.php $permissiontoadd=$user->rights->bom->write; // Used by the include of actions_addupdatedelete.inc.php +$permissiontodelete = $user->rights->bom->delete || ($permissiontoadd && $object->status == 0); /* @@ -93,11 +94,11 @@ if (empty($reshook)) { $error=0; - $permissiontoadd = $user->rights->bom->write; - $permissiontodelete = $user->rights->bom->delete || ($permissiontoadd && $object->status == 0); $backurlforlist = DOL_URL_ROOT.'/bom/bom_list.php'; - if (empty($backtopage)) { - if (empty($id) && $action != 'add' && $action != 'create') $backtopage = $backurlforlist; + + if (empty($backtopage) || ($cancel && empty($id))) { + //var_dump($backurlforlist);exit; + if (empty($id) && (($action != 'add' && $action != 'create') || $cancel)) $backtopage = $backurlforlist; else $backtopage = DOL_URL_ROOT.'/bom/bom_card.php?id='.($id > 0 ? $id : '__ID__'); } $triggermodname = 'BOM_MODIFY'; // Name of trigger action code to execute when we modify record @@ -218,7 +219,7 @@ if ($action == 'create') dol_fiche_head(array(), ''); - print ''."\n"; + print '
'."\n"; // Common attributes include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_add.tpl.php'; @@ -252,7 +253,9 @@ if (($id || $ref) && $action == 'edit') dol_fiche_head(); - print '
'."\n"; + //$object->fields['keyfield']['disabled'] = 1; + + print '
'."\n"; // Common attributes include DOL_DOCUMENT_ROOT . '/core/tpl/commonfields_edit.tpl.php'; diff --git a/htdocs/bom/bom_list.php b/htdocs/bom/bom_list.php index 46473d52ddb..6e192a06545 100644 --- a/htdocs/bom/bom_list.php +++ b/htdocs/bom/bom_list.php @@ -454,12 +454,12 @@ while ($i < min($num, $limit)) $cssforfield=(empty($val['css'])?'':$val['css']); if (in_array($val['type'], array('date','datetime','timestamp'))) $cssforfield.=($cssforfield?' ':'').'center'; elseif ($key == 'status') $cssforfield.=($cssforfield?' ':'').'center'; - + if (in_array($val['type'], array('timestamp'))) $cssforfield.=($cssforfield?' ':'').'nowrap'; elseif ($key == 'ref') $cssforfield.=($cssforfield?' ':'').'nowrap'; - + if (in_array($val['type'], array('double(24,8)', 'double(6,3)', 'integer', 'real', 'price')) && $key != 'status') $cssforfield.=($cssforfield?' ':'').'right'; - + if (! empty($arrayfields['t.'.$key]['checked'])) { print ''; diff --git a/htdocs/bom/class/api_boms.class.php b/htdocs/bom/class/api_boms.class.php index f6b25d0cca7..471fb4f2cce 100644 --- a/htdocs/bom/class/api_boms.class.php +++ b/htdocs/bom/class/api_boms.class.php @@ -100,7 +100,7 @@ class Boms extends DolibarrApi $obj_ret = array(); $tmpobject = new BOM($db); - + $socid = DolibarrApiAccess::$user->socid ? DolibarrApiAccess::$user->socid : ''; $restrictonsocid = 0; // Set to 1 if there is a field socid in table of object diff --git a/htdocs/bom/class/bom.class.php b/htdocs/bom/class/bom.class.php index 07ae81e2994..02e39149364 100644 --- a/htdocs/bom/class/bom.class.php +++ b/htdocs/bom/class/bom.class.php @@ -91,7 +91,7 @@ class BOM extends CommonObject 'ref' => array('type'=>'varchar(128)', 'label'=>'Ref', 'enabled'=>1, 'noteditable'=>1, 'visible'=>4, 'position'=>10, 'notnull'=>1, 'default'=>'(PROV)', 'index'=>1, 'searchall'=>1, 'comment'=>"Reference of BOM", 'showoncombobox'=>'1',), 'label' => array('type'=>'varchar(255)', 'label'=>'Label', 'enabled'=>1, 'visible'=>1, 'position'=>30, 'notnull'=>1, 'searchall'=>1, 'showoncombobox'=>'1',), 'description' => array('type'=>'text', 'label'=>'Description', 'enabled'=>1, 'visible'=>-1, 'position'=>60, 'notnull'=>-1,), - 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'help'=>'ProductBOMHelp'), + 'fk_product' => array('type'=>'integer:Product:product/class/product.class.php:1', 'label'=>'Product', 'enabled'=>1, 'visible'=>1, 'position'=>35, 'notnull'=>1, 'index'=>1, 'help'=>'ProductBOMHelp'), 'qty' => array('type'=>'real', 'label'=>'Quantity', 'enabled'=>1, 'visible'=>1, 'default'=>1, 'position'=>55, 'notnull'=>1, 'isameasure'=>'1', 'css'=>'maxwidth75imp'), 'efficiency' => array('type'=>'real', 'label'=>'ManufacturingEfficiency', 'enabled'=>1, 'visible'=>-1, 'default'=>1, 'position'=>100, 'notnull'=>0, 'css'=>'maxwidth50imp', 'help'=>'ValueOfMeansLoss'), 'duration' => array('type'=>'real', 'label'=>'EstimatedDuration', 'enabled'=>1, 'visible'=>-1, 'position'=>101, 'notnull'=>-1, 'css'=>'maxwidth50imp', 'help'=>'EstimatedDurationDesc'), diff --git a/htdocs/bom/tpl/objectline_view.tpl.php b/htdocs/bom/tpl/objectline_view.tpl.php index f569516e535..f68372c721d 100644 --- a/htdocs/bom/tpl/objectline_view.tpl.php +++ b/htdocs/bom/tpl/objectline_view.tpl.php @@ -92,9 +92,9 @@ $coldisplay++; echo $line->efficiency; print ''; -if ($this->statut == 0 && ($object_rights->write) && $action != 'selectlines' ) { - print '
'; - $coldisplay++; +if ($this->status == 0 && ($object_rights->write) && $action != 'selectlines' ) { + print ''; + $coldisplay++; if (($line->info_bits & 2) == 2 || ! empty($disableedit)) { } else { print 'id.'#line_'.$line->id.'">'.img_edit().''; diff --git a/htdocs/comm/action/class/actioncomm.class.php b/htdocs/comm/action/class/actioncomm.class.php index 1314463cd2a..871ec6b9ed2 100644 --- a/htdocs/comm/action/class/actioncomm.class.php +++ b/htdocs/comm/action/class/actioncomm.class.php @@ -1543,7 +1543,7 @@ class ActionComm extends CommonObject $event['uid']='dolibarragenda-'.$this->db->database_name.'-'.$obj->id."@".$_SERVER["SERVER_NAME"]; $event['type']=$type; $datestart=$this->db->jdate($obj->datep)-(empty($conf->global->AGENDA_EXPORT_FIX_TZ)?0:($conf->global->AGENDA_EXPORT_FIX_TZ*3600)); - + // fix for -> Warning: A non-numeric value encountered if(is_numeric($this->db->jdate($obj->datep2))) { diff --git a/htdocs/comm/mailing/info.php b/htdocs/comm/mailing/info.php index 0dbc6fc07ab..7b270e460c8 100644 --- a/htdocs/comm/mailing/info.php +++ b/htdocs/comm/mailing/info.php @@ -58,11 +58,11 @@ if ($object->fetch($id) >= 0) $morehtmlright=''; if ($object->statut == 2) $morehtmlright.=' ('.$object->countNbOfTargets('alreadysent').'/'.$object->nbemail.') '; - + dol_banner_tab($object, 'id', $linkback, 1, 'rowid', 'ref', '', '', 0, '', $morehtmlright); - + print '

'; - + //print '
'; $object->user_creation=$object->user_creat; $object->date_creation=$object->date_creat; @@ -70,7 +70,7 @@ if ($object->fetch($id) >= 0) $object->date_validation=$object->date_valid; dol_print_object_info($object, 0); //print '
'; - + dol_fiche_end(); } diff --git a/htdocs/compta/deplacement/info.php b/htdocs/compta/deplacement/info.php index a0accd11a87..510675265a0 100644 --- a/htdocs/compta/deplacement/info.php +++ b/htdocs/compta/deplacement/info.php @@ -47,15 +47,15 @@ if ($id) $object = new Deplacement($db); $object->fetch($id); $object->info($id); - + $head = trip_prepare_head($object); - + dol_fiche_head($head, 'info', $langs->trans("TripCard"), 0, 'trip'); print '
'; dol_print_object_info($object); print '
'; - + print ''; } diff --git a/htdocs/compta/facture/card.php b/htdocs/compta/facture/card.php index f264bb074b3..fe88c9ec717 100644 --- a/htdocs/compta/facture/card.php +++ b/htdocs/compta/facture/card.php @@ -278,8 +278,11 @@ if (empty($reshook)) $action = ''; } } else { - // Si non avoir, le signe doit etre positif - if (empty($conf->global->FACTURE_ENABLE_NEGATIVE) && $object->total_ht < 0) { + // If not a credit note, amount with tax must be positive or nul. + // Note that amount excluding tax can be negative because you can have a invoice of 100 with vat of 20 that + // consumes a credit note of 100 with vat 0 (total with tax is 0 but without tax is -20). + // For some cases, credit notes can have a vat of 0 (for example when selling goods in France). + if (empty($conf->global->FACTURE_ENABLE_NEGATIVE) && $object->total_ttc < 0) { setEventMessages($langs->trans("ErrorInvoiceOfThisTypeMustBePositive"), null, 'errors'); $action = ''; } @@ -2563,6 +2566,7 @@ $form = new Form($db); $formother = new FormOther($db); $formfile = new FormFile($db); $formmargin = new FormMargin($db); +$soc = new Societe($db); $paymentstatic=new Paiement($db); $bankaccountstatic = new Account($db); if (! empty($conf->projet->enabled)) { $formproject = new FormProjets($db); } @@ -2583,7 +2587,6 @@ if ($action == 'create') print load_fiche_titre($langs->trans('NewBill'), '', 'invoicing'); - $soc = new Societe($db); if ($socid > 0) $res = $soc->fetch($socid); @@ -3462,7 +3465,6 @@ elseif ($id > 0 || ! empty($ref)) $result = $object->fetch_thirdparty(); - $soc = new Societe($db); $result=$soc->fetch($object->socid); if ($result < 0) dol_print_error($db); $selleruserevenustamp = $mysoc->useRevenueStamp(); diff --git a/htdocs/compta/paiement/class/cpaiement.class.php b/htdocs/compta/paiement/class/cpaiement.class.php index a4e115dfdb0..37614f7e36e 100644 --- a/htdocs/compta/paiement/class/cpaiement.class.php +++ b/htdocs/compta/paiement/class/cpaiement.class.php @@ -34,7 +34,7 @@ class Cpaiement * @var string Id to identify managed objects */ public $element = 'cpaiement'; - + /** * @var string Name of table without prefix where object is stored */ diff --git a/htdocs/compta/tva/document.php b/htdocs/compta/tva/document.php index 46cd0e281a5..d26d8954cc4 100644 --- a/htdocs/compta/tva/document.php +++ b/htdocs/compta/tva/document.php @@ -114,7 +114,7 @@ if ($object->id) $morehtmlref.=$form->editfieldval("Label", 'lib', $object->label, $object, $user->rights->tax->charges->creer, 'string', '', null, null, '', 1); $morehtmlref.=''; - $linkback = '' . $langs->trans("BackToList") . ''; + $linkback = '' . $langs->trans("BackToList") . ''; $object->totalpaye = $totalpaye; // To give a chance to dol_banner_tab to use already paid amount to show correct status diff --git a/htdocs/contact/class/contact.class.php b/htdocs/contact/class/contact.class.php index a17f6f27259..3465b3478a0 100644 --- a/htdocs/contact/class/contact.class.php +++ b/htdocs/contact/class/contact.class.php @@ -628,7 +628,7 @@ class Contact extends CommonObject if ($this->birthday_alert) { //check existing - $sql_check = "SELECT * FROM ".MAIN_DB_PREFIX."user_alert WHERE type=1 AND fk_contact=".$this->db->escape($id)." AND fk_user=".$user->id; + $sql_check = "SELECT rowid FROM ".MAIN_DB_PREFIX."user_alert WHERE type=1 AND fk_contact=".$this->db->escape($id)." AND fk_user=".$user->id; $result_check = $this->db->query($sql_check); if (! $result_check || ($this->db->num_rows($result_check)<1)) { diff --git a/htdocs/core/actions_addupdatedelete.inc.php b/htdocs/core/actions_addupdatedelete.inc.php index e87333e4c01..d618a0702c8 100644 --- a/htdocs/core/actions_addupdatedelete.inc.php +++ b/htdocs/core/actions_addupdatedelete.inc.php @@ -32,6 +32,8 @@ if ($cancel) { + /*var_dump($cancel); + var_dump($backtopage);exit;*/ if (! empty($backtopage)) { header("Location: ".$backtopage); @@ -80,7 +82,8 @@ if ($action == 'add' && ! empty($permissiontoadd)) if ($result > 0) { // Creation OK - $urltogo=$backtopage?str_replace('__ID__', $result, $backtopage):$backurlforlist; + $urltogo = $backtopage ? str_replace('__ID__', $result, $backtopage) : $backurlforlist; + $urltogo = preg_replace('/--IDFORBACKTOPAGE--/', $object->id, $urltogo); // New method to autoselect project after a New on another form object creation header("Location: ".$urltogo); exit; } diff --git a/htdocs/core/actions_massactions.inc.php b/htdocs/core/actions_massactions.inc.php index c81c013bc08..7d8d621ff92 100644 --- a/htdocs/core/actions_massactions.inc.php +++ b/htdocs/core/actions_massactions.inc.php @@ -71,7 +71,9 @@ if (! $error && $massaction == 'confirm_presend') $listofobjectid=array(); $listofobjectthirdparties=array(); + $listofobjectcontacts = array(); $listofobjectref=array(); + $contactidtosend=array(); $attachedfilesThirdpartyObj=array(); $oneemailperrecipient=(GETPOST('oneemailperrecipient')=='on'?1:0); @@ -97,11 +99,21 @@ if (! $error && $massaction == 'confirm_presend') if ($objecttmp->element == 'holiday') $thirdpartyid=$objecttmp->fk_user; if (empty($thirdpartyid)) $thirdpartyid=0; - $listofobjectthirdparties[$thirdpartyid]=$thirdpartyid; - $listofobjectref[$thirdpartyid][$toselectid]=$objecttmp; - } - } - } + if ($objectclass == 'Facture') { + $tmparraycontact = array(); + $tmparraycontact = $objecttmp->liste_contact(-1, 'external', 0, 'BILLING'); + if (is_array($tmparraycontact) && count($tmparraycontact) > 0) { + foreach ($tmparraycontact as $data_email) { + $listofobjectcontacts[$toselectid][$data_email['id']] = $data_email['email']; + } + } + } + + $listofobjectthirdparties[$thirdpartyid]=$thirdpartyid; + $listofobjectref[$thirdpartyid][$toselectid]=$objecttmp; + } + } + } // Check mandatory parameters if (GETPOST('fromtype', 'alpha') === 'user' && empty($user->email)) @@ -248,6 +260,21 @@ if (! $error && $massaction == 'confirm_presend') $fuser->fetch($objectobj->fk_user); $sendto = $fuser->email; } + elseif ($objectobj->element == 'facture' && !empty($listofobjectcontacts[$objectid])) + { + $emails_to_sends = array(); + $objectobj->fetch_thirdparty(); + $contactidtosend=array(); + foreach ($listofobjectcontacts[$objectid] as $contactemailid => $contactemailemail) { + $emails_to_sends[] = $objectobj->thirdparty->contact_get_property($contactemailid, 'email'); + if (!in_array($contactemailid, $contactidtosend)) { + $contactidtosend[] = $contactemailid; + } + } + if (count($emails_to_sends) > 0) { + $sendto = implode(',', $emails_to_sends); + } + } else { $objectobj->fetch_thirdparty(); @@ -498,8 +525,8 @@ if (! $error && $massaction == 'confirm_presend') } $actionmsg2=''; - // Initialisation donnees - $objectobj2->sendtoid = 0; + // Initialisation donnees + $objectobj2->sendtoid = (empty($contactidtosend)?0:$contactidtosend); $objectobj2->actionmsg = $actionmsg; // Long text $objectobj2->actionmsg2 = $actionmsg2; // Short text $objectobj2->fk_element = $objid2; diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index cc8ae3238c0..abd8e38ce97 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -5556,16 +5556,20 @@ abstract class CommonObject $type=''; $param = array(); $param['options']=array(); - $size =$this->fields[$key]['size']; + $reg=array(); + $size = $this->fields[$key]['size']; // Because we work on extrafields - if(preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)){ - $param['options']=array($reg[1].':'.$reg[2]=>'N'); - $type ='link'; - } elseif(preg_match('/^link:(.*):(.*)/i', $val['type'], $reg)) { - $param['options']=array($reg[1].':'.$reg[2]=>'N'); + if (preg_match('/^(integer|link):(.*):(.*):(.*):(.*)/i', $val['type'], $reg)){ + $param['options']=array($reg[2].':'.$reg[3].':'.$reg[4].':'.$reg[5] => 'N'); + $type ='link'; + } elseif (preg_match('/^(integer|link):(.*):(.*):(.*)/i', $val['type'], $reg)){ + $param['options']=array($reg[2].':'.$reg[3].':'.$reg[4] => 'N'); + $type ='link'; + } elseif (preg_match('/^(integer|link):(.*):(.*)/i', $val['type'], $reg)){ + $param['options']=array($reg[2].':'.$reg[3] => 'N'); $type ='link'; } elseif(preg_match('/^sellist:(.*):(.*):(.*):(.*)/i', $val['type'], $reg)) { - $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4]=>'N'); + $param['options']=array($reg[1].':'.$reg[2].':'.$reg[3].':'.$reg[4] => 'N'); $type ='sellist'; } elseif(preg_match('/varchar\((\d+)\)/', $val['type'], $reg)) { $param['options']=array(); @@ -6078,16 +6082,26 @@ abstract class CommonObject } elseif ($type == 'link') { - $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath' + $param_list=array_keys($param['options']); // $param_list='ObjectName:classPath[:AddCreateButtonOrNot[:Filter]]' + $param_list_array = explode(':', $param_list[0]); $showempty=(($required && $default != '')?0:1); - $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty); - if ($conf->global->MAIN_FEATURES_LEVEL >= 2) + + $out=$form->selectForForms($param_list[0], $keyprefix.$key.$keysuffix, $value, $showempty, '', '', '', '', 0, empty($val['disabled'])?0:1); + + if (! empty($param_list_array[2])) // If we set to add a create button { - list($class,$classfile)=explode(':', $param_list[0]); - if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php', 1); - else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.$class.'_card.php', 1); - $out.=''; - // TODO Add Javascript code to add input fields contents to new elements urls + if (! GETPOSTISSET('backtopage') && empty($val['disabled'])) // To avoid to open several infinitely the 'Create Object' button and to avoid to have button if field is protected by a "disabled". + { + list($class,$classfile)=explode(':', $param_list[0]); + if (file_exists(dol_buildpath(dirname(dirname($classfile)).'/card.php'))) $url_path=dol_buildpath(dirname(dirname($classfile)).'/card.php', 1); + else $url_path=dol_buildpath(dirname(dirname($classfile)).'/'.strtolower($class).'_card.php', 1); + $paramforthenewlink = ''; + $paramforthenewlink .= (GETPOSTISSET('action')?'&action='.GETPOST('action', 'aZ09'):''); + $paramforthenewlink .= (GETPOSTISSET('id')?'&id='.GETPOST('id', 'int'):''); + $paramforthenewlink .= '&fk_'.strtolower($class).'=--IDFORBACKTOPAGE--'; + // TODO Add Javascript code to add input fields already filled into $paramforthenewlink so we won't loose them when going back to main page + $out.=''; + } } } elseif ($type == 'password') @@ -6167,6 +6181,7 @@ abstract class CommonObject $label = $val['label']; $type = $val['type']; $size = $val['css']; + $reg = array(); // Convert var to be able to share same code than showOutputField of extrafields if (preg_match('/varchar\((\d+)\)/', $type, $reg)) @@ -6182,7 +6197,9 @@ abstract class CommonObject $computed=$val['computed']; $unique=$val['unique']; $required=$val['required']; - $param=$val['param']; + $param=array(); + $param['options']=array(); + if (is_array($val['arrayofkeyval'])) $param['options'] = $val['arrayofkeyval']; if (preg_match('/^integer:(.*):(.*)/i', $val['type'], $reg)) { diff --git a/htdocs/core/class/cunits.class.php b/htdocs/core/class/cunits.class.php index 1837f82a2a4..07cd778d3a0 100644 --- a/htdocs/core/class/cunits.class.php +++ b/htdocs/core/class/cunits.class.php @@ -234,8 +234,6 @@ class CUnits // extends CommonObject dol_syslog(__METHOD__, LOG_DEBUG); - $records=array(); - $sql = 'SELECT'; $sql.= " t.rowid,"; $sql.= " t.code,"; @@ -273,6 +271,7 @@ class CUnits // extends CommonObject if (!empty($limit)) { $sql .= ' ' . $this->db->plimit($limit, $offset); } + $resql = $this->db->query($sql); if ($resql) { $this->records=array(); diff --git a/htdocs/core/class/discount.class.php b/htdocs/core/class/discount.class.php index ab1448bc412..71c0566f352 100644 --- a/htdocs/core/class/discount.class.php +++ b/htdocs/core/class/discount.class.php @@ -91,13 +91,15 @@ class DiscountAbsolute public $fk_facture; /** - * @var int ID credit note having caused the discount + * @var int ID credit note or deposit used to create the discount */ public $fk_facture_source; + public $ref_facture_source; // Ref credit note or deposit used to create the discount + public $type_facture_source; - public $ref_facture_source; // Ref credit note having caused the discount - - public $ref_invoice_supplier_source; + public $fk_invoice_supplier_source; + public $ref_invoice_supplier_source; // Ref credit note or deposit used to create the discount + public $type_invoice_supplier_source; /** * Constructor @@ -135,11 +137,12 @@ class DiscountAbsolute $sql.= " sr.multicurrency_amount_ht, sr.multicurrency_amount_tva, sr.multicurrency_amount_ttc,"; $sql.= " sr.fk_facture_line, sr.fk_facture, sr.fk_facture_source, sr.fk_invoice_supplier_line, sr.fk_invoice_supplier, sr.fk_invoice_supplier_source, sr.description,"; $sql.= " sr.datec,"; - $sql.= " f.ref as ref_facture_source, fsup.ref as ref_invoice_supplier_source"; + $sql.= " f.ref as ref_facture_source, f.type as type_facture_source,"; + $sql.= " fsup.ref as ref_invoice_supplier_source, fsup.type as type_invoice_supplier_source"; $sql.= " FROM ".MAIN_DB_PREFIX."societe_remise_except as sr"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as f ON sr.fk_facture_source = f.rowid"; $sql.= " LEFT JOIN ".MAIN_DB_PREFIX."facture as fsup ON sr.fk_invoice_supplier_source = fsup.rowid"; - $sql.= " WHERE sr.entity IN (".getEntity('invoice').")"; + $sql.= " WHERE sr.entity IN (".getEntity('invoice').")"; if ($rowid) $sql.= " AND sr.rowid=".$rowid; if ($fk_facture_source) $sql.= " AND sr.fk_facture_source=".$fk_facture_source; if ($fk_invoice_supplier_source) $sql.= " AND sr.fk_invoice_supplier_source=".$fk_invoice_supplier_source; @@ -168,12 +171,14 @@ class DiscountAbsolute $this->fk_user = $obj->fk_user; $this->fk_facture_line = $obj->fk_facture_line; $this->fk_facture = $obj->fk_facture; - $this->fk_facture_source = $obj->fk_facture_source; // Id avoir source - $this->ref_facture_source = $obj->ref_facture_source; // Ref avoir source + $this->fk_facture_source = $obj->fk_facture_source; // Id credit note or deposit source + $this->ref_facture_source = $obj->ref_facture_source; // Ref credit note or deposit source + $this->type_facture_source = $obj->type_facture_source; // Type credit note or deposit source $this->fk_invoice_supplier_line = $obj->fk_invoice_supplier_line; $this->fk_invoice_supplier = $obj->fk_invoice_supplier; - $this->fk_invoice_supplier_source = $obj->fk_invoice_supplier_source; // Id avoir source - $this->ref_invoice_supplier_source = $obj->ref_invoice_supplier_source; // Ref avoir source + $this->fk_invoice_supplier_source = $obj->fk_invoice_supplier_source; // Id credit note or deposit source + $this->ref_invoice_supplier_source = $obj->ref_invoice_supplier_source; // Ref credit note or deposit source + $this->type_invoice_supplier_source = $obj->type_invoice_supplier_source; // Type credit note or deposit source $this->description = $obj->description; $this->datec = $this->db->jdate($obj->datec); @@ -688,7 +693,7 @@ class DiscountAbsolute if ($option == 'invoice') { $facid=! empty($this->discount_type)?$this->fk_invoice_supplier_source:$this->fk_facture_source; $link=! empty($this->discount_type)?'/fourn/facture/card.php':'/compta/facture/card.php'; - $label=$langs->trans("ShowDiscount").': '.$this->ref_facture_source; + $label=$langs->trans("ShowSourceInvoice").': '.$this->ref_facture_source; $link = ''; $linkend=''; $ref=! empty($this->discount_type)?$this->ref_invoice_supplier_source:$this->ref_facture_source; diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 61558434105..b4c52117ea9 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -5614,7 +5614,7 @@ class Form }; var d = new Date();"; } - + // Generate the date part, depending on the use or not of the javascript calendar if($addnowlink==1) // server time expressed in user time setup { @@ -5815,7 +5815,7 @@ class Form * Generic method to select a component from a combo list. * This is the generic method that will replace all specific existing methods. * - * @param string $objectdesc Objectclassname:Objectclasspath + * @param string $objectdesc ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]] * @param string $htmlname Name of HTML select component * @param int $preselectedvalue Preselected value (ID of element) * @param string $showempty ''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...) @@ -5824,10 +5824,11 @@ class Form * @param string $morecss More CSS * @param string $moreparams More params provided to ajax call * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) + * @param int $disabled 1=Html component is disabled * @return string Return HTML string * @see selectForFormsList() select_thirdparty */ - public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0) + public function selectForForms($objectdesc, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $disabled = 0) { global $conf, $user; @@ -5836,12 +5837,16 @@ class Form $InfoFieldList = explode(":", $objectdesc); $classname=$InfoFieldList[0]; $classpath=$InfoFieldList[1]; + $addcreatebuttonornot=empty($InfoFieldList[2])?0:$InfoFieldList[2]; + $filter=empty($InfoFieldList[3])?'':$InfoFieldList[3]; + if (! empty($classpath)) { dol_include_once($classpath); if ($classname && class_exists($classname)) { $objecttmp = new $classname($this->db); + $objecttmp->filter = $filter; } } if (! is_object($objecttmp)) @@ -5854,12 +5859,12 @@ class Form if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company'; $confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT - dol_syslog(get_class($this)."::selectForForms", LOG_DEBUG); + dol_syslog(get_class($this)."::selectForForms object->filter=".$objecttmp->filter, LOG_DEBUG); $out=''; if (! empty($conf->use_javascript_ajax) && ! empty($conf->global->$confkeyforautocompletemode) && ! $forcecombo) { - $objectdesc=$classname.':'.$classpath; + $objectdesc=$classname.':'.$classpath.':'.$addcreatebuttonornot.':'.$filter; $urlforajaxcall = DOL_URL_ROOT.'/core/ajax/selectobject.php'; // No immediate load of all database @@ -5868,22 +5873,50 @@ class Form $out.= ajax_autocompleter($preselectedvalue, $htmlname, $urlforajaxcall, $urloption, $conf->global->$confkeyforautocompletemode, 0, array()); $out.= ''; if ($placeholder) $placeholder=' placeholder="'.$placeholder.'"'; - $out.= ''; + $out.= ''; } else { - // Immediate load of all database - $out.=$this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo); + // Immediate load of table record. Note: filter is inside $objecttmp->filter + $out.=$this->selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty, $searchkey, $placeholder, $morecss, $moreparams, $forcecombo, 0, $disabled); } return $out; } + /** + * Function to forge a SQL criteria + * + * @param array $matches Array of found string by regex search. Example: "t.ref:like:'SO-%'" or "t.date_creation:<:'20160101'" or "t.nature:is:NULL" + * @return string Forged criteria. Example: "t.field like 'abc%'" + */ + protected static function forgeCriteriaCallback($matches) + { + global $db; + + //dol_syslog("Convert matches ".$matches[1]); + if (empty($matches[1])) return ''; + $tmp=explode(':', $matches[1]); + if (count($tmp) < 3) return ''; + + $tmpescaped=$tmp[2]; + $regbis = array(); + if (preg_match('/^\'(.*)\'$/', $tmpescaped, $regbis)) + { + $tmpescaped = "'".$db->escape($regbis[1])."'"; + } + else + { + $tmpescaped = $db->escape($tmpescaped); + } + return $db->escape($tmp[0]).' '.strtoupper($db->escape($tmp[1]))." ".$tmpescaped; + } + /** * Output html form to select an object. * Note, this function is called by selectForForms or by ajax selectobject.php * - * @param Object $objecttmp Object + * @param Object $objecttmp Object to knwo the table to scan for combo. * @param string $htmlname Name of HTML select component * @param int $preselectedvalue Preselected value (ID of element) * @param string $showempty ''=empty values not allowed, 'string'=value show if we allow empty values (for example 'All', ...) @@ -5893,13 +5926,16 @@ class Form * @param string $moreparams More params provided to ajax call * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) * @param int $outputmode 0=HTML select string, 1=Array + * @param int $disabled 1=Html component is disabled * @return string Return HTML string * @see selectForForms() */ - public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0) + public function selectForFormsList($objecttmp, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled = 0) { global $conf, $langs, $user; + //print "$objecttmp->filter, $htmlname, $preselectedvalue, $showempty = '', $searchkey = '', $placeholder = '', $morecss = '', $moreparams = '', $forcecombo = 0, $outputmode = 0, $disabled"; + $prefixforautocompletemode=$objecttmp->element; if ($prefixforautocompletemode == 'societe') $prefixforautocompletemode='company'; $confkeyforautocompletemode=strtoupper($prefixforautocompletemode).'_USE_SEARCH_TO_SELECT'; // For example COMPANY_USE_SEARCH_TO_SELECT @@ -5923,19 +5959,28 @@ class Form // Search data $sql = "SELECT t.rowid, ".$fieldstoshow." FROM ".MAIN_DB_PREFIX .$objecttmp->table_element." as t"; if ($objecttmp->ismultientitymanaged == 2) - if (!$user->rights->societe->client->voir && !$user->societe_id) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; + if (!$user->rights->societe->client->voir && !$user->socid) $sql .= ", ".MAIN_DB_PREFIX."societe_commerciaux as sc"; $sql.= " WHERE 1=1"; if(! empty($objecttmp->ismultientitymanaged)) $sql.= " AND t.entity IN (".getEntity($objecttmp->table_element).")"; - if ($objecttmp->ismultientitymanaged == 1 && ! empty($user->societe_id)) - { - if ($objecttmp->element == 'societe') $sql.= " AND t.rowid = ".$user->societe_id; - else $sql.= " AND t.fk_soc = ".$user->societe_id; + if ($objecttmp->ismultientitymanaged == 1 && ! empty($user->socid)) { + if ($objecttmp->element == 'societe') $sql.= " AND t.rowid = ".$user->socid; + else $sql.= " AND t.fk_soc = ".$user->socid; } if ($searchkey != '') $sql.=natural_search(explode(',', $fieldstoshow), $searchkey); - if ($objecttmp->ismultientitymanaged == 2) - if (!$user->rights->societe->client->voir && !$user->societe_id) $sql.= " AND t.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + if ($objecttmp->ismultientitymanaged == 2) { + if (!$user->rights->societe->client->voir && !$user->socid) $sql.= " AND t.rowid = sc.fk_soc AND sc.fk_user = " .$user->id; + } + if ($objecttmp->filter) { // Syntax example "(t.ref:like:'SO-%') and (t.date_creation:<:'20160101')" + /*if (! DolibarrApi::_checkFilters($objecttmp->filter)) + { + throw new RestException(503, 'Error when validating parameter sqlfilters '.$objecttmp->filter); + }*/ + $regexstring='\(([^:\'\(\)]+:[^:\'\(\)]+:[^:\(\)]+)\)'; + $sql.=" AND (".preg_replace_callback('/'.$regexstring.'/', 'Form::forgeCriteriaCallback', $objecttmp->filter).")"; + } $sql.=$this->db->order($fieldstoshow, "ASC"); //$sql.=$this->db->plimit($limit, 0); + //print $sql; // Build output string $resql=$this->db->query($sql); @@ -5948,7 +5993,7 @@ class Form } // Construct $out and $outarray - $out.= ''."\n"; // Warning: Do not use textifempty = ' ' or ' ' here, or search on key will search on ' key'. Seems it is no more true with selec2 v4 $textifempty=' '; diff --git a/htdocs/core/class/html.formfile.class.php b/htdocs/core/class/html.formfile.class.php index 8a0341135c7..82bfe17bf69 100644 --- a/htdocs/core/class/html.formfile.class.php +++ b/htdocs/core/class/html.formfile.class.php @@ -231,10 +231,10 @@ class FormFile if (empty($usewithoutform)) { - $out .= '