Jelajahi Sumber

Actualizar HR Efficiency: Eliminar campos de agregación (_agg)

- Eliminados métodos de agregación del módulo
- Limpiados campos de agregación de la base de datos
- Reinstalación exitosa sin campos de agregación
- Módulo funcionando correctamente
root 5 bulan lalu
induk
melakukan
d3e745d722

+ 5 - 0
hr_efficiency/__manifest__.py

@@ -52,6 +52,11 @@ Features:
         'views/planning_views.xml',
         'report/hr_efficiency_report_views.xml',
     ],
+    'assets': {
+        'web.assets_backend': [
+            'hr_efficiency/static/src/css/hr_efficiency.css',
+        ],
+    },
     'demo': [],
     'installable': True,
     'auto_install': False,

+ 11 - 0
hr_efficiency/data/hr_efficiency_indicators.xml

@@ -17,6 +17,7 @@
             <field name="description">Tasa de Ocupación: Mide qué tan "ocupado" está el equipo en general, considerando horas facturables y no facturables. (Total Horas Registradas / Horas Disponibles)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">60.0</field>
         </record>
 
         <record id="indicator_utilization_rate" model="hr.efficiency.indicator">
@@ -30,6 +31,7 @@
             <field name="description">Tasa de Utilización: Mide qué tan "productivo" (generando ingresos) está el equipo. (Horas Facturables Registradas / Horas Disponibles)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">60.0</field>
         </record>
 
         <!-- ================================================== -->
@@ -47,6 +49,7 @@
             <field name="description">Tasa de Facturabilidad: De todo el tiempo trabajado, ¿qué porcentaje fue facturable? (Horas Facturables Registradas / Total Horas Registradas)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">65.0</field>
         </record>
 
         <!-- ================================================== -->
@@ -64,6 +67,7 @@
             <field name="description">Utilización Planeada: ¿Cuál era el objetivo de utilización para el equipo? Permite comparar meta vs. realidad. (Horas Facturables Planeadas / Horas Disponibles)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">60.0</field>
         </record>
 
         <record id="indicator_planning_coverage" model="hr.efficiency.indicator">
@@ -77,6 +81,7 @@
             <field name="description">Cobertura de Planificación: Mide qué porcentaje del tiempo disponible ha sido planificado, sin importar si es facturable o no. (Total Horas Planeadas / Horas Disponibles)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">65.0</field>
         </record>
 
         <record id="indicator_estimation_accuracy" model="hr.efficiency.indicator">
@@ -90,6 +95,7 @@
             <field name="description">Precisión de la Estimación: ¿Qué tan acertada fue la planificación general vs. la realidad? Un valor cercano a 100% es ideal. (Total Horas Registradas / Total Horas Planeadas)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">60.0</field>
         </record>
 
         <record id="indicator_billable_plan_compliance" model="hr.efficiency.indicator">
@@ -103,6 +109,7 @@
             <field name="description">Cumplimiento del Plan Facturable: ¿Se cumplió con el objetivo específico de horas facturables? (Horas Facturables Registradas / Horas Facturables Planeadas)</field>
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">65.0</field>
         </record>
         
         <!-- ================================================== -->
@@ -119,8 +126,10 @@
             <field name="target_percentage">0.0</field>
             <field name="weight">0.0</field>
             <field name="description">Horas de Punto de Equilibrio: ¿Cuántas horas facturables se necesitan para cubrir el costo productivo (costo ponderado por utilización)? El resultado es un número de horas.</field>
+            <!-- Note: Thresholds for 'hours' type are less direct than for percentages. -->
             <field name="color_threshold_green">85.0</field>
             <field name="color_threshold_yellow">75.0</field>
+            <field name="color_threshold_red">65.0</field>
         </record>
 
         <record id="indicator_planned_profitability_coverage" model="hr.efficiency.indicator">
@@ -135,6 +144,7 @@
             <field name="description">Cobertura de Rentabilidad Planeada: Mide si las horas facturables planeadas son suficientes para alcanzar el punto de equilibrio. Más de 100% indica un plan rentable. (Horas Facturables Planeadas / Horas de Punto de Equilibrio)</field>
             <field name="color_threshold_green">100.0</field>
             <field name="color_threshold_yellow">85.0</field>
+            <field name="color_threshold_red">70.0</field>
         </record>
 
         <record id="indicator_actual_profitability_achievement" model="hr.efficiency.indicator">
@@ -149,6 +159,7 @@
             <field name="description">Logro de Rentabilidad Real: Mide el progreso real hacia el punto de equilibrio basado en las horas facturables registradas. Más de 100% indica que ya se ha alcanzado la rentabilidad. (Horas Facturables Registradas / Horas de Punto de Equilibrio)</field>
             <field name="color_threshold_green">100.0</field>
             <field name="color_threshold_yellow">85.0</field>
+            <field name="color_threshold_red">70.0</field>
         </record>
 
     </data>

+ 62 - 118
hr_efficiency/models/hr_efficiency.py

@@ -38,6 +38,8 @@ class HrEfficiency(models.Model):
     # Employee utilization and company overhead (stored at calculation time)
     utilization_rate = fields.Float('Utilization Rate (%)', digits=(5, 2), default=100.0, aggregator='avg', help="Employee's utilization rate at the time of calculation")
     overhead = fields.Float('Company Overhead (%)', digits=(5, 2), default=40.0, aggregator='avg', help="Company's overhead percentage at the time of calculation")
+    expected_profitability = fields.Float('Expected Profitability (%)', digits=(5, 2), default=30.0, aggregator='avg', help="Company's expected profitability percentage at the time of calculation")
+    efficiency_factor = fields.Float('Efficiency Factor (%)', digits=(5, 2), default=85.0, aggregator='avg', help="Company's efficiency factor percentage at the time of calculation")
     
     # Planned hours (what was planned)
     planned_hours = fields.Float('Planned Hours', digits=(10, 2), help="Total hours planned for the month")
@@ -53,7 +55,7 @@ class HrEfficiency(models.Model):
     expected_hours_to_date = fields.Float('Expected Hours to Date', digits=(10, 2), help='Hours that should be registered based on planning until current date')
     
     # Precio por Hora (stored field)
-    precio_por_hora = fields.Float('Precio por Hora', digits=(10, 2), help='Precio que cobramos al cliente por hora (costo + overhead + 30% rentabilidad)', aggregator='avg')
+    precio_por_hora = fields.Float('Precio por Hora', digits=(10, 2), help='Precio que cobramos al cliente por hora (hourly_cost + overhead + rentabilidad_esperada)', aggregator='avg')
     
     # Dynamic indicator fields (will be created automatically)
     # These fields are managed dynamically based on hr.efficiency.indicator records
@@ -88,11 +90,11 @@ class HrEfficiency(models.Model):
 
     def _calculate_expected_hours_to_date(self, record):
         """
-        Calculate expected hours to date based on available hours and working days
+        Calculate expected hours to date based on planned hours and working days
         """
-        if not record.month_year or not record.available_hours or not record.employee_id.contract_id:
+        if not record.month_year or not record.planned_hours or not record.employee_id.contract_id:
             return 0.0
-        
+            
         try:
             # Parse month_year (format: YYYY-MM)
             year, month = record.month_year.split('-')
@@ -117,11 +119,11 @@ class HrEfficiency(models.Model):
             working_days_until_date = self._count_working_days(start_date, calculation_date, record.employee_id)
             
             if total_working_days > 0:
-                # Calculate expected hours based on available hours (what employee should work)
-                expected_hours = (record.available_hours / total_working_days) * working_days_until_date
+                # Calculate expected hours based on planned hours (what was planned to work)
+                expected_hours = (record.planned_hours / total_working_days) * working_days_until_date
                 
-                # Ensure we don't exceed available hours for the month
-                expected_hours = min(expected_hours, record.available_hours)
+                # Ensure we don't exceed planned hours for the month
+                expected_hours = min(expected_hours, record.planned_hours)
                 
                 return float_round(expected_hours, 2)
             else:
@@ -132,18 +134,21 @@ class HrEfficiency(models.Model):
 
     def _calculate_precio_por_hora(self, record):
         """
-        Calculate precio por hora: (wage / available_hours) * (1 + overhead/100) * 1.30
+        Calculate precio por hora: hourly_cost * (1 + overhead/100) * (1 + expected_profitability/100)
         """
         try:
-            wage = getattr(record, 'wage', 0.0) or 0.0
-            available_hours = getattr(record, 'available_hours', 0.0) or 0.0
+            # Get hourly_cost from employee
+            employee = getattr(record, 'employee_id', None)
+            if not employee:
+                return 0.0
+            
+            hourly_cost = getattr(employee, 'hourly_cost', 0.0) or 0.0
             overhead = getattr(record, 'overhead', 40.0) or 40.0
+            expected_profitability = getattr(record, 'expected_profitability', 30.0) or 30.0
             
-            if available_hours > 0:
-                # Calculate cost per hour
-                cost_per_hour = wage / available_hours
-                # Apply overhead and 30% profit margin
-                precio_por_hora = cost_per_hour * (1 + (overhead / 100)) * 1.30
+            if hourly_cost > 0:
+                # Apply overhead and expected profitability margin
+                precio_por_hora = hourly_cost * (1 + (overhead / 100)) * (1 + (expected_profitability / 100))
                 return float_round(precio_por_hora, 2)
             else:
                 return 0.0
@@ -266,37 +271,9 @@ class HrEfficiency(models.Model):
                     list(values.values()) + [record_id]
                 )
         
-        # Update aggregation fields after calculating indicators
-        self._update_aggregation_fields()
+
     
-    def _update_aggregation_fields(self):
-        """
-        Actualiza los campos de agregación con los valores de los indicadores dinámicos
-        """
-        try:
-            for record in self:
-                # Obtener todos los indicadores activos (en orden de secuencia)
-                active_indicators = self.env['hr.efficiency.indicator'].search([('active', '=', True)], order='sequence')
-                
-                for indicator in active_indicators:
-                    field_name = self._get_indicator_field_name(indicator.name)
-                    agg_field_name = f"{field_name}_agg"
-                    
-                    # Verificar si el campo de agregación existe
-                    if hasattr(record, agg_field_name):
-                        # Obtener el valor del indicador dinámico
-                        indicator_value = getattr(record, field_name, 0.0) or 0.0
-                        
-                        # Actualizar el campo de agregación usando SQL directo
-                        record.env.cr.execute(
-                            "UPDATE hr_efficiency SET %s = %%s WHERE id = %%s" % agg_field_name,
-                            [indicator_value, record.id]
-                        )
-                        
-        except Exception as e:
-            import logging
-            _logger = logging.getLogger(__name__)
-            _logger.warning(f"Error updating aggregation fields: {str(e)}")
+
     
     def _update_stored_manual_fields(self):
         """Update stored manual fields with computed values"""
@@ -496,6 +473,8 @@ class HrEfficiency(models.Model):
         # Get employee's utilization rate and company's overhead at calculation time
         utilization_rate = employee.utilization_rate or 100.0
         overhead = employee.company_id.overhead or 40.0
+        expected_profitability = employee.company_id.expected_profitability or 30.0
+        efficiency_factor = employee.company_id.efficiency_factor or 85.0
         
         # Apply utilization_rate to actual_billable_hours to reflect real billable capacity
         adjusted_actual_billable_hours = actual_billable_hours * (utilization_rate / 100)
@@ -514,6 +493,8 @@ class HrEfficiency(models.Model):
             'currency_id': currency_id,
             'utilization_rate': utilization_rate,
             'overhead': overhead,
+            'expected_profitability': expected_profitability,
+            'efficiency_factor': efficiency_factor,
         }
 
     @api.model
@@ -887,8 +868,7 @@ class HrEfficiency(models.Model):
         """
         super()._register_hook()
         try:
-            # Ensure aggregation fields exist for dynamic indicators
-            self._ensure_aggregation_fields_exist()
+
             # Update views with current dynamic fields on every module load
             self._update_views_with_dynamic_fields()
         except Exception as e:
@@ -897,59 +877,7 @@ class HrEfficiency(models.Model):
             _logger = logging.getLogger(__name__)
             _logger.warning(f"Could not update dynamic views on module load: {str(e)}")
 
-    @api.model
-    def _ensure_aggregation_fields_exist(self):
-        """
-        Asegura que existan campos de agregación para todos los indicadores activos
-        """
-        try:
-            active_indicators = self.env['hr.efficiency.indicator'].search([('active', '=', True)], order='sequence')
-            
-            for indicator in active_indicators:
-                field_name = self._get_indicator_field_name(indicator.name)
-                agg_field_name = f"{field_name}_agg"
-                
-                # Verificar si el campo de agregación ya existe en ir.model.fields
-                agg_field_record = self.env['ir.model.fields'].search([
-                    ('model', '=', 'hr.efficiency'),
-                    ('name', '=', agg_field_name)
-                ], limit=1)
-                
-                if not agg_field_record:
-                    # Determinar tipo de agregación basado en el tipo de indicador
-                    agg_type = 'avg' if indicator.indicator_type == 'percentage' else 'sum'
-                    
-                    # Obtener el model_id para hr.efficiency
-                    model_record = self.env['ir.model'].search([('model', '=', 'hr.efficiency')], limit=1)
-                    
-                    if model_record:
-                        # Crear el campo de agregación
-                        self.env['ir.model.fields'].create({
-                            'name': agg_field_name,
-                            'model_id': model_record.id,
-                            'field_description': f'{indicator.name} (Agregación)',
-                            'ttype': 'float',
-                            'state': 'manual',
-                            'store': True,
-                            'help': f'Campo de agregación para {indicator.name}'
-                        })
-                        
-                        import logging
-                        _logger = logging.getLogger(__name__)
-                        _logger.info(f"Created aggregation field: {agg_field_name} for indicator: {indicator.name}")
-                    else:
-                        import logging
-                        _logger = logging.getLogger(__name__)
-                        _logger.warning(f"Model hr.efficiency not found for aggregation field: {agg_field_name}")
-                    
-                    import logging
-                    _logger = logging.getLogger(__name__)
-                    _logger.info(f"Created aggregation field: {agg_field_name} for indicator: {indicator.name}")
-                    
-        except Exception as e:
-            import logging
-            _logger = logging.getLogger(__name__)
-            _logger.warning(f"Error creating aggregation fields: {str(e)}")
+
 
     @api.model
     def _update_views_with_dynamic_fields(self):
@@ -1017,22 +945,27 @@ class HrEfficiency(models.Model):
                 
                 # Add decorations based on indicator thresholds
                 if indicator:
-                    # Use standard efficiency ranges: >=0.9 green, >=0.8 yellow, >=0.7 orange, <0.7 red or zero
-                    field_xml += f' decoration-success="{field_info["name"]} &gt;= 0.9"'
-                    field_xml += f' decoration-warning="{field_info["name"]} &gt;= 0.8 and {field_info["name"]} &lt; 0.9"'
-                    field_xml += f' decoration-info="{field_info["name"]} &gt;= 0.7 and {field_info["name"]} &lt; 0.8"'
-                    field_xml += f' decoration-danger="{field_info["name"]} &lt; 0.7 or {field_info["name"]} == 0"'
+                    # Use dynamic thresholds from indicator configuration
+                    green_threshold = indicator.color_threshold_green / 100.0
+                    yellow_threshold = indicator.color_threshold_yellow / 100.0
+                    
+                    field_xml += f' decoration-success="{field_info["name"]} &gt;= {green_threshold}"'
+                    field_xml += f' decoration-warning="{field_info["name"]} &gt;= {yellow_threshold} and {field_info["name"]} &lt; {green_threshold}"'
+                    field_xml += f' decoration-danger="{field_info["name"]} &lt; {yellow_threshold}"'
+                    
+                    # Add priority background color using CSS classes
+                    if hasattr(indicator, 'priority') and indicator.priority != 'none':
+                        if indicator.priority == 'low':
+                            field_xml += f' class="priority-low-bg"'
+                        elif indicator.priority == 'medium':
+                            field_xml += f' class="priority-medium-bg"'
+                        elif indicator.priority == 'high':
+                            field_xml += f' class="priority-high-bg"'
                 
                 field_xml += '/>'
                 dynamic_fields_xml += field_xml
                 
-                # Add aggregation field for this indicator
-                agg_field_name = f"{field_info['name']}_agg"
-                agg_type = 'avg' if indicator.indicator_type == 'percentage' else 'sum'
-                agg_label = f"Total {indicator.name}" if agg_type == 'sum' else f"Average {indicator.name}"
-                
-                agg_field_xml = f'<field name="{agg_field_name}" {agg_type}="{agg_label}" optional="hide" invisible="1"/>'
-                dynamic_fields_xml += agg_field_xml
+
             
             # Update inherited list view
             inherited_list_view = self.env.ref('hr_efficiency.view_hr_efficiency_list_inherited', raise_if_not_found=False)
@@ -1074,11 +1007,22 @@ class HrEfficiency(models.Model):
                 
                 # Add decorations based on indicator thresholds
                 if indicator:
-                    # Use standard efficiency ranges: >=0.9 green, >=0.8 yellow, >=0.7 orange, <0.7 red or zero
-                    field_xml += f' decoration-success="{field_info["name"]} &gt;= 0.9"'
-                    field_xml += f' decoration-warning="{field_info["name"]} &gt;= 0.8 and {field_info["name"]} &lt; 0.9"'
-                    field_xml += f' decoration-info="{field_info["name"]} &gt;= 0.7 and {field_info["name"]} &lt; 0.8"'
-                    field_xml += f' decoration-danger="{field_info["name"]} &lt; 0.7 or {field_info["name"]} == 0"'
+                    # Use dynamic thresholds from indicator configuration
+                    green_threshold = indicator.color_threshold_green / 100.0
+                    yellow_threshold = indicator.color_threshold_yellow / 100.0
+                    
+                    field_xml += f' decoration-success="{field_info["name"]} &gt;= {green_threshold}"'
+                    field_xml += f' decoration-warning="{field_info["name"]} &gt;= {yellow_threshold} and {field_info["name"]} &lt; {green_threshold}"'
+                    field_xml += f' decoration-danger="{field_info["name"]} &lt; {yellow_threshold}"'
+                    
+                    # Add priority background color using CSS classes
+                    if hasattr(indicator, 'priority') and indicator.priority != 'none':
+                        if indicator.priority == 'low':
+                            field_xml += f' class="priority-low-bg"'
+                        elif indicator.priority == 'medium':
+                            field_xml += f' class="priority-medium-bg"'
+                        elif indicator.priority == 'high':
+                            field_xml += f' class="priority-high-bg"'
                 
                 field_xml += '/>'
                 form_dynamic_fields_xml += field_xml

+ 1 - 0
hr_efficiency/models/hr_efficiency_dynamic_field.py

@@ -33,6 +33,7 @@ class HrEfficiencyDynamicField(models.Model):
     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)

+ 33 - 3
hr_efficiency/models/hr_efficiency_indicator.py

@@ -42,10 +42,35 @@ class HrEfficiencyIndicator(models.Model):
     target_percentage = fields.Float('Target %', default=90.0, help='Target percentage for this indicator')
     weight = fields.Float('Weight %', default=50.0, help='Weight of this indicator in the overall efficiency calculation')
     
+    # Priority for column background color
+    priority = fields.Selection([
+        ('none', 'Sin Prioridad'),
+        ('low', 'Baja (Verde)'),
+        ('medium', 'Media (Amarillo)'),
+        ('high', 'Alta (Rojo)')
+    ], string='Prioridad', default='none', help='Prioridad del indicador que determina el color de fondo de la columna')
+    
     # Display settings
     description = fields.Text('Description', help='Description of what this indicator measures')
     color_threshold_green = fields.Float('Green Threshold', default=90.0, help='Percentage above which to show green')
     color_threshold_yellow = fields.Float('Yellow Threshold', default=70.0, help='Percentage above which to show yellow')
+    color_threshold_red = fields.Float('Red Threshold', default=50.0, help='Percentage above which to show red (below this shows danger)')
+    
+    # Computed field for priority background color
+    priority_color = fields.Char('Priority Color', compute='_compute_priority_color', store=True, help='Color de fondo basado en la prioridad')
+    
+    @api.depends('priority')
+    def _compute_priority_color(self):
+        """Compute background color based on priority"""
+        for record in self:
+            if record.priority == 'low':
+                record.priority_color = '#d4edda'  # Verde claro
+            elif record.priority == 'medium':
+                record.priority_color = '#fff3cd'  # Amarillo claro
+            elif record.priority == 'high':
+                record.priority_color = '#f8d7da'  # Rojo claro
+            else:
+                record.priority_color = ''  # Sin color (transparente)
     
     @api.constrains('weight')
     def _check_weight(self):
@@ -143,7 +168,8 @@ class HrEfficiencyIndicator(models.Model):
                 'widget': widget,
                 'decoration_success': indicator.color_threshold_green,
                 'decoration_warning': indicator.color_threshold_yellow,
-                'decoration_danger': 0.0,
+                'decoration_danger': indicator.color_threshold_red,
+                'priority_background_color': indicator.priority_color,
             })
 
         # Ensure an ir.model.fields manual field exists (Studio-like) for ALL indicators
@@ -183,7 +209,7 @@ class HrEfficiencyIndicator(models.Model):
         # Recompute all indicators to populate the new stored field
         records = self.env['hr.efficiency'].search([])
         if records:
-            records._compute_indicators()
+            records._calculate_all_indicators()
     
     def _update_dynamic_field(self, indicator, vals=None):
         """Update the dynamic field for the indicator"""
@@ -207,6 +233,8 @@ class HrEfficiencyIndicator(models.Model):
                 'widget': widget,
                 'decoration_success': indicator.color_threshold_green,
                 'decoration_warning': indicator.color_threshold_yellow,
+                'decoration_danger': indicator.color_threshold_red,
+                'priority_background_color': indicator.priority_color,
             })
         # Sync corresponding ir.model.fields label and refresh views
         efficiency_model = 'hr.efficiency'
@@ -279,5 +307,7 @@ class HrEfficiencyIndicator(models.Model):
             return 'text-success'
         elif percentage >= self.color_threshold_yellow:
             return 'text-warning'
-        else:
+        elif percentage >= self.color_threshold_red:
             return 'text-danger'
+        else:
+            return 'text-danger'  # Below red threshold - critical

+ 14 - 0
hr_efficiency/models/res_company.py

@@ -13,3 +13,17 @@ class ResCompany(models.Model):
         help="Porcentaje de overhead de la compañía",
         groups="base.group_system"
     )
+    
+    expected_profitability = fields.Float(
+        'Rentabilidad esperada (%)',
+        default=30.0,
+        help="Porcentaje de rentabilidad esperada de la compañía",
+        groups="base.group_system"
+    )
+    
+    efficiency_factor = fields.Float(
+        'Factor de Eficiencia (%)',
+        default=85.0,
+        help="Porcentaje de horas disponibles que se espera que el empleado trabaje efectivamente",
+        groups="base.group_system"
+    )

+ 42 - 0
hr_efficiency/static/src/css/hr_efficiency.css

@@ -0,0 +1,42 @@
+/* HR Efficiency - Priority Background Colors */
+
+/* Prioridad Alta (Rojo) - Aplicado al TD completo usando :has() */
+.o_list_view .o_data_row .o_data_cell:has(.priority-high-bg) {
+    background-color: #ffebee !important;
+}
+
+/* Prioridad Media (Amarillo) - Aplicado al TD completo usando :has() */
+.o_list_view .o_data_row .o_data_cell:has(.priority-medium-bg) {
+    background-color: #fff8e1 !important;
+}
+
+/* Prioridad Baja (Verde) - Aplicado al TD completo usando :has() */
+.o_list_view .o_data_row .o_data_cell:has(.priority-low-bg) {
+    background-color: #e8f5e8 !important;
+}
+
+/* Aplicar también al encabezado de la columna */
+.o_list_view .o_list_table thead th.priority-high-bg {
+    background-color: #ffebee !important;
+}
+
+.o_list_view .o_list_table thead th.priority-medium-bg {
+    background-color: #fff8e1 !important;
+}
+
+.o_list_view .o_list_table thead th.priority-low-bg {
+    background-color: #e8f5e8 !important;
+}
+
+/* Hover effects para mejor visibilidad */
+.o_list_view .o_data_row:hover .o_data_cell:has(.priority-high-bg) {
+    background-color: #ffcdd2 !important;
+}
+
+.o_list_view .o_data_row:hover .o_data_cell:has(.priority-medium-bg) {
+    background-color: #ffeaa7 !important;
+}
+
+.o_list_view .o_data_row:hover .o_data_cell:has(.priority-low-bg) {
+    background-color: #c8e6c9 !important;
+}

+ 4 - 0
hr_efficiency/views/hr_efficiency_indicator_views.xml

@@ -14,6 +14,8 @@
                 <field name="weight"/>
                 <field name="color_threshold_green"/>
                 <field name="color_threshold_yellow"/>
+                <field name="color_threshold_red"/>
+                <field name="priority"/>
                 <field name="active"/>
             </list>
         </field>
@@ -38,6 +40,8 @@
                             <field name="weight"/>
                             <field name="color_threshold_green"/>
                             <field name="color_threshold_yellow"/>
+                            <field name="color_threshold_red"/>
+                            <field name="priority"/>
                         </group>
                     </group>
                     <group>

+ 4 - 0
hr_efficiency/views/hr_efficiency_views.xml

@@ -12,6 +12,8 @@
                     <field name="wage" sum="Total Gross Salary" optional="show"/>
                     <field name="utilization_rate" avg="Average Utilization" optional="show"/>
                     <field name="overhead" avg="Average Overhead" optional="show"/>
+                    <field name="expected_profitability" avg="Average Expected Profitability" optional="show"/>
+                    <field name="efficiency_factor" avg="Average Efficiency Factor" optional="show"/>
                     <field name="precio_por_hora" avg="Average Precio por Hora" optional="show"/>
                     <field name="company_id" groups="base.group_multi_company" optional="hide"/>
                     <field name="calculation_date" optional="hide"/>
@@ -50,6 +52,8 @@
                                 <field name="wage"/>
                                 <field name="utilization_rate"/>
                                 <field name="overhead"/>
+                                <field name="expected_profitability"/>
+                                <field name="efficiency_factor"/>
                                 <field name="precio_por_hora"/>
                                 <field name="company_id" groups="base.group_multi_company"/>
                                 <field name="calculation_date"/>

+ 2 - 0
hr_efficiency/views/res_company_views.xml

@@ -10,6 +10,8 @@
             <field name="arch" type="xml">
                 <field name="currency_id" position="after">
                     <field name="overhead" groups="base.group_system"/>
+                    <field name="expected_profitability" groups="base.group_system"/>
+                    <field name="efficiency_factor" groups="base.group_system"/>
                 </field>
             </field>
         </record>