From cb5665acd0c8fbf6449bd8921d25bf1e445f6bbb Mon Sep 17 00:00:00 2001 From: ralf Date: Sat, 30 Mar 2024 11:18:28 +0200 Subject: [PATCH] * All apps: new custom-field type serial allowing to generate incremented serial number with a given format e.g. "RE2024-0001" WIP allow to place custom-fields in tabs: --- admin/inc/class.admin_customfields.inc.php | 18 +++++++++++++----- admin/lang/egw_de.lang | 1 + admin/lang/egw_en.lang | 1 + api/js/etemplate/et2_extension_customfields.ts | 3 +-- api/src/Storage/Customfields.php | 16 +++++++++++----- 5 files changed, 27 insertions(+), 12 deletions(-) diff --git a/admin/inc/class.admin_customfields.inc.php b/admin/inc/class.admin_customfields.inc.php index 150bc3a8d8..6ea35cae32 100644 --- a/admin/inc/class.admin_customfields.inc.php +++ b/admin/inc/class.admin_customfields.inc.php @@ -15,9 +15,7 @@ use EGroupware\Api\Framework; use EGroupware\Api\Etemplate; /** - * Customfields class - manages customfield definitions in egw_config table - * - * The repository name (config_name) is 'customfields'. + * Customfields class - manages custom-field definitions in egw_customfields table through Api\Storage\Customfields class. * * Applications can have customfields by sub-type by having a template * named '.admin.types'. See admin.customfields.types as an @@ -381,7 +379,16 @@ class admin_customfields if (!empty($content['cf_values'])) { $values = array(); - if($content['cf_values'][0] === '@') + if ($content['cf_type'] === 'serial') + { + if (!preg_match(Api\Storage\Customfields::SERIAL_PREG, $content['cf_values'])) + { + Api\Etemplate::set_validation_error('cf_values', lang('Invalid Format, must end in a group of digits e.g. %1 or %2', "'0000'", "'RE2024-0000'")); + break; + } + $values = $content['cf_values']; + } + elseif($content['cf_values'][0] === '@') { $values['@'] = substr($content['cf_values'], $content['cf_values'][1] === '=' ? 2:1); } @@ -500,6 +507,7 @@ class admin_customfields else { $readonlys['button[delete]'] = true; + $content['cf_order'] = 10*(1+count($this->fields)); } if (is_array($content['cf_values'])) { @@ -751,7 +759,7 @@ class admin_customfields foreach($rows as &$row) { - $row['cf_values'] = json_decode($row['cf_values'], true); + $row['cf_values'] = json_decode($row['cf_values'], true) ?? $row['cf_values']; if (is_array($row['cf_values'])) { $values = ''; diff --git a/admin/lang/egw_de.lang b/admin/lang/egw_de.lang index 0fdc4d2b0b..5249f51173 100644 --- a/admin/lang/egw_de.lang +++ b/admin/lang/egw_de.lang @@ -571,6 +571,7 @@ interface admin de Schnittstelle international use admin de Internationale Benutzung invalid argument '%1' !!! admin de Ungültiges Argument "%1"! invalid email admin de Ungültige E-Mail-Adresse +invalid format, must end in a group of digits e.g. %1 or %2 admin de Ungültiges Format, muss in einer Gruppe von Zahlen enden z.B. %1 oder %2 invalid formated date "%1"! admin de Ungültig formatiertes Datum "%1"! invalid remote id or name "%1"! admin de Ungültige Remote-ID oder Name "%1"! invalid type "%1"! admin de Ungültiger Typ "%1"! diff --git a/admin/lang/egw_en.lang b/admin/lang/egw_en.lang index 1d8249194d..c76098e70c 100644 --- a/admin/lang/egw_en.lang +++ b/admin/lang/egw_en.lang @@ -571,6 +571,7 @@ interface admin en Interface international use admin en International use invalid argument '%1' !!! admin en Invalid argument '%1'! invalid email admin en Invalid email +invalid format, must end in a group of digits e.g. %1 or %2 admin en Invalid Format, must end in a group of digits e.g. %1 or %2 invalid formated date "%1"! admin en Invalid formated date "%1"! invalid remote id or name "%1"! admin en Invalid remote ID or name "%1"! invalid type "%1"! admin en Invalid type "%1"! diff --git a/api/js/etemplate/et2_extension_customfields.ts b/api/js/etemplate/et2_extension_customfields.ts index f8d2fc8478..d6389a5696 100644 --- a/api/js/etemplate/et2_extension_customfields.ts +++ b/api/js/etemplate/et2_extension_customfields.ts @@ -690,8 +690,7 @@ export class et2_customfields_list extends et2_valueWidget implements et2_IDetac _setup_serial(field_name, field, attrs) { delete (attrs.label); - field.type = "number" - attrs.precision = 0; + field.type = "textbox" attrs.readonly = true; return true; } diff --git a/api/src/Storage/Customfields.php b/api/src/Storage/Customfields.php index 0ac8be06b8..8e04aab6c4 100644 --- a/api/src/Storage/Customfields.php +++ b/api/src/Storage/Customfields.php @@ -407,7 +407,7 @@ class Customfields implements \IteratorAggregate $cfs[$cf['name']] = $cf; } - if($old['order'] != $cf['order'] || $cf['order'] % 10 !== 0) + if($old['order'] != $cf['order'] || (int)$cf['order'] % 10 !== 0) { $cfs[$cf['name']]['order'] = $cf['order']; uasort($cfs, function($a1, $a2){ @@ -650,13 +650,18 @@ class Customfields implements \IteratorAggregate } } + /** + * Regular expression for serial value/format allowing e.g. "RE2024-0000" for using a prefix of "RE2024-" and a 4-digit number + */ + const SERIAL_PREG = '/\d+$/'; + /** * Generate a new serial-number from the database * * @param int $id cf_id for custom-field - * @return int the new serial number + * @return string the new (formatted) serial number */ - public static function getSerial(int $id) : int + public static function getSerial(int $id) : string { self::$db->transaction_begin(); foreach(self::$db->select(self::TABLE, 'cf_values', $where=[ @@ -664,13 +669,14 @@ class Customfields implements \IteratorAggregate 'cf_type' => 'serial', ], __LINE__, __FILE__, false, 'FOR UPDATE') as $row) { - if (empty($row['cf_values']) || !is_numeric($row['cf_values'])) + // we increment the last digit-group + if (empty($row['cf_values']) || !preg_match(self::SERIAL_PREG, $row['cf_values'], $matches)) { $row['cf_values'] = 1; } else { - $row['cf_values'] += 1; + $row['cf_values'] = preg_replace(self::SERIAL_PREG, sprintf('%0'.strlen($matches[0]).'d', 1+(int)$matches[0]), $row['cf_values']); } break; }