Automated merge from 19.0 to 20.0 by tool pullmerge.sh

This commit is contained in:
Laurent Destailleur 2026-07-13 16:28:07 +02:00
commit dc382c14aa
14 changed files with 121 additions and 37 deletions

View file

@ -2443,6 +2443,10 @@ if ($id > 0) {
$valuetoshow = $langs->trans($valuetoshow ? $valuetoshow : $tmpid);
} elseif ($tabname[$id] == 'c_exp_tax_cat') {
$valuetoshow = $langs->trans($valuetoshow);
} elseif ($value == 'libelle' && ($tabname[$id] == 'c_stcomm' || $tabname[$id] == 'c_stcommcontact')) {
$key = 'StatusProspect'.$obj->rowid;
$trans = $langs->trans($key);
$valuetoshow = ($trans != $key ? $trans : $obj->{$value});
} elseif ($value == 'label' && $tabname[$id] == 'c_units') {
$langs->load('other');
$key = $langs->trans($obj->label);

View file

@ -277,11 +277,10 @@ class Setup extends DolibarrApi
// Add sql filters
if ($sqlfilters) {
$errormessage = '';
if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
$sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
if ($errormessage) {
throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
}
$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}
$sql .= $this->db->order($sortfield, $sortorder);
@ -2143,11 +2142,10 @@ class Setup extends DolibarrApi
// Add sql filters
if ($sqlfilters) {
$errormessage = '';
if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
$sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
if ($errormessage) {
throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
}
$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}

View file

@ -485,6 +485,22 @@ class Account extends CommonObject
public function add_url_line($line_id, $url_id, $url, $label, $type)
{
// phpcs:enable
// Avoid uk_bank_url collision when the same target (line_id, url_id, type) is linked twice
// e.g. two distinct credit transfers for the same employee dispatched on the same bank line.
$sqlcheck = "SELECT rowid FROM ".MAIN_DB_PREFIX."bank_url";
$sqlcheck .= " WHERE fk_bank = ".((int) $line_id);
$sqlcheck .= " AND url_id = ".((int) $url_id);
$sqlcheck .= " AND type = '".$this->db->escape($type)."'";
$resqlcheck = $this->db->query($sqlcheck);
if ($resqlcheck) {
$obj = $this->db->fetch_object($resqlcheck);
if ($obj) {
$this->db->free($resqlcheck);
return (int) $obj->rowid;
}
$this->db->free($resqlcheck);
}
$sql = "INSERT INTO ".MAIN_DB_PREFIX."bank_url (";
$sql .= "fk_bank";
$sql .= ", url_id";

View file

@ -278,13 +278,15 @@ class DiscountAbsolute extends CommonObject
$sql .= " (entity, datec, fk_soc, discount_type, fk_user, description,";
$sql .= " amount_ht, amount_tva, amount_ttc, tva_tx, vat_src_code,";
$sql .= " multicurrency_amount_ht, multicurrency_amount_tva, multicurrency_amount_ttc,";
$sql .= " fk_facture_source, fk_invoice_supplier_source";
$sql .= " fk_facture_source, fk_invoice_supplier_source, multicurrency_code, multicurrency_tx";
$sql .= ")";
$sql .= " VALUES (".$conf->entity.", '".$this->db->idate($this->datec != '' ? $this->datec : dol_now())."', ".((int) $this->socid).", ".(empty($this->discount_type) ? 0 : intval($this->discount_type)).", ".((int) $userid).", '".$this->db->escape($this->description)."',";
$sql .= " ".price2num($this->amount_ht).", ".price2num($this->amount_tva).", ".price2num($this->amount_ttc).", ".price2num($this->tva_tx).", '".$this->db->escape($this->vat_src_code)."',";
$sql .= " ".price2num($this->multicurrency_amount_ht).", ".price2num($this->multicurrency_amount_tva).", ".price2num($this->multicurrency_amount_ttc).", ";
$sql .= " ".($this->fk_facture_source ? ((int) $this->fk_facture_source) : "null").",";
$sql .= " ".($this->fk_invoice_supplier_source ? ((int) $this->fk_invoice_supplier_source) : "null");
$sql .= " ".($this->fk_invoice_supplier_source ? ((int) $this->fk_invoice_supplier_source) : "null").",";
$sql .= " ".($this->multicurrency_code ? "'".$this->db->escape($this->multicurrency_code)."'" : "null").",";
$sql .= " ".($this->multicurrency_tx ? price2num($this->multicurrency_tx) : "null");
$sql .= ")";
dol_syslog(get_class($this)."::create", LOG_DEBUG);

View file

@ -517,7 +517,7 @@ class modProduct extends DolibarrModules
'p.price_min' => "MinPrice",
'p.price_ttc' => "SellingPriceTTC", //with tax
'p.price_min_ttc' => "SellingMinPriceTTC",
'p.price_base_type' => "PriceBaseType", //price base: with-tax (TTC) or without (HT) tax. Displays accordingly in Product card
'p.price_base_type' => "PriceBaseType*", //price base: with-tax (TTC) or without (HT) tax. Displays accordingly in Product card
'p.tva_tx' => 'VATRate',
'p.datec' => 'DateCreation',
'p.cost_price' => "CostPrice"

View file

@ -9,7 +9,7 @@
* Copyright (C) 2021-2023 Frédéric France <frederic.france@netlogic.fr>
* Copyright (C) 2022 Charlène Benke <charlene@patas-monkey.com>
* Copyright (C) 2024 William Mead <william.mead@manchenumerique.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024-2026 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Benjamin Falière <benjamin.faliere@altairis.fr>
*
* This program is free software; you can redistribute it and/or modify
@ -325,7 +325,7 @@ if ($search_desc) {
}
}
if ($search_status != '' && $search_status >= 0) {
$sql .= ' AND f.fk_statut = '.urlencode($search_status);
$sql .= ' AND f.fk_statut = '.((int) ($search_status));
}
if (!getDolGlobalString('FICHINTER_DISABLE_DETAILS') && $atleastonefieldinlines) {
if ($search_date_start) {

View file

@ -6,11 +6,12 @@
* Copyright (C) 2010-2011 Juanjo Menent <jmenent@2byte.es>
* Copyright (C) 2014 Marcos García <marcosgdf@gmail.com>
* Copyright (C) 2018 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2018 Frédéric France <frederic.francenetlogic.fr>
* Copyright (C) 2018 Frédéric France <frederic.francenetlogic.fr>
* Copyright (C) 2023 Joachim Kueter <git-jk@bloxera.com>
* Copyright (C) 2023 Sylvain Legrand <technique@infras.fr>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2026 Lionel Vessiller <lvessiller@open-dsi.fr>
*
* 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
@ -202,16 +203,31 @@ class PaiementFourn extends Paiement
$this->error = $langs->trans('FailedToFoundTheConversionRateForInvoice');
return -1;
}
if (empty($currencyofpayment)) {
$currencyofpayment = $this->multicurrency_code[$key];
// Fallback: read invoice multicurrency code/tx if caller did not fill the arrays
$invoice_multicurrency_code = $this->multicurrency_code[$key] ?? '';
$invoice_multicurrency_tx = $this->multicurrency_tx[$key] ?? '';
if (empty($invoice_multicurrency_code) || empty($invoice_multicurrency_tx)) {
$tmparray = MultiCurrency::getInvoiceRate($key, 'facture_fourn');
if ($tmparray !== false) {
if (empty($invoice_multicurrency_code)) {
$invoice_multicurrency_code = $tmparray['invoice_multicurrency_code'];
}
if (empty($invoice_multicurrency_tx)) {
$invoice_multicurrency_tx = $tmparray['invoice_multicurrency_tx'];
}
}
}
if ($currencyofpayment != $this->multicurrency_code[$key]) {
if (empty($currencyofpayment)) {
$currencyofpayment = $invoice_multicurrency_code;
}
if ($currencyofpayment != $invoice_multicurrency_code) {
// If we have invoices with different currencies in the payment, we stop here
$this->error = 'ErrorYouTryToPayInvoicesWithDifferentCurrenciesInSamePayment';
return -1;
}
if (empty($currencytxofpayment)) {
$currencytxofpayment = $this->multicurrency_tx[$key];
$currencytxofpayment = $invoice_multicurrency_tx;
}
$totalamount_converted += $value_converted;
@ -302,6 +318,8 @@ class PaiementFourn extends Paiement
$discount->fk_soc = $invoice->socid;
$discount->socid = $invoice->socid;
$discount->fk_invoice_supplier_source = $invoice->id;
$discount->multicurrency_code = $invoice->multicurrency_code;
$discount->multicurrency_tx = $invoice->multicurrency_tx;
// Loop on each vat rate
$i = 0;
@ -321,9 +339,14 @@ class PaiementFourn extends Paiement
$discount->amount_ht = abs($amount_ht[$tva_tx]);
$discount->amount_tva = abs($amount_tva[$tva_tx]);
$discount->amount_ttc = abs($amount_ttc[$tva_tx]);
$discount->multicurrency_amount_ht = abs($multicurrency_amount_ht[$tva_tx]);
$discount->multicurrency_amount_tva = abs($multicurrency_amount_tva[$tva_tx]);
$discount->multicurrency_amount_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
// multi-currency
$discount->multicurrency_total_ht = abs($multicurrency_amount_ht[$tva_tx]);
$discount->multicurrency_total_tva = abs($multicurrency_amount_tva[$tva_tx]);
$discount->multicurrency_total_ttc = abs($multicurrency_amount_ttc[$tva_tx]);
// keep compatibility
$discount->multicurrency_amount_ht = $discount->multicurrency_total_ht;
$discount->multicurrency_amount_tva = $discount->multicurrency_total_tva;
$discount->multicurrency_amount_ttc = $discount->multicurrency_total_ttc;
$discount->tva_tx = abs($tva_tx);
$result = $discount->create($user);

View file

@ -13,7 +13,8 @@
* Copyright (C) 2019 Ferran Marcet <fmarcet@2byte.es>
* Copyright (C) 2022 Gauthier VERDOL <gauthier.verdol@atm-consulting.fr>
* Copyright (C) 2023 Nick Fragoulis
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2026 Lionel Vessiller <lvessiller@open-dsi.fr>
*
* 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
@ -698,6 +699,15 @@ if (empty($reshook)) {
$discount->tva_tx = 0;
$discount->vat_src_code = '';
// multi-currency
$discount->multicurrency_code = $object->multicurrency_code;
$discount->multicurrency_tx = $object->multicurrency_tx;
$discount->multicurrency_total_ht = $discount->multicurrency_total_ttc = (float) price2num((float) $discount->amount_ttc * (float) $object->multicurrency_tx, 'MT');
$discount->multicurrency_total_tva = 0;
// keep compatibility
$discount->multicurrency_amount_ht = $discount->multicurrency_amount_ttc = $discount->multicurrency_total_ttc;
$discount->multicurrency_amount_tva = 0;
$result = $discount->create($user);
if ($result < 0) {
$error++;
@ -708,9 +718,16 @@ if (empty($reshook)) {
$discount->amount_ht = abs((float) $amount_ht[$tva_tx]);
$discount->amount_tva = abs((float) $amount_tva[$tva_tx]);
$discount->amount_ttc = abs((float) $amount_ttc[$tva_tx]);
$discount->multicurrency_amount_ht = abs((float) $multicurrency_amount_ht[$tva_tx]);
$discount->multicurrency_amount_tva = abs((float) $multicurrency_amount_tva[$tva_tx]);
$discount->multicurrency_amount_ttc = abs((float) $multicurrency_amount_ttc[$tva_tx]);
// multi-currency
$discount->multicurrency_code = $object->multicurrency_code;
$discount->multicurrency_tx = $object->multicurrency_tx;
$discount->multicurrency_total_ht = abs((float) $multicurrency_amount_ht[$tva_tx]);
$discount->multicurrency_total_tva = abs((float) $multicurrency_amount_tva[$tva_tx]);
$discount->multicurrency_total_ttc = abs((float) $multicurrency_amount_ttc[$tva_tx]);
// keep compatibility
$discount->multicurrency_amount_ht = abs((float) $discount->multicurrency_total_ht);
$discount->multicurrency_amount_tva = abs((float) $discount->multicurrency_total_tva);
$discount->multicurrency_amount_ttc = abs((float) $discount->multicurrency_total_ttc);
// Clean vat code
$reg = array();

View file

@ -36,7 +36,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/lib/images.lib.php';
require_once DOL_DOCUMENT_ROOT.'/core/lib/import.lib.php';
// Load translation files required by the page
$langs->loadLangs(array('exports', 'compta', 'errors', 'projects', 'admin'));
$langs->loadLangs(array('exports', 'compta', 'errors', 'projects', 'admin', 'products', 'margins'));
// Security check
$result = restrictedArea($user, 'import');

View file

@ -83,6 +83,10 @@ class Odf
$this->tmpfile = $this->tmpdir.'/'.$md5uniqid.'.odt'; // We keep .odt extension to allow OpenOffice usage during debug.
// A working directory is required for some zip proxy like PclZipProxy
if (in_array($this->config['ZIP_PROXY'], array('PclZipProxy')) && ! is_dir($this->config['PATH_TO_TMP'])) {
$result = mkdir($this->config['PATH_TO_TMP']);
}
// Check the dir has been created
if (in_array($this->config['ZIP_PROXY'], array('PclZipProxy')) && ! is_dir($this->config['PATH_TO_TMP'])) {
throw new OdfException('Temporary directory '.$this->config['PATH_TO_TMP'].' must exists');
}

View file

@ -69,11 +69,10 @@ class MultiCurrencies extends DolibarrApi
// Add sql filters
if ($sqlfilters) {
$errormessage = '';
if (!DolibarrApi::_checkFilters($sqlfilters, $errormessage)) {
throw new RestException(503, 'Error when validating parameter sqlfilters -> '.$errormessage);
$sql .= forgeSQLFromUniversalSearchCriteria($sqlfilters, $errormessage);
if ($errormessage) {
throw new RestException(400, 'Error when validating parameter sqlfilters -> '.$errormessage);
}
$regexstring = '\(([^:\'\(\)]+:[^:\'\(\)]+:[^\(\)]+)\)';
$sql .= " AND (".preg_replace_callback('/'.$regexstring.'/', 'DolibarrApi::_forge_criteria_callback', $sqlfilters).")";
}
$sql .= $this->db->order($sortfield, $sortorder);

View file

@ -2505,15 +2505,26 @@ class Societe extends CommonObject
$discount->socid = $this->id;
$discount->discount_type = $discount_type;
$discount->multicurrency_code = $this->multicurrency_code;
list($this->fk_multicurrency, $this->multicurrency_tx) = MultiCurrency::getIdAndTxFromCode($this->db, $this->multicurrency_code);
$discount->multicurrency_tx = $this->multicurrency_tx;
if ($price_base_type == 'TTC') {
$discount->amount_ttc = $discount->multicurrency_amount_ttc = price2num($remise, 'MT');
$discount->amount_ht = $discount->multicurrency_amount_ht = price2num((float) $remise / (1 + (float) $vatrate / 100), 'MT');
$discount->amount_tva = $discount->multicurrency_amount_tva = price2num((float) $discount->amount_ttc - (float) $discount->amount_ht, 'MT');
$discount->amount_ttc = price2num($remise, 'MT');
$discount->amount_ht = price2num((float) $remise / (1 + (float) $vatrate / 100), 'MT');
$discount->amount_tva = price2num((float) $discount->amount_ttc - (float) $discount->amount_ht, 'MT');
$discount->multicurrency_amount_ttc = price2num($remise * (float) $discount->multicurrency_tx, 'MT');
$discount->multicurrency_amount_ht = price2num(((float) $remise / (1 + (float) $vatrate / 100)) * (float) $discount->multicurrency_tx, 'MT');
$discount->multicurrency_amount_tva = price2num(((float) $discount->amount_ttc - (float) $discount->amount_ht) * (float) $discount->multicurrency_tx, 'MT');
} else {
$discount->amount_ht = $discount->multicurrency_amount_ht = price2num($remise, 'MT');
$discount->amount_tva = $discount->multicurrency_amount_tva = price2num((float) $remise * (float) $vatrate / 100, 'MT');
$discount->amount_ttc = $discount->multicurrency_amount_ttc = price2num((float) $discount->amount_ht + (float) $discount->amount_tva, 'MT');
$discount->amount_ht = price2num($remise, 'MT');
$discount->amount_tva = price2num((float) $remise * (float) $vatrate / 100, 'MT');
$discount->amount_ttc = price2num((float) $discount->amount_ht + (float) $discount->amount_tva, 'MT');
$discount->multicurrency_amount_ht = price2num($remise * (float) $discount->multicurrency_tx, 'MT');
$discount->multicurrency_amount_tva = price2num(((float) $remise * (float) $vatrate / 100) * (float) $discount->multicurrency_tx, 'MT');
$discount->multicurrency_amount_ttc = price2num(((float) $discount->amount_ht + (float) $discount->amount_tva) * (float) $discount->multicurrency_tx, 'MT');
}
$discount->tva_tx = (float) price2num($vatrate);

View file

@ -198,6 +198,14 @@ if ($reshook < 0) {
setEventMessages($hookmanager->error, $hookmanager->errors, 'errors');
}
// Enforce the "edit lines" permission on every action that modifies an existing line
// (delete, quantity, price, discount). Adding a line, a free zone or a note is gated by
// the "run" permission elsewhere and must stay available to a plain cashier (#38949).
if (in_array($action, array('deleteline', 'updateqty', 'updateprice', 'updatereduction', 'update_reduction_global')) && !$user->hasRight('takepos', 'editlines')) {
dol_htmloutput_errors($langs->trans("NotEnoughPermissions", "TakePos"), null, 1);
$action = '';
}
if (empty($reshook)) {
// Action to record a payment on a TakePOS invoice
if ($action == 'valid' && $user->hasRight('facture', 'creer')) {

View file

@ -50,7 +50,9 @@ if (($object->id != $user->id) && (!$user->hasRight("user", "user", "read"))) {
}
// Permissions
$permissionnote = $user->hasRight("user", "self", "write"); // Used by the include of actions_setnotes.inc.php
// Writing notes on own record needs the "self" write right, writing on another user's record needs the "user" write right.
// Without this distinction a user holding only "self" write could edit the notes of any user, including admins.
$permissionnote = ((($object->id == $user->id) && $user->hasRight("user", "self", "write")) || (($object->id != $user->id) && $user->hasRight("user", "user", "write"))); // Used by the include of actions_setnotes.inc.php
// Security check
$socid = 0;