diff --git a/all_in_one_dynamic_custom_fields/__manifest__.py b/all_in_one_dynamic_custom_fields/__manifest__.py index a5468779c..9fcf5d293 100755 --- a/all_in_one_dynamic_custom_fields/__manifest__.py +++ b/all_in_one_dynamic_custom_fields/__manifest__.py @@ -21,13 +21,13 @@ ################################################################################ { 'name': 'All in One Dynamic Fields', - 'version': '17.0.1.0.0', + 'version': '17.0.1.1.1', 'category': 'Extra Tools', 'summary': 'Create Custom Fields As Per Your Need Without Any Coding.', 'description': "The features of module facilitates the addition of fields" - "to any view within a model, allowing users to specify" - "attributes and properties at their preferred " - "location.", + "to any view within a model, allowing users to specify" + "attributes and properties at their preferred " + "location.", 'author': 'Cybrosys Techno Solutions', 'company': 'Cybrosys Techno Solutions', 'maintainer': 'Cybrosys Techno Solutions', diff --git a/all_in_one_dynamic_custom_fields/data/dynamic_field_widgets_data.xml b/all_in_one_dynamic_custom_fields/data/dynamic_field_widgets_data.xml index be0e7c4fe..fd2795e61 100755 --- a/all_in_one_dynamic_custom_fields/data/dynamic_field_widgets_data.xml +++ b/all_in_one_dynamic_custom_fields/data/dynamic_field_widgets_data.xml @@ -2,43 +2,43 @@ - + image binary Image - + many2many_tags many2many Many2many Tags - + binary many2many Binary - + radio selection Radio - + priority selection Priority - - + + monetary float Monetary - + selection many2one Selection diff --git a/all_in_one_dynamic_custom_fields/doc/RELEASE_NOTES.md b/all_in_one_dynamic_custom_fields/doc/RELEASE_NOTES.md index dfe0eed21..ffdd4ff0e 100755 --- a/all_in_one_dynamic_custom_fields/doc/RELEASE_NOTES.md +++ b/all_in_one_dynamic_custom_fields/doc/RELEASE_NOTES.md @@ -5,3 +5,8 @@ ##### ADD - Initial commit for All in One Custom Dynamic Fields + +#### 13.06.2024 +#### Version 17.0.1.1.1 +##### UPDATE +- The latest module update includes enhancements to the list view configuration. You can now add the newly created field to the selected list view at the desired position, with the option to enable or disable its visibility by default. diff --git a/all_in_one_dynamic_custom_fields/models/__init__.py b/all_in_one_dynamic_custom_fields/models/__init__.py index 70627ee22..bca849147 100755 --- a/all_in_one_dynamic_custom_fields/models/__init__.py +++ b/all_in_one_dynamic_custom_fields/models/__init__.py @@ -20,5 +20,5 @@ # ################################################################################ from . import dynamic_fields -from . import field_widgets +from . import dynamic_field_widgets from . import ir_model_fields diff --git a/all_in_one_dynamic_custom_fields/models/field_widgets.py b/all_in_one_dynamic_custom_fields/models/dynamic_field_widgets.py similarity index 97% rename from all_in_one_dynamic_custom_fields/models/field_widgets.py rename to all_in_one_dynamic_custom_fields/models/dynamic_field_widgets.py index 8bf409e49..706797428 100755 --- a/all_in_one_dynamic_custom_fields/models/field_widgets.py +++ b/all_in_one_dynamic_custom_fields/models/dynamic_field_widgets.py @@ -22,7 +22,7 @@ from odoo import fields, models -class FieldWidgets(models.Model): +class DynamicFieldWidgets(models.Model): """We can't filter a selection field dynamically so when we select a field its widgets also need to change according to the selected field type, we can't do it by a 'selection' field, diff --git a/all_in_one_dynamic_custom_fields/models/dynamic_fields.py b/all_in_one_dynamic_custom_fields/models/dynamic_fields.py index 06aca196d..69bf80731 100755 --- a/all_in_one_dynamic_custom_fields/models/dynamic_fields.py +++ b/all_in_one_dynamic_custom_fields/models/dynamic_fields.py @@ -19,6 +19,8 @@ # If not, see . # ################################################################################ +from xlrd.xlsx import ET + from odoo import api, fields, models, _ @@ -65,7 +67,7 @@ class DynamicFields(models.Model): required=True, help="Position of new field") model_id = fields.Many2one(comodel_name='ir.model', string='Model', required=True, - index=True, ondelete='cascade', + index=True, help="The model this field belongs to") ref_model_id = fields.Many2one(comodel_name='ir.model', string='Relational ' 'Model', @@ -76,16 +78,20 @@ class DynamicFields(models.Model): field_type = fields.Selection(selection='get_possible_field_types', string='Field Type', required=True, help="Data type of new field") + tree_field_ids = fields.Many2many('ir.model.fields', + 'tree_field_ids', + compute='_compute_tree_field_ids') ttype = fields.Selection(string="Field Type", related='field_type', help="Field type of field") - widget = fields.Many2one(comodel_name='dynamic.field.widgets', - string='Widget', help="Widgets for field", - domain=lambda self: "[('data_type', '=', " - "field_type)]") + widget_id = fields.Many2one(comodel_name='dynamic.field.widgets', + string='Widget', help="Widgets for field", + domain=lambda self: "[('data_type', '=', " + "field_type)]") groups = fields.Many2many('res.groups', - 'employee_dynamic_fields_group_rel', - 'field_id', 'group_id', - help="Groups of field") + 'dynamic_fields_group_rel', + 'dynamic_field_id', + 'dynamic_group_id', + help="Groups of field") extra_features = fields.Boolean(string="Show Extra Properties", help="Enable to add extra features") status = fields.Selection(selection=[('draft', 'Draft'), ('form', @@ -93,7 +99,7 @@ class DynamicFields(models.Model): string='Status', index=True, readonly=True, tracking=True, copy=False, default='draft', - required=True, help='State for record') + help='State for record') form_view_ids = fields.Many2many(comodel_name='ir.ui.view', string="Form View IDs", help="Stores form view ids") @@ -112,26 +118,78 @@ class DynamicFields(models.Model): help="Form view inherit id(adds" " by selecting form view id)") add_field_in_tree = fields.Boolean(string="Add Field to the Tree View", - default=False, help="Enable to add field in tree view") tree_view_id = fields.Many2one(comodel_name='ir.ui.view', string="Tree View ID", help="Tree view id of the model", domain=lambda self: "[('id', 'in', " "tree_view_ids)]") - tree_view_inherit_id = fields.Char(string="Tree View Inherit Id", + tree_view_inherit_id = fields.Char(string="External Id", related='tree_view_id.xml_id', help="Tree view inherit id(adds" " by selecting tree view id)") + tree_field_id = fields.Many2one('ir.model.fields', + string='Tree Field', + help='Position for new field', + domain="[('id', 'in', tree_field_ids)]") + tree_field_position = fields.Selection(selection=[('before', 'Before'), + ('after', 'After')], + string='Tree Position', + help="Position of new field in " + "tree view") + is_visible_in_tree_view = fields.Boolean(string='Visible In List View', + help="Enable to make the field " + "visible in selected list " + "view of the model") + created_tree_view_id = fields.Many2one('ir.ui.view', + string='Created Tree view', + help='This is the currently ' + 'created tree view') + created_form_view_id = fields.Many2one('ir.ui.view', + string='Created form view', + help='Created form view id for the ' + 'dynamic field') + + @api.depends('tree_view_id') + def _compute_tree_field_ids(self): + """Compute function to find the tree view fields of selected tree view + in field tree_view_id""" + for rec in self: + if rec.tree_view_id: + field_list = [] + if rec.tree_view_id.xml_id: + fields = ET.fromstring(self.env.ref( + rec.tree_view_id.xml_id).arch).findall(".//field") + for field in fields: + field_list.append(field.get('name')) + inherit_id = rec.tree_view_id.inherit_id if rec.tree_view_id.inherit_id else False + while inherit_id: + if inherit_id.xml_id: + fields = ET.fromstring(self.env.ref( + inherit_id.xml_id).arch).findall(".//field") + for field in fields: + field_list.append(field.get('name')) + inherit_id = inherit_id.inherit_id if inherit_id.inherit_id else False + self.tree_field_ids = self.env['ir.model.fields'].search( + [('model_id', '=', self.model_id.id), + ('name', 'in', field_list)]) + else: + rec.tree_field_ids = False + + @api.onchange('add_field_in_tree') + def _onchange_add_field_in_tree(self): + """Function to clear values of tree_view_id and tree_field_id""" + if not self.add_field_in_tree: + self.tree_view_id = False + self.tree_field_id = False def action_create_dynamic_field(self): """Function to create dynamic field to a particular model, data type, properties and etc""" self.write({'status': 'form'}) if self.field_type == 'monetary' and not self.env[ - 'ir.model.fields'].sudo().search([ - ('model', '=', self.model_id.id), - ('name', '=', 'currency_id')]): + 'ir.model.fields'].sudo().search([('model', '=', self.model_id.id), + ('name', '=', 'currency_id')]): self.env['ir.model.fields'].sudo().create({ 'name': 'x_currency_id', 'field_description': 'Currency', @@ -139,6 +197,7 @@ class DynamicFields(models.Model): 'ttype': 'many2one', 'relation': 'res.currency', 'is_dynamic_field': True + }) self.env['ir.model.fields'].sudo().create({ 'name': self.name, @@ -156,8 +215,8 @@ class DynamicFields(models.Model): 'is_dynamic_field': True }) inherit_form_view_name = str( - self.form_view_id.name) + ".inherit.dynamic.custom." + str(self. - field_description) + ".field" + self.form_view_id.name) + ".inherit.dynamic.custom." + str( + self.field_description) + ".field" xml_id = self.form_view_id.xml_id inherit_id = self.env.ref(xml_id) arch_base = _('' @@ -167,7 +226,7 @@ class DynamicFields(models.Model): '' '') % (self.position_field_id.name, self.position, self.name) - if self.widget: + if self.widget_id: arch_base = _('' '' '' @@ -175,8 +234,8 @@ class DynamicFields(models.Model): '' '') % (self.position_field_id.name, self.position, self.name, - self.widget.name) - self.form_view_id = self.env['ir.ui.view'].sudo().create({ + self.widget_id.name) + self.created_form_view_id = self.env['ir.ui.view'].sudo().create({ 'name': inherit_form_view_name, 'type': 'form', 'model': self.model_id.model, @@ -194,22 +253,23 @@ class DynamicFields(models.Model): def action_create_to_tree_view(self): """Function to add field to tree view""" if self.add_field_in_tree: + optional = "show" if self.is_visible_in_tree_view else "hide" + tree_view_arch_base = (_(f''' + + + + + ''')) inherit_tree_view_name = str( self.tree_view_id.name) + ".inherit.dynamic.custom" + \ str(self.field_description) + ".field" - self.tree_view_id = self.env['ir.ui.view'].sudo().create({ + self.created_tree_view_id = self.env['ir.ui.view'].sudo().create({ 'name': inherit_tree_view_name, 'type': 'tree', 'model': self.model_id.model, 'mode': 'extension', 'inherit_id': self.tree_view_id.id, - 'arch_base': _( - '' - '' - '''''' - '''''' - '''''' - '''''') % self.name, + 'arch_base': tree_view_arch_base, 'active': True}) return { 'type': 'ir.actions.client', @@ -219,8 +279,8 @@ class DynamicFields(models.Model): def unlink(self): """Super unlink function""" if self.form_view_id: - self.form_view_id.active = False + self.created_form_view_id.active = False if self.tree_view_id: - self.tree_view_id.active = False + self.created_tree_view_id.active = False res = super(DynamicFields, self).unlink() return res diff --git a/all_in_one_dynamic_custom_fields/security/ir.model.access.csv b/all_in_one_dynamic_custom_fields/security/ir.model.access.csv index 32e953a65..e8d222874 100755 --- a/all_in_one_dynamic_custom_fields/security/ir.model.access.csv +++ b/all_in_one_dynamic_custom_fields/security/ir.model.access.csv @@ -1,4 +1,4 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_all_in_one_dynamic_custom_fields_administrator,dynamic.fields,model_dynamic_fields,all_in_one_dynamic_custom_fields.group_all_in_one_dynamic_custom_fields_administrator,1,1,1,1 access_all_in_one_dynamic_custom_fields_user,dynamic.fields,model_dynamic_fields,all_in_one_dynamic_custom_fields.group_all_in_one_dynamic_custom_fields_user,1,0,0,0 -access_dynamic_field_widgets,"dynamic.field.widgets","model_dynamic_field_widgets",,1,1,1,1 +access_dynamic_field_widgets,dynamic.field.widgets,model_dynamic_field_widgets,base.group_user,1,1,1,1 diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/1.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..4a2db22a8 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/1.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/2.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..9d70df317 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/2.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/3.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..004db3bc5 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/3.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/4.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..8ffad588b Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/4.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/5.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..0cd16a080 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/5.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/6.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..184e14573 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/6.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/7.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..a9361fd41 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/7.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/8.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..5e58c4251 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/8.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/9.png b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..05601c6e3 Binary files /dev/null and b/all_in_one_dynamic_custom_fields/static/description/assets/screenshots/9.png differ diff --git a/all_in_one_dynamic_custom_fields/static/description/index.html b/all_in_one_dynamic_custom_fields/static/description/index.html index 5ccc18a95..6f4156627 100755 --- a/all_in_one_dynamic_custom_fields/static/description/index.html +++ b/all_in_one_dynamic_custom_fields/static/description/index.html @@ -222,7 +222,7 @@ height="auto">
-
@@ -240,12 +240,12 @@ create a custom field.

-
-
@@ -262,7 +262,7 @@ Choose the field type.

-
@@ -281,17 +281,17 @@ module List/Tree view.

-
-
-
@@ -309,7 +309,7 @@ order form view.

-
@@ -327,7 +327,7 @@ order tree view.

-
diff --git a/all_in_one_dynamic_custom_fields/views/dynamic_fields_views.xml b/all_in_one_dynamic_custom_fields/views/dynamic_fields_views.xml index 141b2551e..aad1bee15 100755 --- a/all_in_one_dynamic_custom_fields/views/dynamic_fields_views.xml +++ b/all_in_one_dynamic_custom_fields/views/dynamic_fields_views.xml @@ -51,7 +51,7 @@ required="field_type in ('many2one','many2many')" readonly="field_type not in ('many2one','many2many') or status != 'draft'" invisible="field_type not in ('many2one','many2many')"/> - + + + +