diff --git a/ChangeLog b/ChangeLog index ace6c60c0c0..9cd6f11d1b8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -31,10 +31,17 @@ Following changes may create regression for some external modules, but were nece content by doing a print into function, sometimes by returning content into "resprint". This has been fixed to follow hook specifications so you must return output into "resprint". + ***** ChangeLog for 5.0.4 compared to 5.0.3 ***** -FIX: #6880 -FIX: #6925 +FIX: #5640 Prices of a predefined product/service were incorrect under certain circumstances +FIX: #6541 since 4.0.4 to 5.0.0 autofill zip/town not working +FIX: #6880 #6925 +FIX: #6885 FIX: #6926 +FIX: #7003 +FIX: #7012 +FIX: #7040 +FIX: #7048 #6075 FIX: Can set supplier invoice to billed. FIX: Can't create invoice if PO disapproved FIX: contratligne update @@ -46,6 +53,7 @@ FIX: Redirect to payment page from member subscription page failed if a unique s FIX: REST api to get project when user has permission to read all. FIX: situation_progress param default value must be 100 and not 0 FIX: SQL injection on user/index.php parameter search_statut. +FIX: vat code not saved during product creation. FIX: Warnings ***** ChangeLog for 5.0.3 compared to 5.0.2 ***** diff --git a/build/exe/doliwamp/install.forced.php.install b/build/exe/doliwamp/install.forced.php.install index fd98dbf3984..5b186c17268 100644 --- a/build/exe/doliwamp/install.forced.php.install +++ b/build/exe/doliwamp/install.forced.php.install @@ -5,7 +5,7 @@ // during install process to be used. // // -$force_install_noedit=2; +$force_install_noedit=2; // 1=To block vars specific to distrib, 2 to block all technical parameters $force_install_message='KeepDefaultValuesWamp'; $force_install_main_data_root='WAMPROOT/dolibarr_documents'; $force_install_type='mysqli'; diff --git a/build/rpm/install.forced.php.fedora b/build/rpm/install.forced.php.fedora index 108455a9403..a8db3e25c9e 100644 --- a/build/rpm/install.forced.php.fedora +++ b/build/rpm/install.forced.php.fedora @@ -1,7 +1,7 @@ '; print ''; diff --git a/htdocs/accountancy/admin/categories_list.php b/htdocs/accountancy/admin/categories_list.php index e71482b0efa..cb852d82e0c 100644 --- a/htdocs/accountancy/admin/categories_list.php +++ b/htdocs/accountancy/admin/categories_list.php @@ -74,7 +74,7 @@ $active = 1; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $listlimit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/accountancy/admin/defaultaccounts.php b/htdocs/accountancy/admin/defaultaccounts.php index 227949a3c1c..9cf4d2977fd 100644 --- a/htdocs/accountancy/admin/defaultaccounts.php +++ b/htdocs/accountancy/admin/defaultaccounts.php @@ -1,11 +1,11 @@ - * Copyright (C) 2013-2014 Florian Henry - * Copyright (C) 2013-2016 Alexandre Spangaro - * Copyright (C) 2014-2015 Ari Elbaz (elarifr) +/* Copyright (C) 2013-2014 Olivier Geffroy + * Copyright (C) 2013-2014 Florian Henry + * Copyright (C) 2013-2017 Alexandre Spangaro + * Copyright (C) 2014-2015 Ari Elbaz (elarifr) * Copyright (C) 2014 Marcos García - * Copyright (C) 2014 Juanjo Menent - * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2014 Juanjo Menent + * Copyright (C) 2015 Jean-François Ferry * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -23,7 +23,7 @@ */ /** - * \file htdocs/accountancy/admin/index.php + * \file htdocs/accountancy/admin/defaultaccounts.php * \ingroup Advanced accountancy * \brief Setup page to configure accounting expert module */ @@ -53,10 +53,10 @@ $action = GETPOST('action', 'alpha'); $list_account_main = array ( 'ACCOUNTING_ACCOUNT_CUSTOMER', 'ACCOUNTING_ACCOUNT_SUPPLIER', + 'SALARIES_ACCOUNTING_ACCOUNT_PAYMENT', ); $list_account = array ( - 'SALARIES_ACCOUNTING_ACCOUNT_PAYMENT', 'ACCOUNTING_PRODUCT_BUY_ACCOUNT', 'ACCOUNTING_PRODUCT_SOLD_ACCOUNT', 'ACCOUNTING_SERVICE_BUY_ACCOUNT', diff --git a/htdocs/accountancy/admin/journals_list.php b/htdocs/accountancy/admin/journals_list.php index 3dc932dbab5..dca29fd28b8 100644 --- a/htdocs/accountancy/admin/journals_list.php +++ b/htdocs/accountancy/admin/journals_list.php @@ -58,7 +58,7 @@ $active = 1; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $listlimit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index 3c6d2faec94..28b7b177860 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -500,8 +500,7 @@ if ($action == 'create') { print "\n"; foreach ( $book->linesmvt as $line ) { - $var = ! $var; - print ''; + print ''; $total_debit += $line->debit; $total_credit += $line->credit; diff --git a/htdocs/accountancy/bookkeeping/list.php b/htdocs/accountancy/bookkeeping/list.php index 1062fd50d87..16d27df15fd 100644 --- a/htdocs/accountancy/bookkeeping/list.php +++ b/htdocs/accountancy/bookkeeping/list.php @@ -438,7 +438,6 @@ $total_debit = 0; $total_credit = 0; foreach ($object->lines as $line ) { - $var = ! $var; $total_debit += $line->debit; $total_credit += $line->credit; diff --git a/htdocs/accountancy/customer/index.php b/htdocs/accountancy/customer/index.php index 817811cd0fc..9af3d0d19d9 100644 --- a/htdocs/accountancy/customer/index.php +++ b/htdocs/accountancy/customer/index.php @@ -1,9 +1,9 @@ +/* Copyright (C) 2013 Olivier Geffroy * Copyright (C) 2013-2014 Florian Henry * Copyright (C) 2013-2016 Alexandre Spangaro * Copyright (C) 2014 Juanjo Menent - * Copyright (C) 2015 Jean-François Ferry + * Copyright (C) 2015 Jean-François Ferry * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -40,7 +40,7 @@ $langs->load("accountancy"); // Security check if (empty($conf->accounting->enabled)) { - accessforbidden(); + accessforbidden(); } if ($user->societe_id > 0) accessforbidden(); @@ -187,7 +187,7 @@ if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { } else { $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")"; } -$sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy +$sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy dol_syslog("htdocs/accountancy/customer/index.php sql=" . $sql, LOG_DEBUG); $result = $db->query($sql); @@ -203,10 +203,6 @@ $buttonbind = '' . $langs->trans("CleanHistory", $year_current) . ''; - - -$var = true; - print_fiche_titre($langs->trans("OverviewOfAmountOfLinesNotBound"), $buttonbind, ''); print ''; @@ -269,14 +265,14 @@ print '
'; print ''; print ''; for($i = 1; $i <= 12; $i ++) { - print ''; + print ''; } print ''; $sql = "SELECT " . $db->ifsql('aa.account_number IS NULL', "'".$langs->trans('NotMatch')."'", 'aa.account_number') . " AS codecomptable,"; $sql .= " " . $db->ifsql('aa.label IS NULL', "'".$langs->trans('NotMatch')."'", 'aa.label') . " AS intitule,"; for($i = 1; $i <= 12; $i ++) { - $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, 'fd.total_ht', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; + $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, 'fd.total_ht', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; } $sql .= " SUM(fd.total_ht) as total"; $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd"; @@ -296,22 +292,22 @@ $sql .= " GROUP BY fd.fk_code_ventilation,aa.account_number,aa.label"; dol_syslog("htdocs/accountancy/customer/index.php sql=" . $sql, LOG_DEBUG); $resql = $db->query($sql); if ($resql) { - $num = $db->num_rows($resql); + $num = $db->num_rows($resql); - while ( $row = $db->fetch_row($resql)) { + while ( $row = $db->fetch_row($resql)) { - print ''; - print ''; - for($i = 2; $i <= 12; $i ++) { - print ''; - } - print ''; - print ''; - print ''; - } - $db->free($resql); + print ''; + print ''; + for($i = 2; $i <= 12; $i ++) { + print ''; + } + print ''; + print ''; + print ''; + } + $db->free($resql); } else { - print $db->lasterror(); // Show last sql error + print $db->lasterror(); // Show last sql error } print "
' . $langs->trans("Account") . '' . $langs->trans("Label") . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans("Total") . '
' . length_accountg($row[0]) . '' . $row[1] . '' . price($row[$i]) . '' . price($row[13]) . '' . price($row[14]) . '
' . length_accountg($row[0]) . '' . $row[1] . '' . price($row[$i]) . '' . price($row[13]) . '' . price($row[14]) . '
\n"; @@ -319,101 +315,101 @@ print "\n"; if ($conf->global->MAIN_FEATURES_LEVEL > 0) // This part of code looks strange. Why showing a report that should rely on result of this step ? { - print '
'; - print '
'; + print '
'; + print '
'; - print_fiche_titre($langs->trans("OtherInfo"), '', ''); + print_fiche_titre($langs->trans("OtherInfo"), '', ''); - print "
\n"; - print ''; - print ''; - for($i = 1; $i <= 12; $i ++) { - print ''; - } - print ''; + print "
\n"; + print '
' . $langs->trans("TotalVente") . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans("Total") . '
'; + print ''; + for($i = 1; $i <= 12; $i ++) { + print ''; + } + print ''; - $sql = "SELECT '" . $langs->trans("TotalVente") . "' AS total,"; - for($i = 1; $i <= 12; $i ++) { - $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, 'fd.total_ht', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; - } - $sql .= " SUM(fd.total_ht) as total"; - $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd"; - $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture"; - $sql .= " WHERE f.datef >= '" . $db->idate(dol_get_first_day($y, 1, false)) . "'"; - $sql .= " AND f.datef <= '" . $db->idate(dol_get_last_day($y, 12, false)) . "'"; - $sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { - $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; - } else { - $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")"; - } + $sql = "SELECT '" . $langs->trans("TotalVente") . "' AS total,"; + for($i = 1; $i <= 12; $i ++) { + $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, 'fd.total_ht', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; + } + $sql .= " SUM(fd.total_ht) as total"; + $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture"; + $sql .= " WHERE f.datef >= '" . $db->idate(dol_get_first_day($y, 1, false)) . "'"; + $sql .= " AND f.datef <= '" . $db->idate(dol_get_last_day($y, 12, false)) . "'"; + $sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { + $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; + } else { + $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")"; + } - dol_syslog('htdocs/accountancy/customer/index.php'); - $resql = $db->query($sql); - if ($resql) { - $i = 0; - $num = $db->num_rows($resql); + dol_syslog('htdocs/accountancy/customer/index.php'); + $resql = $db->query($sql); + if ($resql) { + $i = 0; + $num = $db->num_rows($resql); - while ($row = $db->fetch_row($resql)) { - print ''; - for($i = 1; $i <= 12; $i ++) { - print ''; - } - print ''; - print ''; - $i ++; - } - $db->free($resql); - } else { - print $db->lasterror(); // Show last sql error - } - print "
' . $langs->trans("TotalVente") . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans("Total") . '
' . $row[0] . '' . price($row[$i]) . '' . price($row[13]) . '
\n"; + while ($row = $db->fetch_row($resql)) { + print '' . $row[0] . ''; + for($i = 1; $i <= 12; $i ++) { + print '' . price($row[$i]) . ''; + } + print '' . price($row[13]) . ''; + print ''; + $i ++; + } + $db->free($resql); + } else { + print $db->lasterror(); // Show last sql error + } + print "\n"; - if (! empty($conf->margin->enabled)) { - print "
\n"; - print ''; - print ''; - for($i = 1; $i <= 12; $i ++) { - print ''; - } - print ''; + if (! empty($conf->margin->enabled)) { + print "
\n"; + print '
' . $langs->trans("TotalMarge") . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans("Total") . '
'; + print ''; + for($i = 1; $i <= 12; $i ++) { + print ''; + } + print ''; - $sql = "SELECT '" . $langs->trans("Vide") . "' AS marge,"; - for($i = 1; $i <= 12; $i ++) { - $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, '(fd.total_ht-(fd.qty * fd.buy_price_ht))', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; - } - $sql .= " SUM((fd.total_ht-(fd.qty * fd.buy_price_ht))) as total"; - $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd"; - $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture"; - $sql .= " WHERE f.datef >= '" . $db->idate(dol_get_first_day($y, 1, false)) . "'"; - $sql .= " AND f.datef <= '" . $db->idate(dol_get_last_day($y, 12, false)) . "'"; - $sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy - if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { - $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; - } else { - $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")"; - } + $sql = "SELECT '" . $langs->trans("Vide") . "' AS marge,"; + for($i = 1; $i <= 12; $i ++) { + $sql .= " SUM(" . $db->ifsql('MONTH(f.datef)=' . $i, '(fd.total_ht-(fd.qty * fd.buy_price_ht))', '0') . ") AS month" . str_pad($i, 2, '0', STR_PAD_LEFT) . ","; + } + $sql .= " SUM((fd.total_ht-(fd.qty * fd.buy_price_ht))) as total"; + $sql .= " FROM " . MAIN_DB_PREFIX . "facturedet as fd"; + $sql .= " LEFT JOIN " . MAIN_DB_PREFIX . "facture as f ON f.rowid = fd.fk_facture"; + $sql .= " WHERE f.datef >= '" . $db->idate(dol_get_first_day($y, 1, false)) . "'"; + $sql .= " AND f.datef <= '" . $db->idate(dol_get_last_day($y, 12, false)) . "'"; + $sql .= " AND f.entity IN (" . getEntity('facture', 0) . ")"; // We don't share object for accountancy + if (! empty($conf->global->FACTURE_DEPOSITS_ARE_JUST_PAYMENTS)) { + $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_SITUATION . ")"; + } else { + $sql .= " AND f.type IN (" . Facture::TYPE_STANDARD . "," . Facture::TYPE_REPLACEMENT . "," . Facture::TYPE_CREDIT_NOTE . "," . Facture::TYPE_DEPOSIT . "," . Facture::TYPE_SITUATION . ")"; + } - dol_syslog('htdocs/accountancy/customer/index.php:: $sql=' . $sql); - $resql = $db->query($sql); - if ($resql) { - $num = $db->num_rows($resql); + dol_syslog('htdocs/accountancy/customer/index.php:: $sql=' . $sql); + $resql = $db->query($sql); + if ($resql) { + $num = $db->num_rows($resql); - while ($row = $db->fetch_row($resql)) { + while ($row = $db->fetch_row($resql)) { - print ''; - for($i = 1; $i <= 12; $i ++) { - print ''; - } - print ''; - print ''; - } - $db->free($resql); - } else { - print $db->lasterror(); // Show last sql error - } - print "
' . $langs->trans("TotalMarge") . '' . $langs->trans('MonthShort' . str_pad($i, 2, '0', STR_PAD_LEFT)) . '' . $langs->trans("Total") . '
' . $row[0] . '' . price(price2num($row[$i])) . '' . price(price2num($row[13])) . '
\n"; - } + print '' . $row[0] . ''; + for($i = 1; $i <= 12; $i ++) { + print '' . price(price2num($row[$i])) . ''; + } + print '' . price(price2num($row[13])) . ''; + print ''; + } + $db->free($resql); + } else { + print $db->lasterror(); // Show last sql error + } + print "\n"; + } } diff --git a/htdocs/accountancy/expensereport/index.php b/htdocs/accountancy/expensereport/index.php index e9ce1b2e729..fdbf4d1ce4b 100644 --- a/htdocs/accountancy/expensereport/index.php +++ b/htdocs/accountancy/expensereport/index.php @@ -178,9 +178,6 @@ $buttonreset = 'liste_limit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/adherents/subscription/list.php b/htdocs/adherents/subscription/list.php index 628ceb390e3..369c56b068c 100644 --- a/htdocs/adherents/subscription/list.php +++ b/htdocs/adherents/subscription/list.php @@ -46,7 +46,7 @@ $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $limit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/admin/dict.php b/htdocs/admin/dict.php index 6db098f0750..485c5713636 100644 --- a/htdocs/admin/dict.php +++ b/htdocs/admin/dict.php @@ -73,7 +73,7 @@ $active = 1; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $listlimit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/admin/mails_templates.php b/htdocs/admin/mails_templates.php index 123877f7f4e..16277811b72 100644 --- a/htdocs/admin/mails_templates.php +++ b/htdocs/admin/mails_templates.php @@ -67,7 +67,7 @@ $active = 1; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $listlimit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/admin/modulehelp.php b/htdocs/admin/modulehelp.php index 21e3afb3921..143ebc627f8 100644 --- a/htdocs/admin/modulehelp.php +++ b/htdocs/admin/modulehelp.php @@ -225,20 +225,6 @@ asort($orders); //var_dump($modules); - -$h = 0; - -$head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=desc'; -$head[$h][1] = $langs->trans("Description"); -$head[$h][2] = 'desc'; -$h++; - -$head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=feature'; -$head[$h][1] = $langs->trans("TechnicalServicesProvided"); -$head[$h][2] = 'feature'; -$h++; - - $i=0; foreach($orders as $tmpkey => $tmpvalue) { @@ -257,6 +243,28 @@ $special = $objMod->special; $tab=explode('_',$value); $familyposition=$tab[0]; $familykey=$tab[1]; $module_position=$tab[2]; $numero=$tab[3]; + + +$h = 0; + +$head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=desc'; +$head[$h][1] = $langs->trans("Description"); +$head[$h][2] = 'desc'; +$h++; + +$head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=feature'; +$head[$h][1] = $langs->trans("TechnicalServicesProvided"); +$head[$h][2] = 'feature'; +$h++; + +if ($objMod->isCoreOrExternalModule() == 'external') +{ + $head[$h][0] = DOL_URL_ROOT."/admin/modulehelp.php?id=".$id.'&mode=changelog'; + $head[$h][1] = $langs->trans("ChangeLog"); + $head[$h][2] = 'changelog'; + $h++; +} + // Check filters $modulename=$objMod->getName(); $moduledesc=$objMod->getDesc(); @@ -536,6 +544,13 @@ if ($mode == 'feature') } +if ($mode == 'changelog') +{ + $changelog=$objMod->getChangeLog(); + if ($changelog) $text.='
'.$changelog.'
'; + else $text.='
'.$langs->trans("NotAvailable").'
'; +} + print $text; diff --git a/htdocs/admin/modules.php b/htdocs/admin/modules.php index 23d87791103..a59d6fca3bb 100644 --- a/htdocs/admin/modules.php +++ b/htdocs/admin/modules.php @@ -207,8 +207,19 @@ if ($action == 'set' && $user->admin) //var_dump($resarray);exit; if ($resarray['nbperms'] > 0) { - $msg = $langs->trans('ModuleEnabledAdminMustCheckRights'); - setEventMessages($msg, null, 'warnings'); + $tmpsql="SELECT COUNT(rowid) as nb FROM ".MAIN_DB_PREFIX."user WHERE admin <> 1"; + $resqltmp=$db->query($tmpsql); + if ($resqltmp) + { + $obj=$db->fetch_object($resqltmp); + //var_dump($obj->nb);exit; + if ($obj && $obj->nb > 1) + { + $msg = $langs->trans('ModuleEnabledAdminMustCheckRights'); + setEventMessages($msg, null, 'warnings'); + } + } + else dol_print_error($db); } } header("Location: ".$_SERVER["PHP_SELF"]."?mode=".$mode.$param.($page_y?'&page_y='.$page_y:'')); diff --git a/htdocs/admin/tools/listsessions.php b/htdocs/admin/tools/listsessions.php index 56db6eb2ad7..c57a78974ed 100644 --- a/htdocs/admin/tools/listsessions.php +++ b/htdocs/admin/tools/listsessions.php @@ -47,7 +47,7 @@ $langs->load("other"); $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $conf->liste_limit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/admin/websites.php b/htdocs/admin/websites.php index 1dc91786ada..4dbd154096f 100644 --- a/htdocs/admin/websites.php +++ b/htdocs/admin/websites.php @@ -54,7 +54,7 @@ $status = 1; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $listlimit * $page ; $pageprev = $page - 1; $pagenext = $page + 1; diff --git a/htdocs/api/README.md b/htdocs/api/README.md index b4ff7a89f7b..0b773888882 100644 --- a/htdocs/api/README.md +++ b/htdocs/api/README.md @@ -1,41 +1,54 @@ -API REST howto -============== +API REST +======== -This directory contains files to make Dolibarr a server of REST Web Services. -It depends on external library Restler. +## Integrate your ERP with any other applications using Dolibarr APIs + +This module provides the service to make Dolibarr a server of REST Web Services. It depends on external library Restler. + +Extract any data or push insert, update or delete record using our new REST APIs. Using standard HTTP and Json format, it is compatible with any language (PHP, Java, Ruby, Python, C#, C++, JavaScript, JQuery, Basic, ...). Use the embedded APIs explorer tool to test APIs or get generated URLs to use in your own code. -Explore the api ---------------- +
+ Dolibarr API explorer +
-You can explore API method by using web interface : https://**yourdolibarr.tld**/mydolibarr/api/admin/explorer.php (replace **yourdolibarr.tld** by real hostname of your Dolibarr installation) -Access to the API + +Explore the APIs +---------------- + +You can explore all available APIs by using the API explorer : [**yourdolibarr.tld**/api/index.php/explorer](../api/index.php/explorer) (replace **yourdolibarr.tld** by real hostname of your Dolibarr installation) + + +Access to an API ----------------- -> **Warning : access to the API should (or better : must!) be secured with SSL connection** +> **Warning : access to any API should (or better : must!) be secured with SSL connection** -To access to the API you need a token to identify. When you access the API for the first time, you need to log in with user name and password to get a token. **Only** this token will allow to access API with. +To access to the API you need a token to identify. **Only** this token will allow to access API with. +The token is dedicated to a user and it **must** be put into requests as **DOLAPIKEY** parameter in HTTP header (or among URL parameters, but this is less secured). -To log in with the API, use this uri : https://**yourdolibarr.tld**/mydolibarr/api/index.php/login?login=**username**&password=**password** (replace bold strings with real values) +To get a token you can: -The token will be saved by Dolibarr for next user accesses to the API and it **must** be put into request uri as **api_key** parameter. +* Edit the user card to set the value of token. Each user can have a different token. +* or Call the *login* API with login and password. This will return the value of token for the user used to login. Then call other services with -https://**yourdolibarr.tld**/mydolibarr/api/index.php/otherservice?api_key=**api_key** +https://**yourdolibarr.tld**/mydolibarr/api/index.php/otherservice?DOLAPIKEY=**api_key** -Develop the API ---------------- +Develop an API +-------------- The API uses Lucarast Restler framework. Please check documentation https://www.luracast.com/products/restler and examples http://help.luracast.com/restler/examples/ + Github contains also usefull informations : https://github.com/Luracast/Restler -To implement it into Dolibarr, we need to create a specific class for object we want to use. A skeleton file is available into /dev directory : *skeleton_api_class.class.php* +To implement it into Dolibarr, you need to create a specific class for object we want to use. A skeleton file is available into /modulebuilder/class directory : *api_mymodule_class.class.php* The API class file must be put into object class directory, with specific file name. By example, API class file for '*myobject*' must be put as : /htdocs/*myobject*/class/api_*myobject*.class.php. Class must be named **MyobjectApi**. -If a module provide several object, use a different name for '*myobject*' and put the file into the same directory. +If a module provide several object, use a different name for *'myobject'* and put the file into the same directory. **Define url for methods** diff --git a/htdocs/api/class/api.class.php b/htdocs/api/class/api.class.php index 190e24d326c..40e00d01ffd 100644 --- a/htdocs/api/class/api.class.php +++ b/htdocs/api/class/api.class.php @@ -42,10 +42,11 @@ class DolibarrApi /** * Constructor * - * @param DoliDb $db Database handler - * @param string $cachedir Cache dir + * @param DoliDb $db Database handler + * @param string $cachedir Cache dir + * @param boolean $refreshCache Update cache */ - function __construct($db, $cachedir='') + function __construct($db, $cachedir='', $refreshCache=false) { global $conf; @@ -54,7 +55,7 @@ class DolibarrApi $this->db = $db; $production_mode = ( empty($conf->global->API_PRODUCTION_MODE) ? false : true ); - $this->r = new Restler($production_mode); + $this->r = new Restler($production_mode, $refreshCache); $this->r->setAPIVersion(1); } @@ -66,7 +67,7 @@ class DolibarrApi * * @return array */ - /* Disabled, most APIs does not share same signature for method index + /* Disabled, most APIs does not share same signature for method index function index() { return array( @@ -93,9 +94,9 @@ class DolibarrApi unset($object->linkedObjects); unset($object->lines); // should be ->lines - + unset($object->fields); - + unset($object->oldline); unset($object->error); @@ -175,7 +176,7 @@ class DolibarrApi * @throws RestException */ static function _checkAccessToResource($resource, $resource_id=0, $dbtablename='', $feature2='', $dbt_keyfield='fk_soc', $dbt_select='rowid') { - + // Features/modules to check $featuresarray = array($resource); if (preg_match('/&/', $resource)) { diff --git a/htdocs/api/class/api_access.class.php b/htdocs/api/class/api_access.class.php index 407f94ac915..b2dcfefa49f 100644 --- a/htdocs/api/class/api_access.class.php +++ b/htdocs/api/class/api_access.class.php @@ -80,25 +80,25 @@ class DolibarrApiAccess implements iAuthenticate { dol_syslog($key.' - '.$val); }*/ - + // api key can be provided in url with parameter api_key=xxx or ni header with header DOLAPIKEY:xxx $api_key = ''; - if (isset($_GET['api_key'])) + if (isset($_GET['api_key'])) { // TODO Add option to disable use of api key on url. Return errors if used. $api_key = $_GET['api_key']; // For backward compatibility } - if (isset($_GET['DOLAPIKEY'])) + if (isset($_GET['DOLAPIKEY'])) { // TODO Add option to disable use of api key on url. Return errors if used. $api_key = $_GET['DOLAPIKEY']; // With GET method } - if (isset($_SERVER['HTTP_DOLAPIKEY'])) + if (isset($_SERVER['HTTP_DOLAPIKEY'])) // Param DOLAPIKEY in header can be read with HTTP_DOLAPIKEY { $api_key = $_SERVER['HTTP_DOLAPIKEY']; // With header method (recommanded) } - - if ($api_key) + + if ($api_key) { $sql = "SELECT u.login, u.datec, u.api_key, "; $sql.= " u.tms as date_modification, u.entity"; diff --git a/htdocs/api/class/api_login.class.php b/htdocs/api/class/api_login.class.php index 9b965e24c33..c6b71e8b25c 100644 --- a/htdocs/api/class/api_login.class.php +++ b/htdocs/api/class/api_login.class.php @@ -34,25 +34,25 @@ class Login /** * Login * - * Request the API token for a couple username / password. + * Request the API token for a couple username / password. * Using method POST is recommanded for security reasons (method GET is often logged by default by web servers with parameters so with login and pass into server log file). - * Both methods are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page). - * + * Both methods are provided for developer conveniance. Best is to not use at all the login API method and enter directly the "api_key" into field at the top right of page (Note: "api_key" can be found/set on the user page). + * * @param string $login User login * @param string $password User password - * @param int $entity Entity (when multicompany module is used). Empty means 1=first company. + * @param string $entity Entity (when multicompany module is used). '' means 1=first company. * @param int $reset Reset token (0=get current token, 1=ask a new token and canceled old token. This means access using current existing API token of user will fails: new token will be required for new access) * @return array Response status and user token * * @throws RestException - * + * * @url GET / * @url POST / */ - public function index($login, $password, $entity=0, $reset=0) { + public function index($login, $password, $entity='', $reset=0) { global $conf, $dolibarr_main_authentication, $dolibarr_auto_user; - + // Authentication mode if (empty($dolibarr_main_authentication)) $dolibarr_main_authentication = 'http,dolibarr'; @@ -62,6 +62,8 @@ class Login // Set authmode $authmode = explode(',', $dolibarr_main_authentication); + if ($entity == '') $entity=1; + include_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php'; $login = checkLoginPassEntity($login, $password, $entity, $authmode); if (empty($login)) @@ -70,21 +72,21 @@ class Login } $token = 'failedtogenerateorgettoken'; - + $tmpuser=new User($this->db); - $tmpuser->fetch(0, $login); - + $tmpuser->fetch(0, $login, 0, 0, $entity); + // Renew the hash if (empty($tmpuser->api_key) || $reset) { // Generate token for user $token = dol_hash($login.uniqid().$conf->global->MAIN_API_KEY,1); - + // We store API token into database $sql = "UPDATE ".MAIN_DB_PREFIX."user"; $sql.= " SET api_key = '".$this->db->escape($token)."'"; $sql.= " WHERE login = '".$this->db->escape($login)."'"; - + dol_syslog(get_class($this)."::login", LOG_DEBUG); // No log $result = $this->db->query($sql); if (!$result) @@ -96,13 +98,14 @@ class Login { $token = $tmpuser->api_key; } - + //return token return array( 'success' => array( 'code' => 200, 'token' => $token, - 'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call). You can use it to make any REST API call, or enter it into the DOLAPIKEY field to use the Dolibarr API explorer.') + 'entity' => $tmpuser->entity, + 'message' => 'Welcome ' . $login.($reset?' - Token is new':' - This is your token (generated by a previous call). You can use it to make any REST API call, or enter it into the DOLAPIKEY field to use the Dolibarr API explorer.') ) ); } diff --git a/htdocs/api/index.php b/htdocs/api/index.php index 1e04590da14..0e54d0cb8af 100644 --- a/htdocs/api/index.php +++ b/htdocs/api/index.php @@ -21,13 +21,21 @@ * \defgroup api Module DolibarrApi * \brief API loader * Search files htdocs//class/api_.class.php - * \file htdocs/api/indexphp - * - * @todo User authentication with api_key + * \file htdocs/api/index.php */ -if (! defined("NOLOGIN")) define("NOLOGIN",'1'); -if (! defined("NOCSRFCHECK")) define("NOCSRFCHECK",'1'); +//if (! defined('NOREQUIREUSER')) define('NOREQUIREUSER','1'); +//if (! defined('NOREQUIREDB')) define('NOREQUIREDB','1'); +//if (! defined('NOREQUIRESOC')) define('NOREQUIRESOC','1'); +//if (! defined('NOREQUIRETRAN')) define('NOREQUIRETRAN','1'); +if (! defined('NOCSRFCHECK')) define('NOCSRFCHECK','1'); // Do not check anti CSRF attack test +//if (! defined('NOSTYLECHECK')) define('NOSTYLECHECK','1'); // Do not check style html tag into posted data +if (! defined('NOTOKENRENEWAL')) define('NOTOKENRENEWAL','1'); // Do not check anti POST attack test +if (! defined('NOREQUIREMENU')) define('NOREQUIREMENU','1'); // If there is no need to load and show top and left menu +if (! defined('NOREQUIREHTML')) define('NOREQUIREHTML','1'); // If we don't need to load the html.form.class.php +if (! defined('NOREQUIREAJAX')) define('NOREQUIREAJAX','1'); // Do not load ajax.lib.php library +if (! defined("NOLOGIN")) define("NOLOGIN",'1'); // If this page is public (can be called outside logged session) + $res=0; if (! $res && file_exists("../main.inc.php")) $res=include '../main.inc.php'; @@ -67,7 +75,31 @@ if (preg_match('/api\/index\.php\/explorer/', $_SERVER["PHP_SELF"]) && ! empty($ } -$api = new DolibarrApi($db); + + +// Analyze URLs +// index.php/explorer do a redirect to index.php/explorer/ +// index.php/explorer/ called by swagger to build explorer page +// index.php/explorer/.../....png|.css|.js called by swagger for resources to build explorer page +// index.php/explorer/resources.json called by swagger to get list of all services +// index.php/explorer/resources.json/xxx called by swagger to get detail of services xxx +// index.php/xxx called by any REST client to run API + + +preg_match('/index\.php\/([^\/]+)(.*)$/', $_SERVER["PHP_SELF"], $reg); +// .../index.php/categories?sortfield=t.rowid&sortorder=ASC + + +// Set the flag to say to refresh (when we reload the explorer, production must be for API call only) +$refreshcache=false; +if (! empty($reg[1]) && $reg[1] == 'explorer' && ($reg[2] == '/resources.json' || $reg[2] == '/resources.json/root')) +{ + $refreshcache=true; +} + + +$api = new DolibarrApi($db, '', $refreshcache); +//var_dump($api->r->apiVersionMap); // Enable the Restler API Explorer. // See https://github.com/Luracast/Restler-API-Explorer for more info. @@ -79,110 +111,82 @@ $api->r->addAuthenticationClass('DolibarrApiAccess',''); // Define accepted mime types UploadFormat::$allowedMimeTypes = array('image/jpeg', 'image/png', 'text/plain', 'application/octet-stream'); -$listofapis = array(); -$modulesdir = dolGetModulesDirs(); -foreach ($modulesdir as $dir) + +// Call Explorer file for all APIs definitions +if (! empty($reg[1]) && $reg[1] == 'explorer' && ($reg[2] == '/resources.json' || $reg[2] == '/resources.json/root')) { - /* - * Search available module - */ - //dol_syslog("Scan directory ".$dir." for API modules"); + // Scan all API files to load them - $handle=@opendir(dol_osencode($dir)); - if (is_resource($handle)) + $listofapis = array(); + + $modulesdir = dolGetModulesDirs(); + foreach ($modulesdir as $dir) { - while (($file = readdir($handle))!==false) + // Search available module + dol_syslog("Scan directory ".$dir." for module descriptor to after search for API files"); + + $handle=@opendir(dol_osencode($dir)); + if (is_resource($handle)) { - if (is_readable($dir.$file) && preg_match("/^mod(.*)\.class\.php$/i",$file,$reg)) + while (($file = readdir($handle))!==false) { - $module = strtolower($reg[1]); - $moduledirforclass = $module; - $moduleforperm = $module; - - if ($module == 'propale') { - $moduledirforclass = 'comm/propal'; - $moduleforperm='propal'; - } - elseif ($module == 'agenda') { - $moduledirforclass = 'comm/action'; - } - elseif ($module == 'adherent') { - $moduledirforclass = 'adherents'; - } - elseif ($module == 'banque') { - $moduledirforclass = 'compta/bank'; - } - elseif ($module == 'categorie') { - $moduledirforclass = 'categories'; - } - elseif ($module == 'facture') { - $moduledirforclass = 'compta/facture'; - } - elseif ($module == 'project') { - $moduledirforclass = 'projet'; - } - elseif ($module == 'task') { - $moduledirforclass = 'projet'; - } - elseif ($module == 'stock') { - $moduledirforclass = 'product/stock'; - } - elseif ($module == 'fournisseur') { - $moduledirforclass = 'fourn'; - } - //dol_syslog("Found module file ".$file." - module=".$module." - moduledirforclass=".$moduledirforclass); - - // Defined if module is enabled - $enabled=true; - if (empty($conf->$moduleforperm->enabled)) $enabled=false; - - if ($enabled) + if (is_readable($dir.$file) && preg_match("/^mod(.*)\.class\.php$/i",$file,$reg)) { - /* - * If exists, load the API class for enable module - * - * Search files named api_.class.php into /htdocs//class directory - * - * @todo : use getElementProperties() function ? - */ - $dir_part = dol_buildpath('/'.$moduledirforclass.'/class/'); + $module = strtolower($reg[1]); + $moduledirforclass = getModuleDirForApiClass($module); + $moduleforperm = $module; + if ($module == 'propale') { $moduleforperm='propal'; } - $handle_part=@opendir(dol_osencode($dir_part)); - if (is_resource($handle_part)) + //dol_syslog("Found module file ".$file." - module=".$module." - moduledirforclass=".$moduledirforclass); + + // Defined if module is enabled + $enabled=true; + if (empty($conf->$moduleforperm->enabled)) $enabled=false; + + if ($enabled) { - while (($file_searched = readdir($handle_part))!==false) - { - if ($file_searched == 'api_access.class.php') continue; + // If exists, load the API class for enable module + // Search files named api_.class.php into /htdocs//class directory + // @todo : use getElementProperties() function ? + $dir_part = dol_buildpath('/'.$moduledirforclass.'/class/'); - // Support of the deprecated API. - if (is_readable($dir_part.$file_searched) && preg_match("/^api_deprecated_(.*)\.class\.php$/i",$file_searched,$reg)) + $handle_part=@opendir(dol_osencode($dir_part)); + if (is_resource($handle_part)) + { + while (($file_searched = readdir($handle_part))!==false) { - $classname = ucwords($reg[1]).'Api'; - require_once $dir_part.$file_searched; - if (class_exists($classname)) + if ($file_searched == 'api_access.class.php') continue; + + // Support of the deprecated API. + if (is_readable($dir_part.$file_searched) && preg_match("/^api_deprecated_(.*)\.class\.php$/i",$file_searched,$reg)) { - //dol_syslog("Found deprecated API by index.php: classname=".$classname." for module ".$dir." into ".$dir_part.$file_searched); - $api->r->addAPIClass($classname, '/'); + $classname = ucwords($reg[1]).'Api'; + require_once $dir_part.$file_searched; + if (class_exists($classname)) + { + //dol_syslog("Found deprecated API by index.php: classname=".$classname." for module ".$dir." into ".$dir_part.$file_searched); + $api->r->addAPIClass($classname, '/'); + } + else + { + dol_syslog("We found an api_xxx file (".$file_searched.") but class ".$classname." does not exists after loading file", LOG_WARNING); + } } - else + elseif (is_readable($dir_part.$file_searched) && preg_match("/^api_(.*)\.class\.php$/i",$file_searched,$reg)) { - dol_syslog("We found an api_xxx file (".$file_searched.") but class ".$classname." does not exists after loading file", LOG_WARNING); - } - } - elseif (is_readable($dir_part.$file_searched) && preg_match("/^api_(.*)\.class\.php$/i",$file_searched,$reg)) - { - $classname = ucwords($reg[1]); - $classname = str_replace('_', '', $classname); - require_once $dir_part.$file_searched; - if (class_exists($classname)) - { - //dol_syslog("Found API by index.php: classname=".$classname." for module ".$dir." into ".$dir_part.$file_searched); - $listofapis[] = $classname; - } - else - { - dol_syslog("We found an api_xxx file (".$file_searched.") but class ".$classname." does not exists after loading file", LOG_WARNING); + $classname = ucwords($reg[1]); + $classname = str_replace('_', '', $classname); + require_once $dir_part.$file_searched; + if (class_exists($classname)) + { + //dol_syslog("Found API by index.php: classname=".$classname." for module ".$dir." into ".$dir_part.$file_searched); + $listofapis[] = $classname; + } + else + { + dol_syslog("We found an api_xxx file (".$file_searched.") but class ".$classname." does not exists after loading file", LOG_WARNING); + } } } } @@ -191,20 +195,60 @@ foreach ($modulesdir as $dir) } } } + + // Sort the classes before adding them to Restler. + // The Restler API Explorer shows the classes in the order they are added and it's a mess if they are not sorted. + sort($listofapis); + foreach ($listofapis as $classname) + { + $api->r->addAPIClass($classname); + } } -// Sort the classes before adding them to Restler. The Restler API Explorer -// shows the classes in the order they are added and it's a mess if they are -// not sorted. -sort($listofapis); -//var_dump($listofapis); -foreach ($listofapis as $classname) +// Call one APIs or one definition of an API +if (! empty($reg[1]) && ($reg[1] != 'explorer' || ($reg[2] != '/resources.json' && preg_match('/^\/resources.json\/(.+)$/', $reg[2], $regbis)))) { - $api->r->addAPIClass($classname); + $module = $reg[1]; + if ($module == 'explorer') // If we call page to explore details of a service + { + $module = $regbis[1]; + } + + // Load a dedicated API file + dol_syslog("Load a dedicated API file"); + + $module=strtolower($module); + $moduledirforclass = getModuleDirForApiClass($module); + + if (in_array($module, array('category','contact','customer','invoice','order','product','thirdparty','user'))) // Old Apis + { + $classfile = $module; + if ($module == 'customer') { $classfile = 'thirdparty'; } + if ($module == 'order') { $classfile = 'commande'; } + $dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_deprecated_'.$classfile.'.class.php'); + $classname=ucwords($module); + if ($module == 'customer') { $classname='Thirdparty'; } + if ($module == 'order') { $classname='Commande'; } + //var_dump($classfile);var_dump($classname);exit; + + require_once $dir_part_file; + if (class_exists($classname.'Api')) $api->r->addAPIClass($classname.'Api', '/'); + } + else + { + $classfile = str_replace('_', '', $module); + if ($module == 'supplierinvoices') $classfile = 'supplier_invoices'; + $dir_part_file = dol_buildpath('/'.$moduledirforclass.'/class/api_'.$classfile.'.class.php'); + $classname=ucwords($module); + + require_once $dir_part_file; + if (class_exists($classname)) $api->r->addAPIClass($classname); + } } // TODO If not found, redirect to explorer -//var_dump($api); +//var_dump($api->r->apiVersionMap); +//exit; // Call API (we suppose we found it) $api->r->handle(); diff --git a/htdocs/comm/action/listactions.php b/htdocs/comm/action/listactions.php index 01094a78164..35fccdef2c8 100644 --- a/htdocs/comm/action/listactions.php +++ b/htdocs/comm/action/listactions.php @@ -80,7 +80,7 @@ $limit = GETPOST('limit','int')?GETPOST('limit','int'):$conf->liste_limit; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $limit * $page ; if (! $sortorder) { diff --git a/htdocs/comm/action/rapport/index.php b/htdocs/comm/action/rapport/index.php index e83506d8206..dcda4e0cf04 100644 --- a/htdocs/comm/action/rapport/index.php +++ b/htdocs/comm/action/rapport/index.php @@ -42,7 +42,7 @@ $limit = GETPOST('limit')?GETPOST('limit','int'):$conf->liste_limit; $sortfield = GETPOST("sortfield",'alpha'); $sortorder = GETPOST("sortorder",'alpha'); $page = GETPOST("page",'int'); -if ($page == -1) { $page = 0 ; } +if ($page == -1 || $page == null) { $page = 0 ; } $offset = $limit * $page ; if (! $sortorder) $sortorder="DESC"; if (! $sortfield) $sortfield="a.datep"; diff --git a/htdocs/compta/bank/bankentries.php b/htdocs/compta/bank/bankentries.php index d9dd8241248..2bc2242abc4 100644 --- a/htdocs/compta/bank/bankentries.php +++ b/htdocs/compta/bank/bankentries.php @@ -108,7 +108,7 @@ $offset = $limit * $page; $pageprev = $page - 1; $pagenext = $page + 1; if (! $sortorder) $sortorder='ASC'; -if (! $sortfield) $sortfield='b.datev'; +if (! $sortfield) $sortfield='b.datev, b.dateo, b.rowid'; $mode_balance_ok=false; //if (($sortfield == 'b.datev' || $sortfield == 'b.datev, b.dateo, b.rowid')) // TODO Manage balance when account not selected @@ -436,6 +436,7 @@ if ($id > 0 || ! empty($ref)) print ''.$langs->trans("Conciliate").''; } } + print ''; } } @@ -636,6 +637,7 @@ if ($resql) // print ''; } + /// ajax to adjust value date with plus and less picto print '