hr_employee (emp)emp.nameemp.id = ep.employee_id (LEFT JOIN)Complete field-level reference for the PostgreSQL view mrp_19_emp_res_eff โ every output column, its Odoo source table and CTE, and all calculated formulas explained with technical field names and SQL logic. Covers Employee KPIs, Workcenter KPIs, and OEE calculations.
4 Common Table Expressions that pre-aggregate data before the main SELECT
Aggregates actual working minutes per employee per workorder from the workcenter productivity log. Captures the resource calendar the employee was working under.
Counts the number of distinct employees who logged time on each workorder. Used to split planned_runtime proportionally across employees.
Aggregates finished product outputs (estimated_units, net_weight, lot names) from stock move lines. Resolves workorder_id from both stock_move and mrp_output_log to handle cases where workorder_id on the move is NULL.
Aggregates quantity and weight produced per employee per workorder directly from the output log (only 'done' state entries). Provides the employee-level production figures.
All PostgreSQL / Odoo tables referenced in the view
What does one row represent?
INNER JOIN employee_productivity ep ON ep.workorder_id = wo.id.
This means only workorders that have at least one employee productivity log entry appear.
Each unique (employee, workorder) pair produces one row.ROW_NUMBER() OVER (PARTITION BY wo.id ORDER BY ep.employee_id) = 1 guards so that SUM in Power BI does not double-count machine-level metrics across multiple employees on the same WO.
Identification and slicing fields โ direct column reads
hr_employee (emp)emp.nameemp.id = ep.employee_id (LEFT JOIN)mrp_workorder (wo)wo.namework_order in the workcenter section.mrp_production (mp)mp.namemp.id = wo.production_id (LEFT JOIN)WH/MO/00214). Exposed twice โ as mo_name for employee section and manufacturing_order for workcenter section.mrp_workcenter (wc)wc.namewc.id = wo.workcenter_id (LEFT JOIN)product_product โ product_templateCOALESCE(wo_output.product_id, mp.product_id)workorder_output CTE), falling back to the MO-level finished product. Exposed twice for filtering flexibility.pp.province_code โ custom field on product_productproduct_format (pf) โ custom tablept.product_format_id = pf.id (LEFT JOIN)product_template โ product_category โ src_type / src_categoryst.name, sc.nameworkorder_outputmp.create_dateOne value per employee per workorder โ no dedup guard needed
employee_output (alias: eo)mrp_output_logemployee_output (alias: eo)employee_productivity (alias: ep)mrp_workorder (wo)wo.duration_expectedmrp_workorder (wo)wo.total_actual_workcenter_timeresource_calendar (alias: rc_emp)rc_emp.hours_per_dayMachine-level KPIs โ protected by ROW_NUMBER() dedup guard to prevent double-counting across employees
ep.employee_id) in each workorder partition, and 0.0 for all subsequent employees. This ensures Power BI SUM gives the correct per-workorder total even when multiple employees share one WO.workorder_output (alias: wo_output)wo.total_actual_workcenter_timeresource_calendar (alias: rc_wc)rc_wc.id = wc.resource_calendar_idOEE = Availability ร Performance ร Quality
mrp_routing_workcenter (rw)rw.time_cycle_manualrw.id = wo.operation_id (LEFT JOIN)All 34 output columns at a glance
| # | Alias | Type | Section | Source / Formula Summary |
|---|---|---|---|---|
| 1 | employee_name | VARCHAR | Dimension | emp.name (hr_employee) |
| 2 | workorder_name | VARCHAR | Dimension | wo.name (mrp_workorder) |
| 3 | mo_name | VARCHAR | Dimension | mp.name (mrp_production) |
| 4 | workcenter_name | VARCHAR | Dimension | wc.name (mrp_workcenter) |
| 5 | product_name | VARCHAR | Dimension / Calc | pt.name->>'en_US' โ product resolved via COALESCE(wo_output.product_id, mp.product_id) |
| 6 | province_code | VARCHAR | Filter | pp.province_code (custom) |
| 7 | product_format | VARCHAR | Filter | pf.name (custom table) |
| 8 | src_type | VARCHAR | Filter | st.name (custom via product_category) |
| 9 | src_category | VARCHAR | Filter | sc.name (custom via product_category) |
| 10 | lot_name | VARCHAR | Filter / Calc | STRING_AGG(DISTINCT COALESCE(sml.lot_name, lot.name), ', ') โ from CTE 3 |
| 11 | mo_creation_date | TIMESTAMPTZ | Filter | mp.create_date |
| 12 | quantity_produced | NUMERIC | Employee KPI | COALESCE(eo.quantity_produced, 0) โ from CTE 4 (done output logs) |
| 13 | weight_produced | NUMERIC | Employee KPI | COALESCE(eo.weight_produced, 0) โ from CTE 4 |
| 14 | employee_working_minutes | NUMERIC | Employee KPI | ep.employee_working_minutes โ SUM(wp.duration) from CTE 1 |
| 15 | employee_working_hours | NUMERIC | Employee KPI | ep.employee_working_minutes / 60.0 |
| 16 | units_per_employee_per_hour | NUMERIC | Employee KPI | CASE: quantity_produced / (emp_minutes/60) ELSE NULL |
| 17 | standard_time | NUMERIC | Employee KPI | wo.duration_expected (minutes) |
| 18 | actual_time | NUMERIC | Employee KPI | wo.total_actual_workcenter_time (minutes) |
| 19 | employee_efficiency_pct | NUMERIC | Employee KPI | CASE: (duration_expected / emp_working_minutes) ร 100 ELSE NULL |
| 20 | total_available_labour_time | NUMERIC | Employee KPI | rc_emp.hours_per_day โ COALESCE(ep.calendar, res.calendar, wc.calendar) |
| 21 | labour_utilization_pct | NUMERIC | Employee KPI | CASE: (emp_hours / rc_emp.hours_per_day) ร 100 ELSE NULL |
| 22 | attendance_to_output_ratio | NUMERIC | Employee KPI | COALESCE(quantity_produced, 0) / 6.0 |
| 23 | workcenter | VARCHAR | WC Dimension | wc.name (duplicate alias) |
| 24 | manufacturing_order | VARCHAR | WC Dimension | mp.name (duplicate alias) |
| 25 | work_order | VARCHAR | WC Dimension | wo.name (duplicate alias) |
| 26 | product | VARCHAR | WC Dimension | pt.name->>'en_US' (duplicate alias) |
| 27 | workcenter_quantity_produced | NUMERIC | WC KPI | CASE ROW=1: wo_output.estimated_units ELSE 0 โ ROW_NUMBER dedup guard |
| 28 | runtime_minutes | NUMERIC | WC KPI | CASE ROW=1: wo.total_actual_workcenter_time ELSE 0 โ ROW_NUMBER guard |
| 29 | planned_runtime | NUMERIC | WC KPI | CASE: duration_expected / wec.employee_count ELSE 0 |
| 30 | workcenter_efficiency_pct | NUMERIC | WC KPI | CASE ROW=1 AND actual>0: (duration_expected/actual_time)ร100 ELSE 0 |
| 31 | units_per_minute | NUMERIC | WC KPI | CASE ROW=1 AND actual>0: estimated_units/actual_time ELSE 0 |
| 32 | units_per_hour | NUMERIC | WC KPI | CASE ROW=1 AND actual>0: estimated_units/(actual_time/60) ELSE 0 |
| 33 | total_available_machine_time | NUMERIC | WC KPI | CASE ROW=1: rc_wc.hours_per_day ELSE 0 |
| 34 | machine_utilization_pct | NUMERIC | WC KPI | CASE ROW=1 AND cal>0: (actual_hours/rc_wc.hours_per_day)ร100 ELSE 0 |
| 35 | ideal_cycle_time | NUMERIC | OEE | COALESCE(rw.time_cycle_manual, 0) โ mrp_routing_workcenter |
| 36 | availability_pct | NUMERIC | OEE | CASE: (actual_time/duration_expected)ร100 ELSE 100 |
| 37 | performance_pct | NUMERIC | OEE | CASE: (ideal_cycle_time ร qty / actual_time)ร100 ELSE 100 |
| 38 | quality_pct | NUMERIC | OEE | CASE: (units/units)ร100 = 100% always (no defect data yet) |
| 39 | oee_pct | NUMERIC | OEE | Availability_ratio ร Performance_ratio ร Quality_ratio ร 100 |