Merge branch '20.0' of git@github.com:Dolibarr/dolibarr.git into 20.0

This commit is contained in:
Laurent Destailleur (aka Eldy) 2024-12-02 01:52:08 +01:00
commit 5c321cc678
15 changed files with 119 additions and 28 deletions

42
.github/workflows/pr-18.yaml vendored Normal file
View File

@ -0,0 +1,42 @@
on:
pull_request:
types: [opened, synchronize, reopened]
branches:
- "18.0"
push:
branches:
- "18.0"
permissions: write-all
jobs:
run:
runs-on: ubuntu-latest
env:
# GH_TOKEN: ${{ secrets.GH_TOKEN }}
GH_TOKEN: ${{ github.token }}
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Install GitHub CLI
run: |
sudo apt update
sudo apt install gh -y
#- name: Authenticate GitHub CLI
# run: |
# echo "GH_TOKEN=$GH_TOKEN"
# gh auth login --with-token <<< "$GH_TOKEN"
- name: Assign reviewer
env:
#REVIEWER: "eldy,lvessiller-opendsi,rycks" # Remplacez par le nom d'utilisateur GitHub du reviewer
REVIEWER: "rycks" # Remplacez par le nom d'utilisateur GitHub du reviewer
run: |
echo "GH_TOKEN=$GH_TOKEN"
pr_number=$(jq --raw-output .number < $GITHUB_EVENT_PATH)
gh pr edit $pr_number --add-reviewer "$REVIEWER"
continue-on-error: true

19
.github/workflows/test.yaml vendored Normal file
View File

@ -0,0 +1,19 @@
on:
workflow_dispatch:
pull_request:
types: [opened, reopened, synchronize]
branches:
- "18.0"
permissions: write-all
jobs:
testjob:
runs-on: ubuntu-latest
steps:
- name: Log
run: |
echo "variable org: ${{vars.AAA}}"
echo "env prg: ${{env.AAA}}"
echo "secret org: ${{secrets.BBB}}"
echo "variable repository of orga: ${{vars.CCC}}"

View File

@ -44,7 +44,7 @@ if (!$user->admin) {
$usersignature = $user->signature;
// For action = test or send, we ensure that content is not html, even for signature, because for this we want a test with NO html.
if ($action == 'test' || ($action == 'send' && $trackid = 'test')) {
if ($action == 'test' || ($action == 'send' && $trackid == 'test')) {
$usersignature = dol_string_nohtmltag($usersignature, 2);
}

View File

@ -598,9 +598,9 @@ $sql = "SELECT b.rowid, b.dateo as do, b.datev as dv, b.amount, b.label, b.rappr
$sql .= " b.fk_account, b.fk_type, b.fk_bordereau,";
$sql .= " ba.rowid as bankid, ba.ref as bankref";
// Add fields from extrafields
if (!empty($extrafields->attributes[$object->table_element]['label'])) {
foreach ($extrafields->attributes[$object->table_element]['label'] as $key => $val) {
$sql .= ($extrafields->attributes[$object->table_element]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
if (!empty($extrafields->attributes[$extrafieldsobjectkey]['label'])) {
foreach ($extrafields->attributes[$extrafieldsobjectkey]['label'] as $key => $val) {
$sql .= ($extrafields->attributes[$extrafieldsobjectkey]['type'][$key] != 'separate' ? ", ef.".$key." as options_".$key : '');
}
}
// Add fields from hooks
@ -613,8 +613,8 @@ if ($search_bid > 0) {
}
$sql .= " ".MAIN_DB_PREFIX."bank_account as ba,";
$sql .= " ".MAIN_DB_PREFIX."bank as b";
if (!empty($extrafields->attributes[$object->table_element]['label']) && is_array($extrafields->attributes[$object->table_element]['label']) && count($extrafields->attributes[$object->table_element]['label'])) {
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$object->table_element."_extrafields as ef on (b.rowid = ef.fk_object)";
if (!empty($extrafields->attributes[$extrafieldsobjectkey]['label']) && is_array($extrafields->attributes[$extrafieldsobjectkey]['label']) && count($extrafields->attributes[$extrafieldsobjectkey]['label'])) {
$sql .= " LEFT JOIN ".MAIN_DB_PREFIX.$extrafieldsobjectkey."_extrafields as ef on (b.rowid = ef.fk_object)";
}
// Add fields from hooks
@ -1842,6 +1842,7 @@ if ($resql) {
}
// Extra fields
$obj = $objp; // Because extrafield template use $obj and not $objp as object variable name
include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_list_print_fields.tpl.php';
// Fields from hook
$parameters = array('arrayfields' => $arrayfields, 'object'=>$object, 'obj' => $objp, 'i' => $i, 'totalarray' => &$totalarray);

View File

@ -8947,6 +8947,10 @@ abstract class CommonObject
if (($mode == 'create') && !in_array(abs($visibility), array(1, 3))) {
continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list
} elseif (($mode == 'edit') && !in_array(abs($visibility), array(1, 3, 4))) {
// We need to make sure, that the values of hidden extrafields are also part of $_POST. Otherwise, they would be empty after an update of the object. See also getOptionalsFromPost
$ef_name = 'options_' . $key;
$ef_value = $this->array_options[$ef_name];
$out .= '<input type="hidden" name="' . $ef_name . '" id="' . $ef_name . '" value="' . $ef_value . '" />' . "\n";
continue; // <> -1 and <> 1 and <> 3 = not visible on forms, only on list and <> 4 = not visible at the creation
} elseif ($mode == 'view' && empty($visibility)) {
continue;

View File

@ -11,7 +11,8 @@
* Copyright (C) 2017 Nicolas ZABOURI <info@inovea-conseil.com>
* Copyright (C) 2018-2024 Frédéric France <frederic.france@free.fr>
* Copyright (C) 2022 Antonin MARCHAL <antonin@letempledujeu.fr>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
* Copyright (C) 2024 Joachim Kueter <git-jk@bloxera.com>
*
* 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
@ -2690,7 +2691,11 @@ class ExtraFields
if (!GETPOSTISSET($keyprefix."options_".$key.$keysuffix)) {
continue; // Value was not provided, we should not set it.
}
$value_key = GETPOST($keyprefix."options_".$key.$keysuffix);
if ($value_key === '') {
$value_key = null;
}
}
$array_options[$keyprefix."options_".$key] = $value_key; // No keyprefix here. keyprefix is used only for read.

View File

@ -113,8 +113,10 @@ if (empty($conf->dol_no_mouse_hover)) {
success: function(response){
// Setting content option
console.log("ajax success");
elemfortooltip.tooltip("option","content",response);
elemfortooltip.tooltip("open");
if (elemfortooltip.is(":hover")) {
elemfortooltip.tooltip("option","content",response);
elemfortooltip.tooltip("open");
}
}
});
}, opendelay));

View File

@ -1829,7 +1829,7 @@ class EmailCollector extends CommonObject
// Note: we can have
// Message-ID=A, In-Reply-To=B, References=B and message can BE an answer or NOT (a transfer rewritten)
$isanswer = 0;
if (preg_match('/Re\s*:\s+/i', $headers['Subject'])) {
if (preg_match('/^(回复|回覆|SV|Antw|VS|RE|Re|AW|Aw|ΑΠ|השב| תשובה | הועבר|Vá|R|RIF|BLS|Atb|RES|Odp|பதில்|YNT|ATB)\s*:\s+/i', $headers['Subject'])) {
$isanswer = 1;
}
//if ($headers['In-Reply-To'] != $headers['Message-ID'] && empty($headers['References'])) $isanswer = 1; // If in-reply-to differs of message-id, this is a reply
@ -1898,7 +1898,7 @@ class EmailCollector extends CommonObject
if ($imapemail->hasHTMLBody()) {
$htmlmsg = $imapemail->getHTMLBody();
}
if ($imapemail->hasTextBody()) {
if ($imapemail->hasTextBody() && $imapemail->getTextBody() != "\n") {
$plainmsg = $imapemail->getTextBody();
}
if ($imapemail->hasAttachments()) {

View File

@ -400,6 +400,7 @@ if (empty($reshook)) {
$societe = new Societe($db);
$societe->fetch($cmd->socid);
$objecttmp->vat_reverse_charge = $societe->vat_reverse_charge;
$objecttmp->thirdparty = $societe;
}
$objecttmp->socid = $cmd->socid;
$objecttmp->type = $objecttmp::TYPE_STANDARD;
@ -508,10 +509,16 @@ if (empty($reshook)) {
if (($lines[$i]->product_type != 9 && empty($lines[$i]->fk_parent_line)) || $lines[$i]->product_type == 9) {
$fk_parent_line = 0;
}
$tva_tx = $lines[$i]->tva_tx;
if (!empty($lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) {
$tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
}
$result = $objecttmp->addline(
$desc,
$lines[$i]->subprice,
$lines[$i]->tva_tx,
$tva_tx,
$lines[$i]->localtax1_tx,
$lines[$i]->localtax2_tx,
$lines[$i]->qty,

View File

@ -1338,6 +1338,11 @@ if (empty($reshook)) {
$date_end = $lines[$i]->date_end;
}
$tva_tx = $lines[$i]->tva_tx;
if (!empty($lines[$i]->vat_src_code) && !preg_match('/\(/', $tva_tx)) {
$tva_tx .= ' ('.$lines[$i]->vat_src_code.')';
}
// FIXME Missing special_code into addline and updateline methods
$object->special_code = $lines[$i]->special_code;
@ -1354,7 +1359,7 @@ if (empty($reshook)) {
$result = $object->addline(
$desc,
$pu,
$lines[$i]->tva_tx,
$tva_tx,
$lines[$i]->localtax1_tx,
$lines[$i]->localtax2_tx,
$lines[$i]->qty,
@ -2718,7 +2723,9 @@ if ($action == 'create') {
require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php';
print '<tr><td>' . $langs->trans('VATReverseCharge') . '</td><td>';
// Try to propose to use VAT reverse charge even if the VAT reverse charge is not activated in the supplier card, if this corresponds to the context of use, the activation is proposed
if ($vat_reverse_charge == 1 || $societe->vat_reverse_charge == 1 || ($societe->country_code != 'FR' && isInEEC($societe) && !empty($societe->tva_intra))) {
if (GETPOSTISSET('vat_reverse_charge')) { // Check if form was submitted previously
$vat_reverse_charge = (GETPOST('vat_reverse_charge', 'alpha') == 'on' || GETPOST('vat_reverse_charge', 'alpha') == '1') ? 1 : 0;
} elseif ($vat_reverse_charge == 1 || $societe->vat_reverse_charge == 1 || ($societe->country_code != 'FR' && isInEEC($societe) && !empty($societe->tva_intra))) {
$vat_reverse_charge = 1;
} else {
$vat_reverse_charge = 0;
@ -3198,14 +3205,12 @@ if ($action == 'create') {
$formconfirm = $form->formconfirm($_SERVER["PHP_SELF"].'?id='.$object->id.'&lineid='.$lineid, $langs->trans('DeleteProductLine'), $langs->trans('ConfirmDeleteProductLine'), 'confirm_deleteline', '', 0, 1);
}
if (!$formconfirm) {
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$formconfirm .= $hookmanager->resPrint;
} elseif ($reshook > 0) {
$formconfirm = $hookmanager->resPrint;
}
$parameters = array('formConfirm' => $formconfirm, 'lineid' => $lineid);
$reshook = $hookmanager->executeHooks('formConfirm', $parameters, $object, $action); // Note that $action and $object may have been modified by hook
if (empty($reshook)) {
$formconfirm .= $hookmanager->resPrint;
} elseif ($reshook > 0) {
$formconfirm = $hookmanager->resPrint;
}
// Print form confirm

View File

@ -422,7 +422,7 @@ drop table tmp_c_shipment_mode;
-- Restore id of user on link for payment of expense report
drop table tmp_bank_url_expense_user;
create table tmp_bank_url_expense_user (select e.fk_user_author, bu2.fk_bank from llx_expensereport as e, llx_bank_url as bu2 where bu2.url_id = e.rowid and bu2.type = 'payment_expensereport');
create table tmp_bank_url_expense_user as (select e.fk_user_author, bu2.fk_bank from llx_expensereport as e, llx_bank_url as bu2 where bu2.url_id = e.rowid and bu2.type = 'payment_expensereport');
update llx_bank_url as bu set url_id = (select e.fk_user_author from tmp_bank_url_expense_user as e where e.fk_bank = bu.fk_bank) where (bu.url_id = 0 OR bu.url_id IS NULL) and bu.type ='user';
drop table tmp_bank_url_expense_user;
@ -682,4 +682,4 @@ alter table llx_product_attribute_combination_price_level drop index fk_product_
ALTER TABLE llx_product_attribute_combination_price_level ADD UNIQUE INDEX uk_prod_att_comb_price_level(fk_product_attribute_combination, fk_price_level);
-- delete a constant that should not be set
DELETE FROM llx_const WHERE name = 'INVOICE_USE_RETAINED_WARRANTY' AND value = -1;
DELETE FROM llx_const WHERE name = 'INVOICE_USE_RETAINED_WARRANTY' AND value = -1;

View File

@ -919,7 +919,7 @@ foreach ($listofreferent as $key => $value) {
$total_ttc_by_line = $element->total_ttc;
}
// Change sign of $total_ht_by_line and $total_ttc_by_line for some cases
// Change sign of $total_ht_by_line and $total_ttc_by_line for various payments
if ($tablename == 'payment_various') {
if ($element->sens == 1) {
$total_ht_by_line = -$total_ht_by_line;
@ -927,6 +927,12 @@ foreach ($listofreferent as $key => $value) {
}
}
// Change sign of $total_ht_by_line and $total_ttc_by_line for supplier proposal and supplier order
if ($tablename == 'commande_fournisseur' || $tablename == 'supplier_proposal') {
$total_ht_by_line = -$total_ht_by_line;
$total_ttc_by_line = -$total_ttc_by_line;
}
// Add total if we have to
if ($qualifiedfortotal) {
$total_ht = $total_ht + $total_ht_by_line;

View File

@ -241,7 +241,7 @@ if ($action == 'getProducts') {
'label' => $obj->label,
'tosell' => $obj->tosell,
'tobuy' => $obj->tobuy,
'barcode' => $obj->barcode,
'barcode' => $term, // there is only one product matches the barcode rule and so the term is considered as the barcode of this product,
'price' => empty($objProd->multiprices[$pricelevel]) ? $obj->price : $objProd->multiprices[$pricelevel],
'price_ttc' => empty($objProd->multiprices_ttc[$pricelevel]) ? $obj->price_ttc : $objProd->multiprices_ttc[$pricelevel],
'object' => 'product',

View File

@ -807,7 +807,7 @@ function Search2(keyCodeForEnter, moreorless) {
console.log("There is only 1 answer with barcode matching the search, so we change the thirdparty "+data[0]['rowid']);
ChangeThirdparty(data[0]['rowid']);
}
else if ($('#search').val() == data[0]['barcode'] && 'product' == data[0]['object']) {
else if ('product' == data[0]['object'] && $('#search').val() == data[0]['barcode']) {
console.log("There is only 1 answer and we found search on a barcode, so we add the product in basket, qty="+data[0]['qty']);
ClickProduct(0, data[0]['qty']);
}

View File

@ -419,7 +419,7 @@ if (empty($reshook)) {
// Action to add a message (private or not, with email or not).
// This may also send an email (concatenated with email_intro and email footer if checkbox was selected)
if ($action == 'add_message' && GETPOSTISSET('btn_add_message') && $permissiontoread) {
$ret = $object->newMessage($user, $action, (GETPOST('private_message', 'alpha') == "on" ? 1 : 0), 0);
$ret = $object->newMessage($user, $action, (GETPOST('private_message', 'alpha') == "1" ? 1 : 0), 0);
if ($ret > 0) {
if (!empty($backtopage)) {