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..4ba65941254 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -105,6 +105,7 @@ 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".
For developers:
@@ -140,9 +141,128 @@ 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
+***** 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 +617,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 '
';
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/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".''."\n";
print "\n";
diff --git a/htdocs/paypal/admin/paypal.php b/htdocs/paypal/admin/paypal.php
index f4edec7630c..df5bb4161a5 100644
--- a/htdocs/paypal/admin/paypal.php
+++ b/htdocs/paypal/admin/paypal.php
@@ -350,7 +350,7 @@ $sandboxpaypalurl = 'developer.paypal.com';
print '
';
print 'Your API authentication information can be found with following steps. We recommend that you open a separate Web browser session when carrying out this procedure.
-1. Log in to your PayPal account (on real paypal '.$realpaypalurl.' (or sandbox '.$sandboxpaypalurl.').
+1. Log in to your PayPal account (on real paypal '.$realpaypalurl.' (or sandbox '.$sandboxpaypalurl.').
2. Click the "Profile" or "Preferencies" subtab located under the My Account heading.
3. Click the link "API Access".
4. Click the View API Certificate link in the right column.
diff --git a/htdocs/product/ajax/products.php b/htdocs/product/ajax/products.php
index 84562bf95a4..e230d148026 100644
--- a/htdocs/product/ajax/products.php
+++ b/htdocs/product/ajax/products.php
@@ -85,10 +85,15 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
if ($ret > 0) {
$outref = $object->ref;
$outlabel = $object->label;
- $outlabel_trans ='';
+ $outlabel_trans = '';
$outdesc = $object->description;
- $outdesc_trans ='';
+ $outdesc_trans = '';
$outtype = $object->type;
+ $outprice_ht = null;
+ $outprice_ttc = null;
+ $outpricebasetype = null;
+ $outtva_tx = 0;
+ $outdefault_vat_code = '';
$outqty = 1;
$outdiscount = 0;
$mandatory_period = $object->mandatory_period;
@@ -132,17 +137,21 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
$found = true;
$outprice_ht = price($objp->unitprice);
$outprice_ttc = price($objp->unitprice * (1 + ($object->tva_tx / 100)));
+
$outpricebasetype = $object->price_base_type;
$outtva_tx = $object->tva_tx;
+ $outdefault_vat_code = $object->default_vat_code;
+
$outqty = $objp->quantity;
$outdiscount = $objp->remise_percent;
}
}
}
- // Multiprice
+ // Multiprice (1 price per level)
if (!$found && isset($price_level) && $price_level >= 1 && (!empty($conf->global->PRODUIT_MULTIPRICES) || !empty($conf->global->PRODUIT_CUSTOMER_PRICES_BY_QTY_MULTIPRICES))) { // If we need a particular price level (from 1 to 6)
- $sql = "SELECT price, price_ttc, price_base_type, tva_tx";
+ $sql = "SELECT price, price_ttc, price_base_type,";
+ $sql .= " tva_tx, default_vat_code"; // Vat rate and code will be used if PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL is on.
$sql .= " FROM ".MAIN_DB_PREFIX."product_price ";
$sql .= " WHERE fk_product = ".((int) $id);
$sql .= " AND entity IN (".getEntity('productprice').")";
@@ -158,7 +167,14 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
$outprice_ht = price($objp->price);
$outprice_ttc = price($objp->price_ttc);
$outpricebasetype = $objp->price_base_type;
- $outtva_tx = $objp->tva_tx;
+ if (!empty($conf->global->PRODUIT_MULTIPRICES_USE_VAT_PER_LEVEL)) {
+ $outtva_tx = $objp->tva_tx;
+ $outdefault_vat_code = $objp->default_vat_code;
+ } else {
+ // The common and default behaviour.
+ $outtva_tx = $object->tva_tx;
+ $outdefault_vat_code = $object->default_vat_code;
+ }
}
}
}
@@ -175,10 +191,11 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
if ($result) {
if (count($prodcustprice->lines) > 0) {
$found = true;
- $outprice_ht = price($prodcustprice->lines [0]->price);
- $outprice_ttc = price($prodcustprice->lines [0]->price_ttc);
- $outpricebasetype = $prodcustprice->lines [0]->price_base_type;
- $outtva_tx = $prodcustprice->lines [0]->tva_tx;
+ $outprice_ht = price($prodcustprice->lines[0]->price);
+ $outprice_ttc = price($prodcustprice->lines[0]->price_ttc);
+ $outpricebasetype = $prodcustprice->lines[0]->price_base_type;
+ $outtva_tx = $prodcustprice->lines[0]->tva_tx;
+ $outdefault_vat_code = $prodcustprice->lines[0]->default_vat_code;
}
}
}
@@ -188,6 +205,7 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
$outprice_ttc = price($object->price_ttc);
$outpricebasetype = $object->price_base_type;
$outtva_tx = $object->tva_tx;
+ $outdefault_vat_code = $object->default_vat_code;
}
$outjson = array(
@@ -201,6 +219,7 @@ if (!empty($action) && $action == 'fetch' && !empty($id)) {
'price_ttc' => $outprice_ttc,
'pricebasetype' => $outpricebasetype,
'tva_tx' => $outtva_tx,
+ 'default_vat_code' => $outdefault_vat_code,
'qty' => $outqty,
'discount' => $outdiscount,
'mandatory_period' => $mandatory_period,
diff --git a/htdocs/product/class/product.class.php b/htdocs/product/class/product.class.php
index 1d4a5926b6e..a7865474014 100644
--- a/htdocs/product/class/product.class.php
+++ b/htdocs/product/class/product.class.php
@@ -2037,7 +2037,7 @@ class Product extends CommonObject
/**
- * Modify customer price of a product/Service
+ * Modify customer price of a product/Service
*
* @param double $newprice New price
* @param string $newpricebase HT or TTC
diff --git a/htdocs/product/class/productcustomerprice.class.php b/htdocs/product/class/productcustomerprice.class.php
index 407eac7c30a..a9444d1c569 100644
--- a/htdocs/product/class/productcustomerprice.class.php
+++ b/htdocs/product/class/productcustomerprice.class.php
@@ -392,9 +392,9 @@ class Productcustomerprice extends CommonObject
$sql .= " t.import_key,";
$sql .= " soc.nom as socname,";
$sql .= " prod.ref as prodref";
- $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price as t ";
- $sql .= " ,".MAIN_DB_PREFIX."product as prod ";
- $sql .= " ,".MAIN_DB_PREFIX."societe as soc ";
+ $sql .= " FROM ".MAIN_DB_PREFIX."product_customer_price as t,";
+ $sql .= " ".MAIN_DB_PREFIX."product as prod,";
+ $sql .= " ".MAIN_DB_PREFIX."societe as soc";
$sql .= " WHERE soc.rowid=t.fk_soc ";
$sql .= " AND prod.rowid=t.fk_product ";
$sql .= " AND prod.entity IN (".getEntity('product').")";
diff --git a/htdocs/product/fournisseurs.php b/htdocs/product/fournisseurs.php
index 02e0211c01d..b79fe5fb843 100644
--- a/htdocs/product/fournisseurs.php
+++ b/htdocs/product/fournisseurs.php
@@ -1211,7 +1211,7 @@ END;
$obj = $db->fetch_object($resql);
foreach ($extralabels as $key => $value) {
if (!empty($arrayfields['ef.'.$key]['checked']) && !empty($extrafields->attributes["product_fournisseur_price"]['list'][$key]) && $extrafields->attributes["product_fournisseur_price"]['list'][$key] != 3) {
- print '