diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e7edb002653..328005d7a4d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -235,25 +235,26 @@ repos: - id: shellcheck args: [-W, "100"] + # Check sql file syntax - repo: https://github.com/sqlfluff/sqlfluff rev: 3.0.4 hooks: - id: sqlfluff-lint stages: [pre-commit, manual] # manual needed for ci exclude: (?x)^ - (htdocs/includes/.* - |htdocs/install/doctemplates/websites/.*_template + (dev/initdemo/mysqldump_.*\.sql |htdocs/core/menus/init_menu_auguria\.sql - |htdocs/install/doctemplates/websites/website_template-.*\.sql - |(htdocs/install/mysql/data/(llx_20_c_departements\.sql - |llx_accounting_account_.*\.sql) - |(htdocs/install/mysql/migration/3\.[256]\.0-.*\.sql) - ) + |htdocs/includes/.* + |htdocs/install/doctemplates/websites/.*_template + |htdocs/install/doctemplates/websites/website_template.*\.sql + |htdocs/install/mysql/data/llx_20_c_departements\.sql + |htdocs/install/mysql/data/llx_accounting_account_.*\.sql + |htdocs/install/mysql/migration/3\..*\.sql |htdocs/install/mysql/migration/(1[0-5]|[456789])\.0\.0-.*\.sql - |htdocs/install/mysql/migration/3\.([0134789])\.0-.*\.sql |htdocs/install/mysql/migration/repair\.sql |htdocs/install/mysql/tables/llx_bookcal_availabilities-bookcal\.sql - |htdocs/install/mysql/tables/llx_categorie(_(account|actioncomm|contact|fournisseur|knowledgemanagement-knowledgemanagement|member|product|project|societe|ticket-ticket|user|warehouse|website_page-website)?\.key\.sql) + |htdocs/install/mysql/tables/llx_categorie.*\.key\.sql |htdocs/install/mysql/tables/llx_rights_def\.key\.sql - |htdocs/install/pgsql/functions/functions(-(don|loan|mailing|opensurvey|partnership|recruitment|website))?\.sql + |htdocs/install/pgsql/functions/functions.*\.sql + |htdocs/modulebuilder/template/sql/.*\.sql )$ diff --git a/dev/setup/pre-commit/README.md b/dev/setup/pre-commit/README.md index c2a1e4901cb..e610a55c411 100644 --- a/dev/setup/pre-commit/README.md +++ b/dev/setup/pre-commit/README.md @@ -25,7 +25,10 @@ the project: `pre-commit-config.yaml`. 1. Install pre-commit tool.\ If you do not have python installed, install [python](https://www.python.org) first.\ + `sudo apt install python3` + If you do not have [`pip`](https://pypi.org/project/pip), install that as well.\\ + `sudo apt install pip` Then you can install pre-commit tool: `python3 -m pip install pre-commit` diff --git a/htdocs/admin/openid_connect.php b/htdocs/admin/openid_connect.php new file mode 100644 index 00000000000..baa95cb2519 --- /dev/null +++ b/htdocs/admin/openid_connect.php @@ -0,0 +1,249 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/openid_connect.php + * \ingroup openid_connect + * \brief Page to setup openid_connect module + */ + +// Load Dolibarr environment +require '../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/admin.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/openid_connect.lib.php'; +require_once DOL_DOCUMENT_ROOT.'/core/class/html.form.class.php'; +dol_include_once('/core/lib/openid_connect.lib.php'); + +$langs->load("admin"); +$langs->load("openidconnect"); + +if (!$user->admin) accessforbidden(); + +$action = GETPOST('action', 'alpha'); + + +/* + * Actions + */ + +$errors = []; +$error = 0; + +if ($action == 'set') { + $client_id = GETPOST('MAIN_AUTHENTICATION_OIDC_LOGIN_CLAIM', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_LOGIN_CLAIM', $client_id, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $client_id = GETPOST('MAIN_AUTHENTICATION_OIDC_CLIENT_ID', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_CLIENT_ID', $client_id, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $client_secret = GETPOST('MAIN_AUTHENTICATION_OIDC_CLIENT_SECRET', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_CLIENT_SECRET', $client_secret, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $scopes = GETPOST('MAIN_AUTHENTICATION_OIDC_SCOPES', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_SCOPES', $scopes, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $authorize_url = GETPOST('MAIN_AUTHENTICATION_OIDC_AUTHORIZE_URL', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_AUTHORIZE_URL', $authorize_url, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $value = GETPOST('MAIN_AUTHENTICATION_OIDC_TOKEN_URL', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_TOKEN_URL', $value, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $value = GETPOST('MAIN_AUTHENTICATION_OIDC_USERINFO_URL', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_USERINFO_URL', $value, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } + + $logout_url = GETPOST('MAIN_AUTHENTICATION_OIDC_LOGOUT_URL', 'alpha'); + $res = dolibarr_set_const($db, 'MAIN_AUTHENTICATION_OIDC_LOGOUT_URL', $logout_url, 'chaine', 0, '', 0); + if (!$res > 0) { + $errors[] = $db->lasterror(); + $error++; + } +} + +if ($action != '') { + if (!$error) { + setEventMessage($langs->trans("SetupSaved")); + header("Location: " . $_SERVER["PHP_SELF"]); + exit; + } else { + setEventMessages('', $errors, 'errors'); + } +} + + +/* + * View + */ + +$form = new Form($db); + +llxHeader(); + +$linkback=''.$langs->trans("BackToModuleList").''; +print load_fiche_titre($langs->trans("OpenIDconnectSetup"), $linkback, 'title_setup'); +print "
\n"; + +$head = openid_connect_prepare_head(); + +print dol_get_fiche_head($head, 'settings', $langs->trans("Parameters"), 0, 'action'); + + +print '
'; +print '
'; +print ''; +print ''; + +$var=true; + +print ''; +print ''; +print ''."\n"; +print ''."\n"; +print ''."\n"; +print "\n"; + +// MAIN_AUTHENTICATION_OIDC_LOGIN_CLAIM +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_CLIENT_ID +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_CLIENT_SECRET +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_SCOPES +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_AUTHORIZE_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_TOKEN_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_USERINFO_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// MAIN_AUTHENTICATION_OIDC_LOGOUT_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// REDIRECT_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +// LOGOUT_URL +$var = !$var; +print '' . "\n"; +print ''."\n"; +print ''."\n"; +print ''; +print '' . "\n"; + +print '
'.$langs->trans("Parameters").' '.$langs->trans("Value").'
'.$langs->trans("MainAuthenticationOidcLoginClaimName").''.$langs->trans("MainAuthenticationOidcLoginClaimDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcClientIdName").''.$langs->trans("MainAuthenticationOidcClientIdDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcClientSecretName").''.$langs->trans("MainAuthenticationOidcClientSecretDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcScopesName").''.$langs->trans("MainAuthenticationOidcScopesDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcAuthorizeUrlName").''.$langs->trans("MainAuthenticationOidcAuthorizeUrlDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcTokenUrlName").''.$langs->trans("MainAuthenticationOidcTokenUrlDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcUserinfoUrlName").''.$langs->trans("MainAuthenticationOidcUserinfoUrlDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcLogoutUrlName").''.$langs->trans("MainAuthenticationOidcLogoutUrlDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcRedirectUrlName").''.$langs->trans("MainAuthenticationOidcRedirectUrlDesc").'' . "\n"; +print '
'.$langs->trans("MainAuthenticationOidcLogoutRedirectUrlName").''.$langs->trans("MainAuthenticationOidcLogoutRedirectUrlDesc").'' . "\n"; +print '
'."\n"; + +print '
'; +print '
'; +print ''; +print '
'; + +print '
'; + +print '
'; + +print dol_get_fiche_end(); + +llxFooter(); diff --git a/htdocs/comm/card.php b/htdocs/comm/card.php index 46758f40670..ff2d9fd5aa6 100644 --- a/htdocs/comm/card.php +++ b/htdocs/comm/card.php @@ -42,6 +42,7 @@ require_once DOL_DOCUMENT_ROOT.'/contact/class/contact.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formcompany.class.php'; require_once DOL_DOCUMENT_ROOT.'/categories/class/categorie.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formfile.class.php'; +require_once DOL_DOCUMENT_ROOT . '/projet/class/project.class.php'; if (isModEnabled('invoice')) { require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture-rec.class.php'; @@ -311,6 +312,7 @@ $contactstatic = new Contact($db); $userstatic = new User($db); $form = new Form($db); $formcompany = new FormCompany($db); +$project = new Project($db); $title = $langs->trans("ThirdParty")." - ".$langs->trans('Customer'); if (getDolGlobalString('MAIN_HTML_TITLE') && preg_match('/thirdpartynameonly/', getDolGlobalString('MAIN_HTML_TITLE')) && $object->name) { @@ -824,7 +826,7 @@ if ($object->id > 0) { if (isModEnabled("propal") && $user->hasRight('propal', 'lire')) { $langs->load("propal"); - $sql = "SELECT s.nom, s.rowid, p.rowid as propalid, p.fk_statut, p.total_ht"; + $sql = "SELECT s.nom, s.rowid, p.rowid as propalid, p.fk_projet, p.fk_statut, p.total_ht"; $sql .= ", p.total_tva"; $sql .= ", p.total_ttc"; $sql .= ", p.ref, p.ref_client, p.remise"; @@ -845,7 +847,7 @@ if ($object->id > 0) { print ''; print ''; - print '
'; + print ''; print ''; @@ -861,6 +863,7 @@ if ($object->id > 0) { $propal_static->ref = $objp->ref; $propal_static->ref_client = $objp->ref_client; // deprecated $propal_static->ref_customer = $objp->ref_client; + $propal_static->fk_project = $objp->fk_projet; $propal_static->total_ht = $objp->total_ht; $propal_static->total_tva = $objp->total_tva; $propal_static->total_ttc = $objp->total_ttc; @@ -891,6 +894,11 @@ if ($object->id > 0) { $relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf'; print $formfile->showPreview($file_list, $propal_static->element, $relativepath, 0); } + print '
'.$langs->trans("LastPropals", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllPropals").''.$num.''; print ''; print '
'.$langs->trans("LastPropals", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllPropals").''.$num.''.img_picto($langs->trans("Statistics"), 'stats').'
'; + if ($propal_static->fk_project > 0) { + $project->fetch($propal_static->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = $conf->propal->multidir_output[$objp->entity].'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/comm/propal/card.php?id='.$objp->cid; @@ -921,7 +929,7 @@ if ($object->id > 0) { $param =""; $sql = "SELECT s.nom, s.rowid"; - $sql .= ", c.rowid as cid, c.entity, c.total_ht"; + $sql .= ", c.rowid as cid, c.entity, c.fk_projet, c.total_ht"; $sql .= ", c.total_tva"; $sql .= ", c.total_ttc"; $sql .= ", c.ref, c.ref_client, c.fk_statut, c.facture"; @@ -957,7 +965,7 @@ if ($object->id > 0) { print ''; print ''; - print '
'; + print ''; print ''; @@ -970,6 +978,7 @@ if ($object->id > 0) { $commande_static->id = $objp->cid; $commande_static->ref = $objp->ref; $commande_static->ref_client = $objp->ref_client; + $commande_static->fk_project = $objp->fk_projet; $commande_static->total_ht = $objp->total_ht; $commande_static->total_tva = $objp->total_tva; $commande_static->total_ttc = $objp->total_ttc; @@ -1003,6 +1012,11 @@ if ($object->id > 0) { $relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf'; print $formfile->showPreview($file_list, $commande_static->element, $relativepath, 0, $param); } + print '
'.$langs->trans("LastCustomerOrders", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllOrders").''.$num.''; print ''; print '
'.$langs->trans("LastCustomerOrders", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllOrders").''.$num.''.img_picto($langs->trans("Statistics"), 'stats').'
'; + if ($commande_static->fk_project > 0) { + $project->fetch($commande_static->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = $conf->order->multidir_output[$objp->entity].'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/commande/card.php?id='.$objp->cid; @@ -1030,7 +1044,7 @@ if ($object->id > 0) { */ if (isModEnabled("shipping") && $user->hasRight('expedition', 'lire')) { $sql = 'SELECT e.rowid as id'; - $sql .= ', e.ref, e.entity'; + $sql .= ', e.ref, e.entity, e.fk_projet'; $sql .= ', e.date_creation'; $sql .= ', e.fk_statut as statut'; $sql .= ', s.nom'; @@ -1056,7 +1070,7 @@ if ($object->id > 0) { print ''; print ''; - print '
'; + print ''; print ''; @@ -1068,6 +1082,7 @@ if ($object->id > 0) { $sendingstatic->id = $objp->id; $sendingstatic->ref = $objp->ref; + $sendingstatic->fk_project = $objp->fk_projet; print ''; print ''; } - print ''; + print ''; print "\n"; $i++; } @@ -1127,7 +1147,7 @@ if ($object->id > 0) { * Latest contracts */ if (isModEnabled('contract') && $user->hasRight('contrat', 'lire')) { - $sql = "SELECT s.nom, s.rowid, c.rowid as id, c.ref as ref, c.statut as contract_status, c.datec as dc, c.date_contrat as dcon, c.ref_customer as refcus, c.ref_supplier as refsup, c.entity,"; + $sql = "SELECT s.nom, s.rowid, c.rowid as id, c.ref as ref, c.fk_projet, c.statut as contract_status, c.datec as dc, c.date_contrat as dcon, c.ref_customer as refcus, c.ref_supplier as refsup, c.entity,"; $sql .= " c.last_main_doc, c.model_pdf"; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."contrat as c"; $sql .= " WHERE c.fk_soc = s.rowid "; @@ -1145,7 +1165,7 @@ if ($object->id > 0) { print '
'.$langs->trans("LastSendings", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllSendings").''.$num.''; print ''; print '
'.$langs->trans("LastSendings", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllSendings").''.$num.''.img_picto($langs->trans("Statistics"), 'stats').'
'; @@ -1097,6 +1112,11 @@ if ($object->id > 0) { $relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf'; print $formfile->showPreview($file_list, $sendingstatic->table_element, $relativepath, 0, $param); } + print ''; + if ($sendingstatic->fk_project > 0) { + $project->fetch($sendingstatic->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = $conf->expedition->multidir_output[$objp->entity].'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/expedition/card.php?id='.$objp->cid; @@ -1108,7 +1128,7 @@ if ($object->id > 0) { print '!!!'.$sendingstatic->LibStatut($objp->statut, 5).''.$sendingstatic->LibStatut($objp->statut, 5).'
'; print ''; - print '
'; + print ''; @@ -1160,6 +1180,7 @@ if ($object->id > 0) { $contrat->ref = $objp->ref ? $objp->ref : $objp->id; $contrat->ref_customer = $objp->refcus; $contrat->ref_supplier = $objp->refsup; + $contrat->fk_project = $objp->fk_projet; $contrat->statut = $objp->contract_status; $contrat->last_main_doc = $objp->last_main_doc; $contrat->model_pdf = $objp->model_pdf; @@ -1204,6 +1225,11 @@ if ($object->id > 0) { print $formfile->showPreview($file_list, $contrat->element, $relativepath, 0); } } + print '
'.$langs->trans("LastContracts", ($num <= $MAXLIST ? "" : $MAXLIST)).''; print ''; //print ''; print '
'.$langs->trans("LastContracts", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllContracts").''.$num.''.img_picto($langs->trans("Statistics"),'stats').'
'; + if ($contrat->fk_project > 0) { + $project->fetch($contrat->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = $conf->contrat->multidir_output[$objp->entity].'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/contrat/card.php?id='.$objp->cid; @@ -1237,7 +1263,7 @@ if ($object->id > 0) { * Latest interventions */ if (isModEnabled('intervention') && $user->hasRight('ficheinter', 'lire')) { - $sql = "SELECT s.nom, s.rowid, f.rowid as id, f.ref, f.fk_statut, f.duree as duration, f.datei as startdate, f.entity"; + $sql = "SELECT s.nom, s.rowid, f.rowid as id, f.ref, f.fk_projet, f.fk_statut, f.duree as duration, f.datei as startdate, f.entity"; $sql .= " FROM ".MAIN_DB_PREFIX."societe as s, ".MAIN_DB_PREFIX."fichinter as f"; $sql .= " WHERE f.fk_soc = s.rowid"; $sql .= " AND s.rowid = ".((int) $object->id); @@ -1254,7 +1280,7 @@ if ($object->id > 0) { print ''; print ''; - print '
'; + print ''; print ''; @@ -1267,6 +1293,7 @@ if ($object->id > 0) { $fichinter_static->id = $objp->id; $fichinter_static->ref = $objp->ref; $fichinter_static->statut = $objp->fk_statut; + $fichinter_static->fk_project = $objp->fk_projet; print ''; print '
'.$langs->trans("LastInterventions", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllInterventions").''.$num.''; print ''; print '
'.$langs->trans("LastInterventions", ($num <= $MAXLIST ? "" : $MAXLIST)).''.$langs->trans("AllInterventions").''.$num.''.img_picto($langs->trans("Statistics"), 'stats').'
'; @@ -1296,6 +1323,11 @@ if ($object->id > 0) { $relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf'; print $formfile->showPreview($file_list, $fichinter_static->element, $relativepath, 0); } + print ''; + if ($fichinter_static->fk_project > 0) { + $project->fetch($fichinter_static->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = getMultidirOutput($fichinter_static).'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/fichinter/card.php?id='.$objp->cid; @@ -1323,7 +1355,7 @@ if ($object->id > 0) { * Latest invoices templates */ if (isModEnabled('invoice') && $user->hasRight('facture', 'lire')) { - $sql = 'SELECT f.rowid as id, f.titre as ref'; + $sql = 'SELECT f.rowid as id, f.titre as ref, f.fk_projet'; $sql .= ', f.total_ht'; $sql .= ', f.total_tva'; $sql .= ', f.total_ttc'; @@ -1351,7 +1383,7 @@ if ($object->id > 0) { print '
'; print ''; print ''; - $colspan = 4; + $colspan = 5; if (getDolGlobalString('MAIN_SHOW_PRICE_WITH_TAX_IN_SUMMARIES')) { $colspan++; } @@ -1369,6 +1401,7 @@ if ($object->id > 0) { $invoicetemplate->id = $objp->id; $invoicetemplate->ref = $objp->ref; + $invoicetemplate->fk_project = $objp->fk_projet; $invoicetemplate->suspended = $objp->suspended; $invoicetemplate->frequency = $objp->frequency; $invoicetemplate->unit_frequency = $objp->unit_frequency; @@ -1381,6 +1414,11 @@ if ($object->id > 0) { print ''; print ''; if ($objp->frequency && $objp->date_last_gen > 0) { @@ -1424,7 +1462,7 @@ if ($object->id > 0) { * Latest invoices */ if (isModEnabled('invoice') && $user->hasRight('facture', 'lire')) { - $sql = 'SELECT f.rowid as facid, f.ref, f.type, f.ref_client'; + $sql = 'SELECT f.rowid as facid, f.ref, f.type, f.ref_client, f.fk_projet'; $sql .= ', f.total_ht'; $sql .= ', f.total_tva'; $sql .= ', f.total_ttc'; @@ -1450,7 +1488,7 @@ if ($object->id > 0) { print '
'; print '
'; print $invoicetemplate->getNomUrl(1); + print ''; + if ($invoicetemplate->fk_project > 0) { + $project->fetch($invoicetemplate->fk_project); + print $project->getNomUrl(1); + } print '
'; print ''; - $colspan = 5; + $colspan = 6; if (getDolGlobalString('MAIN_SHOW_PRICE_WITH_TAX_IN_SUMMARIES')) { $colspan++; } @@ -1472,6 +1510,7 @@ if ($object->id > 0) { $facturestatic->id = $objp->facid; $facturestatic->ref = $objp->ref; $facturestatic->ref_client = $objp->ref_client; + $facturestatic->fk_project = $objp->fk_projet; $facturestatic->type = $objp->type; $facturestatic->total_ht = $objp->total_ht; $facturestatic->total_tva = $objp->total_tva; @@ -1512,6 +1551,11 @@ if ($object->id > 0) { $relativepath = dol_sanitizeFileName($objp->ref).'/'.dol_sanitizeFileName($objp->ref).'.pdf'; print $formfile->showPreview($file_list, $facturestatic->element, $relativepath, 0); } + print '
'; + if ($facturestatic->fk_project > 0) { + $project->fetch($facturestatic->fk_project); + print $project->getNomUrl(1); + } // $filename = dol_sanitizeFileName($objp->ref); // $filedir = $conf->facture->multidir_output[$objp->entity].'/'.dol_sanitizeFileName($objp->ref); // $urlsource = '/compta/facture/card.php?id='.$objp->cid; diff --git a/htdocs/compta/prelevement/class/bonprelevement.class.php b/htdocs/compta/prelevement/class/bonprelevement.class.php index 9f60156c6a8..e8770f12f0e 100644 --- a/htdocs/compta/prelevement/class/bonprelevement.class.php +++ b/htdocs/compta/prelevement/class/bonprelevement.class.php @@ -2211,13 +2211,13 @@ class BonPrelevement extends CommonObject $XML_DEBITOR .= ' false' . $CrLf; $XML_DEBITOR .= ' ' . $CrLf; $XML_DEBITOR .= ' ' . $CrLf; + $XML_DEBITOR .= ' ' . $CrLf; + $XML_DEBITOR .= ' ' . $CrLf; if (getDolGlobalInt('WITHDRAWAL_WITHOUT_BIC')==0) { - $XML_DEBITOR .= ' ' . $CrLf; - $XML_DEBITOR .= ' ' . $CrLf; $XML_DEBITOR .= ' ' . $row_bic . '' . $CrLf; - $XML_DEBITOR .= ' ' . $CrLf; - $XML_DEBITOR .= ' ' . $CrLf; } + $XML_DEBITOR .= ' ' . $CrLf; + $XML_DEBITOR .= ' ' . $CrLf; $XML_DEBITOR .= ' ' . $CrLf; $XML_DEBITOR .= ' ' . dolEscapeXML(strtoupper(dol_string_nospecial(dol_string_unaccent($row_nom), ' '))) . '' . $CrLf; $XML_DEBITOR .= ' ' . $CrLf; diff --git a/htdocs/core/boxes/box_factures_imp.php b/htdocs/core/boxes/box_factures_imp.php index 4c7473046d5..86e9b986a31 100644 --- a/htdocs/core/boxes/box_factures_imp.php +++ b/htdocs/core/boxes/box_factures_imp.php @@ -139,10 +139,9 @@ class box_factures_imp extends ModeleBoxes while ($line < min($num, $this->max)) { $objp = $this->db->fetch_object($result); - $datelimite = $this->db->jdate($objp->datelimite); $date = $this->db->jdate($objp->date); $datem = $this->db->jdate($objp->tms); - $datelimit = $this->db->jdate(datelimite); + $datelimit = $this->db->jdate($objp->datelimite); $facturestatic->id = $objp->facid; $facturestatic->ref = $objp->ref; @@ -182,7 +181,7 @@ class box_factures_imp extends ModeleBoxes $late = ''; if ($facturestatic->hasDelay()) { // @phan-suppress-next-line PhanPluginPrintfVariableFormatString - $late = img_warning(sprintf($l_due_date, dol_print_date($datelimite, 'day', 'tzuserrel'))); + $late = img_warning(sprintf($l_due_date, dol_print_date($datelimit, 'day', 'tzuserrel'))); } $this->info_box_contents[$line][] = array( @@ -204,8 +203,8 @@ class box_factures_imp extends ModeleBoxes ); $this->info_box_contents[$line][] = array( - 'td' => 'class="center nowraponall" title="'.dol_escape_htmltag($langs->trans("DateDue").': '.dol_print_date($datelimite, 'day', 'tzuserrel')).'"', - 'text' => dol_print_date($datelimite, 'day', 'tzuserrel'), + 'td' => 'class="center nowraponall" title="'.dol_escape_htmltag($langs->trans("DateDue").': '.dol_print_date($datelimit, 'day', 'tzuserrel')).'"', + 'text' => dol_print_date($datelimit, 'day', 'tzuserrel'), ); $this->info_box_contents[$line][] = array( diff --git a/htdocs/core/lib/openid_connect.lib.php b/htdocs/core/lib/openid_connect.lib.php new file mode 100644 index 00000000000..21cf8ef30cc --- /dev/null +++ b/htdocs/core/lib/openid_connect.lib.php @@ -0,0 +1,76 @@ + + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/admin/openid_connect.php + * \ingroup openid_connect + * \brief Functions for the module openid_connect + */ + +/** + * Prepare array with list of tabs + * + * @return array Array of tabs to show + */ +function openid_connect_prepare_head() +{ + global $langs, $conf, $user; + $h = 0; + $head = array(); + + $head[$h][0] = dol_buildpath("/admin/openid_connect.php", 1); + $head[$h][1] = $langs->trans("Parameters"); + $head[$h][2] = 'settings'; + $h++; + + complete_head_from_modules($conf, $langs, null, $head, $h, 'openid_connect_admin'); + + return $head; +} + + +/** + * return the current state + * + * @return string String containing the state + */ +function openid_connect_get_state() +{ + return hash('sha256', session_id()); +} + + +/** + * return the redirect url + * + * @return string Redirect url + */ +function openid_connect_get_redirect_url() +{ + return DOL_MAIN_URL_ROOT . '/core/modules/openid_connect/callback.php'; +} + + +/** + * Return authentication url + * + * @return string Authentication url + */ +function openid_connect_get_url() +{ + return getDolGlobalString('MAIN_AUTHENTICATION_OIDC_AUTHORIZE_URL') . '?client_id=' . getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_ID') . '&redirect_uri=' . openid_connect_get_redirect_url() . '&scope=' . getDolGlobalString('MAIN_AUTHENTICATION_OIDC_SCOPES') . '&response_type=code&state=' . openid_connect_get_state(); +} diff --git a/htdocs/core/login/functions_openid_connect.php b/htdocs/core/login/functions_openid_connect.php index 81b829b1890..82689da653c 100644 --- a/htdocs/core/login/functions_openid_connect.php +++ b/htdocs/core/login/functions_openid_connect.php @@ -27,6 +27,7 @@ */ include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php'; +include_once DOL_DOCUMENT_ROOT.'/core/lib/openid_connect.lib.php'; /** * Check validity of user/password/entity @@ -41,6 +42,12 @@ function check_user_password_openid_connect($usertotest, $passwordtotest, $entit { global $db; + if (getDolGlobalInt('MAIN_MODULE_OPENIDCONNECT', 0) <= 0) { + $_SESSION["dol_loginmesg"] = "OpenID Connect is disabled"; + dol_syslog("functions_openid_connect::check_user_password_openid_connect Module disabled"); + return false; + } + // Force master entity in transversal mode $entity = $entitytotest; if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) { @@ -72,7 +79,7 @@ function check_user_password_openid_connect($usertotest, $passwordtotest, $entit $state = GETPOST('state', 'aZ09'); dol_syslog('functions_openid_connect::check_user_password_openid_connect code='.$auth_code.' state='.$state); - if ($state !== hash('sha256', session_id())) { + if ($state !== openid_connect_get_state()) { // State does not match $_SESSION["dol_loginmesg"] = "Error in OAuth 2.0 flow (state does not match)"; dol_syslog("functions_openid_connect::check_user_password_openid_connect::state does not match", LOG_ERR); @@ -85,7 +92,7 @@ function check_user_password_openid_connect($usertotest, $passwordtotest, $entit 'client_id' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_ID'), 'client_secret' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_SECRET'), 'code' => $auth_code, - 'redirect_uri' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_REDIRECT_URL') + 'redirect_uri' => openid_connect_get_redirect_url() ]; $token_response = getURLContent(getDolGlobalString('MAIN_AUTHENTICATION_OIDC_TOKEN_URL'), 'POST', http_build_query($auth_param), 1, array(), array('https'), 2); diff --git a/htdocs/core/modules/modOpenIDConnect.class.php b/htdocs/core/modules/modOpenIDConnect.class.php new file mode 100644 index 00000000000..d8166c46ec0 --- /dev/null +++ b/htdocs/core/modules/modOpenIDConnect.class.php @@ -0,0 +1,113 @@ + + * Copyright (C) 2015 Frederic France + * Copyright (C) 2023 Maximilien Rozniecki + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** \defgroup openid_connect Module OpenID Connect + * \brief Module for activation of OpenID Connect authentication method + */ + +/** + * \file htdocs/core/modules/modOpenIDConnect.class.php + * \ingroup openid_connect + * \brief Description and activation file for the module OpenID Connect + */ +include_once DOL_DOCUMENT_ROOT.'/core/modules/DolibarrModules.class.php'; + + + +/** + * Class to describe and activate module OpenID Connect + */ +class modOpenIDConnect extends DolibarrModules +{ + /** + * Constructor + * + * @param DoliDB $db Database handler + */ + public function __construct($db) + { + $this->db = $db; + $this->numero = 69000; // ToDo + // Family can be 'crm','financial','hr','projects','products','ecm','technic','other' + // It is used to group modules in module setup page + $this->family = "interface"; + $this->module_position = '32'; + // Module label (no space allowed), used if translation string 'ModuleXXXName' not found (where XXX is value of numeric property 'numero' of module) + $this->name = preg_replace('/^mod/i', '', get_class($this)); + // Module description, used if translation string 'ModuleXXXDesc' not found (where XXX is value of numeric property 'numero' of module) + $this->description = "Enable OpenID Connect authentication"; + // Possible values for version are: 'development', 'experimental', 'dolibarr' or 'dolibarr_deprecated' or version + $this->version = 'dolibarr'; + $this->const_name = 'MAIN_MODULE_'.strtoupper($this->name); + // Name of image file used for this module. + // If file is in theme/yourtheme/img directory under name object_pictovalue.png, use this->picto='pictovalue' + // If file is in module/img directory under name object_pictovalue.png, use this->picto='pictovalue@module' + $this->picto = 'technic'; + + // Data directories to create when module is enabled. + $this->dirs = array(); + + // Config pages + $this->config_page_url = array("openid_connect.php"); + + // Dependencies + $this->hidden = false; // A condition to hide module + $this->depends = array(); // List of module class names as string that must be enabled if this module is enabled + $this->requiredby = array(); // List of module ids to disable if this one is disabled + $this->conflictwith = array(); // List of module class names as string this module is in conflict with + $this->phpmin = array(7, 0); // Minimum version of PHP required by module // Minimum version of PHP required by module + $this->need_dolibarr_version = array(3, 7, -2); // Minimum version of Dolibarr required by module + $this->conflictwith = array(); + $this->langfiles = array("openid_connect"); + + // Constants + $this->const = array(); + + // Boxes + $this->boxes = array(); + + // Permissions + $this->rights = array(); + $this->rights_class = 'openid_connect'; + + // List of menus to add + $this->menu = array(); + } + + + /** + * Function called when module is enabled. + * The init function add constants, boxes, permissions and menus (defined in constructor) into Dolibarr database. + * It also creates data directories + * + * @param string $options Options when enabling module ('', 'noboxes') + * @return int 1 if OK, 0 if KO + */ + public function init($options = '') + { + global $conf; + + // Clean before activation + $this->remove($options); + + $sql = array(); + + return $this->_init($sql, $options); + } +} diff --git a/htdocs/core/modules/openid_connect/callback.php b/htdocs/core/modules/openid_connect/callback.php new file mode 100644 index 00000000000..9fd4ffde67d --- /dev/null +++ b/htdocs/core/modules/openid_connect/callback.php @@ -0,0 +1,72 @@ +top_htmlhead + * + * 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 + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/** + * \file htdocs/core/modules/openid_connect/public/callback.php + * \ingroup openid_connect + * \brief OpenID Connect: Authorization Code flow authentication + */ + + + +define('NOLOGIN', '1'); +if (!defined('NOTOKENRENEWAL')) { + define('NOTOKENRENEWAL', '1'); +} + +require '../../../main.inc.php'; +require_once DOL_DOCUMENT_ROOT.'/core/lib/functions.lib.php'; + +// Javascript code on logon page only to detect user tz, dst_observed, dst_first, dst_second +$arrayofjs = array( + '/includes/jstz/jstz.min.js'.(empty($conf->dol_use_jmobile) ? '' : '?version='.urlencode(DOL_VERSION)), + '/core/js/dst.js'.(empty($conf->dol_use_jmobile) ? '' : '?version='.urlencode(DOL_VERSION)) +); + +top_htmlhead('', '', 0, 0, $arrayofjs); + +$prefix = dol_getprefix(''); +$rollback_url = $_COOKIE["DOL_rollback_url_$prefix"]; +if (empty($rollback_url) || $rollback_url === '/') { + $action = $dolibarr_main_url_root . '/index.php?mainmenu=home&leftmenu='; +} else { + $action = $rollback_url; + setcookie('DOL_rollback_url_' . dol_getprefix(''), "", time() + 1, '/'); +} +?> + +
+ + + + + + + + + + + + + + +
+ diff --git a/htdocs/core/modules/societe/mod_codeclient_elephant.php b/htdocs/core/modules/societe/mod_codeclient_elephant.php index c30145891ed..5101606ea32 100644 --- a/htdocs/core/modules/societe/mod_codeclient_elephant.php +++ b/htdocs/core/modules/societe/mod_codeclient_elephant.php @@ -5,7 +5,8 @@ * Copyright (C) 2011 Juanjo Menent * Copyright (C) 2013-2018 Philippe Grand * Copyright (C) 2020-2024 Frédéric France - * Copyright (C) 2024 MDW + * Copyright (C) 2024 MDW + * Copyright (C) 2024 Eric Seigne * * 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 @@ -93,6 +94,8 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode $texte .= ''; $texte .= ''; $texte .= ''; + $texte .= ''; + $texte .= ''; $texte .= ''; $tooltip = $langs->trans("GenericMaskCodes", $langs->transnoentities("ThirdParty"), $langs->transnoentities("ThirdParty")); @@ -103,7 +106,7 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode // Parametrage du prefix customers $texte .= ''; - $texte .= ''; + $texte .= ''; $texte .= ''; @@ -111,7 +114,35 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode // Parametrage du prefix suppliers $texte .= ''; - $texte .= ''; + $texte .= ''; + $texte .= ''; + + // Date of switch to that numbering model + $datedb = getDolGlobalString('COMPANY_ELEPHANT_DATE_START'); + // After save, default dolibarr store data like displayed : 20/05/2024 and we need a timestamp -> override data + if (!empty($datedb)) { + if (!is_numeric($datedb) && GETPOSTISSET('value3')) { + if (GETPOST('value4') == 1) { + $dateinput = GETPOSTDATE('value3'); + $res = dolibarr_set_const($this->db, 'COMPANY_ELEPHANT_DATE_START', $dateinput, 'chaine', 0, '', $conf->entity); + } else { + $res = dolibarr_set_const($this->db, 'COMPANY_ELEPHANT_DATE_START', '', 'chaine', 0, '', $conf->entity); + } + } else { + $dateinput = $datedb; + } + } + if (empty($dateinput)) { + $dateinput = dol_now(); + } + $texte .= ''; + $texte .= ''; $texte .= ''; $texte .= '
'.$langs->trans("Mask").' ('.$langs->trans("CustomerCodeModel").'):'.$form->textwithpicto('', $tooltip, 1, 1).''.$form->textwithpicto('', $tooltip, 1, 1).' 
'.$langs->trans("Mask").' ('.$langs->trans("SupplierCodeModel").'):'.$form->textwithpicto('', $tooltip, 1, 1).''.$form->textwithpicto('', $tooltip, 1, 1).'
'; + $texte .= $form->textwithpicto($langs->trans("DateStartThatModel"), $langs->trans("DateStartThatModelHelp")).''; + $texte .= ''; + $texte .= ''; + $texte .= '
'; @@ -271,6 +302,9 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode $result = 0; $code = strtoupper(trim($code)); + if (getDolGlobalString('COMPANY_ELEPHANT_DATE_START_ENABLE') && $soc->date_creation < getDolGlobalString('COMPANY_ELEPHANT_DATE_START')) { + return -5; + } if (empty($code) && $this->code_null && !getDolGlobalString('MAIN_COMPANY_CODE_ALWAYS_REQUIRED')) { $result = 0; } elseif (empty($code) && (!$this->code_null || getDolGlobalString('MAIN_COMPANY_CODE_ALWAYS_REQUIRED'))) { @@ -325,7 +359,7 @@ class mod_codeclient_elephant extends ModeleThirdPartyCode $sql .= " WHERE code_client = '".$db->escape($code)."'"; } if ($soc->id > 0) { - $sql .= " AND rowid <> ".$soc->id; + $sql .= " AND rowid <> ".((int) $soc->id); } $sql .= " AND entity IN (".getEntity('societe').")"; diff --git a/htdocs/core/tpl/login.tpl.php b/htdocs/core/tpl/login.tpl.php index ef722cdd2a3..8a123b41494 100644 --- a/htdocs/core/tpl/login.tpl.php +++ b/htdocs/core/tpl/login.tpl.php @@ -103,6 +103,29 @@ if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) { $disablenofollow = 0; } +// If OpenID Connect is set as an authentication +if (getDolGlobalInt('MAIN_MODULE_OPENIDCONNECT', 0) > 0 && isset($conf->file->main_authentication) && preg_match('/openid_connect/', $conf->file->main_authentication)) { + // Set a cookie to transfer rollback page information + $prefix = dol_getprefix(''); + if (empty($_COOKIE["DOL_rollback_url_$prefix"])) { + setcookie('DOL_rollback_url_' . $prefix, $_SERVER['REQUEST_URI'], time() + 3600, '/'); + } + + // Auto redirect if OpenID Connect is the only authentication + if ($conf->file->main_authentication === 'openid_connect') { + // Avoid redirection hell + if (empty(GETPOST('openid_mode'))) { + dol_include_once('/core/lib/openid_connect.lib.php'); + header("Location: " . openid_connect_get_url(), true, 302); + } elseif (!empty($_SESSION['dol_loginmesg'])) { + // Show login error without the login form + print ''; + } + // We shouldn't continue executing this page + exit(); + } +} + top_htmlhead('', $titleofloginpage, 0, 0, $arrayofjs, array(), 1, $disablenofollow); @@ -335,15 +358,19 @@ if ($forgetpasslink || $helpcenterlink) { echo ''; } -if (isset($conf->file->main_authentication) && preg_match('/openid/', $conf->file->main_authentication)) { +if (getDolGlobalInt('MAIN_MODULE_OPENIDCONNECT', 0) > 0 && isset($conf->file->main_authentication) && preg_match('/openid/', $conf->file->main_authentication)) { + dol_include_once('/core/lib/openid_connect.lib.php'); $langs->load("users"); //if (!empty($conf->global->MAIN_OPENIDURL_PERUSER)) $url= print '
'; print '
'; - $state = hash('sha256', session_id()); - $url = getDolGlobalString('MAIN_AUTHENTICATION_OPENID_URL').'&state='.$state; + if (!getDolGlobalString("MAIN_AUTHENTICATION_OPENID_URL")) { + $url = openid_connect_get_url(); + } else { + $url = getDolGlobalString('MAIN_AUTHENTICATION_OPENID_URL').'&state=' . openid_connect_get_state(); + } if (!empty($url)) { print ''.$langs->trans("LoginUsingOpenID").''; } else { @@ -400,20 +427,34 @@ if (isset($conf->file->main_authentication) && preg_match('/google/', $conf->fil -