From 7b5ddac96354e3b992741419ed1e94a07a2cda01 Mon Sep 17 00:00:00 2001 From: kkhelifa-opendsi Date: Sun, 8 Feb 2026 22:25:58 +0100 Subject: [PATCH 1/8] FIX: Backport fix on v20 for result page of compta (/compta/resultat/index.php) (#37127) * FIX: Backport fix on v20 for result page of compta (/compta/resultat/index.php). The expense report were not included when the module was activated * Update index.php --------- Co-authored-by: Laurent Destailleur --- htdocs/compta/resultat/index.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/compta/resultat/index.php b/htdocs/compta/resultat/index.php index 6a1fd134562..b7de1fe19eb 100644 --- a/htdocs/compta/resultat/index.php +++ b/htdocs/compta/resultat/index.php @@ -45,7 +45,7 @@ $date_endyear = GETPOST('date_endyear', 'int'); $nbofyear = 4; -// Change this to test different cases of setup +// Change this to test different cases of setup. //$conf->global->SOCIETE_FISCAL_MONTH_START = 7; @@ -678,7 +678,7 @@ if (isModEnabled('salaries') && ($modecompta == 'CREANCES-DETTES' || $modecompta * Expense reports */ -if (!isModEnabled('expensereport') && ($modecompta == 'CREANCES-DETTES' || $modecompta == "RECETTES-DEPENSES")) { +if (isModEnabled('expensereport') && ($modecompta == 'CREANCES-DETTES' || $modecompta == "RECETTES-DEPENSES")) { $langs->load('trips'); if ($modecompta == 'CREANCES-DETTES') { From 0cc80e65ed41be9546ec85b1e7afd01bdbbb9947 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 9 Feb 2026 18:33:54 +0100 Subject: [PATCH 2/8] FIX SQL Error on VAT not defined in product card (#37159) --- htdocs/core/class/html.form.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/core/class/html.form.class.php b/htdocs/core/class/html.form.class.php index 8a285587b79..e8b04307c2f 100644 --- a/htdocs/core/class/html.form.class.php +++ b/htdocs/core/class/html.form.class.php @@ -15,7 +15,7 @@ * Copyright (C) 2012-2016 Marcos García * Copyright (C) 2012 Cedric Salvador * Copyright (C) 2012-2015 Raphaël Doursenaud - * Copyright (C) 2014-2023 Alexandre Spangaro + * Copyright (C) 2014-2026 Alexandre Spangaro * Copyright (C) 2018-2022 Ferran Marcet * Copyright (C) 2018-2021 Frédéric France * Copyright (C) 2018 Nicolas ZABOURI @@ -6446,7 +6446,7 @@ class Form if (!empty($user) && $user->admin && preg_match('/\'(..)\'/', $country_code, $reg)) { $langs->load("errors"); $new_country_code = $reg[1]; - $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_pays', 'code', 'rowid'); + $country_id = dol_getIdFromCode($this->db, $new_country_code, 'c_country', 'code', 'rowid'); $this->error .= '
'.$langs->trans("ErrorFixThisHere", DOL_URL_ROOT.'/admin/dict.php?id=10'.($country_id > 0 ? '&countryidforinsert='.$country_id : '')); } $this->error .= ''; From 0b8e0c4765d79a37314d2a6875fdd546ad2c15b1 Mon Sep 17 00:00:00 2001 From: ThomasNgr-OpenDSI Date: Tue, 10 Feb 2026 15:30:40 +0100 Subject: [PATCH 3/8] FIX display of DLC/DLUO in tooltip (#37164) --- htdocs/product/stock/class/productlot.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/product/stock/class/productlot.class.php b/htdocs/product/stock/class/productlot.class.php index 7e54fd90622..8070fc45a6b 100644 --- a/htdocs/product/stock/class/productlot.class.php +++ b/htdocs/product/stock/class/productlot.class.php @@ -956,10 +956,10 @@ class Productlot extends CommonObject //$datas['divopen'] = '
'; $datas['batch'] = '
'.$langs->trans('Batch').': '.$this->batch; if ($this->eatby && empty($conf->global->PRODUCT_DISABLE_EATBY)) { - $datas['eatby'] = '
'.$langs->trans('EatByDate').': '.dol_print_date($this->db->jdate($this->eatby), 'day'); + $datas['eatby'] = '
'.$langs->trans('EatByDate').': '.dol_print_date($this->eatby, 'day'); } if ($this->sellby && empty($conf->global->PRODUCT_DISABLE_SELLBY)) { - $datas['sellby'] = '
'.$langs->trans('SellByDate').': '.dol_print_date($this->db->jdate($this->sellby), 'day'); + $datas['sellby'] = '
'.$langs->trans('SellByDate').': '.dol_print_date($this->sellby, 'day'); } //$datas['divclose'] = '
'; From e43438cc7b82239e1438282437bb6c4c397950fc Mon Sep 17 00:00:00 2001 From: Vincent Penel Date: Tue, 10 Feb 2026 15:40:05 +0100 Subject: [PATCH 4/8] Fix/ticket status (#37129) * set oldCopy and Status * Update ticket.class.php * Question Eldy * Fix event status change --------- Co-authored-by: Laurent Destailleur --- htdocs/core/class/commonobject.class.php | 4 ++++ htdocs/ticket/card.php | 4 ++-- htdocs/ticket/class/ticket.class.php | 2 +- htdocs/ticket/list.php | 2 +- 4 files changed, 8 insertions(+), 4 deletions(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 1561867c858..385b493b2d7 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -4478,7 +4478,11 @@ abstract class CommonObject } } + $this->context = array_merge($this->context, array('newstatus' => $status)); + if ($trigkey) { + $this->oldcopy = dol_clone($this); + // Call trigger $result = $this->call_trigger($trigkey, $user); if ($result < 0) { diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index e207479cacc..9832970bdfa 100755 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -568,7 +568,7 @@ if (empty($reshook)) { if ($object->fetch(GETPOST('id', 'int'), '', GETPOST('track_id', 'alpha')) >= 0) { // prevent browser refresh from reopening ticket several times if ($object->status == Ticket::STATUS_CLOSED || $object->status == Ticket::STATUS_CANCELED) { - $res = $object->setStatut(Ticket::STATUS_ASSIGNED); + $res = $object->setStatut(Ticket::STATUS_ASSIGNED, null, '', 'TICKET_MODIFY'); if ($res) { // Log action in ticket logs table //$log_action = $langs->trans('TicketLogReopen'); @@ -626,7 +626,7 @@ if (empty($reshook)) { if ($object->fetch(GETPOST('id', 'int'), GETPOST('track_id', 'alpha')) >= 0) { $new_status = GETPOST('new_status', 'int'); $old_status = $object->status; - $res = $object->setStatut($new_status); + $res = $object->setStatut($new_status, null, '', 'TICKET_MODIFY'); if ($res) { // Log action in ticket logs table $log_action = $langs->trans('TicketLogStatusChanged', $langs->transnoentities($object->statuts_short[$old_status]), $langs->transnoentities($object->statuts_short[$new_status])); diff --git a/htdocs/ticket/class/ticket.class.php b/htdocs/ticket/class/ticket.class.php index e821b4e80d4..fadcb371358 100644 --- a/htdocs/ticket/class/ticket.class.php +++ b/htdocs/ticket/class/ticket.class.php @@ -2714,7 +2714,7 @@ class Ticket extends CommonObject if (($object->status < self::STATUS_IN_PROGRESS && !$user->socid && !$private) || ($object->status > self::STATUS_IN_PROGRESS && $public_area) ) { - $object->setStatut(3); + $object->setStatut(3, null, '', 'TICKET_MODIFY'); } return 1; } else { diff --git a/htdocs/ticket/list.php b/htdocs/ticket/list.php index 4c4dce5a428..1fddd77010c 100644 --- a/htdocs/ticket/list.php +++ b/htdocs/ticket/list.php @@ -284,7 +284,7 @@ if (empty($reshook)) { $result = $objecttmp->fetch($toselectid); if ($result > 0) { if ($objecttmp->status == Ticket::STATUS_CLOSED || $objecttmp->status == Ticket::STATUS_CANCELED) { - $result = $objecttmp->setStatut(Ticket::STATUS_ASSIGNED); + $result = $objecttmp->setStatut(Ticket::STATUS_ASSIGNED, null, '', 'TICKET_MODIFY'); if ($result < 0) { setEventMessages($objecttmp->error, $objecttmp->errors, 'errors'); $error++; From 673659de986ecd65929671fbe5dfe263f50bb0aa Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Thu, 12 Feb 2026 01:23:06 +0100 Subject: [PATCH 5/8] FIX Accountancy - Update height of the export popup (#37206) --- htdocs/accountancy/bookkeeping/export.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/export.php b/htdocs/accountancy/bookkeeping/export.php index 246b8e99ebe..45934b646f6 100644 --- a/htdocs/accountancy/bookkeeping/export.php +++ b/htdocs/accountancy/bookkeeping/export.php @@ -1,7 +1,7 @@ * Copyright (C) 2013-2016 Florian Henry - * Copyright (C) 2013-2024 Alexandre Spangaro + * Copyright (C) 2013-2026 Alexandre Spangaro * Copyright (C) 2022 Lionel Vessiller * Copyright (C) 2016-2017 Laurent Destailleur * Copyright (C) 2018-2021 Frédéric France @@ -778,7 +778,7 @@ if ($action == 'export_file') { ); } - $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").'...', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 420, 600); + $formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?'.$param, $langs->trans("ExportFilteredList").'...', $langs->trans('ConfirmExportFile'), 'export_fileconfirm', $form_question, '', 1, 500, 600); } // Print form confirm From e850355b3034bb46e3fa5257bf8fbaf19441bf2b Mon Sep 17 00:00:00 2001 From: Eric - CAP-REL <1468823+rycks@users.noreply.github.com> Date: Thu, 12 Feb 2026 09:37:04 +0100 Subject: [PATCH 6/8] Refactor GitHub Actions workflow steps Remove depends on gh and only use curl and requests on github api ... --- .github/workflows/pr-18.yaml | 52 +++++++++++++++--------------------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/.github/workflows/pr-18.yaml b/.github/workflows/pr-18.yaml index e606aa233e1..39e34ae88f3 100644 --- a/.github/workflows/pr-18.yaml +++ b/.github/workflows/pr-18.yaml @@ -49,23 +49,6 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - # 3) Install / configure GitHub CLI (gh) on the runner - #- name: Setup GitHub CLI (gh) - # uses: cli/gh-action@v3 - # -> Error: Unable to resolve action cli/gh-action, repository not found - - name: Setup GitHub CLI (gh) (install locally) - run: | - set -euo pipefail - sudo apt-get update - sudo apt-get install -y gh || { - curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg - sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg - echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null - sudo apt-get update - sudo apt-get install -y gh - } - gh --version - # Debug information (useful for diagnostics) - name: Debug info run: | @@ -74,7 +57,7 @@ jobs: echo "Run id: $GITHUB_RUN_ID" echo "Reviewers configured: $REVIEWERS" - # 4) Add the label to the PR (PR events only) + # 3) Add the label to the PR (PR events only) # -> tolerant to errors: log on failure but do not fail the job - name: Add label to PR (pull_request events only) if: ${{ github.event_name == 'pull_request' }} @@ -82,16 +65,23 @@ jobs: GH_TOKEN: ${{ steps.generate-token.outputs.token }} PR_NUMBER: ${{ github.event.pull_request.number }} V18_LABEL: ${{ env.V18_LABEL }} + REPO: ${{ github.repository }} run: | set -euo pipefail echo "Adding label '$V18_LABEL' to PR #${PR_NUMBER}" - if gh pr edit "$PR_NUMBER" --add-label "$V18_LABEL"; then + response=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${REPO}/issues/${PR_NUMBER}/labels" \ + -d "{\"labels\": [\"${V18_LABEL}\"]}") + + if [ "$response" -eq 200 ]; then echo "Label added successfully." else - echo "Warning: failed to add label '$V18_LABEL' to PR #${PR_NUMBER}. Continuing." + echo "Warning: failed to add label '$V18_LABEL' to PR #${PR_NUMBER} (HTTP $response). Continuing." fi - # 5) Compute final reviewers list excluding the PR author + # 4) Compute final reviewers list excluding the PR author - name: Compute reviewers (exclude PR author) if: ${{ github.event_name == 'pull_request' }} id: set-reviewers @@ -118,7 +108,7 @@ jobs: echo "author=$AUTHOR" >> $GITHUB_OUTPUT echo "Computed reviewers: ${reviewers_csv:-}" - # 6) Assign reviewers one-by-one with fine-grained error handling + # 5) Assign reviewers one-by-one with fine-grained error handling # - try each reviewer, track successes and failures # - fail the step only if none could be added # - succeed if at least one was added (but log failures) @@ -128,8 +118,8 @@ jobs: GH_TOKEN: ${{ steps.generate-token.outputs.token }} PR_NUMBER: ${{ github.event.pull_request.number }} REVIEWERS_CSV: ${{ steps.set-reviewers.outputs.reviewers }} + REPO: ${{ github.repository }} run: | - # Note: avoid 'set -e' to handle per-reviewer failures manually set -uo pipefail IFS=',' read -ra TO_ADD <<< "${REVIEWERS_CSV}" SUCCESS=0 @@ -140,26 +130,28 @@ jobs: continue fi echo "Attempting to add reviewer: $r_trimmed" - if gh pr edit "$PR_NUMBER" --add-reviewer "$r_trimmed"; then + response=$(curl -s -o /dev/null -w "%{http_code}" -X POST \ + -H "Authorization: Bearer ${GH_TOKEN}" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${REPO}/pulls/${PR_NUMBER}/requested_reviewers" \ + -d "{\"reviewers\": [\"${r_trimmed}\"]}") + + if [ "$response" -eq 201 ] || [ "$response" -eq 200 ]; then echo "Added reviewer: $r_trimmed" SUCCESS=$((SUCCESS+1)) else - echo "Warning: failed to add reviewer: $r_trimmed" - echo "Debug: PR view:" - gh pr view "$PR_NUMBER" --json number,title,author,reviewRequests || true + echo "Warning: failed to add reviewer: $r_trimmed (HTTP $response)" FAILED+=("$r_trimmed") fi done if [ $SUCCESS -eq 0 ]; then echo "Error: none of the configured reviewers could be added: ${FAILED[*]:-}" - # Fail the step because no reviewer was added exit 1 else echo "Reviewers added: ${SUCCESS}. Failed to add: ${FAILED[*]:-none}" - # Step succeeds even if some reviewers failed fi - # 7) Push event notice (no PR-specific actions performed) + # 6) Push event notice (no PR-specific actions performed) - name: Push event notice if: ${{ github.event_name == 'push' }} run: | From a8e050834312b1c9a5736f550ab012e941e72434 Mon Sep 17 00:00:00 2001 From: ThomasNgr-OpenDSI Date: Thu, 12 Feb 2026 16:30:45 +0100 Subject: [PATCH 7/8] Sec: Can init a page with php content without permission for php content (#37211) edition (reported by phdwg1410) Co-authored-by: Laurent Destailleur --- htdocs/website/class/websitepage.class.php | 12 ++++++++++++ htdocs/website/index.php | 3 +++ 2 files changed, 15 insertions(+) diff --git a/htdocs/website/class/websitepage.class.php b/htdocs/website/class/websitepage.class.php index 40ca4231d7d..0e3c84cbb8e 100644 --- a/htdocs/website/class/websitepage.class.php +++ b/htdocs/website/class/websitepage.class.php @@ -226,6 +226,18 @@ class WebsitePage extends CommonObject // Remove spaces and be sure we have main language only $this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en + // Test if page contains dynamic PHP content + if (!$user->hasRight('website', 'writephp')) { + // Check there is no PHP content into the imported file (must be only HTML + JS) + $phpcontent = dolKeepOnlyPhpCode($this->content); + + if ($phpcontent) { + $this->error = 'Error: you try to create a page with PHP content without having permissions for that.'; + $this->errors = $this->error; + return -1; + } + } + return $this->createCommon($user, $notrigger); } diff --git a/htdocs/website/index.php b/htdocs/website/index.php index c67e80dee29..e8725ad8b56 100644 --- a/htdocs/website/index.php +++ b/htdocs/website/index.php @@ -806,6 +806,7 @@ if ($action == 'addcontainer' && $usercanedit) { // Remove comments $tmp['content'] = removeHtmlComment($tmp['content']); + /* disable this, moved into the create() method // Check there is no PHP content into the imported file (must be only HTML + JS) $phpcontent = dolKeepOnlyPhpCode($tmp['content']); if ($phpcontent) { @@ -813,6 +814,7 @@ if ($action == 'addcontainer' && $usercanedit) { setEventMessages('Error getting '.$urltograb.': file that include PHP content is not allowed', null, 'errors'); $action = 'createcontainer'; } + */ } if (!$error) { @@ -1169,6 +1171,7 @@ if ($action == 'addcontainer' && $usercanedit) { } if (!$error) { + // Create page. This also check there is no PHP content if user has no pemrissions for that. $pageid = $objectpage->create($user); if ($pageid <= 0) { $error++; From 30f7f34708bd0cd7752901994a4a2887ddeaf361 Mon Sep 17 00:00:00 2001 From: Alexandre SPANGARO Date: Mon, 16 Feb 2026 19:54:09 +0100 Subject: [PATCH 8/8] FIX Societe - Wrong control on update of VAT Intra (#37224) --- htdocs/societe/class/societe.class.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/htdocs/societe/class/societe.class.php b/htdocs/societe/class/societe.class.php index 9ffd25427be..a78c66f95c6 100644 --- a/htdocs/societe/class/societe.class.php +++ b/htdocs/societe/class/societe.class.php @@ -8,7 +8,7 @@ * Copyright (C) 2008 Patrick Raguin * Copyright (C) 2010-2018 Juanjo Menent * Copyright (C) 2013 Florian Henry - * Copyright (C) 2013-2023 Alexandre Spangaro + * Copyright (C) 2013-2026 Alexandre Spangaro * Copyright (C) 2013 Peter Fontaine * Copyright (C) 2014-2015 Marcos García * Copyright (C) 2015 Raphaël Doursenaud @@ -1368,7 +1368,7 @@ class Societe extends CommonObject $this->supplier_order_min_amount = price2num($this->supplier_order_min_amount); $this->tva_assuj = trim($this->tva_assuj); - $this->tva_intra = dol_sanitizeFileName($this->tva_intra, ''); + $this->tva_intra = trim($this->tva_intra); $this->vat_reverse_charge = empty($this->vat_reverse_charge) ? '0' : '1'; if (empty($this->status)) { $this->status = 0;