]*>.*$/s','',$firstline); // The s pattern modifier means the . can match newline characters
+ if (dol_textishtml($text))
+ {
+ $firstline=preg_replace('/
]*>.*$/s','',$text); // The s pattern modifier means the . can match newline characters
+ $firstline=preg_replace('/
]*>.*$/s','',$firstline); // The s pattern modifier means the . can match newline characters
+ }
+ else
+ {
+ $firstline=preg_replace('/[\n\r].*/','',$text);
+ }
+ return $firstline.((strlen($firstline) != strlen($text))?'...':'');
}
else
{
- $firstline=preg_replace('/[\n\r].*/','',$text);
+ $ishtml=0;
+ if (dol_textishtml($text))
+ {
+ $text=preg_replace('/\n/','',$text);
+ $ishtml=1;
+ $repTable = array("\t" => " ", "\n" => " ", "\r" => " ", "\0" => " ", "\x0B" => " ");
+ }
+ else
+ {
+ $repTable = array("\t" => " ", "\n" => "
", "\r" => " ", "\0" => " ", "\x0B" => " ");
+ }
+
+ $text = strtr($text, $repTable);
+ if ($charset == 'UTF-8') { $pattern = '/(
]*>)/Uu'; } // /U is to have UNGREEDY regex to limit to one html tag. /u is for UTF8 support
+ else $pattern = '/(
]*>)/U'; // /U is to have UNGREEDY regex to limit to one html tag.
+ $a = preg_split($pattern, $text, -1, PREG_SPLIT_DELIM_CAPTURE | PREG_SPLIT_NO_EMPTY);
+
+ $firstline='';
+ $i=0;
+ $nba = count($a); // 2x nb of lines in $a because $a contains also a line for each new line separator
+ while (($i < $nba) && ($i < ($nboflines * 2)))
+ {
+ if ($i % 2 == 0) $firstline .= $a[$i];
+ elseif (($i < (($nboflines * 2) - 1)) && ($i < ($nba - 1))) $firstline .= ($ishtml?"
\n":"\n");
+ $i++;
+ }
+ unset($a);
+ return $firstline.(($i < $nba)?'...':'');
}
- return $firstline.((strlen($firstline) != strlen($text))?'...':'');
}
@@ -4665,7 +4700,7 @@ function dol_nboflines($s,$maxchar=0)
/**
- * Return nb of lines of a formated text with \n and
(we can't have both \n and br)
+ * Return nb of lines of a formated text with \n and
(WARNING: string must not have mixed \n and br separators)
*
* @param string $text Text
* @param int $maxlinesize Largeur de ligne en caracteres (ou 0 si pas de limite - defaut)
@@ -4701,6 +4736,8 @@ function dol_nboflines_bis($text,$maxlinesize=0,$charset='UTF-8')
}
}
}
+
+ unset($a);
return $nblines;
}
diff --git a/htdocs/core/modules/DolibarrModules.class.php b/htdocs/core/modules/DolibarrModules.class.php
index f0dce5f37a1..3d3e8339aca 100644
--- a/htdocs/core/modules/DolibarrModules.class.php
+++ b/htdocs/core/modules/DolibarrModules.class.php
@@ -1255,55 +1255,55 @@ class DolibarrModules // Can not be abstract, because we need to insta
*
* @return int Error count (0 if ok)
*/
- function insert_tabs()
- {
- global $conf;
+ function insert_tabs()
+ {
+ global $conf;
- $err=0;
+ $err=0;
- if (! empty($this->tabs))
- {
- $i=0;
- foreach ($this->tabs as $key => $value)
- {
- if (is_array($value) && count($value) == 0) continue; // Discard empty arrays
+ if (! empty($this->tabs))
+ {
+ $i=0;
+ foreach ($this->tabs as $key => $value)
+ {
+ if (is_array($value) && count($value) == 0) continue; // Discard empty arrays
- $entity=$conf->entity;
- $newvalue = $value;
+ $entity=$conf->entity;
+ $newvalue = $value;
- if (is_array($value))
- {
- $newvalue = $value['data'];
- if (isset($value['entity'])) $entity = $value['entity'];
- }
+ if (is_array($value))
+ {
+ $newvalue = $value['data'];
+ if (isset($value['entity'])) $entity = $value['entity'];
+ }
- if ($newvalue)
- {
- $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
- $sql.= "name";
- $sql.= ", type";
- $sql.= ", value";
- $sql.= ", note";
- $sql.= ", visible";
- $sql.= ", entity";
- $sql.= ")";
- $sql.= " VALUES (";
- $sql.= $this->db->encrypt($this->const_name."_TABS_".$i,1);
- $sql.= ", 'chaine'";
- $sql.= ", ".$this->db->encrypt($value,1);
- $sql.= ", null";
- $sql.= ", '0'";
- $sql.= ", ".$conf->entity;
- $sql.= ")";
+ if ($newvalue)
+ {
+ $sql = "INSERT INTO ".MAIN_DB_PREFIX."const (";
+ $sql.= "name";
+ $sql.= ", type";
+ $sql.= ", value";
+ $sql.= ", note";
+ $sql.= ", visible";
+ $sql.= ", entity";
+ $sql.= ")";
+ $sql.= " VALUES (";
+ $sql.= $this->db->encrypt($this->const_name."_TABS_".$i,1);
+ $sql.= ", 'chaine'";
+ $sql.= ", ".$this->db->encrypt($newvalue,1);
+ $sql.= ", null";
+ $sql.= ", '0'";
+ $sql.= ", ".$entity;
+ $sql.= ")";
- dol_syslog(get_class($this)."::insert_tabs", LOG_DEBUG);
- $this->db->query($sql);
- }
- $i++;
- }
- }
- return $err;
- }
+ dol_syslog(get_class($this)."::insert_tabs", LOG_DEBUG);
+ $this->db->query($sql);
+ }
+ $i++;
+ }
+ }
+ return $err;
+ }
/**
* Adds constants
diff --git a/htdocs/fourn/commande/list.php b/htdocs/fourn/commande/list.php
index 42773058471..5998cab9343 100644
--- a/htdocs/fourn/commande/list.php
+++ b/htdocs/fourn/commande/list.php
@@ -475,7 +475,7 @@ if ($resql)
$moreforfilter.='
';
$moreforfilter.=$langs->trans('IncludingProductWithTag'). ': ';
$cate_arbo = $form->select_all_categories(Categorie::TYPE_PRODUCT, null, 'parent', null, null, 1);
- $moreforfilter.=$form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, '', 1);
+ $moreforfilter.=$form->selectarray('search_product_category', $cate_arbo, $search_product_category, 1, 0, 0, '', 0, 0, 0, 0, 'maxwidth300', 1);
$moreforfilter.='
';
}
$parameters=array();
@@ -719,7 +719,7 @@ if ($resql)
if (! empty($arrayfields['cf.ref']['checked']))
{
print '
';
-
+
print '';
// Picto + Ref
print '| ';
@@ -734,7 +734,7 @@ if ($resql)
$filedir=$conf->fournisseur->dir_output.'/commande' . '/' . dol_sanitizeFileName($obj->ref);
print $formfile->getDocumentsLink($objectstatic->element, $filename, $filedir);
print ' | ';
-
+
print ' | '."\n";
if (! $i) $totalarray['nbfield']++;
}
diff --git a/htdocs/fourn/facture/list.php b/htdocs/fourn/facture/list.php
index 8022eb7ef17..118ef3df3b1 100644
--- a/htdocs/fourn/facture/list.php
+++ b/htdocs/fourn/facture/list.php
@@ -232,7 +232,7 @@ if (empty($reshook))
}
-
+
/*
* View
*/
@@ -389,7 +389,7 @@ if ($resql)
$num = $db->num_rows($resql);
$arrayofselected=is_array($toselect)?$toselect:array();
-
+
if ($socid)
{
$soc = new Societe($db);
@@ -424,9 +424,9 @@ if ($resql)
$tmpkey=preg_replace('/search_options_/','',$key);
if ($val != '') $param.='&search_options_'.$tmpkey.'='.urlencode($val);
}
-
+
$massactionbutton=$form->selectMassAction('', $massaction == 'presend' ? array() : array('presend'=>$langs->trans("SendByMail"), 'builddoc'=>$langs->trans("PDFMerge")));
-
+
$i = 0;
print '
\n";
diff --git a/htdocs/install/mysql/migration/3.8.0-3.9.0.sql b/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
index d747d5098f5..cc31ed38b40 100644
--- a/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
+++ b/htdocs/install/mysql/migration/3.8.0-3.9.0.sql
@@ -611,3 +611,7 @@ INSERT INTO llx_c_tva(rowid,fk_pays,taux,recuperableonly,note,active) VALUES (14
-- VMYSQL4.1 ALTER TABLE llx_c_type_resource CHANGE COLUMN rowid rowid integer NOT NULL AUTO_INCREMENT;
ALTER TABLE llx_import_model MODIFY COLUMN type varchar(50);
+
+-- Negative buying prices
+
+UPDATE llx_facturedet SET buy_price_ht = ABS(buy_price_ht)
diff --git a/htdocs/langs/en_US/stocks.lang b/htdocs/langs/en_US/stocks.lang
index 746268f7e98..231f5bb3a2e 100644
--- a/htdocs/langs/en_US/stocks.lang
+++ b/htdocs/langs/en_US/stocks.lang
@@ -67,6 +67,7 @@ NoPredefinedProductToDispatch=No predefined products for this object. So no disp
DispatchVerb=Dispatch
StockLimitShort=Limit for alert
StockLimit=Stock limit for alert
+StockLimitDesc="" (empty) default value means no alert.
"0" can be used with 'Stock can be negative' configuration.
PhysicalStock=Physical stock
RealStock=Real Stock
RealStockDesc=Physical or real stock is the stock you currently have into your internal warehouses/emplacements.
@@ -142,4 +143,4 @@ OptionMULTIPRICESIsOn=Option "several prices per segment" is on. It means a prod
ProductStockWarehouseCreated=Stock limit for alert and desired optimal stock correctly created
ProductStockWarehouseUpdated=Stock limit for alert and desired optimal stock correctly updated
ProductStockWarehouseDeleted=Stock limit for alert and desired optimal stock correctly deleted
-AddNewProductStockWarehouse=Set new limit for alert and desired optimal stock
\ No newline at end of file
+AddNewProductStockWarehouse=Set new limit for alert and desired optimal stock
diff --git a/test/phpunit/FunctionsLibTest.php b/test/phpunit/FunctionsLibTest.php
index 3345d780b7e..814adfb390b 100644
--- a/test/phpunit/FunctionsLibTest.php
+++ b/test/phpunit/FunctionsLibTest.php
@@ -120,10 +120,75 @@ class FunctionsLibTest extends PHPUnit_Framework_TestCase
+ /**
+ * testDolGetFirstLineOfText
+ *
+ * @return void
+ */
+ public function testDolGetFirstLineOfText()
+ {
+ // Nb of line is same than entry text
+
+ $input="aaaa";
+ $result=dolGetFirstLineOfText($input);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa", $result);
+
+ $input="aaaa\nbbbbbbbbbbbb\n";
+ $result=dolGetFirstLineOfText($input, 2);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa\nbbbbbbbbbbbb", $result);
+
+ $input="aaaa
bbbbbbbbbbbb
";
+ $result=dolGetFirstLineOfText($input, 2);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa
\nbbbbbbbbbbbb", $result);
+
+ // Nb of line is lower
+
+ $input="aaaa\nbbbbbbbbbbbb\ncccccc\n";
+ $result=dolGetFirstLineOfText($input);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa...", $result);
+
+ $input="aaaa
bbbbbbbbbbbb
cccccc
";
+ $result=dolGetFirstLineOfText($input);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa...", $result);
+
+ $input="aaaa\nbbbbbbbbbbbb\ncccccc\n";
+ $result=dolGetFirstLineOfText($input, 2);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa\nbbbbbbbbbbbb...", $result);
+
+ $input="aaaa
bbbbbbbbbbbb
cccccc
";
+ $result=dolGetFirstLineOfText($input, 2);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa
\nbbbbbbbbbbbb...", $result);
+
+ // Nb of line is higher
+
+ $input="aaaa
bbbbbbbbbbbb
cccccc";
+ $result=dolGetFirstLineOfText($input, 100);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa
\nbbbbbbbbbbbb
\ncccccc", $result, 'dolGetFirstLineOfText with nb 100 a');
+
+ $input="aaaa
bbbbbbbbbbbb
cccccc
";
+ $result=dolGetFirstLineOfText($input, 100);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa
\nbbbbbbbbbbbb
\ncccccc", $result, 'dolGetFirstLineOfText with nb 100 b');
+
+ $input="aaaa
bbbbbbbbbbbb
cccccc
\n";
+ $result=dolGetFirstLineOfText($input, 100);
+ print __METHOD__." result=".$result."\n";
+ $this->assertEquals("aaaa
\nbbbbbbbbbbbb
\ncccccc", $result, 'dolGetFirstLineOfText with nb 100 c');
+ }
+
+
/**
* testDolBuildPath
*
- * @return boolean
+ * @return void
*/
public function testDolBuildPath()
{