diff --git a/htdocs/core/class/html.formsetup.class.php b/htdocs/core/class/html.formsetup.class.php
index 8f4c23ea5d7..9e7ed642c1d 100644
--- a/htdocs/core/class/html.formsetup.class.php
+++ b/htdocs/core/class/html.formsetup.class.php
@@ -82,6 +82,7 @@ class FormSetup
*/
public $errors = array();
+
/**
* Constructor
*
diff --git a/htdocs/core/db/DoliDB.class.php b/htdocs/core/db/DoliDB.class.php
index a6469cf6939..a9769ef9a8a 100644
--- a/htdocs/core/db/DoliDB.class.php
+++ b/htdocs/core/db/DoliDB.class.php
@@ -114,18 +114,18 @@ abstract class DoliDB implements Database
/**
* Format a SQL REGEXP
*
- * @param string $subject string tested
+ * @param string $subject Field name to test
* @param string $pattern SQL pattern to match
- * @param int $sqlstring whether or not the string being tested is an SQL expression
+ * @param int $sqlstring 0=the string being tested is a hard coded string, 1=the string is a field
* @return string SQL string
*/
public function regexpsql($subject, $pattern, $sqlstring = 0)
{
if ($sqlstring) {
- return "(". $subject ." REGEXP '" . $pattern . "')";
+ return "(". $subject ." REGEXP '" . $this->escape($pattern) . "')";
}
- return "('". $subject ."' REGEXP '" . $pattern . "')";
+ return "('". $this->escape($subject) ."' REGEXP '" . $this->escape($pattern) . "')";
}
diff --git a/htdocs/core/db/pgsql.class.php b/htdocs/core/db/pgsql.class.php
index 566cccf332a..cfd258fca9b 100644
--- a/htdocs/core/db/pgsql.class.php
+++ b/htdocs/core/db/pgsql.class.php
@@ -754,18 +754,18 @@ class DoliDBPgsql extends DoliDB
/**
* Format a SQL REGEXP
*
- * @param string $subject string tested
+ * @param string $subject Field name to test
* @param string $pattern SQL pattern to match
- * @param int $sqlstring whether or not the string being tested is an SQL expression
+ * @param int $sqlstring 0=the string being tested is a hard coded string, 1=the string is a field
* @return string SQL string
*/
public function regexpsql($subject, $pattern, $sqlstring = 0)
{
if ($sqlstring) {
- return "(". $subject ." ~ '" . $pattern . "')";
+ return "(". $subject ." ~ '" . $this->escape($pattern) . "')";
}
- return "('". $subject ."' ~ '" . $pattern . "')";
+ return "('". $this->escape($subject) ."' ~ '" . $this->escape($pattern) . "')";
}
diff --git a/htdocs/core/lib/files.lib.php b/htdocs/core/lib/files.lib.php
index 29b956c9d7a..b568a87a64e 100644
--- a/htdocs/core/lib/files.lib.php
+++ b/htdocs/core/lib/files.lib.php
@@ -2644,7 +2644,11 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
}
// Wrapping for miscellaneous medias files
- if ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
+ if ($modulepart == 'common') {
+ // Wrapping for some images
+ $accessallowed = 1;
+ $original_file = DOL_DOCUMENT_ROOT.'/public/theme/common/'.$original_file;
+ } elseif ($modulepart == 'medias' && !empty($dolibarr_main_data_root)) {
if (empty($entity) || empty($conf->medias->multidir_output[$entity])) {
return array('accessallowed'=>0, 'error'=>'Value entity must be provided');
}
@@ -2662,7 +2666,7 @@ function dol_check_secure_access_document($modulepart, $original_file, $entity,
// Wrapping for doctemplates of websites
$accessallowed = ($fuser->rights->website->write && preg_match('/\.jpg$/i', basename($original_file)));
$original_file = $dolibarr_main_data_root.'/doctemplates/websites/'.$original_file;
- } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) {
+ } elseif ($modulepart == 'packages' && !empty($dolibarr_main_data_root)) { // To download zip of modules
// Wrapping for *.zip package files, like when used with url http://.../document.php?modulepart=packages&file=module_myfile.zip
// Dir for custom dirs
$tmp = explode(',', $dolibarr_main_document_root_alt);
diff --git a/htdocs/core/lib/functions.lib.php b/htdocs/core/lib/functions.lib.php
index d686883cd7f..1df5f6a4a4c 100644
--- a/htdocs/core/lib/functions.lib.php
+++ b/htdocs/core/lib/functions.lib.php
@@ -10847,8 +10847,6 @@ function ajax_autoselect($htmlname, $addlink = '', $textonlink = 'Link')
*/
function dolIsAllowedForPreview($file)
{
- global $conf;
-
// Check .noexe extension in filename
if (preg_match('/\.noexe$/i', $file)) {
return 0;
diff --git a/htdocs/core/lib/images.lib.php b/htdocs/core/lib/images.lib.php
index b1959900794..dfafcdf8537 100644
--- a/htdocs/core/lib/images.lib.php
+++ b/htdocs/core/lib/images.lib.php
@@ -65,8 +65,6 @@ function getDefaultImageSizes()
*/
function getListOfPossibleImageExt($acceptsvg = 0)
{
- global $conf;
-
$regeximgext = '\.gif|\.jpg|\.jpeg|\.png|\.bmp|\.webp|\.xpm|\.xbm'; // See also into product.class.php
if ($acceptsvg || getDolGlobalString('MAIN_ALLOW_SVG_FILES_AS_IMAGES')) {
$regeximgext .= '|\.svg'; // Not allowed by default. SVG can contains javascript
diff --git a/htdocs/core/lib/website.lib.php b/htdocs/core/lib/website.lib.php
index 5f0bfd8915d..3f2f01c47c7 100644
--- a/htdocs/core/lib/website.lib.php
+++ b/htdocs/core/lib/website.lib.php
@@ -1,4 +1,6 @@
*
* This program is free software; you can redistribute it and/or modify
@@ -968,6 +970,85 @@ function getSocialNetworkSharingLinks()
return $out;
}
+
+/**
+ * Return HTML content to add structured data for an article, news or Blog Post.
+ *
+ * @param Object $object Object
+ * @param int $no Numero of image (if there is several images. 1st one by default)
+ * @param string $extName Extension to differentiate thumb file name ('', '_small', '_mini')
+ * @param string $morecss More CSS
+ * @return string HTML img content or '' if no image found
+ */
+function getPublicImageOfObject($object, $no = 1, $extName = '', $morecss = '')
+{
+ global $db;
+
+ $result = '';
+ $image_path = '';
+ $filename = '';
+
+ include_once DOL_DOCOUMENT_ROOT.'/core/lib/images.lib.php';
+ $regexforimg = getListOfPossibleImageExt(0);
+ $regexforimg = '('.$regexforimg.')$';
+
+ $sql = "SELECT rowid, ref, share, filename, cover, position";
+ $sql .= " FROM ".MAIN_DB_PREFIX."ecm_files";
+ $sql .= " WHERE entity IN (".getEntity($object->element).")";
+ $sql .= " AND src_object_type = '".$db->escape($object->element)."' AND src_object_id = ".((int) $object->id); // Filter on object
+ $sql .= " AND ".$db->regexpsql('filename', $regexforimg, 1);
+ $sql .= $db->order("cover,position,rowid", "ASC,ASC,ASC");
+
+ $resql = $db->query($sql);
+ if ($resql) {
+ $num = $db->num_rows($resql);
+ $i = 0;
+ $found = 0;
+ $foundnotshared = 0;
+ while ($i < $num) {
+ $obj = $db->fetch_object($resql);
+ if ($obj) {
+ if (empty($obj->share)) {
+ $foundnotshared++;
+ } else {
+ $found++;
+
+ $filename = $obj->filename;
+ $image_path = DOL_URL_ROOT.'/viewimage.php?hashp='.urlencode($obj->share);
+ if ($extName) {
+ $image_path .= '&extname='.urlencode($extName);
+ }
+ }
+ }
+ if ($found >= $no) {
+ break;
+ }
+ $i++;
+ }
+ if (!$found && $foundnotshared) {
+ $image_path = DOL_URL_ROOT.'/viewimage.php?modulepart=common&file=nophotopublic.png';
+ }
+ }
+
+ //getImageFileNameForSize($dir.$file, '_small')
+
+ if (empty($image_path)) {
+ $image_path = DOL_URL_ROOT.'/viewimage.php?modulepart=common&file=nophoto.png';
+ }
+
+ $result .= '';
+ if ($image_path) {
+ $result .= '';
+ }
+
+ return $result;
+}
+
+
/**
* Return list of containers object that match a criteria.
* WARNING: This function can be used by websites.
diff --git a/htdocs/core/modules/modTakePos.class.php b/htdocs/core/modules/modTakePos.class.php
index 06b5b79dbf3..366f8a98549 100644
--- a/htdocs/core/modules/modTakePos.class.php
+++ b/htdocs/core/modules/modTakePos.class.php
@@ -295,11 +295,11 @@ class modTakePos extends DolibarrModules
}
}
- //Create category if not exists
+ // Create product category DefaultPOSCatLabel if not exists
$categories = new Categorie($this->db);
$cate_arbo = $categories->get_full_arbo('product', 0, 1);
if (is_array($cate_arbo)) {
- if (!count($cate_arbo)) {
+ if (!count($cate_arbo) || !getDolGlobalString('TAKEPOS_ROOT_CATEGORY_ID')) {
$category = new Categorie($this->db);
$category->label = $langs->trans("DefaultPOSCatLabel");
@@ -308,6 +308,8 @@ class modTakePos extends DolibarrModules
$result = $category->create($user);
if ($result > 0) {
+ dolibarr_set_const($this->db, 'TAKEPOS_ROOT_CATEGORY_ID', $result, 'chaine', 0, 'Id of category for products visible in TakePOS', $conf->entity);
+
/* TODO Create a generic product only if there is no product yet. If 0 product, we create 1. If there is already product, it is better to show a message to ask to add product in the category */
/*
$product = new Product($this->db);
@@ -323,7 +325,7 @@ class modTakePos extends DolibarrModules
}
}
- //Create cash account if not exists
+ // Create cash account CASH-POS / DefaultCashPOSLabel if not exists
if (!getDolGlobalInt('CASHDESK_ID_BANKACCOUNT_CASH1')) {
require_once DOL_DOCUMENT_ROOT.'/compta/bank/class/account.class.php';
$cashaccount = new Account($this->db);
diff --git a/htdocs/install/mysql/migration/19.0.0-20.0.0.sql b/htdocs/install/mysql/migration/19.0.0-20.0.0.sql
index e6363ba41eb..33490b212d0 100644
--- a/htdocs/install/mysql/migration/19.0.0-20.0.0.sql
+++ b/htdocs/install/mysql/migration/19.0.0-20.0.0.sql
@@ -201,3 +201,5 @@ CREATE TABLE llx_c_product_thirdparty_relation_type
ALTER TABLE llx_c_tva ADD COLUMN type_vat smallint NOT NULL DEFAULT 0 AFTER fk_pays;
+ALTER TABLE llx_product DROP COLUMN onportal;
+
diff --git a/htdocs/install/mysql/tables/llx_product.sql b/htdocs/install/mysql/tables/llx_product.sql
index f63a4145569..0dd84d550f5 100644
--- a/htdocs/install/mysql/tables/llx_product.sql
+++ b/htdocs/install/mysql/tables/llx_product.sql
@@ -59,7 +59,6 @@ create table llx_product
fk_user_modif integer, -- user making last change
tosell tinyint DEFAULT 1, -- Product you sell
tobuy tinyint DEFAULT 1, -- Product you buy
- onportal tinyint DEFAULT 0, -- If it is a product you sell and you want to sell it from internal portal (module 'portal')
tobatch tinyint DEFAULT 0 NOT NULL, -- Is it a product that need a batch management (eat-by or lot management)
sell_or_eat_by_mandatory tinyint DEFAULT 0 NOT NULL, -- Make sell-by or eat-by date mandatory
batch_mask varchar(32) DEFAULT NULL, -- If the product has batch feature, you may want to use a batch mask per product
diff --git a/htdocs/langs/en_US/accountancy.lang b/htdocs/langs/en_US/accountancy.lang
index 7939e82498d..1d9215fdedd 100644
--- a/htdocs/langs/en_US/accountancy.lang
+++ b/htdocs/langs/en_US/accountancy.lang
@@ -446,8 +446,8 @@ AccountancyOneUnletteringModifiedSuccessfully=One unreconcile successfully modif
AccountancyUnletteringModifiedSuccessfully=%s unreconcile successfully modified
## Closure
-AccountancyClosureStep1=Step 1 : Validate and lock movements
-AccountancyClosureStep2=Step 2 : Close fiscal period
+AccountancyClosureStep1=Step 1 : Validate and lock the movements
+AccountancyClosureStep2=Step 2 : Close the fiscal period
AccountancyClosureStep3=Step 3 : Extract entries (Optional)
AccountancyClosureClose=Close fiscal period
AccountancyClosureAccountingReversal=Extract and record "Retained earnings" entries
diff --git a/htdocs/langs/en_US/main.lang b/htdocs/langs/en_US/main.lang
index 8c40379b67b..227b546ba74 100644
--- a/htdocs/langs/en_US/main.lang
+++ b/htdocs/langs/en_US/main.lang
@@ -1095,7 +1095,7 @@ KeyboardShortcut=Keyboard shortcut
AssignedTo=Assigned to
Deletedraft=Delete draft
ConfirmMassDraftDeletion=Draft mass delete confirmation
-FileSharedViaALink=File shared with a public link
+FileSharedViaALink=Public file shared via link
SelectAThirdPartyFirst=Select a third party first...
YouAreCurrentlyInSandboxMode=You are currently in the %s "sandbox" mode
Inventory=Inventory
diff --git a/htdocs/modulebuilder/index.php b/htdocs/modulebuilder/index.php
index 2fbddca8900..5930dce7225 100644
--- a/htdocs/modulebuilder/index.php
+++ b/htdocs/modulebuilder/index.php
@@ -3470,7 +3470,8 @@ if ($module == 'initmodule') {
foreach ($listofsetuppages as $setuppage) {
//var_dump($setuppage);
print '