From 9bbe0e6b1cf0be3a1dc10aa6476a0595be8dffeb Mon Sep 17 00:00:00 2001
From: Laurent Destailleur <eldy@destailleur.fr>
Date: Sat, 22 Sep 2012 20:27:06 +0200
Subject: [PATCH] Qual: Mutuamize codeby using tpl. New: Support unique field
 for extrafields

---
 .../adherents/admin/adherent_extrafields.php  | 69 ++--------------
 htdocs/core/admin_extrafields.inc.php         | 10 +--
 htdocs/core/class/extrafields.class.php       | 81 ++++++++++++++-----
 htdocs/core/tpl/admin_extrafields_add.tpl.php | 66 +++++++++++++++
 .../core/tpl/admin_extrafields_edit.tpl.php   | 72 +++++++++++++++++
 .../install/mysql/migration/3.2.0-3.3.0.sql   |  3 +-
 .../install/mysql/tables/llx_extrafields.sql  |  1 +
 htdocs/product/admin/product_extrafields.php  | 36 ++-------
 htdocs/societe/admin/contact_extrafields.php  | 36 ++-------
 htdocs/societe/admin/societe_extrafields.php  | 73 ++---------------
 htdocs/theme/amarok/style.css.php             | 10 ++-
 htdocs/theme/auguria/style.css.php            |  7 ++
 htdocs/theme/bureau2crea/style.css.php        |  7 ++
 htdocs/theme/cameleo/style.css.php            |  7 ++
 htdocs/theme/eldy/style.css.php               |  4 +
 15 files changed, 265 insertions(+), 217 deletions(-)
 create mode 100644 htdocs/core/tpl/admin_extrafields_add.tpl.php
 create mode 100644 htdocs/core/tpl/admin_extrafields_edit.tpl.php

diff --git a/htdocs/adherents/admin/adherent_extrafields.php b/htdocs/adherents/admin/adherent_extrafields.php
index e948b54482f..4941cff79c5 100755
--- a/htdocs/adherents/admin/adherent_extrafields.php
+++ b/htdocs/adherents/admin/adherent_extrafields.php
@@ -88,6 +88,7 @@ print '<td>'.$langs->trans("Label").'</td>';
 print '<td>'.$langs->trans("AttributeCode").'</td>';
 print '<td>'.$langs->trans("Type").'</td>';
 print '<td align="right">'.$langs->trans("Size").'</td>';
+print '<td align="right">'.$langs->trans("Unique").'</td>';
 print '<td width="80">&nbsp;</td>';
 print "</tr>\n";
 
@@ -100,6 +101,7 @@ foreach($extrafields->attribute_type as $key => $value)
 	print "<td>".$key."</td>\n";
 	print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n";
 	print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n";
+    print '<td align="right">'.yn($extrafields->attribute_unique[$key])."</td>\n";
 	print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>';
 	print "&nbsp; <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=".$key."\">".img_delete()."</a></td>\n";
 	print "</tr>";
@@ -110,10 +112,8 @@ print "</table>";
 
 dol_fiche_end();
 
-/*
- * Barre d'actions
- *
- */
+
+// Buttons
 if ($action != 'create' && $action != 'edit')
 {
 	print '<div class="tabsAction">';
@@ -133,29 +133,7 @@ if ($action == 'create')
 	print "<br>";
 	print_titre($langs->trans('NewAttribute'));
 
-	print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
-	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-	print '<table summary="listofattributes" class="border" width="100%">';
-
-	print '<input type="hidden" name="action" value="add">';
-
-	// Label
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.GETPOST('label').'"></td></tr>';
-	// Code
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("AttributeCode").' ('.$langs->trans("AlphaNumOnlyCharsAndNoSpace").')</td><td class="valeur"><input type="text" name="attrname" size="10" value="'.GETPOST('attrname').'"></td></tr>';
-	// Type
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td><td class="valeur">';
-    print $form->selectarray('type',$type2label,GETPOST('type'));
-	print '</td></tr>';
-	// Size
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td><input id="size" type="text" name="size" size="5" value="'.(GETPOST('size')?GETPOST('size'):'').'"></td></tr>';
-
-    print '</table>';
-
-    print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-    print "</form>\n";
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php';
 }
 
 /* ************************************************************************** */
@@ -168,42 +146,7 @@ if ($action == 'edit' && ! empty($attrname))
 	print "<br>";
 	print_titre($langs->trans("FieldEdition", $attrname));
 
-	/*
-	 * formulaire d'edition
-	 */
-	print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?attrname='.$attrname.'">';
-	print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-	print '<input type="hidden" name="attrname" value="'.$attrname.'">';
-	print '<input type="hidden" name="action" value="update">';
-	print '<table summary="listofattributes" class="border" width="100%">';
-
-    // Label
-    print '<tr>';
-    print '<td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.$extrafields->attribute_label[$attrname].'"></td>';
-    print '</tr>';
-	// Code
-	print '<tr>';
-	print '<td class="fieldrequired" required>'.$langs->trans("AttributeCode").'</td>';
-	print '<td class="valeur">'.$attrname.'&nbsp;</td>';
-	print '</tr>';
-	// Type
-	$type=$extrafields->attribute_type[$attrname];
-	$size=$extrafields->attribute_size[$attrname];
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td>';
-	print '<td class="valeur">';
-	print $type2label[$type];
-	print '<input type="hidden" name="type" value="'.$type.'">';
-	print '</td></tr>';
-    // Size
-	print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td class="valeur"><input type="text" name="size" size="5" value="'.$size.'"></td></tr>';
-
-	print '</table>';
-
-	print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-	print "</form>";
-
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php';
 }
 
 $db->close();
diff --git a/htdocs/core/admin_extrafields.inc.php b/htdocs/core/admin_extrafields.inc.php
index 35492db4fdc..c1a7da31374 100644
--- a/htdocs/core/admin_extrafields.inc.php
+++ b/htdocs/core/admin_extrafields.inc.php
@@ -1,5 +1,5 @@
 <?php
-/* Copyright (C) 2011 Laurent Destailleur  <eldy@users.sourceforge.net>
+/* Copyright (C) 2011-2012 Laurent Destailleur  <eldy@users.sourceforge.net>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -64,7 +64,7 @@ if ($action == 'add')
     		// Type et taille non encore pris en compte => varchar(255)
     		if (isset($_POST["attrname"]) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$_POST['attrname']))
     		{
-                $result=$extrafields->addExtraField($_POST['attrname'],$_POST['label'],$_POST['type'],$_POST['pos'],$extrasize,$elementtype);
+                $result=$extrafields->addExtraField($_POST['attrname'],$_POST['label'],$_POST['type'],$_POST['pos'],$extrasize,$elementtype,(GETPOST('unique')?1:0));
     			if ($result > 0)
     			{
     				header("Location: ".$_SERVER["PHP_SELF"]);
@@ -119,13 +119,9 @@ if ($action == 'update')
 	    {
             if (isset($_POST["attrname"]) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$_POST['attrname']))
     		{
-    			$result=$extrafields->update($_POST['attrname'],$_POST['type'],$extrasize,$elementtype);
+    			$result=$extrafields->update($_POST['attrname'],$_POST['label'],$_POST['type'],$extrasize,$elementtype,(GETPOST('unique')?1:0));
     			if ($result > 0)
     			{
-    				if (isset($_POST['label']))
-    				{
-    					$extrafields->update_label($_POST['attrname'],$_POST['label'],$_POST['type'],$extrasize,$elementtype);
-    				}
     				header("Location: ".$_SERVER["PHP_SELF"]);
     				exit;
     			}
diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php
index 92c38a2d408..9fead0436b7 100755
--- a/htdocs/core/class/extrafields.class.php
+++ b/htdocs/core/class/extrafields.class.php
@@ -38,6 +38,8 @@ class ExtraFields
 	var $attribute_label;
 	// Tableau contenant le nom des champs en clef et la taille de ces champs en value
 	var $attribute_size;
+	// Tableau contenant le statut unique ou non
+	var $attribute_unique;
 
 	var $error;
 	var $errno;
@@ -64,6 +66,7 @@ class ExtraFields
 		$this->attribute_label = array();
 		$this->attribute_size = array();
 		$this->attribute_elementtype = array();
+		$this->attribute_unique = array();
 	}
 
     /**
@@ -75,9 +78,10 @@ class ExtraFields
      *  @param  int		$pos                Position of attribute
      *  @param  int		$size               Size/length of attribute
      *  @param  string	$elementtype        Element type ('member', 'product', 'company', ...)
+     *  @param	int		$unique				Is field unique or not
      *  @return int      					<=0 if KO, >0 if OK
      */
-    function addExtraField($attrname,$label,$type='',$pos=0,$size=0, $elementtype='member')
+    function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique=0)
 	{
         if (empty($attrname)) return -1;
         if (empty($label)) return -1;
@@ -88,7 +92,7 @@ class ExtraFields
         if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS')
         {
         	// Add declaration of field into table
-            $result2=$this->create_label($attrname,$label,$type,$pos,$size,$elementtype);
+            $result2=$this->create_label($attrname,$label,$type,$pos,$size,$elementtype, $unique);
             $err2=$this->errno;
             if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS'))
             {
@@ -111,9 +115,10 @@ class ExtraFields
 	 *  @param	int		$type				Type of attribute ('int', 'text', 'varchar', 'date', 'datehour')
 	 *  @param	int		$length				Size/length of attribute
      *  @param  string	$elementtype        Element type ('member', 'product', 'company', ...)
+     *  @param	int		$unique				Is field unique or not
      *  @return int      	           		<=0 if KO, >0 if OK
 	 */
-	function create($attrname,$type='varchar',$length=255,$elementtype='member')
+	private function create($attrname, $type='varchar', $length=255, $elementtype='member', $unique=0)
 	{
         $table='';
         if ($elementtype == 'member')  $table='adherent_extrafields';
@@ -132,6 +137,11 @@ class ExtraFields
 			$result=$this->db->DDLAddField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
 			if ($result > 0)
 			{
+				if ($unique)
+				{
+					$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
+					$resql=$this->db->query($sql,1,'dml');
+				}
 				return 1;
 			}
 			else
@@ -156,9 +166,10 @@ class ExtraFields
 	 *  @param	int		$pos				Position of attribute
 	 *  @param	int		$size				Size/length of attribute
 	 *  @param  string	$elementtype        Element type ('member', 'product', 'company', ...)
+     *  @param	int		$unique				Is field unique or not
 	 *  @return	int							<=0 if KO, >0 if OK
 	 */
-	function create_label($attrname,$label='',$type='',$pos=0,$size=0, $elementtype='member')
+	private function create_label($attrname, $label='', $type='', $pos=0, $size=0, $elementtype='member', $unique=0)
 	{
 		global $conf;
 
@@ -168,15 +179,16 @@ class ExtraFields
 
 		if (isset($attrname) && $attrname != '' && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
 		{
-			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype)";
+			$sql = "INSERT INTO ".MAIN_DB_PREFIX."extrafields(name, label, type, pos, size, entity, elementtype, fieldunique)";
 			$sql.= " VALUES('".$attrname."',";
 			$sql.= " '".$this->db->escape($label)."',";
 			$sql.= " '".$type."',";
 			$sql.= " '".$pos."',";
 			$sql.= " '".$size."',";
 			$sql.= " ".$conf->entity.",";
-            $sql.= " '".$elementtype."'";
-			$sql.=')';
+            $sql.= " '".$elementtype."',";
+            $sql.= " '".$unique."'";
+            $sql.=')';
 
 			dol_syslog(get_class($this)."::create_label sql=".$sql);
 			if ($this->db->query($sql))
@@ -199,7 +211,7 @@ class ExtraFields
 	 *  @param  string	$elementtype    Element type ('member', 'product', 'company', ...)
 	 *  @return int              		< 0 if KO, 0 if nothing is done, 1 if OK
 	 */
-	function delete($attrname,$elementtype='member')
+	function delete($attrname, $elementtype='member')
 	{
 	    $table='';
 	    if ($elementtype == 'member')  $table='adherent_extrafields';
@@ -214,7 +226,7 @@ class ExtraFields
 
 		if (! empty($attrname) && preg_match("/^\w[a-zA-Z0-9-_]*$/",$attrname))
 		{
-		    $result=$this->db->DDLDropField(MAIN_DB_PREFIX.$table,$attrname);
+		    $result=$this->db->DDLDropField(MAIN_DB_PREFIX.$table,$attrname);	// This also drop the unique key
 			if ($result < 0)
 			{
 				$this->error=$this->db->lasterror();
@@ -239,7 +251,7 @@ class ExtraFields
      *  @param  string	$elementtype        Element type ('member', 'product', 'company', ...)
      *  @return int              			< 0 if KO, 0 if nothing is done, 1 if OK
 	 */
-	function delete_label($attrname,$elementtype='member')
+	private function delete_label($attrname, $elementtype='member')
 	{
 		global $conf;
 
@@ -273,12 +285,14 @@ class ExtraFields
 	 * 	Modify type of a personalized attribute
 	 *
 	 *  @param	string	$attrname			Name of attribute
+	 *  @param	string	$label				Label of attribute
 	 *  @param	string	$type				Type of attribute
 	 *  @param	int		$length				Length of attribute
      *  @param  string	$elementtype        Element type ('member', 'product', 'company', ...)
+     *  @param	int		$unique				Is field unique or not
 	 * 	@return	int							>0 if OK, <=0 if KO
 	 */
-	function update($attrname,$type='varchar',$length=255,$elementtype='member')
+	function update($attrname,$label,$type,$length,$elementtype,$unique=0)
 	{
         $table='';
         if ($elementtype == 'member')  $table='adherent_extrafields';
@@ -297,7 +311,30 @@ class ExtraFields
 			$result=$this->db->DDLUpdateField(MAIN_DB_PREFIX.$table, $attrname, $field_desc);
 			if ($result > 0)
 			{
-				return 1;
+				if ($label)
+				{
+					$result=$this->update_label($attrname,$label,$type,$length,$elementtype,$unique);
+				}
+				if ($result > 0)
+				{
+					$sql='';
+					if ($unique)
+					{
+						$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." ADD UNIQUE INDEX uk_".$table."_".$attrname." (".$attrname.")";
+					}
+					else
+					{
+						$sql="ALTER TABLE ".MAIN_DB_PREFIX.$table." DROP INDEX uk_".$table."_".$attrname;
+					}
+					dol_syslog(get_class($this).'::update sql='.$sql);
+					$resql=$this->db->query($sql,1,'dml');
+					return 1;
+				}
+				else
+				{
+					$this->error=$this->db->lasterror();
+					return -1;
+				}
 			}
 			else
 			{
@@ -320,9 +357,10 @@ class ExtraFields
      *  @param  string	$type               Type of attribute
      *  @param  int		$size		        Length of attribute
      *  @param  string	$elementtype		Element type ('member', 'product', 'company', ...)
-     *  @return	int							<0 if KO, >0 if OK
+     *  @param	int		$unique				Is field unique or not
+     *  @return	int							<=0 if KO, >0 if OK
      */
-	function update_label($attrname,$label,$type,$size,$elementtype='member')
+	private function update_label($attrname,$label,$type,$size,$elementtype,$unique=0)
 	{
 		global $conf;
 		dol_syslog(get_class($this)."::update_label $attrname,$label,$type,$size");
@@ -344,15 +382,17 @@ class ExtraFields
 			$sql.= " label,";
 			$sql.= " type,";
 			$sql.= " size,";
-			$sql.= " elementtype";
+			$sql.= " elementtype,";
+			$sql.= " fieldunique";
 			$sql.= ") VALUES (";
 			$sql.= "'".$attrname."',";
 			$sql.= " ".$conf->entity.",";
 			$sql.= " '".$this->db->escape($label)."',";
 			$sql.= " '".$type."',";
 			$sql.= " '".$size."',";
-            $sql.= " '".$elementtype."'";
-			$sql.= ")";
+            $sql.= " '".$elementtype."',";
+            $sql.= " '".$unique."'";
+            $sql.= ")";
 			dol_syslog(get_class($this)."::update_label sql=".$sql);
 			$resql2=$this->db->query($sql);
 
@@ -365,7 +405,7 @@ class ExtraFields
 			{
 				$this->db->rollback();
 				print dol_print_error($this->db);
-				return 0;
+				return -1;
 			}
 		}
 		else
@@ -399,7 +439,7 @@ class ExtraFields
 
 		$array_name_label=array();
 
-		$sql = "SELECT rowid,name,label,type,size,elementtype";
+		$sql = "SELECT rowid,name,label,type,size,elementtype,fieldunique";
 		$sql.= " FROM ".MAIN_DB_PREFIX."extrafields";
 		$sql.= " WHERE entity = ".$conf->entity;
 		if ($elementtype) $sql.= " AND elementtype = '".$elementtype."'";
@@ -419,6 +459,7 @@ class ExtraFields
 					$this->attribute_label[$tab->name]=$tab->label;
 					$this->attribute_size[$tab->name]=$tab->size;
                     $this->attribute_elementtype[$tab->name]=$tab->elementtype;
+                    $this->attribute_unique[$tab->name]=$tab->fieldunique;
 				}
 			}
 			return $array_name_label;
@@ -446,6 +487,7 @@ class ExtraFields
 	    $type =$this->attribute_type[$key];
         $size =$this->attribute_size[$key];
         $elementtype=$this->attribute_elementtype[$key];
+        $unique=$this->attribute_unique[$key];
         if ($type == 'date')
         {
             $showsize=10;
@@ -506,6 +548,7 @@ class ExtraFields
         $type=$this->attribute_type[$key];
         $size=$this->attribute_size[$key];
         $elementtype=$this->attribute_elementtype[$key];
+        $unique=$this->attribute_unique[$key];
         if ($type == 'date')
         {
             $showsize=10;
diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php
new file mode 100644
index 00000000000..a4ebedcc54c
--- /dev/null
+++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php
@@ -0,0 +1,66 @@
+<?php
+/* Copyright (C) 2010-2012	Laurent Destailleur	<eldy@users.sourceforge.net>
+ * Copyright (C) 2012		Regis Houssin		<regis@dolibarr.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+?>
+
+<!-- BEGIN PHP TEMPLATE admin_extrafields.tpl.php -->
+<script type="text/javascript">
+    jQuery(document).ready(function() {
+    	function init_typeoffields(type)
+    	{
+    		var size = jQuery("#size");
+    		if (type == 'date') { size.val('').attr('disabled','disabled'); }
+    		else if (type == 'datetime') { size.val('').attr('disabled','disabled'); }
+    		else if (type == 'double') { size.val('24,8').removeAttr('disabled'); }
+    		else if (type == 'int') { size.val('10').removeAttr('disabled'); }
+    		else if (type == 'text') { size.val('2000').removeAttr('disabled'); }
+    		else if (type == 'varchar') { size.val('255').removeAttr('disabled'); }
+    		else size.val('').attr('disabled','disabled');
+    	}
+    	init_typeoffields('');
+    	jQuery("#type").change(function() {
+    		init_typeoffields($(this).val());
+    	});
+    });
+</script>
+
+<form action="<?php echo $_SERVER["PHP_SELF"]; ?>" method="post">
+<input type="hidden" name="token" value="<?php echo $_SESSION['newtoken']; ?>">
+<input type="hidden" name="action" value="add">
+
+<table summary="listofattributes" class="border centpercent">
+
+<!-- Label -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("Label"); ?></td><td class="valeur"><input type="text" name="label" size="40" value="<?php echo GETPOST('label'); ?>"></td></tr>
+<!-- Code -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("AttributeCode"); ?> (<?php echo $langs->trans("AlphaNumOnlyCharsAndNoSpace"); ?>)</td><td class="valeur"><input type="text" name="attrname" size="10" value="<?php echo GETPOST('attrname'); ?>"></td></tr>
+<!-- Type -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("Type"); ?></td><td class="valeur">
+<?php print $form->selectarray('type',$type2label,GETPOST('type')); ?>
+</td></tr>
+<!-- Size -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td class="valeur"><input id="size" type="text" name="size" size="5" value="<?php echo (GETPOST('size')?GETPOST('size'):''); ?>"></td></tr>
+<!-- Unique -->
+<tr><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input type="checkbox" name="unique" <?php echo (GETPOST('unique')?' checked="true"':''); ?>"></td></tr>
+</table>
+
+<div align="center"><br><input type="submit" name="button" class="button" value="<?php echo $langs->trans("Save"); ?>"> &nbsp;
+<input type="submit" name="button" class="button" value="<?php echo $langs->trans("Cancel"); ?>"></div>
+
+</form>
+
+<!-- END PHP TEMPLATE admin_extrafields.tpl.php -->
diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php
new file mode 100644
index 00000000000..b93f136bc5d
--- /dev/null
+++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php
@@ -0,0 +1,72 @@
+<?php
+/* Copyright (C) 2010-2012	Laurent Destailleur	<eldy@users.sourceforge.net>
+ * Copyright (C) 2012		Regis Houssin		<regis@dolibarr.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+?>
+
+<!-- BEGIN PHP TEMPLATE admin_extrafields.tpl.php -->
+<script type="text/javascript">
+    jQuery(document).ready(function() {
+    	function init_typeoffields(type)
+    	{
+    		var size = jQuery("#size");
+    		if (type == 'date') { size.attr('disabled','disabled'); }
+    		else if (type == 'datetime') { size.attr('disabled','disabled'); }
+    		else if (type == 'double') { size.removeAttr('disabled'); }
+    		else if (type == 'int') { size.removeAttr('disabled'); }
+    		else if (type == 'text') { size.removeAttr('disabled'); }
+    		else if (type == 'varchar') { size.removeAttr('disabled'); }
+    		else size.val('').attr('disabled','disabled');
+    	}
+    	init_typeoffields(jQuery("#type").val());
+    });
+</script>
+
+
+<form action="<?php echo $_SERVER["PHP_SELF"]; ?>?attrname=<?php echo $attrname; ?>" method="post">
+<input type="hidden" name="token" value="<?php echo $_SESSION['newtoken']; ?>">
+<input type="hidden" name="attrname" value="<?php echo $attrname; ?>">
+<input type="hidden" name="action" value="update">
+
+<table summary="listofattributes" class="border centpercent">
+
+<!-- Label -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("Label"); ?></td><td class="valeur"><input type="text" name="label" size="40" value="<?php echo $extrafields->attribute_label[$attrname]; ?>"></td></tr>
+<!-- Code -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("AttributeCode"); ?></td><td class="valeur"><?php echo $attrname; ?></td></tr>
+<!-- Type -->
+<?php
+$type=$extrafields->attribute_type[$attrname];
+$size=$extrafields->attribute_size[$attrname];
+$unique=$extrafields->attribute_unique[$attrname];
+?>
+<tr><td class="fieldrequired"><?php echo $langs->trans("Type"); ?></td><td class="valeur">
+<?php print $type2label[$type]; ?>
+<input type="hidden" name="type" id="type" value="<?php print $type; ?>">
+</td></tr>
+<!-- Size -->
+<tr><td class="fieldrequired"><?php echo $langs->trans("Size"); ?></td><td><input id="size" type="text" name="size" size="5" value="<?php echo $size; ?>"></td></tr>
+<!-- Unique -->
+<tr><td><?php echo $langs->trans("Unique"); ?></td><td class="valeur"><input type="checkbox" name="unique" <?php echo ($unique?' checked="true"':''); ?>"></td></tr>
+
+</table>
+
+<div align="center"><br><input type="submit" name="button" class="button" value="<?php echo $langs->trans("Save"); ?>"> &nbsp;
+<input type="submit" name="button" class="button" value="<?php echo $langs->trans("Cancel"); ?>"></div>
+
+</form>
+
+<!-- END PHP TEMPLATE admin_extrafields.tpl.php -->
diff --git a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql
index 1df3ee24e26..690b429a142 100755
--- a/htdocs/install/mysql/migration/3.2.0-3.3.0.sql
+++ b/htdocs/install/mysql/migration/3.2.0-3.3.0.sql
@@ -225,8 +225,9 @@ ALTER TABLE llx_propaldet MODIFY COLUMN localtax1_type varchar(1);
 ALTER TABLE llx_propaldet MODIFY COLUMN localtax2_type varchar(1);
 -- END TASK #204
 
-ALTER TABLE llx_menu MODIFY COLUMN enabled varchar(255) NULL default '1';
+ALTER TABLE llx_menu MODIFY COLUMN enabled varchar(255) NULL DEFAULT '1';
 
+ALTER TABLE llx_extrafields ADD COLUMN fieldunique INTEGER DEFAULT 0;
 
 create table llx_socpeople_extrafields
 (
diff --git a/htdocs/install/mysql/tables/llx_extrafields.sql b/htdocs/install/mysql/tables/llx_extrafields.sql
index ad480d931fe..79eaffc8347 100755
--- a/htdocs/install/mysql/tables/llx_extrafields.sql
+++ b/htdocs/install/mysql/tables/llx_extrafields.sql
@@ -29,5 +29,6 @@ create table llx_extrafields
 	label           varchar(255) NOT NULL,      -- label correspondant a l'attribut
 	type            varchar(8),
 	size            varchar(8) DEFAULT NULL,
+	fieldunique     integer DEFAULT 0,
 	pos             integer DEFAULT 0
 )ENGINE=innodb;
diff --git a/htdocs/product/admin/product_extrafields.php b/htdocs/product/admin/product_extrafields.php
index 6ad785a35c6..7c445643881 100755
--- a/htdocs/product/admin/product_extrafields.php
+++ b/htdocs/product/admin/product_extrafields.php
@@ -101,6 +101,7 @@ print '<td>'.$langs->trans("Label").'</td>';
 print '<td>'.$langs->trans("AttributeCode").'</td>';
 print '<td>'.$langs->trans("Type").'</td>';
 print '<td align="right">'.$langs->trans("Size").'</td>';
+print '<td align="right">'.$langs->trans("Unique").'</td>';
 print '<td width="80">&nbsp;</td>';
 print "</tr>\n";
 
@@ -108,11 +109,12 @@ $var=True;
 foreach($extrafields->attribute_type as $key => $value)
 {
     $var=!$var;
-    print "<tr $bc[$var]>";
+    print "<tr ".$bc[$var].">";
     print "<td>".$extrafields->attribute_label[$key]."</td>\n";
     print "<td>".$key."</td>\n";
     print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n";
     print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n";
+    print '<td align="right">'.yn($extrafields->attribute_unique[$key])."</td>\n";
     print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>';
     print "&nbsp; <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=$key\">".img_delete()."</a></td>\n";
     print "</tr>";
@@ -123,10 +125,8 @@ print "</table>";
 
 dol_fiche_end();
 
-/*
- * Barre d'actions
- *
- */
+
+// Buttons
 if ($action != 'create' && $action != 'edit')
 {
     print '<div class="tabsAction">';
@@ -146,31 +146,7 @@ if ($action == 'create')
     print "<br>";
     print_titre($langs->trans('NewAttribute'));
 
-    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields.tpl.php';
-
-    print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
-    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-    print '<table summary="listofattributes" class="border" width="100%">';
-
-    print '<input type="hidden" name="action" value="add">';
-
-    // Label
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.GETPOST('label').'"></td></tr>';
-    // Code
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("AttributeCode").' ('.$langs->trans("AlphaNumOnlyCharsAndNoSpace").')</td><td class="valeur"><input type="text" name="attrname" size="10" value="'.GETPOST('attrname').'"></td></tr>';
-    // Type
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td><td class="valeur">';
-    print $form->selectarray('type',$type2label,GETPOST('type'));
-    print '</td></tr>';
-    // Size
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td><input id="size" type="text" name="size" size="5" value="'.(GETPOST('size')?GETPOST('size'):'').'"></td></tr>';
-
-    print "</table>\n";
-
-    print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-    print "</form>\n";
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php';
 }
 
 /* ************************************************************************** */
diff --git a/htdocs/societe/admin/contact_extrafields.php b/htdocs/societe/admin/contact_extrafields.php
index 8accb58f138..baed4711c32 100755
--- a/htdocs/societe/admin/contact_extrafields.php
+++ b/htdocs/societe/admin/contact_extrafields.php
@@ -88,6 +88,7 @@ print '<td>'.$langs->trans("Label").'</td>';
 print '<td>'.$langs->trans("AttributeCode").'</td>';
 print '<td>'.$langs->trans("Type").'</td>';
 print '<td align="right">'.$langs->trans("Size").'</td>';
+print '<td align="right">'.$langs->trans("Unique").'</td>';
 print '<td width="80">&nbsp;</td>';
 print "</tr>\n";
 
@@ -95,11 +96,12 @@ $var=True;
 foreach($extrafields->attribute_type as $key => $value)
 {
     $var=!$var;
-    print "<tr $bc[$var]>";
+    print "<tr ".$bc[$var].">";
     print "<td>".$extrafields->attribute_label[$key]."</td>\n";
     print "<td>".$key."</td>\n";
     print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n";
     print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n";
+    print '<td align="right">'.yn($extrafields->attribute_unique[$key])."</td>\n";
     print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>';
     print "&nbsp; <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=$key\">".img_delete()."</a></td>\n";
     print "</tr>";
@@ -110,10 +112,8 @@ print "</table>";
 
 dol_fiche_end();
 
-/*
- * Barre d'actions
- *
- */
+
+// Buttons
 if ($action != 'create' && $action != 'edit')
 {
     print '<div class="tabsAction">';
@@ -133,31 +133,7 @@ if ($action == 'create')
     print "<br>";
     print_titre($langs->trans('NewAttribute'));
 
-    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields.tpl.php';
-
-    print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
-    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-    print '<table summary="listofattributes" class="border" width="100%">';
-
-    print '<input type="hidden" name="action" value="add">';
-
-    // Label
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.GETPOST('label').'"></td></tr>';
-    // Code
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("AttributeCode").' ('.$langs->trans("AlphaNumOnlyCharsAndNoSpace").')</td><td class="valeur"><input type="text" name="attrname" size="10" value="'.GETPOST('attrname').'"></td></tr>';
-    // Type
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td><td class="valeur">';
-    print $form->selectarray('type',$type2label,GETPOST('type'));
-    print '</td></tr>';
-    // Size
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td><input id="size" type="text" name="size" size="5" value="'.(GETPOST('size')?GETPOST('size'):'').'"></td></tr>';
-
-    print "</table>\n";
-
-    print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-    print "</form>\n";
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php';
 }
 
 /* ************************************************************************** */
diff --git a/htdocs/societe/admin/societe_extrafields.php b/htdocs/societe/admin/societe_extrafields.php
index 1b053ea4b50..8d964f7d264 100755
--- a/htdocs/societe/admin/societe_extrafields.php
+++ b/htdocs/societe/admin/societe_extrafields.php
@@ -88,6 +88,7 @@ print '<td>'.$langs->trans("Label").'</td>';
 print '<td>'.$langs->trans("AttributeCode").'</td>';
 print '<td>'.$langs->trans("Type").'</td>';
 print '<td align="right">'.$langs->trans("Size").'</td>';
+print '<td align="right">'.$langs->trans("Unique").'</td>';
 print '<td width="80">&nbsp;</td>';
 print "</tr>\n";
 
@@ -95,11 +96,12 @@ $var=True;
 foreach($extrafields->attribute_type as $key => $value)
 {
     $var=!$var;
-    print "<tr $bc[$var]>";
+    print "<tr ".$bc[$var].">";
     print "<td>".$extrafields->attribute_label[$key]."</td>\n";
     print "<td>".$key."</td>\n";
     print "<td>".$type2label[$extrafields->attribute_type[$key]]."</td>\n";
     print '<td align="right">'.$extrafields->attribute_size[$key]."</td>\n";
+    print '<td align="right">'.yn($extrafields->attribute_unique[$key])."</td>\n";
     print '<td align="right"><a href="'.$_SERVER["PHP_SELF"].'?action=edit&attrname='.$key.'">'.img_edit().'</a>';
     print "&nbsp; <a href=\"".$_SERVER["PHP_SELF"]."?action=delete&attrname=$key\">".img_delete()."</a></td>\n";
     print "</tr>";
@@ -110,10 +112,8 @@ print "</table>";
 
 dol_fiche_end();
 
-/*
- * Barre d'actions
- *
- */
+
+// Buttons
 if ($action != 'create' && $action != 'edit')
 {
     print '<div class="tabsAction">';
@@ -133,31 +133,7 @@ if ($action == 'create')
     print "<br>";
     print_titre($langs->trans('NewAttribute'));
 
-    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields.tpl.php';
-
-    print '<form action="'.$_SERVER["PHP_SELF"].'" method="post">';
-    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-    print '<table summary="listofattributes" class="border" width="100%">';
-
-    print '<input type="hidden" name="action" value="add">';
-
-    // Label
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.GETPOST('label').'"></td></tr>';
-    // Code
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("AttributeCode").' ('.$langs->trans("AlphaNumOnlyCharsAndNoSpace").')</td><td class="valeur"><input type="text" name="attrname" size="10" value="'.GETPOST('attrname').'"></td></tr>';
-    // Type
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td><td class="valeur">';
-    print $form->selectarray('type',$type2label,GETPOST('type'));
-    print '</td></tr>';
-    // Size
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td><input id="size" type="text" name="size" size="5" value="'.(GETPOST('size')?GETPOST('size'):'').'"></td></tr>';
-
-    print "</table>\n";
-
-    print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-    print "</form>\n";
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_add.tpl.php';
 }
 
 /* ************************************************************************** */
@@ -170,42 +146,7 @@ if ($action == 'edit' && ! empty($attrname))
     print "<br>";
     print_titre($langs->trans("FieldEdition", $attrname));
 
-    /*
-     * formulaire d'edition
-     */
-    print '<form method="post" action="'.$_SERVER["PHP_SELF"].'?attrname='.$attrname.'">';
-    print '<input type="hidden" name="token" value="'.$_SESSION['newtoken'].'">';
-    print '<input type="hidden" name="attrname" value="'.$attrname.'">';
-    print '<input type="hidden" name="action" value="update">';
-    print '<table summary="listofattributes" class="border" width="100%">';
-
-    // Label
-    print '<tr>';
-    print '<td class="fieldrequired" required>'.$langs->trans("Label").'</td><td class="valeur"><input type="text" name="label" size="40" value="'.$extrafields->attribute_label[$attrname].'"></td>';
-    print '</tr>';
-    // Code
-    print '<tr>';
-    print '<td class="fieldrequired" required>'.$langs->trans("AttributeCode").'</td>';
-    print '<td class="valeur">'.$attrname.'&nbsp;</td>';
-    print '</tr>';
-    // Type
-    $type=$extrafields->attribute_type[$attrname];
-    $size=$extrafields->attribute_size[$attrname];
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Type").'</td>';
-    print '<td class="valeur">';
-    print $type2label[$type];
-    print '<input type="hidden" name="type" value="'.$type.'">';
-    print '</td></tr>';
-    // Size
-    print '<tr><td class="fieldrequired" required>'.$langs->trans("Size").'</td><td class="valeur"><input type="text" name="size" size="5" value="'.$size.'"></td></tr>';
-
-    print '</table>';
-
-    print '<center><br><input type="submit" name="button" class="button" value="'.$langs->trans("Save").'"> &nbsp; ';
-    print '<input type="submit" name="button" class="button" value="'.$langs->trans("Cancel").'"></center>';
-
-    print "</form>";
-
+    require DOL_DOCUMENT_ROOT.'/core/tpl/admin_extrafields_edit.tpl.php';
 }
 
 llxFooter();
diff --git a/htdocs/theme/amarok/style.css.php b/htdocs/theme/amarok/style.css.php
index 86f84f2e5a9..a8ccc913f2a 100644
--- a/htdocs/theme/amarok/style.css.php
+++ b/htdocs/theme/amarok/style.css.php
@@ -92,6 +92,14 @@ input, textarea {
 	margin-bottom:6px;
 	}
 
+.valignmiddle {
+	vertical-align: middle;
+}
+.centpercent {
+	width: 100%;
+}
+
+
 /* boutons : */
 .button, .butAction {background: #999;border: solid 1px #666;}
 .butActionRefused {background: #ccc;}
@@ -144,7 +152,7 @@ td.formdocbutton {padding-top:6px;}
 		color-stop(0, rgba(0,0,0,.3))
 	);
 	}
-	
+
 <?php if (! empty($conf->global->MAIN_BUTTON_HIDE_UNAUTHORIZED)) { ?>
 .butActionRefused {
 	display: none;
diff --git a/htdocs/theme/auguria/style.css.php b/htdocs/theme/auguria/style.css.php
index 8ac5fde2fe4..8f232b4219a 100644
--- a/htdocs/theme/auguria/style.css.php
+++ b/htdocs/theme/auguria/style.css.php
@@ -161,6 +161,13 @@ div.float
 {
     float:<?php print $left; ?>;
 }
+.valignmiddle {
+	vertical-align: middle;
+}
+.centpercent {
+	width: 100%;
+}
+
 
 /* ============================================================================== */
 /* Styles to hide objects                                                         */
diff --git a/htdocs/theme/bureau2crea/style.css.php b/htdocs/theme/bureau2crea/style.css.php
index 26f8993c354..bad4dd11af1 100644
--- a/htdocs/theme/bureau2crea/style.css.php
+++ b/htdocs/theme/bureau2crea/style.css.php
@@ -183,6 +183,13 @@ form {
     padding: 0em 0em 0em 0em;
     margin: 0em 0em 0em 0em;
 }
+.valignmiddle {
+	vertical-align: middle;
+}
+.centpercent {
+	width: 100%;
+}
+
 
 /* ============================================================================== */
 /* Styles to hide objects                                                         */
diff --git a/htdocs/theme/cameleo/style.css.php b/htdocs/theme/cameleo/style.css.php
index 54880874716..085e5227251 100644
--- a/htdocs/theme/cameleo/style.css.php
+++ b/htdocs/theme/cameleo/style.css.php
@@ -166,6 +166,13 @@ div.float
 {
     float:<?php print $left; ?>;
 }
+.valignmiddle {
+	vertical-align: middle;
+}
+.centpercent {
+	width: 100%;
+}
+
 
 /* ============================================================================== */
 /* Styles to hide objects                                                         */
diff --git a/htdocs/theme/eldy/style.css.php b/htdocs/theme/eldy/style.css.php
index cc91d44c1e9..84c50773057 100644
--- a/htdocs/theme/eldy/style.css.php
+++ b/htdocs/theme/eldy/style.css.php
@@ -303,6 +303,10 @@ th .button {
 .valignmiddle {
 	vertical-align: middle;
 }
+.centpercent {
+	width: 100%;
+}
+
 
 /* ============================================================================== */
 /* Styles to hide objects                                                         */
-- 
GitLab