| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147 |
- from odoo import models, fields, api, _
- from odoo.exceptions import ValidationError
- class HrEfficiencyDynamicField(models.Model):
- _name = 'hr.efficiency.dynamic.field'
- _description = 'Dynamic Field Configuration'
- _order = 'sequence, name'
- name = fields.Char('Field Name', required=True, help='Technical field name (e.g., planning_efficiency)')
- label = fields.Char('Field Label', required=True, help='Display name (e.g., Planning Efficiency)')
- indicator_id = fields.Many2one('hr.efficiency.indicator', 'Related Indicator', required=True, ondelete='cascade')
-
- # Display settings
- sequence = fields.Integer('Sequence', default=10, help='Order in which fields appear')
- active = fields.Boolean('Active', default=True, help='Whether this field is visible')
-
- # View settings
- show_in_list = fields.Boolean('Show in List View', default=True)
- show_in_form = fields.Boolean('Show in Form View', default=True)
- show_in_search = fields.Boolean('Show in Search View', default=False)
-
- # Formatting
- widget = fields.Selection([
- ('percentage', 'Percentage'),
- ('float_time', 'Float Time'),
- ('number', 'Number'),
- ('text', 'Text'),
- ('monetary', 'Monetary'),
- ], string='Widget', default='percentage', help='How to display the field')
-
- # Styling
- decoration_success = fields.Float('Success Threshold', help='Value above which to show green')
- decoration_warning = fields.Float('Warning Threshold', help='Value above which to show yellow')
- decoration_danger = fields.Float('Danger Threshold', help='Value below which to show red')
- priority_background_color = fields.Char('Priority Background Color', help='Color de fondo de la columna basado en la prioridad del indicador')
-
- # Computed fields
- field_technical_name = fields.Char('Technical Field Name', compute='_compute_technical_name', store=True)
-
- @api.depends('name')
- def _compute_technical_name(self):
- for record in self:
- if record.name:
- # Convert to valid field name
- field_name = record.name.lower()
- field_name = field_name.replace(' ', '_').replace('-', '_').replace('(', '').replace(')', '')
- field_name = field_name.replace('í', 'i').replace('á', 'a').replace('é', 'e').replace('ó', 'o').replace('ú', 'u')
- field_name = field_name.replace('ñ', 'n')
-
- # Ensure it starts with a letter
- if not field_name[0].isalpha():
- field_name = 'indicator_' + field_name
-
- record.field_technical_name = field_name
-
- @api.constrains('name')
- def _check_name_unique(self):
- for record in self:
- if self.search_count([('name', '=', record.name), ('id', '!=', record.id)]) > 0:
- raise ValidationError(_('Field name must be unique'))
-
- @api.model_create_multi
- def create(self, vals_list):
- """Create dynamic fields and update model"""
- records = super().create(vals_list)
- self._update_model_fields()
- return records
-
- def write(self, vals):
- """Update dynamic field and update model"""
- result = super().write(vals)
- self._update_model_fields()
- return result
-
- def unlink(self):
- """Delete dynamic fields and update model"""
- result = super().unlink()
- self._update_model_fields()
- return result
-
- @api.model
- def _update_model_fields(self):
- """Update the hr.efficiency model with dynamic fields"""
- efficiency_model = self.env['hr.efficiency']
-
- # Get all active dynamic fields
- dynamic_fields = self.search([('active', '=', True)], order='sequence')
-
- # Clear existing dynamic fields from model (only those starting with 'indicator_')
- for field_name in list(efficiency_model._fields.keys()):
- if field_name.startswith('indicator_'):
- if hasattr(efficiency_model.__class__, field_name):
- try:
- delattr(efficiency_model.__class__, field_name)
- except AttributeError:
- pass # Field might not exist, ignore
-
- # Add new dynamic fields
- for dynamic_field in dynamic_fields:
- field_name = dynamic_field.field_technical_name
-
-
- # Create field with appropriate widget
- field_kwargs = {
- 'string': dynamic_field.label,
- 'compute': '_compute_indicators',
- 'store': True,
- 'help': f'Dynamic indicator: {dynamic_field.indicator_id.name}',
- }
-
- # Add widget if specified
- if dynamic_field.widget:
- field_kwargs['widget'] = dynamic_field.widget
-
- # Create the field
- field = fields.Float(**field_kwargs)
- setattr(efficiency_model.__class__, field_name, field)
-
- def action_toggle_visibility(self):
- """Toggle field visibility"""
- for record in self:
- record.active = not record.active
- self._update_model_fields()
-
- def action_move_up(self):
- """Move field up in sequence"""
- for record in self:
- prev_record = self.search([
- ('sequence', '<', record.sequence),
- ('active', '=', True)
- ], order='sequence desc', limit=1)
-
- if prev_record:
- record.sequence, prev_record.sequence = prev_record.sequence, record.sequence
-
- def action_move_down(self):
- """Move field down in sequence"""
- for record in self:
- next_record = self.search([
- ('sequence', '>', record.sequence),
- ('active', '=', True)
- ], order='sequence', limit=1)
-
- if next_record:
- record.sequence, next_record.sequence = next_record.sequence, record.sequence
|