From 1a4226ff643d81bf3dfbbf68e8a3f3ac76e8e37d Mon Sep 17 00:00:00 2001 From: Maxime Kohlhaas Date: Mon, 4 Aug 2025 16:48:11 +0200 Subject: [PATCH] NEW : add extrafield option "empty on clone" (#34866) * NEW : add extrafield option "empty on clone" * NEW : empty extrafield value on clone * Fix : missing parameter in function call --------- Co-authored-by: Laurent Destailleur --- htdocs/core/actions_extrafields.inc.php | 6 ++- htdocs/core/class/commonobject.class.php | 7 ++- htdocs/core/class/extrafields.class.php | 50 ++++++++++++------- htdocs/core/tpl/admin_extrafields_add.tpl.php | 15 +++--- .../core/tpl/admin_extrafields_edit.tpl.php | 17 ++++--- .../core/tpl/admin_extrafields_view.tpl.php | 3 ++ .../install/mysql/migration/22.0.0-23.0.0.sql | 6 ++- .../install/mysql/tables/llx_extrafields.sql | 1 + htdocs/langs/en_US/admin.lang | 2 + 9 files changed, 74 insertions(+), 33 deletions(-) diff --git a/htdocs/core/actions_extrafields.inc.php b/htdocs/core/actions_extrafields.inc.php index 2b16bd9faa0..5cbb0e3567c 100644 --- a/htdocs/core/actions_extrafields.inc.php +++ b/htdocs/core/actions_extrafields.inc.php @@ -239,7 +239,8 @@ if ($action == 'add') { (GETPOST('totalizable', 'alpha') ? 1 : 0), GETPOSTINT('printable'), array('css' => $css, 'cssview' => $cssview, 'csslist' => $csslist), - GETPOST("ai_prompt") + GETPOST("ai_prompt"), + (GETPOST('emptyonclone', 'alpha') ? 1 : 0) ); if ($result > 0) { setEventMessages($langs->trans('SetupSaved'), null, 'mesgs'); @@ -424,7 +425,8 @@ if ($action == 'update') { (GETPOST('totalizable', 'alpha') ? 1 : 0), GETPOSTINT('printable'), array('css' => $css, 'cssview' => $cssview, 'csslist' => $csslist), - GETPOST("ai_prompt") + GETPOST("ai_prompt"), + (GETPOST('emptyonclone', 'alpha') ? 1 : 0) ); if ($result > 0) { setEventMessages($langs->trans('SetupSaved'), null, 'mesgs'); diff --git a/htdocs/core/class/commonobject.class.php b/htdocs/core/class/commonobject.class.php index c140e26fc42..ea2e2e0b18d 100644 --- a/htdocs/core/class/commonobject.class.php +++ b/htdocs/core/class/commonobject.class.php @@ -6723,17 +6723,21 @@ abstract class CommonObject $attributeRequired = $extrafields->attributes[$this->table_element]['required'][$attributeKey]; $attributeUnique = $extrafields->attributes[$this->table_element]['unique'][$attributeKey]; $attrfieldcomputed = $extrafields->attributes[$this->table_element]['computed'][$attributeKey]; + $attributeEmptyOnClone = $extrafields->attributes[$this->table_element]['emptyonclone'][$attributeKey]; // If we clone, we have to clean unique extrafields to prevent duplicates. + // If we clone, we have to clean extrafields having "empty on clone" option on. // This behaviour can be prevented by external code by changing $this->context['createfromclone'] value in createFrom hook - if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && !empty($attributeUnique)) { + if (!empty($this->context['createfromclone']) && $this->context['createfromclone'] == 'createfromclone' && (!empty($attributeUnique) || !empty($attributeEmptyOnClone))) { $new_array_options[$key] = null; + continue; } // If we create product combination, we have to clean unique extrafields to prevent duplicates. // This behaviour can be prevented by external code by changing $this->context['createproductcombination'] value in hook if (!empty($this->context['createproductcombination']) && $this->context['createproductcombination'] == 'createproductcombination' && !empty($attributeUnique)) { $new_array_options[$key] = null; + continue; } // Similar code than into insertExtraFields @@ -6755,6 +6759,7 @@ abstract class CommonObject } else { $new_array_options[$key] = null; } + continue; } switch ($attributeType) { diff --git a/htdocs/core/class/extrafields.class.php b/htdocs/core/class/extrafields.class.php index 2b818e09c38..840b8833874 100644 --- a/htdocs/core/class/extrafields.class.php +++ b/htdocs/core/class/extrafields.class.php @@ -47,7 +47,7 @@ class ExtraFields public $db; /** - * @var array,type:array,size:array,default:array,computed:array,unique:array,required:array,param:array,perms:array,list:array,pos:array,totalizable:array,help:array,printable:array,enabled:array,langfile:array,css:array,csslist:array,cssview:array,hidden:array,mandatoryfieldsofotherentities:array,alwayseditable:array>,loaded?:int,count:int,aiprompt:array}> New array to store extrafields definition Note: count set as present to avoid static analysis notices + * @var array,type:array,size:array,default:array,computed:array,unique:array,required:array,param:array,perms:array,list:array,pos:array,totalizable:array,help:array,printable:array,enabled:array,langfile:array,css:array,csslist:array,cssview:array,hidden:array,mandatoryfieldsofotherentities:array,alwayseditable:array>,emptyonclone:array>,loaded?:int,count:int,aiprompt:array}> New array to store extrafields definition Note: count set as present to avoid static analysis notices */ public $attributes = array(); @@ -162,9 +162,10 @@ class ExtraFields * @param int<0,1> $printable Is extrafield displayed on PDF * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>Css on list, 'cssview'=>...) * @param string $aiprompt Ai prompt value + * @param int<0,1> $emptyonclone Is attribute to be emptied after object clone * @return int Return integer <=0 if KO, >0 if OK */ - public function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "") + public function addExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "", $emptyonclone = 0) { if (empty($attrname)) { return -1; @@ -200,7 +201,7 @@ class ExtraFields $err1 = $this->errno; if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') { // Add declaration of field into table - $result2 = $this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, $aiprompt); + $result2 = $this->create_label($attrname, $label, $type, $pos, $size, $elementtype, $unique, $required, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, $aiprompt, $emptyonclone); $err2 = $this->errno; if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS') @@ -240,9 +241,10 @@ class ExtraFields * @param int<0,1> $totalizable Is a measure. Must show a total on lists * @param int<0,1> $printable Is extrafield displayed on PDF * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>Css on list, 'cssview'=>...) + * @param int<0,1> $emptyonclone Is attribute to be emptied after object clone * @return int Return integer <=0 if KO, >0 if OK */ - public function updateExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array()) + public function updateExtraField($attrname, $label, $type, $pos, $size, $elementtype, $unique = 0, $required = 0, $default_value = '', $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $emptyonclone = 0) { if (empty($attrname)) { return -1; @@ -268,13 +270,13 @@ class ExtraFields // Create field into database except for separator type which is not stored in database if ($type != 'separate') { dol_syslog(get_class($this).'::thisupdate', LOG_DEBUG); - $result = $this->update($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams); + $result = $this->update($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, '', $emptyonclone); } $err1 = $this->errno; if ($result > 0 || $err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' || $type == 'separate') { // Add declaration of field into table dol_syslog(get_class($this).'::thislabel', LOG_DEBUG); - $result2 = $this->update_label($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams); + $result2 = $this->update_label($attrname, $label, $type, $size, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default_value, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, '', $emptyonclone); $err2 = $this->errno; if ($result2 > 0 || ($err1 == 'DB_ERROR_COLUMN_ALREADY_EXISTS' && $err2 == 'DB_ERROR_RECORD_ALREADY_EXISTS')) { $this->error = ''; @@ -427,10 +429,11 @@ class ExtraFields * @param int<0,1> $printable Is extrafield displayed on PDF * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>, 'cssview'=>...) * @param string $aiprompt Ai prompt value + * @param int<0,1> $emptyonclone Is attribute to be emptied after object clone * @return int Return integer <=0 if KO, >0 if OK * @throws Exception */ - private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = '', $elementtype = '', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "") + private function create_label($attrname, $label = '', $type = '', $pos = 0, $size = '', $elementtype = '', $unique = 0, $required = 0, $param = '', $alwayseditable = 0, $perms = '', $list = '-1', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "", $emptyonclone = 0) { // phpcs:enable global $conf, $user; @@ -461,6 +464,9 @@ class ExtraFields if (empty($alwayseditable)) { $alwayseditable = 0; } + if (empty($emptyonclone)) { + $emptyonclone = 0; + } if (empty($totalizable)) { $totalizable = 0; } @@ -514,7 +520,8 @@ class ExtraFields $sql .= " css,"; $sql .= " csslist,"; $sql .= " cssview,"; - $sql .= " aiprompt"; + $sql .= " aiprompt,"; + $sql .= " emptyonclone"; $sql .= " )"; $sql .= " VALUES('".$this->db->escape($attrname)."',"; $sql .= " '".$this->db->escape($label)."',"; @@ -542,7 +549,8 @@ class ExtraFields $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").","; $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").","; $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null").","; - $sql .= " '".$this->db->escape($aiprompt)."'"; + $sql .= " '".$this->db->escape($aiprompt)."',"; + $sql .= " ".((int) $emptyonclone); $sql .= ')'; if ($this->db->query($sql)) { @@ -688,10 +696,11 @@ class ExtraFields * @param int<0,1> $printable Is extrafield displayed on PDF * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>, 'cssview'=>...) * @param string $aiprompt Ai prompt value + * @param int<0,1> $emptyonclone Is attribute to be emptied after object clone * @return int >0 if OK, <=0 if KO * @throws Exception */ - public function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "") + public function update($attrname, $label, $type, $length, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "", $emptyonclone = 0) { global $action, $hookmanager; @@ -773,7 +782,7 @@ class ExtraFields if (is_object($hookmanager)) { $hookmanager->initHooks(array('extrafieldsdao')); - $parameters = array('field_desc' => &$field_desc, 'table' => $table, 'attr_name' => $attrname, 'label' => $label, 'type' => $type, 'length' => $length, 'unique' => $unique, 'required' => $required, 'pos' => $pos, 'param' => $param, 'alwayseditable' => $alwayseditable, 'perms' => $perms, 'list' => $list, 'help' => $help, 'default' => $default, 'computed' => $computed, 'entity' => $entity, 'langfile' => $langfile, 'enabled' => $enabled, 'totalizable' => $totalizable, 'printable' => $printable); + $parameters = array('field_desc' => &$field_desc, 'table' => $table, 'attr_name' => $attrname, 'label' => $label, 'type' => $type, 'length' => $length, 'unique' => $unique, 'required' => $required, 'pos' => $pos, 'param' => $param, 'alwayseditable' => $alwayseditable, 'emptyonclone' => $emptyonclone, 'perms' => $perms, 'list' => $list, 'help' => $help, 'default' => $default, 'computed' => $computed, 'entity' => $entity, 'langfile' => $langfile, 'enabled' => $enabled, 'totalizable' => $totalizable, 'printable' => $printable); $reshook = $hookmanager->executeHooks('updateExtrafields', $parameters, $this, $action); // Note that $action and $object may have been modified by some hooks if ($reshook < 0) { @@ -790,7 +799,7 @@ class ExtraFields if ($result > 0 || $type == 'separate') { if ($label) { dol_syslog(get_class($this).'::update_label', LOG_DEBUG); - $result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, $aiprompt); + $result = $this->update_label($attrname, $label, $type, $length, $elementtype, $unique, $required, $pos, $param, $alwayseditable, $perms, $list, $help, $default, $computed, $entity, $langfile, $enabled, $totalizable, $printable, $moreparams, $aiprompt, $emptyonclone); } if ($result > 0) { $sql = ''; @@ -848,10 +857,11 @@ class ExtraFields * @param int<0,1> $printable Is extrafield displayed on PDF * @param array $moreparams More parameters. Example: array('css'=>, 'csslist'=>, 'cssview'=>...) * @param string $aiprompt Ai prompt value + * @param int<0,1> $emptyonclone Is attribute to be emptied after object clone * @return int Return integer <=0 if KO, >0 if OK * @throws Exception */ - private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "") + private function update_label($attrname, $label, $type, $size, $elementtype, $unique = 0, $required = 0, $pos = 0, $param = array(), $alwayseditable = 0, $perms = '', $list = '0', $help = '', $default = '', $computed = '', $entity = '', $langfile = '', $enabled = '1', $totalizable = 0, $printable = 0, $moreparams = array(), $aiprompt = "", $emptyonclone = 0) { // phpcs:enable global $conf, $user; @@ -883,6 +893,9 @@ class ExtraFields if (empty($alwayseditable)) { $alwayseditable = 0; } + if (empty($emptyonclone)) { + $emptyonclone = 0; + } $css = ''; if (!empty($moreparams) && !empty($moreparams['css'])) { @@ -952,7 +965,8 @@ class ExtraFields $sql .= " css,"; $sql .= " csslist,"; $sql .= " cssview,"; - $sql .= " aiprompt"; + $sql .= " aiprompt,"; + $sql .= " emptyonclone"; $sql .= ") VALUES ("; $sql .= "'".$this->db->escape($attrname)."',"; $sql .= " ".($entity === '' ? $conf->entity : $entity).","; @@ -965,7 +979,7 @@ class ExtraFields $sql .= " ".($perms ? "'".$this->db->escape($perms)."'" : "null").","; $sql .= " ".($langfile ? "'".$this->db->escape($langfile)."'" : "null").","; $sql .= " ".((int) $pos).","; - $sql .= " '".$this->db->escape((string) $alwayseditable)."',"; + $sql .= " ".((int) $alwayseditable).","; $sql .= " '".$this->db->escape($params)."',"; $sql .= " '".$this->db->escape($list)."',"; $sql .= " ".((int) $printable).","; @@ -980,7 +994,8 @@ class ExtraFields $sql .= " ".($css ? "'".$this->db->escape($css)."'" : "null").","; $sql .= " ".($csslist ? "'".$this->db->escape($csslist)."'" : "null").","; $sql .= " ".($cssview ? "'".$this->db->escape($cssview)."'" : "null").","; - $sql .= " '".$this->db->escape($aiprompt)."'"; + $sql .= " '".$this->db->escape($aiprompt)."',"; + $sql .= " ".((int) $emptyonclone); $sql .= ")"; $resql2 = $this->db->query($sql); @@ -1034,7 +1049,7 @@ class ExtraFields $array_name_label = array(); // We should not have several time this request. If we have, there is some optimization to do by calling a simple $extrafields->fetch_optionals() in top of code and not into subcode - $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, aiprompt,"; + $sql = "SELECT rowid, name, label, type, size, elementtype, fieldunique, fieldrequired, param, pos, alwayseditable, emptyonclone, perms, langs, list, printable, totalizable, fielddefault, fieldcomputed, entity, enabled, help, aiprompt,"; $sql .= " css, cssview, csslist"; $sql .= " FROM ".$this->db->prefix()."extrafields"; //$sql.= " WHERE entity IN (0,".$conf->entity.")"; // Filter is done later @@ -1076,6 +1091,7 @@ class ExtraFields $this->attributes[$tab->elementtype]['param'][$tab->name] = ($tab->param ? jsonOrUnserialize($tab->param) : ''); $this->attributes[$tab->elementtype]['pos'][$tab->name] = $tab->pos; $this->attributes[$tab->elementtype]['alwayseditable'][$tab->name] = $tab->alwayseditable; + $this->attributes[$tab->elementtype]['emptyonclone'][$tab->name] = $tab->emptyonclone; $this->attributes[$tab->elementtype]['perms'][$tab->name] = $tab->perms; $this->attributes[$tab->elementtype]['langfile'][$tab->name] = $tab->langs; $this->attributes[$tab->elementtype]['list'][$tab->name] = $tab->list; diff --git a/htdocs/core/tpl/admin_extrafields_add.tpl.php b/htdocs/core/tpl/admin_extrafields_add.tpl.php index 97eb229fd60..f36f3bae76e 100644 --- a/htdocs/core/tpl/admin_extrafields_add.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_add.tpl.php @@ -65,6 +65,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con var unique = jQuery("#unique"); var required = jQuery("#required"); var alwayseditable = jQuery("#alwayseditable"); + var emptyonclone = jQuery("#emptyonclone"); var list = jQuery("#list"); var totalizable = jQuery("#totalizable"); Contact:con console.log("We enter a computed formula"); jQuery("#default_value").val(''); /* jQuery("#unique, #required, #alwayseditable, #list").removeAttr('checked'); */ - jQuery("#default_value, #unique, #required, #alwayseditable, #list").attr('disabled', true); - jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_list").hide(); + jQuery("#default_value, #unique, #required, #alwayseditable, #emptyonclone, #list").attr('disabled', true); + jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_emptyonclone, tr.extra_list").hide(); } else { console.log("No computed formula"); - jQuery("#default_value, #unique, #required, #alwayseditable, #list").attr('disabled', false); - jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_list").show(); + jQuery("#default_value, #unique, #required, #alwayseditable, #emptyonclone, #list").attr('disabled', false); + jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_emptyonclone, tr.extra_list").show(); } // Case of ai prompt @@ -139,14 +140,14 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con if (type == 'separate' || type == 'point' || type == 'linestrg' || type == 'polygon') { - required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true); + required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); emptyonclone.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true); jQuery('#size, #default_value, #langfile').val('').prop('disabled', true); jQuery('#list').val(3); // visible on create/update/view form only } else { default_value.removeAttr('disabled'); - langfile.removeAttr('disabled');required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); list.removeAttr('disabled'); + langfile.removeAttr('disabled');required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); emptyonclone.removeAttr('disabled'); list.removeAttr('disabled'); } } init_typeoffields(''); @@ -262,6 +263,8 @@ print $formadmin->selectTypeOfFields('type', GETPOST('type', 'alpha')); trans("Mandatory"); ?>> textwithpicto($langs->trans("AlwaysEditable"), $langs->trans("EditableWhenDraftOnly")); ?>> + +textwithpicto($langs->trans("EmptyOnClone"), $langs->trans("EmptyOnCloneDesc")); ?>> textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'

'.$langs->trans("ItCanBeAnExpression")); ?> diff --git a/htdocs/core/tpl/admin_extrafields_edit.tpl.php b/htdocs/core/tpl/admin_extrafields_edit.tpl.php index 88049c436a7..8ff2ad2a580 100644 --- a/htdocs/core/tpl/admin_extrafields_edit.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_edit.tpl.php @@ -65,6 +65,7 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con var unique = jQuery("#unique"); var required = jQuery("#required"); var alwayseditable = jQuery("#alwayseditable"); + var emptyonclone = jQuery("#emptyonclone"); var list = jQuery("#list"); var totalizable = jQuery("#totalizable"); Contact:con console.log("We enter a computed formula"); jQuery("#default_value").val(''); /* jQuery("#unique, #required, #alwayseditable, #list").removeAttr('checked'); */ - jQuery("#default_value, #unique, #required, #alwayseditable, #list").attr('disabled', true); - jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_list").hide(); + jQuery("#default_value, #unique, #required, #alwayseditable, #emptyonclone, #list").attr('disabled', true); + jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_emptyonclone, tr.extra_list").hide(); } else { console.log("No computed formula"); - jQuery("#default_value, #unique, #required, #alwayseditable, #list").attr('disabled', false); - jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_list").show(); + jQuery("#default_value, #unique, #required, #alwayseditable, #emptyonclone, #list").attr('disabled', false); + jQuery("tr.extra_default_value, tr.extra_unique, tr.extra_required, tr.extra_alwayseditable, tr.extra_emptyonclone, tr.extra_list").show(); } // Case of ai prompt @@ -136,14 +137,14 @@ $listofexamplesforlink = 'Societe:societe/class/societe.class.php
Contact:con if (type == 'separate' || type == 'point' || type == 'linestrg' || type == 'polygon') { - required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true); + required.removeAttr('checked').prop('disabled', true); alwayseditable.removeAttr('checked').prop('disabled', true); emptyonclone.removeAttr('checked').prop('disabled', true); list.removeAttr('checked').prop('disabled', true); jQuery('#size, #default_value, #langfile').val('').prop('disabled', true); jQuery('#list').val(3); // visible on create/update/view form only } else { default_value.removeAttr('disabled'); - required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); list.removeAttr('disabled'); + required.removeAttr('disabled'); alwayseditable.removeAttr('disabled'); emptyonclone.removeAttr('disabled'); list.removeAttr('disabled'); } } init_typeoffields(jQuery("#type").val()); @@ -181,6 +182,7 @@ $unique = $extrafields->attributes[$elementtype]['unique'][$attrname]; $required = $extrafields->attributes[$elementtype]['required'][$attrname]; $pos = $extrafields->attributes[$elementtype]['pos'][$attrname]; $alwayseditable = $extrafields->attributes[$elementtype]['alwayseditable'][$attrname]; +$emptyonclone = $extrafields->attributes[$elementtype]['emptyonclone'][$attrname]; $param = $extrafields->attributes[$elementtype]['param'][$attrname]; $perms = $extrafields->attributes[$elementtype]['perms'][$attrname]; $langfile = $extrafields->attributes[$elementtype]['langfile'][$attrname]; @@ -333,6 +335,9 @@ if (in_array($type, array_keys($typewecanchangeinto))) { textwithpicto($langs->trans("AlwaysEditable"), $langs->trans("EditableWhenDraftOnly")); ?>> + +textwithpicto($langs->trans("EmptyOnClone"), $langs->trans("EmptyOnCloneDesc")); ?>> + textwithpicto($langs->trans("PermissionOnField"), $langs->trans("PermissionToEditField")); ?> diff --git a/htdocs/core/tpl/admin_extrafields_view.tpl.php b/htdocs/core/tpl/admin_extrafields_view.tpl.php index 7ad305e9365..99f969927b6 100644 --- a/htdocs/core/tpl/admin_extrafields_view.tpl.php +++ b/htdocs/core/tpl/admin_extrafields_view.tpl.php @@ -94,6 +94,7 @@ print ''.$langs->trans("ComputedFormula").''; print ''.$langs->trans("Unique").''; print ''.$langs->trans("Mandatory").''; print ''.$form->textwithpicto($langs->trans("AlwaysEditable"), $langs->trans("EditableWhenDraftOnly")).''; +print ''.$form->textwithpicto($langs->trans("EmptyOnClone"), $langs->trans("EmptyOnCloneDesc")).''; print ''.$form->textwithpicto($langs->trans("Visibility"), $langs->trans("VisibleDesc").'

'.$langs->trans("ItCanBeAnExpression")).''; print ''.$form->textwithpicto($langs->trans("DisplayOnPdf"), $langs->trans("DisplayOnPdfDesc")).''; print ''.$form->textwithpicto($langs->trans("Totalizable"), $langs->trans("TotalizableDesc")).''; @@ -163,6 +164,8 @@ if (isset($extrafields->attributes[$elementtype]['type']) && is_array($extrafiel print ''.yn($extrafields->attributes[$elementtype]['required'][$key])."\n"; // Can always be editable ? print ''.yn($extrafields->attributes[$elementtype]['alwayseditable'][$key])."\n"; + // Will be emptied on clone ? + print ''.yn($extrafields->attributes[$elementtype]['emptyonclone'][$key])."\n"; // Visible print ''.dol_escape_htmltag($extrafields->attributes[$elementtype]['list'][$key])."\n"; // Print on PDF diff --git a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql index ebfeb27c492..bb833ecfadd 100644 --- a/htdocs/install/mysql/migration/22.0.0-23.0.0.sql +++ b/htdocs/install/mysql/migration/22.0.0-23.0.0.sql @@ -54,6 +54,10 @@ ALTER TABLE llx_oauth_token ADD COLUMN apicount_previous_month BIGINT UNSIGNED D ALTER TABLE llx_oauth_token ADD COLUMN apicount_month BIGINT UNSIGNED DEFAULT 0; -- increased by 1 at each page access, saved into pageviews_previous_month when on different month than lastaccess ALTER TABLE llx_oauth_token ADD COLUMN apicount_total BIGINT UNSIGNED DEFAULT 0; -- increased by 1 at each page access, no reset + +ALTER TABLE llx_extrafields ADD COLUMN emptyonclone integer DEFAULT 0 AFTER alwayseditable; + + INSERT INTO llx_c_country (rowid, code, code_iso, label, active, favorite, numeric_code) VALUES (248, 'BQ', 'BES', 'Bonaire, Sint Eustatius and Saba', 1, 0, 535); INSERT INTO llx_c_country (rowid, code, code_iso, label, active, favorite, numeric_code) VALUES (249, 'GP', 'GLP', 'Guadeloupe', 0, 0, 312); INSERT INTO llx_c_country (rowid, code, code_iso, label, active, favorite, numeric_code) VALUES (250, 'GY', 'GUY', 'Guyana', 0, 0, 328); @@ -63,9 +67,9 @@ INSERT INTO llx_c_country (rowid, code, code_iso, label, active, favorite, numer UPDATE llx_c_country SET sepa = 1 WHERE code IN ('AD','AL','AT','AX','BE','BG','BL','CH','CY','CZ','DE','DK','EE','ES','FI','FR','GB','GF','GG','GI','GP','GR','HR','HU','IE','IM','IS','IT','JE','LI','LT','LU','LV','MC','MD','ME','MF','MK','MQ','MT','NL','NO','PL','PM','PT','RE','RO','RS','SE','SI','SK','SM','VA','YT'); + ALTER TABLE llx_adherent ADD COLUMN birth_place varchar(64) after birth; ALTER TABLE llx_societe ADD COLUMN birth date DEFAULT NULL after fk_forme_juridique; - -- end of migration diff --git a/htdocs/install/mysql/tables/llx_extrafields.sql b/htdocs/install/mysql/tables/llx_extrafields.sql index c9d928e6039..2b069ae802c 100644 --- a/htdocs/install/mysql/tables/llx_extrafields.sql +++ b/htdocs/install/mysql/tables/llx_extrafields.sql @@ -35,6 +35,7 @@ create table llx_extrafields module varchar(64), pos integer DEFAULT 0, alwayseditable integer DEFAULT 0, -- 1 if field can be edited whatever is element status + emptyonclone integer DEFAULT 0, -- 1 if field can be edited whatever is element status param text, -- extra parameters to define possible values of field list varchar(255) DEFAULT '1', -- visibility of field. 0=Never visible, 1=Visible on list and forms, 2=Visible on list only. Using a negative value means field is not shown by default on list but can be selected for viewing printable integer DEFAULT 0, -- is the extrafield output on documents diff --git a/htdocs/langs/en_US/admin.lang b/htdocs/langs/en_US/admin.lang index 062d405ad2b..29448257696 100644 --- a/htdocs/langs/en_US/admin.lang +++ b/htdocs/langs/en_US/admin.lang @@ -2010,6 +2010,8 @@ ShowFiscalYear=Show accounting period ##### Assets ##### AssetNumberingModules=Assets numbering module AlwaysEditable=Editable for any status +EmptyOnClone=Empty on clone +EmptyOnCloneDesc=Value will be emptied after cloning an object PermissionOnField=Permission on the field MAIN_APPLICATION_TITLE=Force visible name of application (warning: setting your own name here may break autofill login feature when using DoliDroid mobile application) NbMajMin=Minimum number of uppercase characters