From 9f5ef68123ad6336f99a36a7c791afaa7f4547e3 Mon Sep 17 00:00:00 2001 From: thomas-Ngr Date: Thu, 5 Sep 2024 16:01:31 +0200 Subject: [PATCH 01/19] fix replenish with multicurrency (#30832) * fix replenish * Use multicurrency supplier price instead of recomputing from EUR supplier price --- htdocs/product/stock/replenish.php | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/htdocs/product/stock/replenish.php b/htdocs/product/stock/replenish.php index e3f27476488..a1a99523d91 100644 --- a/htdocs/product/stock/replenish.php +++ b/htdocs/product/stock/replenish.php @@ -194,6 +194,13 @@ if ($action == 'order' && GETPOST('valid')) { // TODO Get desc in language of thirdparty } + // If we use multicurrency + if (isModEnabled('multicurrency') && !empty($productsupplier->fourn_multicurrency_code) && $productsupplier->fourn_multicurrency_code != $conf->currency) { + $line->multicurrency_code = $productsupplier->fourn_multicurrency_code; + $line->fk_multicurrency = $productsupplier->fourn_multicurrency_id; + $line->multicurrency_subprice = $productsupplier->fourn_multicurrency_unitprice; + } + $line->tva_tx = $productsupplier->vatrate_supplier; $line->subprice = $productsupplier->fourn_pu; $line->total_ht = $productsupplier->fourn_pu * $qty; @@ -262,7 +269,8 @@ if ($action == 'order' && GETPOST('valid')) { null, null, 0, - $line->fk_unit + $line->fk_unit, + $line->multicurrency_subprice ?? 0 ); } if ($result < 0) { @@ -277,6 +285,7 @@ if ($action == 'order' && GETPOST('valid')) { } else { $order->socid = $suppliersid[$i]; $order->fetch_thirdparty(); + $order->multicurrency_code = $order->thirdparty->multicurrency_code; // Trick to know which orders have been generated using the replenishment feature $order->source = $order::SOURCE_ID_REPLENISHMENT; From 61c5a61623125af2297bceffd1ad470b46173a66 Mon Sep 17 00:00:00 2001 From: HENRY Florian Date: Fri, 20 Sep 2024 17:46:52 +0200 Subject: [PATCH 02/19] fix: better error reporting in CMailFile (#31058) --- htdocs/core/class/CMailFile.class.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index da861fbfb0d..4110c7ee731 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -875,7 +875,7 @@ class CMailFile } } elseif ($this->sendmode == 'smtps') { if (!is_object($this->smtps)) { - $this->error = "Failed to send mail with smtps lib to HOST=".$server.", PORT=".$conf->global->$keyforsmtpport."
Constructor of object CMailFile was not initialized without errors."; + $this->error = "Failed to send mail with smtps lib to HOST=".ini_get('SMTP').", PORT=".$conf->global->$keyforsmtpport."
Constructor of object CMailFile was not initialized without errors."; dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); return false; } @@ -1165,9 +1165,10 @@ class CMailFile $res = true; if (!empty($this->error) || !empty($this->errors) || !$result) { if (!empty($failedRecipients)) { - $this->errors[] = 'Transport failed for the following addresses: "' . join('", "', $failedRecipients) . '".'; + $this->error = 'Transport failed for the following addresses: "' . join('", "', $failedRecipients) . '".'; + $this->errors[] = $this->error; } - dol_syslog("CMailFile::sendfile: mail end error=".$this->error, LOG_ERR); + dol_syslog("CMailFile::sendfile: mail end error=". join(' ', $this->errors), LOG_ERR); $res = false; if (!empty($conf->global->MAIN_MAIL_DEBUG)) { From b3bbe22f233a9159036c5944285070c4722ddeed Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 21 Sep 2024 12:51:41 +0200 Subject: [PATCH 03/19] FIX Extrafields does not appear on form --- htdocs/public/company/new.php | 34 +++++++++++-------- .../public/eventorganization/attendee_new.php | 24 +++++++++++-- 2 files changed, 41 insertions(+), 17 deletions(-) diff --git a/htdocs/public/company/new.php b/htdocs/public/company/new.php index a77e3c84a23..90e5bc33e58 100644 --- a/htdocs/public/company/new.php +++ b/htdocs/public/company/new.php @@ -92,10 +92,11 @@ $hookmanager->initHooks(array('publicnewmembercard', 'globalcard')); $extrafields = new ExtraFields($db); - $objectsoc = new Societe($db); $user->loadDefaultValues(); +$extrafields->fetch_name_optionals_label($objectsoc->table_element); // fetch optionals attributes and labels + /** * Show header for new prospect @@ -219,26 +220,27 @@ if (empty($reshook) && $action == 'add') { $societe->name = GETPOST('name', 'alphanohtml'); - $societe->client = GETPOSTINT('client') ? GETPOSTINT('client') : $societe->client; - $societe->address = GETPOST('address', 'alphanohtml'); - $societe->country_id = GETPOSTINT('country_id'); - $societe->phone = GETPOST('phone', 'alpha'); - $societe->fax = GETPOST('fax', 'alpha'); - $societe->email = trim(GETPOST('email', 'custom', 0, FILTER_SANITIZE_EMAIL)); - $societe->client = 2 ; // our client is a prospect - $societe->code_client = '-1'; - $societe->name_alias = GETPOST('name_alias', 'alphanohtml'); + $societe->note_private = GETPOST('note_private', 'alphanohtml'); + + // Fill array 'array_options' with data from add form + /* + $extrafields->fetch_name_optionals_label($societe->table_element); + $ret = $extrafields->setOptionalsFromPost(null, $societe); + if ($ret < 0) { + $error++; + $errmsg .= $societe->error; + } + */ - $societe->note_private = GETPOST('note_private'); if (!$error) { $result = $societe->create($user); if ($result > 0) { @@ -298,7 +300,6 @@ $form = new Form($db); $formcompany = new FormCompany($db); $adht = new AdherentType($db); $formadmin = new FormAdmin($db); -$extrafields->fetch_name_optionals_label($objectsoc->table_element); // fetch optionals attributes and labels llxHeaderVierge($langs->trans("ContactUs")); @@ -436,10 +437,15 @@ print ''; print '' . $langs->trans("Comments") . ''; print ''; print '' . "\n"; + + +// Other attributes +$parameters['tpl_context'] = 'public'; // define template context to public +include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; + + // TODO Move this into generic feature. - - // Display Captcha code if is enabled if (getDolGlobalString('MAIN_SECURITY_ENABLECAPTCHA')) { require_once DOL_DOCUMENT_ROOT . '/core/lib/security2.lib.php'; diff --git a/htdocs/public/eventorganization/attendee_new.php b/htdocs/public/eventorganization/attendee_new.php index f8bacc3d940..ad08f71fbe9 100644 --- a/htdocs/public/eventorganization/attendee_new.php +++ b/htdocs/public/eventorganization/attendee_new.php @@ -86,7 +86,9 @@ if ($type == 'conf') { } $conference = new ConferenceOrBooth($db); +$confattendee = new ConferenceOrBoothAttendee($db); $project = new Project($db); +$object = $confattendee; if ($type == 'conf') { $resultconf = $conference->fetch($id); @@ -151,6 +153,8 @@ if (empty($conf->eventorganization->enabled)) { httponly_accessforbidden('Module Event organization not enabled'); } +$extrafields->fetch_name_optionals_label($object->table_element); // fetch optionals attributes and labels + /** * Show header for new member @@ -264,8 +268,6 @@ if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conferen if (!$error) { // Check if attendee already exists (by email and for this event) - $confattendee = new ConferenceOrBoothAttendee($db); - $filter = array(); if ($type == 'global') { @@ -292,6 +294,15 @@ if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conferen $confattendee->firstname = $firstname; $confattendee->lastname = $lastname; + // Fill array 'array_options' with data from add form + $extrafields->fetch_name_optionals_label($confattendee->table_element); + $ret = $extrafields->setOptionalsFromPost(null, $confattendee); + if ($ret < 0) { + $error++; + $errmsg .= $confattendee->error; + } + + // Count recent already posted event $confattendee->ip = getUserRemoteIP(); $nb_post_max = getDolGlobalInt("MAIN_SECURITY_MAX_POST_ON_PUBLIC_PAGES_BY_IP_ADDRESS", 200); $now = dol_now(); @@ -488,6 +499,7 @@ if (empty($reshook) && $action == 'add' && (!empty($conference->id) && $conferen $tmpcode = $modCodeClient->getNextValue($thirdparty, 0); } $thirdparty->code_client = $tmpcode; + $readythirdparty = $thirdparty->create($user); if ($readythirdparty < 0) { $error++; @@ -891,14 +903,20 @@ if ((!empty($conference->id) && $conference->status == ConferenceOrBooth::STATUS print ''; } + // Other attributes + $parameters['tpl_context'] = 'public'; // define template context to public + include DOL_DOCUMENT_ROOT.'/core/tpl/extrafields_add.tpl.php'; + $notetoshow = $note_public; print '' . $langs->trans('Note') . ''; if (getDolGlobalString('EVENTORGANIZATION_DEFAULT_NOTE_ON_REGISTRATION')) { - $notetoshow = str_replace('\n', "\n", $conf->global->EVENTORGANIZATION_DEFAULT_NOTE_ON_REGISTRATION); + $notetoshow = str_replace('\n', "\n", getDolGlobalString('EVENTORGANIZATION_DEFAULT_NOTE_ON_REGISTRATION')); } print ''; print ''; + + print "\n"; print dol_get_fiche_end(); From 98c7c7deefd823cfb31c086fd81d6bda4a8668d8 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Sat, 21 Sep 2024 15:35:25 +0200 Subject: [PATCH 04/19] Fix css too large --- htdocs/theme/eldy/global.inc.php | 5 +++++ htdocs/theme/md/style.css.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/htdocs/theme/eldy/global.inc.php b/htdocs/theme/eldy/global.inc.php index 15ec4611f64..c8d2c2117fb 100644 --- a/htdocs/theme/eldy/global.inc.php +++ b/htdocs/theme/eldy/global.inc.php @@ -1690,6 +1690,11 @@ table.paymenttable td.amountpaymentcomplete, table.paymenttable td.amountremaint .fa-15 { font-size: 1.5em; } + +.fa-map-marked-alt:before { + font-size: 0.85em; +} + .text-security { -webkit-text-security: disc; } diff --git a/htdocs/theme/md/style.css.php b/htdocs/theme/md/style.css.php index eb9c7ccff12..3755aa1f2eb 100644 --- a/htdocs/theme/md/style.css.php +++ b/htdocs/theme/md/style.css.php @@ -1847,6 +1847,11 @@ select.flat.selectlimit { .fa-15 { font-size: 1.5em; } + +.fa-map-marked-alt:before { + font-size: 0.85em; +} + .text-security { -webkit-text-security: disc; } From 8f54f06e122ecb5a026af59f86f028f873964170 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 02:24:43 +0200 Subject: [PATCH 05/19] FIX #31076 Bad position of hooks --- htdocs/modulebuilder/template/myobject_list.php | 3 --- htdocs/product/stock/card.php | 8 ++++---- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/htdocs/modulebuilder/template/myobject_list.php b/htdocs/modulebuilder/template/myobject_list.php index c5a342f1f24..c653d95d619 100644 --- a/htdocs/modulebuilder/template/myobject_list.php +++ b/htdocs/modulebuilder/template/myobject_list.php @@ -577,9 +577,6 @@ if (empty($reshook)) { if (!empty($moreforfilter)) { print '
'; print $moreforfilter; - $parameters = array(); - $reshook = $hookmanager->executeHooks('printFieldPreListTitle', $parameters, $object, $action); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; print '
'; } diff --git a/htdocs/product/stock/card.php b/htdocs/product/stock/card.php index 407d621e47c..1e2950c5431 100644 --- a/htdocs/product/stock/card.php +++ b/htdocs/product/stock/card.php @@ -758,10 +758,6 @@ if ($action == 'create') { //print ''.dol_print_date($objp->datem).''; print ''; - $parameters = array('obj' => $objp, 'totalarray' => &$totalarray); - $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook - print $hookmanager->resPrint; - $productstatic->id = $objp->rowid; $productstatic->ref = $objp->ref; $productstatic->label = $objp->produit; @@ -842,6 +838,10 @@ if ($action == 'create') { print ""; } + $parameters = array('obj' => $objp, 'totalarray' => &$totalarray); + $reshook = $hookmanager->executeHooks('printFieldListValue', $parameters); // Note that $action and $object may have been modified by hook + print $hookmanager->resPrint; + print ""; $i++; From f6ae2815c1c3087c0fbab6669546a9b9ce76b783 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 03:00:19 +0200 Subject: [PATCH 06/19] Fix missing translation --- htdocs/product/stats/card.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/htdocs/product/stats/card.php b/htdocs/product/stats/card.php index 8a6eca21ac8..231d24828c7 100644 --- a/htdocs/product/stats/card.php +++ b/htdocs/product/stats/card.php @@ -355,12 +355,14 @@ if ($result || !($id > 0)) { } if (isModEnabled('order')) { + $langs->load("orders"); $graphfiles['orders'] = array('modulepart' => 'productstats_orders', 'file' => $object->id.'/orders12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year > 0 ? '_year'.$search_year : '').'.png', 'label' => $langs->transnoentitiesnoconv($arrayforlabel[$mode], $langs->transnoentitiesnoconv("Orders"))); } if (isModEnabled('supplier_order')) { + $langs->load("orders"); $graphfiles['orderssuppliers'] = array('modulepart' => 'productstats_orderssuppliers', 'file' => $object->id.'/orderssuppliers12m'.((string) $type != '' ? '_type'.$type : '').'_'.$mode.($search_year > 0 ? '_year'.$search_year : '').'.png', 'label' => $langs->transnoentitiesnoconv($arrayforlabel[$mode], $langs->transnoentitiesnoconv("SuppliersOrders"))); From 6feefbb8c59387109425fc509b2d3ff08083aba6 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 03:16:12 +0200 Subject: [PATCH 07/19] Fix trans --- htdocs/product/stats/commande_fournisseur.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/product/stats/commande_fournisseur.php b/htdocs/product/stats/commande_fournisseur.php index fd0b1f092bf..ce70067b2da 100644 --- a/htdocs/product/stats/commande_fournisseur.php +++ b/htdocs/product/stats/commande_fournisseur.php @@ -31,7 +31,7 @@ require_once DOL_DOCUMENT_ROOT.'/core/class/html.formother.class.php'; require_once DOL_DOCUMENT_ROOT.'/core/class/html.formorder.class.php'; // Load translation files required by the page -$langs->loadLangs(array('orders', 'products', 'companies')); +$langs->loadLangs(array('orders', 'products', 'companies', 'sendings')); $id = GETPOSTINT('id'); $ref = GETPOST('ref', 'alpha'); From fd0338cb1cef30ba5e53d4b4cb6ee1ed246cea2e Mon Sep 17 00:00:00 2001 From: MaximilienR-easya <122890855+MaximilienR-easya@users.noreply.github.com> Date: Mon, 23 Sep 2024 03:53:22 +0200 Subject: [PATCH 08/19] Backport Fix error on empty(NOLOGIN) (#30594) * initial commit * Backport Fix from develop * Fix precommit * Correction as sugested in the PR * Deleted too much last commit * this time it's good --- ...e_20_modWorkflow_WorkflowManager.class.php | 45 +++++++++---------- 1 file changed, 21 insertions(+), 24 deletions(-) diff --git a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php index 66df0c0b4fb..6684aba2bc2 100644 --- a/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php +++ b/htdocs/core/triggers/interface_20_modWorkflow_WorkflowManager.class.php @@ -459,45 +459,42 @@ class InterfaceWorkflowManager extends DolibarrTriggers if ($action == 'TICKET_CREATE') { dol_syslog("Trigger '".$this->name."' for action '$action' launched by ".__FILE__.". id=".$object->id); - // Auto link contract - if (!empty($conf->contract->enabled) && isModEnabled('ticket') && isModEnabled('ficheinter') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_TICKET_LINK_CONTRACT) && !empty($conf->global->TICKET_PRODUCT_CATEGORY) && !empty($object->fk_soc)) { + // Auto link ticket to contract + if (isModEnabled('contract') && isModEnabled('ticket') && isModEnabled('workflow') && getDolGlobalString('WORKFLOW_TICKET_LINK_CONTRACT') && getDolGlobalString('TICKET_PRODUCT_CATEGORY') && !empty($object->fk_soc)) { $societe = new Societe($this->db); - $company_ids = (empty($conf->global->WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS)) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]); + $company_ids = (!getDolGlobalString('WORKFLOW_TICKET_USE_PARENT_COMPANY_CONTRACTS')) ? [$object->fk_soc] : $societe->getParentsForCompany($object->fk_soc, [$object->fk_soc]); $contrat = new Contrat($this->db); $number_contracts_found = 0; foreach ($company_ids as $company_id) { $contrat->socid = $company_id; - $list = $contrat->getListOfContracts($option = 'all', $status = [Contrat::STATUS_DRAFT, Contrat::STATUS_VALIDATED], $product_categories = [$conf->global->TICKET_PRODUCT_CATEGORY], $line_status = [ContratLigne::STATUS_INITIAL, ContratLigne::STATUS_OPEN]); - if (is_array($list) && !empty($list)) { - $number_contracts_found = count($list); - if ($number_contracts_found == 1) { - foreach ($list as $linked_contract) { - $object->setContract($linked_contract->id); - } - break; - } elseif ($number_contracts_found > 1) { - foreach ($list as $linked_contract) { - $object->setContract($linked_contract->id); - // don't set '$contractid' so it is not used when creating an intervention. - } - if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketManyContractsLinked'), 'warnings'); - break; - } + $list = $contrat->getListOfContracts('all', array(Contrat::STATUS_DRAFT, Contrat::STATUS_VALIDATED), array(getDolGlobalString('TICKET_PRODUCT_CATEGORY')), array(ContratLigne::STATUS_INITIAL, ContratLigne::STATUS_OPEN)); + if (!is_array($list) || empty($list)) { + continue; + } + $number_contracts_found = count($list); + + foreach ($list as $linked_contract) { + $object->setContract($linked_contract->id); + // don't set '$contractid' so it is not used when creating an intervention. + } + + if ($number_contracts_found > 1 && !defined('NOLOGIN')) { + setEventMessage($langs->trans('TicketManyContractsLinked'), 'warnings'); } } - if ($number_contracts_found == 0) { - if (empty(NOLOGIN)) setEventMessage($langs->trans('TicketNoContractFoundToLink'), 'mesgs'); + if ($number_contracts_found == 0 && !defined('NOLOGIN')) { + setEventMessage($langs->trans('TicketNoContractFoundToLink'), 'mesgs'); } } // Automatically create intervention - if (isModEnabled('ficheinter') && isModEnabled('ticket') && !empty($conf->workflow->enabled) && !empty($conf->global->WORKFLOW_TICKET_CREATE_INTERVENTION)) { + if (isModEnabled('ficheinter') && isModEnabled('ticket') && isModEnabled('workflow') && getDolGlobalString('WORKFLOW_TICKET_CREATE_INTERVENTION')) { $fichinter = new Fichinter($this->db); $fichinter->socid = (int) $object->fk_soc; - $fichinter->fk_project = $projectid; + $fichinter->fk_project = (int) $object->fk_project; $fichinter->fk_contrat = (int) $object->fk_contract; $fichinter->author = $user->id; - $fichinter->model_pdf = (!empty($conf->global->FICHEINTER_ADDON_PDF)) ? $conf->global->FICHEINTER_ADDON_PDF : 'soleil'; + $fichinter->model_pdf = getDolGlobalString('FICHEINTER_ADDON_PDF', 'soleil'); $fichinter->origin = $object->element; $fichinter->origin_id = $object->id; From 21d8c40fc0b674fa188d994709c95a0e87c471a4 Mon Sep 17 00:00:00 2001 From: William Mead Date: Mon, 23 Sep 2024 03:55:18 +0200 Subject: [PATCH 09/19] Fixed select list for long third party names (#30948) --- htdocs/core/tpl/contacts.tpl.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/tpl/contacts.tpl.php b/htdocs/core/tpl/contacts.tpl.php index 7f4b3971205..75bc8de4791 100644 --- a/htdocs/core/tpl/contacts.tpl.php +++ b/htdocs/core/tpl/contacts.tpl.php @@ -143,7 +143,7 @@ if ($permission) {
socid) ? 0 : $object->socid); - $selectedCompany = $formcompany->selectCompaniesForNewContact($object, 'id', $selectedCompany, 'newcompany', '', 0, '', 'minwidth300imp'); // This also print the select component + $selectedCompany = $formcompany->selectCompaniesForNewContact($object, 'id', $selectedCompany, 'newcompany', '', 0, '', 'minwidth300imp maxwidth400 widthcentpercentminusx'); // This also print the select component ?>
From 1bf09629cb7ec512c6feff6972192288f4e7d8e3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 11:32:14 +0200 Subject: [PATCH 10/19] Fix holiday types common to all entities --- htdocs/core/lib/functions.lib.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index 762910dc8dd..bf814e08e5f 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -434,7 +434,7 @@ function getEntity($element, $shared = 1, $currentobject = null) $out = $mc->getEntity($element, $shared, $currentobject); } else { $out = ''; - $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'email_template', 'default_values', 'overwrite_trans'); + $addzero = array('user', 'usergroup', 'cronjob', 'c_email_templates', 'c_holiday_types', 'email_template', 'default_values', 'overwrite_trans'); if (in_array($element, $addzero)) { $out .= '0,'; } From 073facfee55c2fc7ec326d84064e439eac1cd039 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 12:18:47 +0200 Subject: [PATCH 11/19] Trans --- htdocs/langs/en_US/holiday.lang | 4 ++-- htdocs/langs/fr_FR/holiday.lang | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/htdocs/langs/en_US/holiday.lang b/htdocs/langs/en_US/holiday.lang index cab8fce1da1..fa0dd6d69a0 100644 --- a/htdocs/langs/en_US/holiday.lang +++ b/htdocs/langs/en_US/holiday.lang @@ -41,8 +41,8 @@ TitreRequestCP=Leave request TypeOfLeaveId=Type of leave ID TypeOfLeaveCode=Type of leave code TypeOfLeaveLabel=Type of leave label -NbUseDaysCP=Number of days of leave used -NbUseDaysCPHelp=The calculation takes into account the non-working days and the holidays defined in the dictionary. +NbUseDaysCP=Number of days +NbUseDaysCPHelp=The calculation of the number of days o fleave used takes into account the non-working days and the holidays defined in the dictionary. NbUseDaysCPShort=Days of leave NbUseDaysCPShortInMonth=Days of leave in month DayIsANonWorkingDay=%s is a non-working day diff --git a/htdocs/langs/fr_FR/holiday.lang b/htdocs/langs/fr_FR/holiday.lang index a86d739b1a8..82e08b6ab15 100644 --- a/htdocs/langs/fr_FR/holiday.lang +++ b/htdocs/langs/fr_FR/holiday.lang @@ -41,9 +41,9 @@ TitreRequestCP=Demande de congés TypeOfLeaveId=Type de la demande de congès TypeOfLeaveCode=Code du type de congès TypeOfLeaveLabel=Libellé du type de congès -NbUseDaysCP=Nombre de jours de congés consommés -NbUseDaysCPHelp=Le calcul prend en compte les jours non ouvrés et les jours fériés définis dans le dictionnaire. -NbUseDaysCPShort=Jours consommés +NbUseDaysCP=Nombre de jours de congés +NbUseDaysCPHelp=Le calcul du nombre de jours de congés pris prend en compte les jours non ouvrés et les jours fériés définis dans le dictionnaire. +NbUseDaysCPShort=Jours NbUseDaysCPShortInMonth=Jours consommés pour le mois DayIsANonWorkingDay=%s est un jour non ouvré DateStartInMonth=Date de début pour le mois From 6ca2e746cabc0fdf5da9f275c44fd3f01fc0aef4 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 13:09:45 +0200 Subject: [PATCH 12/19] Fix DOS attack by using num_public_holiday() - repeated sql in loop --- htdocs/core/lib/date.lib.php | 100 +++++++++++++++++++---------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/htdocs/core/lib/date.lib.php b/htdocs/core/lib/date.lib.php index abe83bbd1a3..f2b69036218 100644 --- a/htdocs/core/lib/date.lib.php +++ b/htdocs/core/lib/date.lib.php @@ -762,7 +762,7 @@ function getGMTEasterDatetime($year) */ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', $lastday = 0, $includesaturday = -1, $includesunday = -1, $includefriday = -1, $includemonday = -1) { - global $db, $mysoc; + global $conf, $db, $mysoc; $nbFerie = 0; @@ -789,21 +789,10 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', $country_id = dol_getIdFromCode($db, $country_code, 'c_country', 'code', 'rowid'); - $i = 0; - while ((($lastday == 0 && $timestampStart < $timestampEnd) || ($lastday && $timestampStart <= $timestampEnd)) - && ($i < 50000)) { // Loop end when equals (Test on i is a security loop to avoid infinite loop) - $ferie = false; - $specialdayrule = array(); - - $jour = (int) gmdate("d", $timestampStart); - $mois = (int) gmdate("m", $timestampStart); - $annee = (int) gmdate("Y", $timestampStart); - - //print "jour=".$jour." month=".$mois." year=".$annee." includesaturday=".$includesaturday." includesunday=".$includesunday."\n"; - + if (empty($conf->cache['arrayOfActivePublicHolidays_'.$country_id])) { // Loop on public holiday defined into hrm_public_holiday for the day, month and year analyzed - // TODO Execute this request first and store results into an array, then reuse this array. - $sql = "SELECT code, entity, fk_country, dayrule, year, month, day, active"; + $tmpArrayOfPublicHolidays = array(); + $sql = "SELECT id, code, entity, fk_country, dayrule, year, month, day, active"; $sql .= " FROM ".MAIN_DB_PREFIX."c_hrm_public_holiday"; $sql .= " WHERE active = 1 and fk_country IN (0".($country_id > 0 ? ", ".$country_id : 0).")"; $sql .= " AND entity IN (0," .getEntity('holiday') .")"; @@ -814,34 +803,55 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', $i = 0; while ($i < $num_rows) { $obj = $db->fetch_object($resql); - - if (!empty($obj->dayrule) && $obj->dayrule != 'date') { // For example 'easter', '...' - $specialdayrule[$obj->dayrule] = $obj->dayrule; - } else { - $match = 1; - if (!empty($obj->year) && $obj->year != $annee) { - $match = 0; - } - if ($obj->month != $mois) { - $match = 0; - } - if ($obj->day != $jour) { - $match = 0; - } - - if ($match) { - $ferie = true; - } - } - + $tmpArrayOfPublicHolidays[$obj->id] = array('dayrule' => $obj->dayrule, 'year' => $obj->year, 'month' => $obj->month, 'day' => $obj->day); $i++; } } else { dol_syslog($db->lasterror(), LOG_ERR); return 'Error sql '.$db->lasterror(); } - //var_dump($specialdayrule)."\n"; - //print "ferie=".$ferie."\n"; + + //var_dump($tmpArrayOfPublicHolidays); + $conf->cache['arrayOfActivePublicHolidays_'.$country_id] = $tmpArrayOfPublicHolidays; + } + + $arrayOfPublicHolidays = $conf->cache['arrayOfActivePublicHolidays_'.$country_id]; + + $i = 0; + while ((($lastday == 0 && $timestampStart < $timestampEnd) || ($lastday && $timestampStart <= $timestampEnd)) + && ($i < 50000)) { // Loop end when equals (Test on i is a security loop to avoid infinite loop) + $ferie = false; + $specialdayrule = array(); + + $jour = (int) gmdate("d", $timestampStart); + $mois = (int) gmdate("m", $timestampStart); + $annee = (int) gmdate("Y", $timestampStart); + + //print "jour=".$jour." month=".$mois." year=".$annee." includesaturday=".$includesaturday." includesunday=".$includesunday."\n"; + foreach ($arrayOfPublicHolidays as $entrypublicholiday) { + if (!empty($entrypublicholiday['dayrule']) && $entrypublicholiday['dayrule'] != 'date') { // For example 'easter', '...' + $specialdayrule[$entrypublicholiday['dayrule']] = $entrypublicholiday['dayrule']; + } else { + $match = 1; + if (!empty($entrypublicholiday['year']) && $entrypublicholiday['year'] != $annee) { + $match = 0; + } + if ($entrypublicholiday['month'] != $mois) { + $match = 0; + } + if ($entrypublicholiday['day'] != $jour) { + $match = 0; + } + + if ($match) { + $ferie = true; + } + } + + $i++; + } + //var_dump($specialdayrule)."\n"; + //print "ferie=".$ferie."\n"; if (!$ferie) { // Special dayrules @@ -955,9 +965,9 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', // Geneva fast in Switzerland } } - //print "ferie=".$ferie."\n"; + //print "ferie=".$ferie."\n"; - // If we have to include Friday, Saturday and Sunday + // If we have to include Friday, Saturday and Sunday if (!$ferie) { if ($includefriday || $includesaturday || $includesunday) { $jour_julien = unixtojd($timestampStart); @@ -979,18 +989,18 @@ function num_public_holiday($timestampStart, $timestampEnd, $country_code = '', } } } - //print "ferie=".$ferie."\n"; + //print "ferie=".$ferie."\n"; - // We increase the counter of non working day + // We increase the counter of non working day if ($ferie) { $nbFerie++; } - // Increase number of days (on go up into loop) - $timestampStart = dol_time_plus_duree($timestampStart, 1, 'd'); - //var_dump($jour.' '.$mois.' '.$annee.' '.$timestampStart); + // Increase number of days (on go up into loop) + $timestampStart = dol_time_plus_duree($timestampStart, 1, 'd'); + //var_dump($jour.' '.$mois.' '.$annee.' '.$timestampStart); - $i++; + $i++; } //print "nbFerie=".$nbFerie."\n"; From 50fba3e99e1cf0904eeec57d4630ccfcea647dff Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 13:54:48 +0200 Subject: [PATCH 13/19] Fix log level --- htdocs/core/class/CMailFile.class.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/htdocs/core/class/CMailFile.class.php b/htdocs/core/class/CMailFile.class.php index b7005ffb076..0d213873b2e 100644 --- a/htdocs/core/class/CMailFile.class.php +++ b/htdocs/core/class/CMailFile.class.php @@ -193,7 +193,7 @@ class CMailFile { global $conf, $dolibarr_main_data_root, $user; - dol_syslog("CMailFile::CMailfile: charset=".$conf->file->character_set_client." from=$from, to=$to, addr_cc=$addr_cc, addr_bcc=$addr_bcc, errors_to=$errors_to, replyto=$replyto trackid=$trackid sendcontext=$sendcontext", LOG_DEBUG); + dol_syslog("CMailFile::CMailfile: charset=".$conf->file->character_set_client." from=$from, to=$to, addr_cc=$addr_cc, addr_bcc=$addr_bcc, errors_to=$errors_to, replyto=$replyto trackid=$trackid sendcontext=$sendcontext"); dol_syslog("CMailFile::CMailfile: subject=".$subject.", deliveryreceipt=".$deliveryreceipt.", msgishtml=".$msgishtml, LOG_DEBUG); @@ -282,7 +282,7 @@ class CMailFile if (getDolGlobalString('MAIN_MAIL_FORCE_CONTENT_TYPE_TO_HTML')) { $this->msgishtml = 1; // To force to send everything with content type html. } - dol_syslog("CMailFile::CMailfile: msgishtml=".$this->msgishtml); + dol_syslog("CMailFile::CMailfile: msgishtml=".$this->msgishtml, LOG_DEBUG); // Detect images if ($this->msgishtml) { @@ -904,7 +904,7 @@ class CMailFile if ($this->sendmode == 'mail') { // Use mail php function (default PHP method) // ------------------------------------------ - dol_syslog("CMailFile::sendfile addr_to=".$this->addr_to.", subject=".$this->subject, LOG_DEBUG); + dol_syslog("CMailFile::sendfile addr_to=".$this->addr_to.", subject=".$this->subject, LOG_NOTICE); //dol_syslog("CMailFile::sendfile header=\n".$this->headers, LOG_DEBUG); //dol_syslog("CMailFile::sendfile message=\n".$message); @@ -1137,7 +1137,7 @@ class CMailFile } if ($res) { - dol_syslog("CMailFile::sendfile: sendMsg, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_DEBUG); + dol_syslog("CMailFile::sendfile: sendMsg, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_NOTICE); if (getDolGlobalString('MAIN_MAIL_DEBUG')) { $this->smtps->setDebug(true); @@ -1310,7 +1310,7 @@ class CMailFile $this->mailer->registerPlugin(new Swift_Plugins_LoggerPlugin($this->logger)); } - dol_syslog("CMailFile::sendfile: mailer->send, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_DEBUG); + dol_syslog("CMailFile::sendfile: mailer->send, HOST=".$server.", PORT=" . getDolGlobalString($keyforsmtpport), LOG_NOTICE); // send mail $failedRecipients = array(); @@ -1618,7 +1618,7 @@ class CMailFile $out .= "Content-Type: multipart/mixed;".$this->eol2." boundary=\"".$this->mixed_boundary."\"".$this->eol2; $out .= "Content-Transfer-Encoding: 8bit".$this->eol2; // TODO Seems to be ignored. Header is 7bit once received. - dol_syslog("CMailFile::write_smtpheaders smtp_header=\n".$out); + dol_syslog("CMailFile::write_smtpheaders smtp_header=\n".$out, LOG_DEBUG); return $out; } From dcc8bc9936312f14552658e20adb3cc180999cf5 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 14:10:24 +0200 Subject: [PATCH 14/19] Fix CSS --- htdocs/core/class/commonobject.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index f57c443ad12..c10d7c9343a 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -9091,7 +9091,7 @@ abstract class CommonObject if (getDolGlobalString('MAIN_VIEW_LINE_NUMBER') && ($action == 'view' || $action == 'valid' || $action == 'editline' || $action == 'confirm_valid' || $action == 'confirm_cancel')) { $out .= ''; } - $out .= 'attributes[$this->table_element]['type'][$key] == 'text') { $out .= ' tdtop'; } From eee62347af7972602e567527faa74fed031699b3 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 12:46:29 +0200 Subject: [PATCH 15/19] Fix CSS --- htdocs/core/class/html.formother.class.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/core/class/html.formother.class.php b/htdocs/core/class/html.formother.class.php index cf55a4366d1..6fa34cd6535 100644 --- a/htdocs/core/class/html.formother.class.php +++ b/htdocs/core/class/html.formother.class.php @@ -1253,7 +1253,7 @@ class FormOther if (preg_match('/graph/', $box->class) && $conf->browser->layout != 'phone') { $label = $label.' '; } - $arrayboxtoactivatelabel[$box->id] = array('label' => $label, 'data-html' => img_picto('', $box->boximg, 'class="pictofixedwidth"').$langs->trans($label)); // We keep only boxes not shown for user, to show into combo list + $arrayboxtoactivatelabel[$box->id] = array('label' => $label, 'data-html' => img_picto('', $box->boximg, 'class="pictofixedwidth valignmiddle"').''.$langs->trans($label).''); // We keep only boxes not shown for user, to show into combo list } foreach ($boxidactivatedforuser as $boxid) { if (empty($boxorder)) { From 0e590151a00bd19cec730795f07822e88c5f205f Mon Sep 17 00:00:00 2001 From: sonikf <93765174+sonikf@users.noreply.github.com> Date: Mon, 23 Sep 2024 16:01:53 +0300 Subject: [PATCH 16/19] fix #31089 (#31092) --- htdocs/admin/multicurrency.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/htdocs/admin/multicurrency.php b/htdocs/admin/multicurrency.php index 5afd1ce8c85..08822da9a59 100644 --- a/htdocs/admin/multicurrency.php +++ b/htdocs/admin/multicurrency.php @@ -121,7 +121,7 @@ if ($action == 'add_currency') { $currency = new MultiCurrency($db); if ($currency->fetch($fk_multicurrency) > 0) { - if ($currency->delete() > 0) { + if ($currency->delete($user) > 0) { setEventMessages($langs->trans('RecordDeleted'), array()); } else { setEventMessages($langs->trans('ErrorDeleteCurrencyFail'), array(), 'errors'); From 77367f349f1464f594aaaf662b54c32f49887ca4 Mon Sep 17 00:00:00 2001 From: Mohamed DAOUD Date: Mon, 23 Sep 2024 15:04:16 +0200 Subject: [PATCH 17/19] fix inventory det (#31097) --- htdocs/core/modules/modStock.class.php | 8 ++++---- htdocs/exports/export.php | 7 +++++-- htdocs/langs/en_US/stocks.lang | 11 +++++++++++ htdocs/langs/fr_FR/stocks.lang | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/htdocs/core/modules/modStock.class.php b/htdocs/core/modules/modStock.class.php index 1de2d1952ac..172dd642863 100644 --- a/htdocs/core/modules/modStock.class.php +++ b/htdocs/core/modules/modStock.class.php @@ -395,8 +395,8 @@ class modStock extends DolibarrModules $this->export_sql_end[$r] .= ' WHERE p.rowid = sm.fk_product AND sm.fk_entrepot = e.rowid'; $this->export_sql_end[$r] .= ' AND e.entity IN ('.getEntity('stock').')'; - // Export inventory + // Export inventories $r++; $this->export_code[$r] = $this->rights_class.'_inventory'; $this->export_label[$r] = "Inventories"; // Translation key (used only if key ExportDataset_xxx_z not found) @@ -404,7 +404,7 @@ class modStock extends DolibarrModules $this->export_permission[$r] = array(array("stock", "lire")); $this->export_fields_array[$r] = array( 'i.rowid' => 'InventoryId', 'i.ref' => 'InventoryRef', 'i.date_inventory' => 'DateInventory', 'i.status' => 'InventoryStatus', 'i.title' => 'InventoryTitle', - 'id.rowid' => 'InventoryLineId', 'id.qty_view' => 'QtyViewed', 'id.qty_stock' => 'QtyStock', 'id.qty_regulated' => 'QtyRegulated', 'id.fk_warehouse' => 'InventoryEntrepot', + 'id.rowid' => 'InventoryLineId', 'id.qty_view' => 'QtyViewed', 'id.qty_stock' => 'QtyStock', 'id.qty_regulated' => 'QtyRegulated', 'id.batch' => 'Lotserial', 'e.rowid' => 'IdWarehouse', 'e.ref' => 'LocationSummary', 'e.description' => 'DescWareHouse', 'e.lieu' => 'LieuWareHouse', 'e.address' => 'Address', 'e.zip' => 'Zip', 'e.town' => 'Town', 'p.rowid' => "ProductId", 'p.ref' => "Ref", 'p.fk_product_type' => "Type", 'p.label' => "Label", 'p.description' => "Description", 'p.note' => "Note", @@ -426,14 +426,14 @@ class modStock extends DolibarrModules $this->export_TypeFields_array[$r] = array_merge($this->export_TypeFields_array[$r], array('p.barcode' => 'Text')); } $this->export_entities_array[$r] = array( - 'e.rowid' => 'warehouse', 'e.ref' => 'warehouse', 'e.description' => 'warehouse', 'e.lieu' => 'warehouse', 'e.address' => 'warehouse', 'e.zip' => 'warehouse', 'e.town' => 'warehouse', + 'id.qty_view' => 'inventory_line', 'id.qty_stock' => 'inventory_line', 'id.batch' => 'inventory_line', 'id.qty_regulated' => 'inventory_line', 'id.fk_warehouse' => 'inventory_line', 'id.rowid' => 'inventory_line', 'e.rowid' => 'warehouse', 'e.ref' => 'warehouse', 'e.description' => 'warehouse', 'e.lieu' => 'warehouse', 'e.address' => 'warehouse', 'e.zip' => 'warehouse', 'e.town' => 'warehouse', 'p.rowid' => "product", 'p.ref' => "product", 'p.fk_product_type' => "product", 'p.label' => "product", 'p.description' => "product", 'p.note' => "product", 'p.barcode' => "product", 'p.price' => "product", 'p.tva_tx' => 'product', 'p.tosell' => "product", 'p.tobuy' => "product", 'p.duration' => "product", 'p.datec' => 'product', 'p.tms' => 'product' ); // We define here only fields that use another icon that the one defined into export_icon if (isModEnabled('productbatch')) { $this->export_fields_array[$r]['id.batch'] = 'Batch'; $this->export_TypeFields_array[$r]['id.batch'] = 'Text'; - $this->export_entities_array[$r]['id.batch'] = 'movement'; + $this->export_entities_array[$r]['id.batch'] = 'inventory_line'; } if (isModEnabled('barcode')) { $this->export_entities_array[$r] = array_merge($this->export_entities_array[$r], array('p.barcode' => 'product')); diff --git a/htdocs/exports/export.php b/htdocs/exports/export.php index 9c134d69974..b2bb1e7756f 100644 --- a/htdocs/exports/export.php +++ b/htdocs/exports/export.php @@ -78,7 +78,8 @@ $entitytoicon = array( 'translation' => 'generic', 'bomm' => 'bom', 'bomline' => 'bom', - 'conferenceorboothattendee' => 'contact' + 'conferenceorboothattendee' => 'contact', + 'inventory_line' => 'inventory' ); // Translation code, array duplicated in import.php, was not synchronized, TODO put it somewhere only once @@ -130,7 +131,9 @@ $entitytolang = array( 'translation' => 'Translation', 'bom' => 'BOM', 'bomline' => 'BOMLine', - 'conferenceorboothattendee' => 'Attendee' + 'conferenceorboothattendee' => 'Attendee', + 'inventory' => 'Inventory', + 'inventory_line' => 'InventoryLine' ); $array_selected = isset($_SESSION["export_selected_fields"]) ? $_SESSION["export_selected_fields"] : array(); diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang index b3cdf9d3e61..8c02662f1e2 100644 --- a/htdocs/langs/en_US/stocks.lang +++ b/htdocs/langs/en_US/stocks.lang @@ -336,3 +336,14 @@ LatestModifiedWarehouses=Latest %s modified warehouses LatestStockMovements=Latest %s stock movements QtyCurrentlyKnownInStock=System estimated quantity you have in stock. As long as the inventory is not closed, this is a realtime value and it may change if you continue to make stock movement during the inventory (not recommended). QtyInStockWhenInventoryWasValidated=System estimated quantity you had in stock when the inventory was validated (before the stock correction) +InventoryId=Inventory id +DateInventory=Inventory date +InventoryStatus=Inventory status +InventoryTitle=Inventory name +InventoryLine=Inventory line +InventoryLineId=Inventory line ID +InventoryRef=Inventory ref +QtyViewed=Quantity viewed +QtyStock=Quantity on stock +QtyRegulated=Quantity on stock correction +InventoryEntrepot=Warehouse identity diff --git a/htdocs/langs/fr_FR/stocks.lang b/htdocs/langs/fr_FR/stocks.lang index 566fa580c37..8b9e7b2c5b4 100644 --- a/htdocs/langs/fr_FR/stocks.lang +++ b/htdocs/langs/fr_FR/stocks.lang @@ -341,7 +341,7 @@ InventoryId=ID d'inventaire DateInventory=Date d'inventaire InventoryStatus=Statut inventaire InventoryTitle=Nom de l'inventaire -InventoryLineId=Ligne d'inventaire +InventoryLineId=ID Ligne d'inventaire InventoryRef=Réf d'inventaire QtyViewed=Quantité vue QtyStock=Quantité en stock From 8065dd8d96bc249eeecd253484b47f95dda2c182 Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 15:42:43 +0200 Subject: [PATCH 18/19] Add country flag for country MF (Saint Martin France) --- htdocs/theme/eldy/flags-sprite.inc.php | 5 +++++ htdocs/theme/md/flags-sprite.inc.php | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/htdocs/theme/eldy/flags-sprite.inc.php b/htdocs/theme/eldy/flags-sprite.inc.php index 274235f844a..022505a5e31 100644 --- a/htdocs/theme/eldy/flags-sprite.inc.php +++ b/htdocs/theme/eldy/flags-sprite.inc.php @@ -739,6 +739,11 @@ if (!defined('ISLOADEDBYSTEELSHEET')) { width: 16px; height: 12px; } +.flag-sprite.mf { + background-position:0 -847px; + width: 16px; + height: 12px; +} .flag-sprite.mg { background-position:0 -1563px; width: 16px; diff --git a/htdocs/theme/md/flags-sprite.inc.php b/htdocs/theme/md/flags-sprite.inc.php index 56300e37e3f..dbc1328a902 100644 --- a/htdocs/theme/md/flags-sprite.inc.php +++ b/htdocs/theme/md/flags-sprite.inc.php @@ -717,6 +717,11 @@ if (!defined('ISLOADEDBYSTEELSHEET')) { width: 16px; height: 12px; } +.flag-sprite.mf { + background-position:0 -847px; + width: 16px; + height: 12px; +} .flag-sprite.mg { background-position:0 -1563px; width: 16px; From 0f5e5e1e5bab7de71f3b5e6a4b3dd19fc5cd472c Mon Sep 17 00:00:00 2001 From: Laurent Destailleur Date: Mon, 23 Sep 2024 20:16:39 +0200 Subject: [PATCH 19/19] FIX Maxi debug edit/delete accounting transaction --- htdocs/accountancy/bookkeeping/card.php | 202 ++++++++++++++---- .../accountancy/class/bookkeeping.class.php | 21 +- htdocs/accountancy/closure/index.php | 2 +- htdocs/core/lib/functions.lib.php | 31 +-- 4 files changed, 193 insertions(+), 63 deletions(-) diff --git a/htdocs/accountancy/bookkeeping/card.php b/htdocs/accountancy/bookkeeping/card.php index d1b6d6f212b..c157fe493b0 100644 --- a/htdocs/accountancy/bookkeeping/card.php +++ b/htdocs/accountancy/bookkeeping/card.php @@ -35,18 +35,20 @@ require_once DOL_DOCUMENT_ROOT.'/compta/facture/class/facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/fourn/class/fournisseur.facture.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingjournal.class.php'; require_once DOL_DOCUMENT_ROOT.'/accountancy/class/accountingaccount.class.php'; +require_once DOL_DOCUMENT_ROOT.'/accountancy/class/lettering.class.php'; // Load translation files required by the page $langs->loadLangs(array("accountancy", "bills", "compta")); $action = GETPOST('action', 'aZ09'); $cancel = GETPOST('cancel', 'aZ09'); +$confirm = GETPOST('confirm', 'alpha'); $optioncss = GETPOST('optioncss', 'aZ'); // Option for the css output (always '' except when 'print') $id = GETPOSTINT('id'); // id of record $mode = GETPOST('mode', 'aZ09'); // '' or '_tmp' -$piece_num = GETPOSTINT("piece_num"); // id of transaction (several lines share the same transaction id) +$piece_num = GETPOSTINT("piece_num") ? GETPOSTINT("piece_num") : GETPOST('ref'); // id of transaction (several lines share the same transaction id) $accountingaccount = new AccountingAccount($db); $accountingjournal = new AccountingJournal($db); @@ -78,6 +80,9 @@ if (!empty($update)) { $action = 'confirm_update'; } +// Initialize a technical object to manage hooks of page. Note that conf->hooks_modules contains an array of hook context +$hookmanager->initHooks(array('bookkeepingcard', 'globalcard')); + $object = new BookKeeping($db); // Security check @@ -92,6 +97,7 @@ if (!$user->hasRight('accounting', 'mouvements', 'lire')) { } $permissiontoadd = $user->hasRight('accounting', 'mouvements', 'creer'); +$permissiontodelete = $user->hasRight('accounting', 'mouvements', 'supprimer'); /* @@ -211,6 +217,7 @@ if (empty($reshook)) { } $result = $object->createStd($user, false, $mode); + if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } else { @@ -224,7 +231,7 @@ if (empty($reshook)) { $action = ''; } } - } elseif ($action == "confirm_delete" && $permissiontoadd) { + } elseif ($action == "confirm_delete" && $permissiontoadd) { // Delete line $object = new BookKeeping($db); $result = $object->fetch($id, null, $mode); @@ -273,6 +280,7 @@ if (empty($reshook)) { $object->amount = 0; $result = $object->createStd($user, 0, $mode); + if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); @@ -339,6 +347,66 @@ if (empty($reshook)) { exit; } } + + // Delete all lines into the transaction + $toselect = explode(',', GETPOST('toselect', 'alphanohtml')); + + if ($action == 'deletebookkeepingwriting' && $confirm == "yes" && $permissiontodelete) { + $db->begin(); + + if (getDolGlobalInt('ACCOUNTING_ENABLE_LETTERING')) { + $lettering = new Lettering($db); + $nb_lettering = $lettering->bookkeepingLetteringAll($toselect, true); + if ($nb_lettering < 0) { + setEventMessages('', $lettering->errors, 'errors'); + $error++; + } + } + + $nbok = 0; + $result = 0; + if (!$error) { + foreach ($toselect as $toselectid) { + $result = $object->fetch($toselectid); + if ($result >= 0 && (!isset($object->date_validation) || $object->date_validation === '')) { + $result = $object->deleteMvtNum($object->piece_num); + if ($result >= 0) { + $nbok += $result; + } else { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + break; + } + } elseif ($result < 0) { + setEventMessages($object->error, $object->errors, 'errors'); + $error++; + break; + } elseif (isset($object->date_validation) && $object->date_validation != '') { + setEventMessages($langs->trans("ValidatedRecordWhereFound"), null, 'errors'); + $error++; + break; + } + } + } + + if (!$error) { + $db->commit(); + + // Message for elements well deleted + if ($nbok > 1) { + setEventMessages($langs->trans("RecordsDeleted", $nbok), null, 'mesgs'); + } elseif ($nbok > 0) { + setEventMessages($langs->trans("RecordDeleted", $nbok), null, 'mesgs'); + } else { + setEventMessages($langs->trans("NoRecordDeleted"), null, 'mesgs'); + } + + header("Location: ".DOL_URL_ROOT.'/accountancy/bookkeeping/list.php?noreset=1'); + exit; + } else { + $db->rollback(); + } + } } @@ -352,6 +420,7 @@ $formaccounting = new FormAccounting($db); $title = $langs->trans("CreateMvts"); $help_url = 'EN:Module_Double_Entry_Accounting|FR:Module_Comptabilité_en_Partie_Double'; + llxHeader('', $title, $help_url, '', 0, 0, '', '', '', 'mod-accountancy accountancy-consultation page-card'); // Confirmation to delete the command @@ -431,11 +500,11 @@ if ($action == 'create') { if (!empty($object->piece_num)) { $backlink = ''.$langs->trans('BackToList').''; - if ($mode == '_tmp') { + /*if ($mode == '_tmp') { print load_fiche_titre($langs->trans("CreateMvts"), $backlink); } else { print load_fiche_titre($langs->trans("UpdateMvts"), $backlink); - } + }*/ $head = array(); $h = 0; @@ -446,13 +515,22 @@ if ($action == 'create') { print dol_get_fiche_head($head, 'transaction', '', -1); - //dol_banner_tab($object, '', $backlink); + $object->ref = $object->piece_num; + $object->label = $object->doc_ref; + + $morehtmlref .= '
'; + $morehtmlref .= '
'; + $morehtmlref .= $object->label; + $morehtmlref .= '
'; + + print dol_banner_tab($object, 'ref', $backlink, 1, 'piece_num', 'piece_num', $morehtmlref); print '
'; + print '
'; print '
'; - print ''; + print '
'; // Account movement print ''; @@ -460,6 +538,37 @@ if ($action == 'create') { print ''; print ''; + // Ref document + print ''; + print ''; + // Date print ''; print ''; print ''; print '
'.($mode == '_tmp' ? ''.$langs->trans("Draft").'' : $object->piece_num).'
'; + print ''; + if ($action != 'editdocref') { + print ''; + } + print '
'; + print $langs->trans('Piece'); + print ''; + if ($permissiontoadd) { + print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; + } + print '
'; + print '
'; + if ($action == 'editdocref') { + print '
'; + if ($optioncss != '') { + print ''; + } + print ''; + print ''; + print ''; + print ''; + print ''; + print '
'; + } else { + print $object->doc_ref; + } + print '
'; print ''; print ''; - // Ref document - print ''; - print ''; - print '
'; @@ -522,41 +631,11 @@ if ($action == 'create') { print '
'; - print ''; - if ($action != 'editdocref') { - print ''; - } - print '
'; - print $langs->trans('Piece'); - print ''; - if ($permissiontoadd) { - print 'piece_num).'&mode='.urlencode((string) $mode).'">'.img_edit($langs->transnoentitiesnoconv('Edit'), 1).''; - } - print '
'; - print '
'; - if ($action == 'editdocref') { - print '
'; - if ($optioncss != '') { - print ''; - } - print ''; - print ''; - print ''; - print ''; - print ''; - print '
'; - } else { - print $object->doc_ref; - } - print '
'; print ''; + print '
'; print '
'; @@ -651,21 +730,52 @@ if ($action == 'create') { print '
'; - print dol_get_fiche_end(); - + print ''; print '
'; - print '
'; + + print dol_get_fiche_end(); + $result = $object->fetchAllPerMvt($piece_num, $mode); // This load $object->linesmvt if ($result < 0) { setEventMessages($object->error, $object->errors, 'errors'); } else { + // Variable that contains all transaction lines + $tmptoselect = array(); + $atleastonevalidated = 0; + $atleastoneexported = 0; + foreach ($object->linesmvt as $line) { + $tmptoselect[] = $line->id; + if (!empty($line->date_validation)) { + $atleastonevalidated = 1; + } + if (!empty($line->date_export) || !empty($line->date_validation)) { + $atleastoneexported = 1; + } + } + + if ($mode != '_tmp' && !$atleastonevalidated) { + print "\n".'
'."\n"; + + $parameters = array(); + $reshook = $hookmanager->executeHooks('addMoreActionsButtons', $parameters, $object, $action); // Note that $action and $object may have been modified by hook + if (empty($reshook)) { + if ($permissiontodelete) { + if (!isset($hookmanager->resArray['no_button_edit']) || $hookmanager->resArray['no_button_edit'] != 1) { + print dolGetButtonAction('', $langs->trans('Delete'), 'delete', DOL_URL_ROOT.'/accountancy/bookkeeping/card.php?action=deletebookkeepingwriting&confirm=yes&token='.newToken().'&piece_num='.((int) $object->piece_num).'&toselect='.implode(',', $tmptoselect), '', $permissiontodelete); + } + } + } + + print '
'; + } + // List of movements print load_fiche_titre($langs->trans("ListeMvts"), '', ''); - print '
'; + print ''; if ($optioncss != '') { print ''; } @@ -745,7 +855,7 @@ if ($action == 'create') { print '
'; - print $formaccounting->select_account('', 'accountingaccount_number', 1, array(), 1, 1, 'minwidth200 maxwidth500'); + print $formaccounting->select_account($action == 'add' ? GETPOST('accountingaccount_number') : '', 'accountingaccount_number', 1, array(), 1, 1, 'minwidth200 maxwidth500'); print ''; // TODO For the moment we keep a free input text instead of a combo. The select_auxaccount has problem because: @@ -830,10 +940,12 @@ if ($action == 'create') { if ($mode == '_tmp' && $action == '' && $permissiontoadd) { print '
'; print '
'; - if ($total_debit == $total_credit) { - print ''.$langs->trans("ValidTransaction").''; + if (empty($total_debit) && empty($total_debit)) { + print ''; + } elseif ($total_debit == $total_credit) { + print ''.$langs->trans("ValidTransaction").''; } else { - print ''; + print ''; } print '   '; diff --git a/htdocs/accountancy/class/bookkeeping.class.php b/htdocs/accountancy/class/bookkeeping.class.php index 40f04f743b2..1e4afa2d45f 100644 --- a/htdocs/accountancy/class/bookkeeping.class.php +++ b/htdocs/accountancy/class/bookkeeping.class.php @@ -1704,7 +1704,7 @@ class BookKeeping extends CommonObject * * @param int $piecenum Piecenum to delete * @param string $mode Mode ('' or '_tmp') - * @return int Result + * @return int Nb of record deleted */ public function deleteMvtNum($piecenum, $mode = '') { @@ -1715,6 +1715,8 @@ class BookKeeping extends CommonObject return -1; } + $nbprocessed = 0; + $this->db->begin(); // first check if line not yet in bookkeeping @@ -1735,10 +1737,13 @@ class BookKeeping extends CommonObject } $this->db->rollback(); return -1; + } else { + $nbprocessed = $this->db->affected_rows($resql); } $this->db->commit(); - return 1; + + return $nbprocessed; } /** @@ -2346,12 +2351,20 @@ class BookKeeping extends CommonObject $sql_list = array(); if (!empty($conf->cache['active_fiscal_period_cached']) && is_array($conf->cache['active_fiscal_period_cached'])) { + $i = 0; foreach ($conf->cache['active_fiscal_period_cached'] as $fiscal_period) { - $sql_list[] = "('" . $this->db->idate($fiscal_period['date_start']) . "' <= ".$this->db->sanitize($alias)."doc_date AND ".$this->db->sanitize($alias)."doc_date <= '" . $this->db->idate($fiscal_period['date_end']) . "')"; + $sql_list[$i] = "("; + $sql_list[$i] .= "'".$this->db->idate($fiscal_period['date_start']) . "' <= ".$this->db->sanitize($alias)."doc_date"; + if (!empty($fiscal_period['date_end'])) { + $sql_list[$i] .= " AND "; + $sql_list[$i] .= $this->db->sanitize($alias)."doc_date <= '" . $this->db->idate($fiscal_period['date_end'])."'"; + } + $sql_list[$i] .= ")"; + $i++; } } $sqlsanitized = implode(' OR ', $sql_list); - self::$can_modify_bookkeeping_sql_cached[$alias] = !empty($sql_list) ? " AND (".$sqlsanitized.")" : ""; + self::$can_modify_bookkeeping_sql_cached[$alias] = empty($sql_list) ? "" : " AND (".$sqlsanitized.")"; } return self::$can_modify_bookkeeping_sql_cached[$alias]; diff --git a/htdocs/accountancy/closure/index.php b/htdocs/accountancy/closure/index.php index 025430976cc..74f2299e269 100644 --- a/htdocs/accountancy/closure/index.php +++ b/htdocs/accountancy/closure/index.php @@ -300,7 +300,7 @@ if (!empty($current_fiscal_period)) { print load_fiche_titre($langs->trans("Closure") . " - " . $fiscal_period_nav_text, '', 'title_accountancy'); if (empty($current_fiscal_period)) { - print $langs->trans('ErrorNoFiscalPeriodActiveFound', $langs->trans("Accounting"), $langs->trans("Setup"), $langs->trans("FiscalPeriod")); + print $langs->trans('ErrorNoFiscalPeriodActiveFound', $langs->transnoentitiesnoconv("Accounting"), $langs->transnoentitiesnoconv("Setup"), $langs->transnoentitiesnoconv("FiscalPeriod")); } if (isset($current_fiscal_period)) { diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php index bf814e08e5f..360cbb05edf 100644 --- a/htdocs/core/lib/functions.lib.php +++ b/htdocs/core/lib/functions.lib.php @@ -2675,19 +2675,19 @@ function dol_get_fiche_end($notab = 0) * Show tab footer of a card. * Note: $object->next_prev_filter can be set to restrict select to find next or previous record by $form->showrefnav. * - * @param CommonObject $object Object to show - * @param string $paramid Name of parameter to use to name the id into the URL next/previous link - * @param string $morehtml More html content to output just before the nav bar - * @param int $shownav Show Condition (navigation is shown if value is 1) - * @param string $fieldid Name of the field in DB to use to select next et previous (we make the select max and min on this field). Use 'none' for no prev/next search. - * @param string $fieldref Name of the field (object->ref) to use to select next et previous - * @param string $morehtmlref More html to show after the ref (see $morehtmlleft for before) - * @param string $moreparam More param to add in nav link url. - * @param int $nodbprefix Do not include DB prefix to forge table name - * @param string $morehtmlleft More html code to show before the ref (see $morehtmlref for after) - * @param string $morehtmlstatus More html code to show under navigation arrows - * @param int $onlybanner Put this to 1, if the card will contains only a banner (this add css 'arearefnobottom' on div) - * @param string $morehtmlright More html code to show before navigation arrows + * @param CommonObject $object Object to show + * @param string $paramid Name of parameter to use to name the id into the URL next/previous link + * @param string $morehtml More html content to output just before the nav bar + * @param int|bool $shownav Show Condition (navigation is shown if value is 1 or true) + * @param string $fieldid Name of the field in DB to use to select next et previous (we make the select max and min on this field). Use 'none' for no prev/next search. + * @param string $fieldref Name of the field (object->ref) to use to select next et previous + * @param string $morehtmlref More html to show after the ref (see $morehtmlleft for before) + * @param string $moreparam More param to add in nav link url. + * @param int $nodbprefix Do not include DB prefix to forge table name + * @param string $morehtmlleft More html code to show before the ref (see $morehtmlref for after) + * @param string $morehtmlstatus More html code to show under navigation arrows + * @param int $onlybanner Put this to 1, if the card will contains only a banner (this add css 'arearefnobottom' on div) + * @param string $morehtmlright More html code to show before navigation arrows * @return void */ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldid = 'rowid', $fieldref = 'ref', $morehtmlref = '', $moreparam = '', $nodbprefix = 0, $morehtmlleft = '', $morehtmlstatus = '', $onlybanner = 0, $morehtmlright = '') @@ -3030,6 +3030,11 @@ function dol_banner_tab($object, $paramid, $morehtml = '', $shownav = 1, $fieldi $morehtmlref = $hookmanager->resPrint; } + // $morehtml is the right part (link "Back to list") + // $morehtmlleft is the picto or photo of banner + // $morehtmlstatus is part under the status + // $morehtmlright is part of htmlright + print '
'; print $form->showrefnav($object, $paramid, $morehtml, $shownav, $fieldid, $fieldref, $morehtmlref, $moreparam, $nodbprefix, $morehtmlleft, $morehtmlstatus, $morehtmlright); print '
';