diff --git a/.gitignore b/.gitignore
index 371c8be2f5e..e4790fe7b4e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -55,3 +55,4 @@ yarn.lock
package-lock.json
doc/install.lock
+/factory/
diff --git a/ChangeLog b/ChangeLog
index 1c0e96fc27c..283b8fc5146 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -105,6 +105,8 @@ NEW: Use an ajax call for the clicktodial feature instead of href link.
NEW: when multiple order linked to facture, show list into note.
NEW: when we delete several objects with massaction, if somes object has child we must see which objects are concerned and nevertheless delete objects which can be deleted
NEW: Editing a page in website module keep old page with name .back
+NEW: External backups can be downloaded from the "About info page".
+NEW: Add massaction to switch status on sale / on purchase of a product.
For developers:
@@ -131,7 +133,7 @@ NEW: printFieldListFrom hook call on several lists
NEW: Use lang selector when using a field key 'lang' in modulebuilder
NEW: we need to be able to put more filters on deleteByParentField() function
NEW: make it easier to set the `keyword`, `keywords` and `description` attributes of an ecm file object
-
+NEW: Experimental feature to manage user sessions in database
Following changes may create regressions for some external modules, but were necessary to make Dolibarr better:
@@ -140,9 +142,133 @@ Following changes may create regressions for some external modules, but were nec
* The method static ActionComm::getActions($db, ...) is no more static. Use $actioncomm->getActions(...) instead (without $db param).
* The 'action=delete&file=...' has been replaced with 'action=deletefile&file=...' to avoid confusion with deletion of object lines.
* Method getDictvalue has been renamed into getDictionaryValue to match camel case rule.
+* To execute shell or command line command, your code must never use method like exec, shell_exec, popen, .. but must use the built-in
+ method executeCLI() available into core/class/utils.class.php
+* Class file expeditionbatch.class.php renamed to expeditionlinebatch.class.php
+* ExpeditionLineBatch::fetchAll is not static anymore and first parameter $db is removed
+* ExtraFields->showOutputField parameter 4 'extrafieldsobjectkey' is now required
+* CommonObject method add_object_linked now sets targettype to 'mymodule_myobject' instead of 'myobject',
+ you can use hook 'setLinkedObjectSourceTargetType' to set your usual targettype
+***** ChangeLog for 14.0.4 compared to 14.0.3 *****
+
+FIX: $totalarray is overwritten, totals were lost
+FIX: 13.0 - due to a typo in the 'mode' parameter, the "first name" column of the list of members displays the full name
+FIX: 13.0: end date required to edit a ticket message
+FIX: 13.0 feedback of PR #18993: make ticket messages punctual events with attr percentage = -1
+FIX: 13.0 PR #18993: add comment on modified part
+FIX: 13.0: sometimes firstname was mistyped as fistname
+FIX: 14.0 - civility field of private third party creation form has inadequate width
+FIX: 14.0 - civility field width inadequate due to select2 calculating the width while the field has no width (display: none)
+FIX: 14.0 - due to a typo in the 'mode' parameter, the "first name" co…
+FIX: #18634 : Problem of virtual stock with reception module enabled
+FIX: #18695 Added ref_ext to supplier invoice
+FIX: #18698 Supplier invoice list - "alert" checkbox not working
+FIX: #18735
+FIX: #18767 : Adherent delete
+FIX: #18797
+FIX: #18854
+FIX: #18875 in v14
+FIX: #18910
+FIX: #18910 : MRP List SQL query syntax error with more than one extrafileds.
+FIX: #18912 Accountancy - SQL error when custom group is added without country defined
+FIX: #18934 on-registration in the extrafieldsline database for deliveries
+FIX: #18968
+FIX: #19008
+FIX: #19014 - the properties of some fields are not updated when you submit the form
+FIX: #19210
+FIX: #19214 : PostgreSQL error on admin/limits.php
+FIX: #19241 Project - Fix display salary in overview
+FIX: #19305
+FIX: 2 columns for total labels
+FIX: Accountancy - Format Quadra export - Missing line type C to create automaticly a subledger account with label
+FIX: Accountancy - If deposit invoice is used, force binding in deposit accounting account to solve transaction
+FIX: Accountancy - Missing specific filename for export on format FEC2, Ciel & repare it
+FIX: Accountancy - Option of export popup are inverted
+FIX: Accountancy - PHP8
+FIX: Accountancy - Product admin - SQL error when we affect accounting account with product_perentity activated
+FIX: Accountancy simplified - Salaries are not present in report
+FIX: Accountancy - Some correction on export name
+FIX: Accountancy - Trunc code_journal to 2 in format XIMPORT (Ciel, Sage50)
+FIX: add warehouse in projects' overview count
+FIX: also on customer index for automatic binding
+FIX: Attachment of pdf into shipment when sending email
+FIX: autocalculation of the supplier price in main currency.
+FIX: avoid warning if $categories is an id
+FIX: bad sign of amount stored for multicurrency columns on credit notes
+FIX: Bad use of a forced contact of another company on PDF/ODT documents
+FIX: Bad use of dol_concatdesc()
+FIX: Button text on proposal card for create a invoice
+FIX: calculateCosts of BOM must not be included into fetch
+FIX: calculation of balance in conciliation page on desc sorting.
+FIX: card.php
+FIX: Change date format of the inventorycode to be equal as mass stock transfert
+FIX: check if greater 0
+FIX: close cash with some terminals in TakePOS
+FIX: compatibility with Multicompany
+FIX: consistent UX when calling a tab from the invoice card with empty ref/id
+FIX: default language defined for IN country
+FIX: Expense report - In edit mode, field qty doesn't accept decimal unlike the create mode
+FIX: fetch of product with modulebuilder load too much data
+FIX: filter for export of accounting documents
+FIX: Filter on categories
+FIX: generate documents with PDF options
+FIX: indentation
+FIX: init hookmanager after loading $conf values
+FIX: invoice: inpossible to create an invoice because of very bad check + warnings when trying to print tabs for invoice with no ID
+FIX: legal issue on expense report pdf (must also show price without tax)
+FIX: list of categories in stats of supplier invoices
+FIX: load tranlate array after setting lang
+FIX: lost superadmin grade after edit user card
+FIX: missing filter status=1 on rss feeds
+FIX: missing permission check reported by me@lainwir3d.net on product api
+FIX: missing return status
+FIX: missing sql filter by entity
+FIX: move fetch_optionnal into $ac_static->fetch()
+FIX: only a superadmin can modify entity
+FIX: only ones value is return for dictionaries
+FIX: optional visibility on create card
+FIX: payment style and html5 tags
+FIX: payment using wrong type in takepos when too many payment mode
+FIX: PR#18931 Remove useless explicit call to dol_shutdown
+FIX: Product accountancy affectation with product_perentity activated (PR #18620)
+FIX: products/services card: hidden extrafields were overridden
+FIX: project task list: extrafields could not be displayed
+FIX: Propal list - Problem of pagination on date
+FIX: reload user lang
+FIX: Remove not complete order from the virtual stock
+FIX: Replenish: SQL error when no warehouse has been created + Warning when there are no warehouses
+FIX: resource list : Use standard code to handle list filters
+FIX: restrictedArea for payment delete
+FIX: Ret PR
+FIX: second approval back in stable feature as is the setting for minimum amount (last part from PR#14286)
+FIX: selected lines on supplier invoice create
+FIX: Selection of type "people" for membership must hide the company
+FIX: select list of orders not complete when field type of company is on
+FIX: show end hours in events linked to objects
+FIX: support of localtax on expense report
+FIX: task time: can't filter by user with pgsql + show error message
+FIX: task time: keep on using natural_search
+FIX: tcpdf vulnerability to roman numeral bomb, cf. tecnickom/TCPDF issue #315
+FIX: Test when date of invoie is in future (pb with TZ and offset)
+FIX: Ticket - Card - Wrong font awesome library
+FIX: Ticket - Duplicate field project when we create ticket from project
+FIX: translation into email for member at membership validation.
+FIX: Travis Sanitize SQL
+FIX: unprivileged user can see task associated with a not allowed project
+FIX: URGENT: impossible to create an invoice
+FIX: Use of accent into filename of GED
+FIX: user date timezone offset
+FIX: User salary card - translation problem
+FIX: user without permission can set ticket subject
+FIX: We need a default price base type in variant creation case with multiprices when parent has been created with only one level price
+FIX: wrong array key value
+FIX: wrong check
+FIX: wrong position of error message
+Sync transifex.
+
***** ChangeLog for 14.0.3 compared to 14.0.2 *****
FIX: #18698 Supplier invoice list - "alert" checkbox not working
@@ -497,7 +623,8 @@ Following changes may create regressions for some external modules, but were nec
* Removed deprecated substitution key __REFCLIENT__ (replaced with __REF_CLIENT__)
* Removed constant MAIN_COUNTRIES_IN_EEC. You can now set if country is in Europe or not from the dictionary of countries.
* v14 seems to work correctly on PHP v8 but it generates a lot of verbose warnings. Currently, v14 i snot yet officialy supported with PHP 8.
-
+* To execute shell or command line command, your code must never use method like exec, shell_exec, popen, .. but must use the built-in
+ method executeCLI() available into core/class/utils.class.php
***** ChangeLog for 13.0.5 compared to 13.0.4 *****
diff --git a/htdocs/accountancy/admin/accountmodel.php b/htdocs/accountancy/admin/accountmodel.php
index 97a460beaac..29c2b7d5510 100644
--- a/htdocs/accountancy/admin/accountmodel.php
+++ b/htdocs/accountancy/admin/accountmodel.php
@@ -495,7 +495,7 @@ if ($id) {
if ($valuetoshow != '') {
print '
';
if (!empty($tabhelp[$id][$value]) && preg_match('/^http(s*):/i', $tabhelp[$id][$value])) {
- print ''.$valuetoshow.' '.img_help(1, $valuetoshow).'';
+ print ''.$valuetoshow.' '.img_help(1, $valuetoshow).'';
} elseif (!empty($tabhelp[$id][$value])) {
print $form->textwithpicto($valuetoshow, $tabhelp[$id][$value]);
} else {
diff --git a/htdocs/accountancy/admin/export.php b/htdocs/accountancy/admin/export.php
index 9e393beeacd..8cef3a05cf4 100644
--- a/htdocs/accountancy/admin/export.php
+++ b/htdocs/accountancy/admin/export.php
@@ -142,7 +142,7 @@ $linkback = '';
print load_fiche_titre($langs->trans('ExportOptions'), $linkback, 'accountancy');
-print "\n".'';
// This ajax service is called only when a directory $selecteddir is opened but not when closed.
- //print '';
}
@@ -169,7 +169,7 @@ if (!empty($conf->use_javascript_ajax) && empty($conf->global->MAIN_ECM_DISABLE_
if (empty($conf->use_javascript_ajax) || !empty($conf->global->MAIN_ECM_DISABLE_JS)) {
print '
';
- // Load full tree from database. We will use it to define nbofsubdir and nboffilesinsubdir
+ // Load full manual tree from database. We will use it to define nbofsubdir and nboffilesinsubdir
if (empty($sqltree)) {
$sqltree = $ecmdirstatic->get_full_arbo(0); // Slow
}
diff --git a/htdocs/core/ajax/objectonoff.php b/htdocs/core/ajax/objectonoff.php
index 05843abed9d..5bac89345ce 100644
--- a/htdocs/core/ajax/objectonoff.php
+++ b/htdocs/core/ajax/objectonoff.php
@@ -65,9 +65,14 @@ if (!empty($user->socid)) {
$socid = $user->socid;
}
-/*if (empty($conf->global->MAIN_DIRECT_STATUS_UPDATE)) {
- accessforbidden('Calling this file is allowed only when MAIN_DIRECT_STATUS_UPDATE is set');
-}*/
+if (in_array($field, array('status'))) {
+ restrictedArea($user, $element, $id);
+} elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) { // Special case for products
+ restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid');
+} else {
+ accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1);
+ exit;
+}
/*
@@ -78,15 +83,6 @@ top_httphead();
print ''."\n";
-if (in_array($field, array('status'))) {
- restrictedArea($user, $element, $id);
-} elseif ($element == 'product' && in_array($field, array('tosell', 'tobuy', 'tobatch'))) { // Special case for products
- restrictedArea($user, 'produit|service', $id, 'product&product', '', '', 'rowid');
-} else {
- accessforbidden("Bad value for combination of parameters element/field.", 0, 0, 1);
- exit;
-}
-
// Registering new values
if (($action == 'set') && !empty($id)) {
$triggerkey = strtoupper($element).'_UPDATE';
diff --git a/htdocs/core/bookmarks_page.php b/htdocs/core/bookmarks_page.php
index 46c4b38988e..9c3b5abb266 100644
--- a/htdocs/core/bookmarks_page.php
+++ b/htdocs/core/bookmarks_page.php
@@ -55,10 +55,22 @@ $left = ($langs->trans("DIRECTION") == 'rtl' ? 'right' : 'left');
* View
*/
+// Important: Following code is to avoid page request by browser and PHP CPU at each Dolibarr page access.
+if (empty($dolibarr_nocache) && GETPOST('cache', 'int')) {
+ header('Cache-Control: max-age='.GETPOST('cache', 'int').', public');
+ // For a .php, we must set an Expires to avoid to have it forced to an expired value by the web server
+ header('Expires: '.gmdate('D, d M Y H:i:s', dol_now('gmt') + GETPOST('cache', 'int')).' GMT');
+ // HTTP/1.0
+ header('Pragma: token=public');
+} else {
+ // HTTP/1.0
+ header('Cache-Control: no-cache');
+}
+
$title = $langs->trans("Bookmarks");
// URL http://mydolibarr/core/bookmarks_page?dol_use_jmobile=1 can be used for tests
-$head = ''."\n";
+$head = ''."\n"; // This is used by DoliDroid to know page is a bookmark selection page
$arrayofjs = array();
$arrayofcss = array();
top_htmlhead($head, $title, 0, 0, $arrayofjs, $arrayofcss);
@@ -77,7 +89,7 @@ $bookmarkList = '';
$searchForm = '';
-if (empty($conf->bookmarks->enabled)) {
+if (empty($conf->bookmark->enabled)) {
$langs->load("admin");
$bookmarkList .= ' '.$langs->trans("WarningModuleNotActive", $langs->transnoentitiesnoconv("Bookmarks")).'';
$bookmarkList .= '
';
diff --git a/htdocs/datapolicy/class/datapolicy.class.php b/htdocs/datapolicy/class/datapolicy.class.php
index 8d74d3e9b4e..d0cf2e48434 100644
--- a/htdocs/datapolicy/class/datapolicy.class.php
+++ b/htdocs/datapolicy/class/datapolicy.class.php
@@ -182,8 +182,8 @@ class DataPolicy
$deliveryreceipt = 0;
$substitutionarray = array(
- '__LINKACCEPT__' => ''.$linka.'',
- '__LINKREFUSED__' => ''.$linkr.'',
+ '__LINKACCEPT__' => ''.$linka.'',
+ '__LINKREFUSED__' => ''.$linkr.'',
'__FIRSTNAME__' => $contact->firstname,
'__NAME__' => $contact->lastname,
'__CIVILITY__' => $contact->civility,
@@ -259,8 +259,8 @@ class DataPolicy
$deliveryreceipt = 0;
$substitutionarray = array(
- '__LINKACCEPT__' => ''.$linka.'',
- '__LINKREFUSED__' => ''.$linkr.'',
+ '__LINKACCEPT__' => ''.$linka.'',
+ '__LINKREFUSED__' => ''.$linkr.'',
);
$subject = make_substitutions($subject, $substitutionarray);
$message = make_substitutions($message, $substitutionarray);
@@ -332,8 +332,8 @@ class DataPolicy
$deliveryreceipt = 0;
$substitutionarray = array(
- '__LINKACCEPT__' => ''.$linka.'',
- '__LINKREFUSED__' => ''.$linkr.'',
+ '__LINKACCEPT__' => ''.$linka.'',
+ '__LINKREFUSED__' => ''.$linkr.'',
);
$subject = make_substitutions($subject, $substitutionarray);
$message = make_substitutions($message, $substitutionarray);
diff --git a/htdocs/datapolicy/langs/en_US/datapolicy.lang b/htdocs/datapolicy/langs/en_US/datapolicy.lang
index 368caffcbda..a870c3499a6 100644
--- a/htdocs/datapolicy/langs/en_US/datapolicy.lang
+++ b/htdocs/datapolicy/langs/en_US/datapolicy.lang
@@ -23,7 +23,7 @@ Module4100Desc = Module to manage Data Privacy (Conformity with the GDPR)
#
datapolicySetup = Module Data Privacy Policy Setup
Deletion = Deletion of data
-datapolicySetupPage = Depending of laws of your countries (Example Article 5 of the GDPR), personal data must be kept for a period not exceeding that necessary for the purposes for which they were collected, except for archival purposes. The deletion will be done automatically after a certain duration without event (the duration which you will have indicated below).
+datapolicySetupPage = Depending of laws of your countries (Example Article 5 of the GDPR), personal data must be kept for a period not exceeding that necessary for the purposes for which they were collected, except for archival purposes. The deletion will be done automatically after a certain duration without event (the duration which you will have indicated below).
NB_MONTHS = %s months
ONE_YEAR = 1 year
NB_YEARS = %s years
diff --git a/htdocs/datapolicy/langs/fr_FR/datapolicy.lang b/htdocs/datapolicy/langs/fr_FR/datapolicy.lang
index 48b6a88cce3..6bf0c6a904d 100644
--- a/htdocs/datapolicy/langs/fr_FR/datapolicy.lang
+++ b/htdocs/datapolicy/langs/fr_FR/datapolicy.lang
@@ -27,7 +27,7 @@ Module4100Desc = Module de gestion de la protection des données (RGPD)
#
datapolicySetup = Configuration du module Protection des données
Settings_DATAPOLICY = Paramétrage du module Protection des données
-datapolicySetupPage = Selon la loi de votre pays (Exemple l’article 5 du RGPD), les données à caractère personnel doivent être conservées pendant une durée n’excédant pas celle nécessaire au regard des finalités pour lesquelles elles ont été traitées, à l’exception de fins archivistiques. La suppression se fera automatiquement après une certaine durée sans évènement (la durée que vous aurez indiquée ci-dessous).
+datapolicySetupPage = Selon la loi de votre pays (Exemple l’article 5 du RGPD), les données à caractère personnel doivent être conservées pendant une durée n’excédant pas celle nécessaire au regard des finalités pour lesquelles elles ont été traitées, à l’exception de fins archivistiques. La suppression se fera automatiquement après une certaine durée sans évènement (la durée que vous aurez indiquée ci-dessous).
NB_MONTHS = %s mois
ONE_YEAR = 1 an
NB_YEARS = %s ans
diff --git a/htdocs/datapolicy/langs/it_IT/datapolicy.lang b/htdocs/datapolicy/langs/it_IT/datapolicy.lang
index d8858b56c5b..68284e17844 100644
--- a/htdocs/datapolicy/langs/it_IT/datapolicy.lang
+++ b/htdocs/datapolicy/langs/it_IT/datapolicy.lang
@@ -10,7 +10,7 @@ Module4100Desc = Conformità con GDPR
#
datapolicySetup = Module Setup
Settings_DATAPOLICY = Configurazione modulo GDPR
-datapolicySetupPage = In accordo con l'art 5 del GDPR i dati personali devono essere conservati per un periodo di tempo che .... ed eliminati se non sono più utili agli scopi per cui sono stati processati.
+datapolicySetupPage = In accordo con l'art 5 del GDPR i dati personali devono essere conservati per un periodo di tempo che .... ed eliminati se non sono più utili agli scopi per cui sono stati processati.
NB_MONTHS = %s mesi
ONE_YEAR = 1 anno
NB_YEARS = %s anni
diff --git a/htdocs/don/card.php b/htdocs/don/card.php
index 7aa7ea802ce..19da17f2be2 100644
--- a/htdocs/don/card.php
+++ b/htdocs/don/card.php
@@ -185,7 +185,7 @@ if (empty($reshook)) {
$object->modepaymentid = (int) GETPOST('modepayment', 'int');
// Fill array 'array_options' with data from add form
- $ret = $extrafields->setOptionalsFromPost(null, $object);
+ $ret = $extrafields->setOptionalsFromPost(null, $object, '@GETPOSTISSET');
if ($ret < 0) {
$error++;
}
diff --git a/htdocs/don/payment/payment.php b/htdocs/don/payment/payment.php
index 719b6e9951b..e81a4a30af5 100644
--- a/htdocs/don/payment/payment.php
+++ b/htdocs/don/payment/payment.php
@@ -162,7 +162,7 @@ if ($action == 'create') {
print load_fiche_titre($langs->trans("DoPayment"));
if (!empty($conf->use_javascript_ajax)) {
- print "\n".'';
+ }
}
return $ret;
diff --git a/htdocs/hrm/skill_agenda.php b/htdocs/hrm/skill_agenda.php
index 9c1821fb8d7..a352988c297 100644
--- a/htdocs/hrm/skill_agenda.php
+++ b/htdocs/hrm/skill_agenda.php
@@ -147,7 +147,7 @@ if ($object->id > 0) {
// Object card
// ------------------------------------------------------------
- $linkback = ''.$langs->trans("BackToList").'';
+ $linkback = ''.$langs->trans("BackToList").'';
$morehtmlref = '