diff --git a/.github/workflows/pr-18.yaml b/.github/workflows/pr-18.yaml new file mode 100644 index 00000000000..2682e99df38 --- /dev/null +++ b/.github/workflows/pr-18.yaml @@ -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 diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml new file mode 100644 index 00000000000..cf263dd0b57 --- /dev/null +++ b/.github/workflows/test.yaml @@ -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}}" diff --git a/htdocs/adherents/class/adherent.class.php b/htdocs/adherents/class/adherent.class.php index eee7fde0377..c138ddb957f 100644 --- a/htdocs/adherents/class/adherent.class.php +++ b/htdocs/adherents/class/adherent.class.php @@ -3077,11 +3077,13 @@ class Adherent extends CommonObject $tmp = dol_getdate($now); $datetosearchfor = dol_time_plus_duree(dol_mktime(0, 0, 0, $tmp['mon'], $tmp['mday'], $tmp['year'], 'tzserver'), (int) $daysbeforeend, 'd'); + $datetosearchforend = dol_time_plus_duree(dol_mktime(23, 59, 59, $tmp['mon'], $tmp['mday'], $tmp['year'], 'tzserver'), (int) $daysbeforeend, 'd'); $sql = 'SELECT rowid FROM '.MAIN_DB_PREFIX.'adherent'; $sql .= " WHERE entity = ".((int) $conf->entity); // Do not use getEntity('adherent').")" here, we want the batch to be on its entity only; $sql .= " AND statut = 1"; - $sql .= " AND datefin = '".$this->db->idate($datetosearchfor)."'"; + $sql .= " AND datefin >= '".$this->db->idate($datetosearchfor)."'"; + $sql .= " AND datefin <= '".$this->db->idate($datetosearchforend)."'"; if ((int) $fk_adherent_type > 0) { $sql .= " AND fk_adherent_type = ".((int) $fk_adherent_type); } diff --git a/htdocs/comm/propal/list.php b/htdocs/comm/propal/list.php index dd089bb36bc..2cc4be7ed80 100644 --- a/htdocs/comm/propal/list.php +++ b/htdocs/comm/propal/list.php @@ -757,8 +757,8 @@ if ($search_note_public) { if ($search_user > 0) { $sql .= " AND EXISTS ("; $sql .= " SELECT ec.fk_c_type_contact, ec.element_id, ec.fk_socpeople"; - $sql .= " FROM llx_element_contact as ec"; - $sql .= " INNER JOIN llx_c_type_contact as tc"; + $sql .= " FROM ".MAIN_DB_PREFIX."element_contact as ec"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_contact as tc"; $sql .= " ON ec.fk_c_type_contact = tc.rowid AND tc.element='propal' AND tc.source='internal'"; $sql .= " WHERE ec.element_id = p.rowid AND ec.fk_socpeople = ".((int) $search_user).")"; } diff --git a/htdocs/commande/list.php b/htdocs/commande/list.php index c81932b460e..06806021db2 100644 --- a/htdocs/commande/list.php +++ b/htdocs/commande/list.php @@ -1084,8 +1084,8 @@ if ($search_fk_input_reason > 0) { if ($search_user > 0) { $sql .= " AND EXISTS ("; $sql .= " SELECT ec.fk_c_type_contact, ec.element_id, ec.fk_socpeople"; - $sql .= " FROM llx_element_contact as ec"; - $sql .= " INNER JOIN llx_c_type_contact as tc"; + $sql .= " FROM ".MAIN_DB_PREFIX."element_contact as ec"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_contact as tc"; $sql .= " ON ec.fk_c_type_contact = tc.rowid AND tc.element='commande' AND tc.source='internal'"; $sql .= " WHERE ec.element_id = c.rowid AND ec.fk_socpeople = ".((int) $search_user).")"; } diff --git a/htdocs/compta/bank/bankentries_list.php b/htdocs/compta/bank/bankentries_list.php index 3dd37bf0d1b..057ef86ec08 100644 --- a/htdocs/compta/bank/bankentries_list.php +++ b/htdocs/compta/bank/bankentries_list.php @@ -609,9 +609,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 @@ -624,8 +624,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 @@ -1910,6 +1910,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); diff --git a/htdocs/compta/facture/list.php b/htdocs/compta/facture/list.php index 36c2f2cd02f..33f8026d589 100644 --- a/htdocs/compta/facture/list.php +++ b/htdocs/compta/facture/list.php @@ -892,8 +892,8 @@ if ($search_fk_fac_rec_source) { if ($search_user > 0) { $sql .= " AND EXISTS ("; $sql .= " SELECT ec.fk_c_type_contact, ec.element_id, ec.fk_socpeople"; - $sql .= " FROM llx_element_contact as ec"; - $sql .= " INNER JOIN llx_c_type_contact as tc"; + $sql .= " FROM ".MAIN_DB_PREFIX."element_contact as ec"; + $sql .= " INNER JOIN ".MAIN_DB_PREFIX."c_type_contact as tc"; $sql .= " ON ec.fk_c_type_contact = tc.rowid AND tc.element='facture' AND tc.source='internal'"; $sql .= " WHERE ec.element_id = f.rowid AND ec.fk_socpeople = ".((int) $search_user).")"; } diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index 8905c7de33e..729e383e1db 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -9201,6 +9201,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 .= '' . "\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; diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 479176290ea..e33f64cd293 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -13,6 +13,7 @@ * Copyright (C) 2022 Antonin MARCHAL * Copyright (C) 2024 MDW * Copyright (C) 2024 Benoît PASCAL + * Copyright (C) 2024 Joachim Kueter * * 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 @@ -2853,7 +2854,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. diff --git a/htdocs/emailcollector/class/emailcollector.class.php b/htdocs/emailcollector/class/emailcollector.class.php index e4dceae159f..cba61e395ae 100644 --- a/htdocs/emailcollector/class/emailcollector.class.php +++ b/htdocs/emailcollector/class/emailcollector.class.php @@ -1895,7 +1895,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 @@ -1964,7 +1964,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()) { diff --git a/htdocs/eventorganization/class/conferenceorboothattendee.class.php b/htdocs/eventorganization/class/conferenceorboothattendee.class.php index dead35a402c..b6695ee91c2 100644 --- a/htdocs/eventorganization/class/conferenceorboothattendee.class.php +++ b/htdocs/eventorganization/class/conferenceorboothattendee.class.php @@ -265,7 +265,7 @@ class ConferenceOrBoothAttendee extends CommonObject if (isset($conf->global->EVENTORGANIZATION_FILTERATTENDEES_TYPE) && getDolGlobalString('EVENTORGANIZATION_FILTERATTENDEES_TYPE') !== '' && getDolGlobalString('EVENTORGANIZATION_FILTERATTENDEES_TYPE') !== '-1') { - $this->fields['fk_soc']['type'] .= ' AND client = '.((int) getDolGlobalInt('EVENTORGANIZATION_FILTERATTENDEES_TYPE', 0)); + $this->fields['fk_soc']['type'] .= ' AND (client:=:'.((int) getDolGlobalInt('EVENTORGANIZATION_FILTERATTENDEES_TYPE', 0) . ')'); } // Example to show how to set values of fields definition dynamically diff --git a/htdocs/eventorganization/conferenceorboothattendee_list.php b/htdocs/eventorganization/conferenceorboothattendee_list.php index e4678534f1d..1474a71eef6 100644 --- a/htdocs/eventorganization/conferenceorboothattendee_list.php +++ b/htdocs/eventorganization/conferenceorboothattendee_list.php @@ -613,7 +613,7 @@ if ($projectstatic->id > 0 || $confOrBooth > 0) { // Show message $message = 'global->MAIN_AGENDA_XCAL_EXPORTKEY ? urlencode(getDolGlobalString('MAIN_AGENDA_XCAL_EXPORTKEY')) : '...'); + $message .= '&exportkey='.(getDolGlobalString('MAIN_AGENDA_XCAL_EXPORTKEY') ? urlencode(getDolGlobalString('MAIN_AGENDA_XCAL_EXPORTKEY')) : '...'); $message .= "&project=".$projectstatic->id.'&module='.urlencode('conforbooth@eventorganization').'&status='.ConferenceOrBooth::STATUS_CONFIRMED.'&output=file">'.$langs->trans('DownloadICSLink').img_picto('', 'download', 'class="paddingleft"').''; print $message; print ""; diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php index 78fb936bfa8..44e6630c970 100644 --- a/htdocs/fourn/commande/list.php +++ b/htdocs/fourn/commande/list.php @@ -419,6 +419,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; @@ -531,10 +532,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, diff --git a/htdocs/fourn/facture/card.php b/htdocs/fourn/facture/card.php index 86c29df095e..c5694200c8a 100644 --- a/htdocs/fourn/facture/card.php +++ b/htdocs/fourn/facture/card.php @@ -1346,6 +1346,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; @@ -1362,7 +1367,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, @@ -2733,7 +2738,9 @@ if ($action == 'create') { require_once DOL_DOCUMENT_ROOT . '/core/lib/company.lib.php'; print '' . $langs->trans('VATReverseCharge') . ''; // 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; @@ -3212,14 +3219,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 diff --git a/htdocs/install/mysql/migration/repair.sql b/htdocs/install/mysql/migration/repair.sql index 6f6762f5cb0..8262a3e1c98 100644 --- a/htdocs/install/mysql/migration/repair.sql +++ b/htdocs/install/mysql/migration/repair.sql @@ -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; diff --git a/htdocs/projet/element.php b/htdocs/projet/element.php index 96d5b569677..bed97fcfd14 100644 --- a/htdocs/projet/element.php +++ b/htdocs/projet/element.php @@ -948,7 +948,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; @@ -956,6 +956,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_by_line; diff --git a/htdocs/ticket/card.php b/htdocs/ticket/card.php index 54c65999286..f885e2fe1d7 100644 --- a/htdocs/ticket/card.php +++ b/htdocs/ticket/card.php @@ -431,7 +431,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)) {