From 84ed2b2571417473fc312c4a0db0ab432dd70d3e Mon Sep 17 00:00:00 2001 From: Haresh Chavda Date: Fri, 24 Aug 2018 18:06:32 +0530 Subject: [PATCH] [ADD]: Add/Remove dynamic digest field, group and misc changes --- addons/digest/__manifest__.py | 4 +- addons/digest/views/digest_views.xml | 37 --------- addons/digest/views/digest_views_inherit.xml | 50 ++++++++++++ addons/digest/wizard/__init__.py | 3 +- addons/digest/wizard/digest_custom_fields.py | 76 +++++++++++-------- .../wizard/digest_custom_fields_view.xml | 8 +- addons/digest/wizard/digest_custom_remove.py | 76 +++++++++++++++++++ .../wizard/digest_custom_remove_view.xml | 31 ++++++++ addons/event/models/event.py | 4 +- 9 files changed, 215 insertions(+), 74 deletions(-) create mode 100644 addons/digest/views/digest_views_inherit.xml create mode 100644 addons/digest/wizard/digest_custom_remove.py create mode 100644 addons/digest/wizard/digest_custom_remove_view.xml diff --git a/addons/digest/__manifest__.py b/addons/digest/__manifest__.py index 1541460e..fc2daee7 100644 --- a/addons/digest/__manifest__.py +++ b/addons/digest/__manifest__.py @@ -19,9 +19,11 @@ Send KPI Digests periodically 'data/ir_cron_data.xml', 'data/res_config_settings_data.xml', 'views/digest_views.xml', + 'wizard/digest_custom_fields_view.xml', + 'wizard/digest_custom_remove_view.xml', + 'views/digest_views_inherit.xml', 'views/digest_templates.xml', 'views/res_config_settings_views.xml', - 'wizard/digest_custom_fields_view.xml', ], 'installable': True, } diff --git a/addons/digest/views/digest_views.xml b/addons/digest/views/digest_views.xml index cf61541f..27f45967 100644 --- a/addons/digest/views/digest_views.xml +++ b/addons/digest/views/digest_views.xml @@ -62,43 +62,6 @@ - -
-
- -
diff --git a/addons/digest/views/digest_views_inherit.xml b/addons/digest/views/digest_views_inherit.xml new file mode 100644 index 00000000..a487680e --- /dev/null +++ b/addons/digest/views/digest_views_inherit.xml @@ -0,0 +1,50 @@ + + + + digest.digest.view.form.inherit + digest.digest + + + + +
+
+ +
+
+
+
+
\ No newline at end of file diff --git a/addons/digest/wizard/__init__.py b/addons/digest/wizard/__init__.py index a10b73b9..fad86bcd 100644 --- a/addons/digest/wizard/__init__.py +++ b/addons/digest/wizard/__init__.py @@ -1,4 +1,5 @@ # -*- coding: utf-8 -*- # Part of Flectra. See LICENSE file for full copyright and licensing details. -from . import digest_custom_fields \ No newline at end of file +from . import digest_custom_fields +from . import digest_custom_remove \ No newline at end of file diff --git a/addons/digest/wizard/digest_custom_fields.py b/addons/digest/wizard/digest_custom_fields.py index b190636b..fcb6120c 100644 --- a/addons/digest/wizard/digest_custom_fields.py +++ b/addons/digest/wizard/digest_custom_fields.py @@ -5,6 +5,7 @@ from flectra import api, fields, models, _ from flectra.exceptions import ValidationError, UserError from lxml import etree from flectra.tools.safe_eval import test_python_expr +import xml.etree.ElementTree as ET class DigestCustomFields(models.TransientModel): @@ -19,29 +20,37 @@ class DigestCustomFields(models.TransientModel): # - time, datetime, dateutil, timezone: useful Python libraries # - log: log(message, level='info'): logging function to record debug information in ir.logging table # - Warning: Warning Exception to use with raise -# To return an action, assign: action = {...}\n\n\n\n""" +# To return an action, assign: action = {...} +for rec in self: + rec[''] = self.env[''].search([])\n\n\n\n""" - # field = fields.Many2one('ir.model.fields', domain="[('model_id', '=', 'digest.digest'), ('name', 'ilike', 'x_kpi'), ('depends', '=', False)]") - # compute_field = fields.Many2one('ir.model.fields', domain="[('model_id', '=', 'digest.digest'), ('name', 'ilike', 'x_kpi'), ('depends', '!=', False)]") - field_name = fields.Char('Field Name', default='x_kpi_', required=True) label_name = fields.Char('Label Name', required=True) - group_name = fields.Char('Group Name', required=True) - ttype = fields.Selection([('integer', 'Integer'), ('monetary', 'Monetary')], string='Field Type', required=True) - # compute = fields.Text(help="Code to compute the value of the field.\n" - # "Iterate on the recordset 'self' and assign the field's value:\n\n" - # " for record in self:\n" - # " record['size'] = len(record.name)\n\n" - # "Modules time, datetime, dateutil are available.") - - + # group_type = fields.Selection([('new', 'New Group'), ('existing', 'Existing Group')], string='Group Type', required=True) + new_group_name = fields.Char('Group Name') + ttype = fields.Selection([('integer', 'Integer'), ('monetary', 'Monetary')], string='Field Type', required=True, default='integer') compute = fields.Text(string='Python Code', groups='base.group_system', default=DEFAULT_PYTHON_CODE, help="Write Python code that the action will execute. Some variables are " "available for use; help about pyhon expression is given in the help tab.") compute_field_name = fields.Char(compute='_compute_get_field_name', string='Compute Field Name') + available_group_name = fields.Selection('_get_group_name', string='Available Group') + position = fields.Selection([('before', 'Before'), ('after', 'After'), ('inside', 'Inside')], string='Position') + + def _get_group_name(self): + print("=====self=========", self.env.context) + digest_view_id = self.env.ref('digest.digest_digest_view_form').id + view_ids = self.env['ir.ui.view'].search([('inherit_id', 'child_of', digest_view_id)]) + group_value = {} + for view_id in view_ids: + root = ET.fromstring(view_id.arch_base) + for group_name in root.iter('group'): + if group_name.attrib.get('name', False) and group_name.attrib.get('string', False): + group_key = str(view_id.id) + '_' + str(group_name.attrib['name']) + group_value.update({group_key : group_name.attrib['string']}) + return [(x) for x in group_value.items()] @api.constrains('compute') def _check_python_code(self): @@ -60,7 +69,9 @@ class DigestCustomFields(models.TransientModel): def _check_name(self): for field in self: if not field.field_name.startswith('x_kpi_'): - raise ValidationError(_("Custom fields must have a name that starts with 'x_kpi_' !")) + raise ValidationError(_("Custom fields must have a name that starts with 'x_kpi_'!")) + # if self.position != 'inside' and not field.new_group_name.startswith('x_kpi_'): + # raise ValidationError(_("Group Name must have a name that starts with 'x_kpi_'!")) try: models.check_pg_name(field.field_name) except ValidationError: @@ -90,41 +101,44 @@ class DigestCustomFields(models.TransientModel): 'depends': first_field_name, 'compute': self.compute } - print("====values=======", values) ir_model_fields_obj.create(values) def field_arch(self): xpath = etree.Element('xpath') - xpath_type = "group" - name = "kpi_general" - position = "after" - xpath_field = self.field_name - expr = '//' + xpath_type + '[@name="' + name + '"][not(ancestor::field)]' + name = self.available_group_name and self.available_group_name.split('_', 1)[1] or "kpis" + expr = '//' + 'group' + '[@name="' + name + '"]' xpath.set('expr', expr) - xpath.set('position', position) - if position == 'after' or position == 'before' or position == 'inside': - expr = '//' + xpath_type + '[@name="' + name + '"][not(ancestor::field)]' - group = etree.Element('group') - group.set('string', self.group_name) + xpath.set('position', self.position) + + if self.position == 'inside': field = etree.Element('field') - field.set('name', xpath_field) + field.set('name', self.field_name) + xpath.set('expr', expr) + xpath.append(field) + else: + group = etree.Element('group') + group.set('name', 'x_kpi_' + self.new_group_name.replace(" ", "_")) + group.set('string', self.new_group_name) + field = etree.Element('field') + field.set('name', self.field_name) xpath.set('expr', expr) group.append(field) xpath.append(group) + return etree.tostring(xpath).decode("utf-8") @api.multi - def action_customize_digest(self): + def action_add_customize_digest(self): self.add_new_fields() - arch = '' + str(self.field_arch()) + '' - print("====arch=======", arch) + arch = '' + str(self.field_arch()) + view_id = self.available_group_name and self.available_group_name.split('_', 1)[0] or False vals = { 'type': 'form', 'model': 'digest.digest', - 'inherit_id': self.env.ref('digest.digest_digest_view_form').id, + 'inherit_id': view_id or self.env.ref('digest.digest_digest_view_form').id, 'mode': 'extension', 'arch_base': arch, - 'name': 'x_kpi_' + self.field_name + "_Customization", + 'name': 'x_kpi_' + self.field_name + "_customization", } ir_model = self.env['ir.model'].search([('model', '=', 'digest.digest')]) if hasattr(ir_model, 'module_id'): diff --git a/addons/digest/wizard/digest_custom_fields_view.xml b/addons/digest/wizard/digest_custom_fields_view.xml index 732608c0..c66c435a 100644 --- a/addons/digest/wizard/digest_custom_fields_view.xml +++ b/addons/digest/wizard/digest_custom_fields_view.xml @@ -5,10 +5,12 @@ digest.custom.fields
- + - + + + @@ -16,7 +18,7 @@
-
diff --git a/addons/digest/wizard/digest_custom_remove.py b/addons/digest/wizard/digest_custom_remove.py new file mode 100644 index 00000000..d8a6344a --- /dev/null +++ b/addons/digest/wizard/digest_custom_remove.py @@ -0,0 +1,76 @@ +# -*- coding: utf-8 -*- +# Part of Flectra. See LICENSE file for full copyright and licensing details. + +from flectra import api, fields, models, _ +from flectra.exceptions import ValidationError, UserError +from lxml import etree +from flectra.tools.safe_eval import test_python_expr +import xml.etree.ElementTree as ET +from flectra.osv import expression + + +class DigestCustomRemove(models.TransientModel): + _name = 'digest.custom.remove' + + remove_type = fields.Selection([('group', 'Group'), ('field', 'Field')], string='Remove Type') + field_id = fields.Many2one('ir.model.fields', 'Field', domain=[('model', '=', 'digest.digest'), ('required', '=', False), ('ttype', '=', 'boolean'), ('name', 'ilike', 'x_kpi_')]) + available_group_name = fields.Selection('_get_group_name', string='Available Group') + + def _get_group_name(self): + digest_view_id = self.env.ref('digest.digest_digest_view_form').id + view_ids = self.env['ir.ui.view'].search([('inherit_id', 'child_of', digest_view_id)]) + group_value = {} + for view_id in view_ids: + root = ET.fromstring(view_id.arch_base) + for group_name in root.iter('group'): + if group_name.attrib.get('name', False) and group_name.attrib.get('string', False) and group_name.attrib['name'].startswith('x_kpi_'): + group_key = str(view_id.id) + '_' + str(group_name.attrib['name']) + group_value.update({group_key : group_name.attrib['string']}) + return [(x) for x in group_value.items()] + + @api.multi + def action_customize_digest_remove(self): + ir_model_fields_obj = self.env['ir.model.fields'] + ir_ui_view_obj = self.env['ir.ui.view'] + if self.remove_type == 'group': + find_view_id = self.available_group_name and self.available_group_name.split('_', 1)[0] or False + print("===find_view_id==", find_view_id) + view_ids = ir_ui_view_obj.search([('inherit_id', 'child_of', int(find_view_id))], order="id desc") + field_list = [] + for view_id in view_ids: + print("===view_id========", view_id) + root = ET.fromstring(view_id.arch_base) + print("==========root=====", root) + for child in root.iter('group'): + name = child.find('field') + if name.attrib and name.attrib.get('name', False): + field_list.append(name.attrib.get('name', False)) + field_ids = ir_model_fields_obj.search([('name', 'in', field_list)]) + print("====field_ids====", field_ids, view_ids.ids) + view_ids.unlink() + for field_id in field_ids: + ir_model_fields_obj.search([('depends', '=', field_id.name)]).unlink() + field_ids.unlink() + else: + domain = expression.OR([('arch_db', 'like', record.name)] for record in self.field_id) + print("===domain======", domain) + view_ids = ir_ui_view_obj.search(domain) + print("==========>>>>>>>>.", view_ids) + for view_id in view_ids: + # print("=====view_id.arch_base======before========", view_id.arch_base) + root = ET.fromstring(view_id.arch_base) + # result = len(root.getchildren()) + # count = sum(1 for root in root.iter("field")) + # print("===============result==============>", result, count) + for child in root.iter('field'): + # print("===========>>>>",child.text, child.attrib, child.tag) + if child.attrib and child.attrib.get('name', False) == self.field_id.name: + view_id.unlink() + # root.remove(child) + # view_id.write({'arch_base': ET.tostring(root)}) + ir_model_fields_obj.search([('depends', '=', self.field_id.name)]).unlink() + self.field_id.unlink() + return { + 'type': 'ir.actions.client', + 'tag': 'reload', + } \ No newline at end of file diff --git a/addons/digest/wizard/digest_custom_remove_view.xml b/addons/digest/wizard/digest_custom_remove_view.xml new file mode 100644 index 00000000..ae3d027b --- /dev/null +++ b/addons/digest/wizard/digest_custom_remove_view.xml @@ -0,0 +1,31 @@ + + + + digest.custom.remove.form + digest.custom.remove + +
+ + + + + + + +
+
+
+
+
+ + + Customized Digest Remove + ir.actions.act_window + digest.custom.remove + form + + new + +
diff --git a/addons/event/models/event.py b/addons/event/models/event.py index a5b2f737..a27e0db5 100644 --- a/addons/event/models/event.py +++ b/addons/event/models/event.py @@ -202,7 +202,9 @@ class EventEvent(models.Model): @api.model def _tz_get(self): - return [(x, x) for x in pytz.all_timezones] + a = [(x, x) for x in pytz.all_timezones] + print("\n\n\n=================>>>>>>.", a) + return a @api.one @api.depends('date_tz', 'date_begin')