From 8bc9c73f28de56d548c150e4fd669937effe5ab8 Mon Sep 17 00:00:00 2001 From: Victor Fraile Garcia Date: Wed, 27 May 2026 13:29:57 +0200 Subject: [PATCH] fix(ucepsa): recreate Odoo reporting views for local sync --- ..._fix_odoo_reporting_views_ucepsa_local.sql | 168 ++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 ucepsa/edge-oee-demo/sql/064_fix_odoo_reporting_views_ucepsa_local.sql diff --git a/ucepsa/edge-oee-demo/sql/064_fix_odoo_reporting_views_ucepsa_local.sql b/ucepsa/edge-oee-demo/sql/064_fix_odoo_reporting_views_ucepsa_local.sql new file mode 100644 index 0000000..77c3385 --- /dev/null +++ b/ucepsa/edge-oee-demo/sql/064_fix_odoo_reporting_views_ucepsa_local.sql @@ -0,0 +1,168 @@ +DROP VIEW IF EXISTS mv_reports_ucepsa_demo.odoo_discrepancies_demo; +DROP VIEW IF EXISTS mv_reports_ucepsa_demo.odoo_vs_machine_demo; +DROP VIEW IF EXISTS mv_reports_ucepsa_demo.odoo_current_order_demo; + +CREATE VIEW mv_reports_ucepsa_demo.odoo_current_order_demo AS +WITH latest AS ( + SELECT + w.*, + row_number() OVER ( + PARTITION BY w.odoo_instance, w.odoo_workorder_id + ORDER BY w.snapshot_at DESC + ) AS rn + FROM mv_edge_oee_ucepsa_demo.odoo_workorders_demo w + WHERE w.odoo_instance = 'odoo_ucepsa_test' + AND w.machine_id = 'CORT-01' +), +candidates AS ( + SELECT * + FROM latest + WHERE rn = 1 + AND COALESCE(odoo_state, '') NOT IN ('done', 'cancel', 'cancelled') +) +SELECT + id, + tenant, + site, + odoo_instance, + odoo_workorder_id, + odoo_production_id, + odoo_order_ref, + odoo_state, + odoo_workcenter_code, + odoo_workcenter_name, + machine_id, + asset, + product, + qty_planned, + qty_done, + uom, + planned_cycles, + target_cycle_rate_ppm, + odoo_start, + odoo_start AS odoo_reference_start, + CASE + WHEN odoo_state IN ('progress', 'in_progress', 'done') THEN true + ELSE false + END AS odoo_is_started, + odoo_end, + notes, + snapshot_at +FROM candidates +ORDER BY + CASE + WHEN odoo_state IN ('progress', 'in_progress') THEN 1 + WHEN odoo_state = 'ready' THEN 2 + WHEN odoo_state IN ('waiting', 'pending', 'confirmed', 'planned') THEN 3 + ELSE 9 + END, + COALESCE(odoo_start, snapshot_at) DESC +LIMIT 1; + +CREATE VIEW mv_reports_ucepsa_demo.odoo_vs_machine_demo AS +WITH odoo AS ( + SELECT * + FROM mv_reports_ucepsa_demo.odoo_current_order_demo +), +machine AS ( + SELECT * + FROM mv_reports_ucepsa_demo.latest_machine_state_fast + WHERE machine_id = 'CORT-01' + ORDER BY ingest_ts DESC + LIMIT 1 +), +machine_activity AS ( + SELECT + MIN(r.ingest_ts) AS first_machine_activity + FROM mv_hot.edge_oee_eastron_readings r + WHERE r.machine_id = 'CORT-01' + AND (r.payload_json ->> 'machine_running')::boolean = true +), +stops AS ( + SELECT + COUNT(*)::int AS stop_count, + COALESCE(ROUND(SUM(duration_min)::numeric, 2), 0) AS stop_min, + COALESCE(ROUND(SUM(cost_eur)::numeric, 2), 0) AS stop_cost_eur + FROM mv_reports_ucepsa_demo.stops_recent + WHERE machine_id = 'CORT-01' +) +SELECT + o.odoo_workorder_id, + o.odoo_production_id, + o.odoo_order_ref, + o.odoo_state, + o.odoo_is_started, + o.product, + o.machine_id, + o.asset, + o.odoo_start, + o.odoo_reference_start, + o.odoo_end, + COALESCE(m.machine_running, false) AS machine_running, + m.age_s AS telemetry_age_s, + COALESCE(m.cycle_pulse_count, 0) AS cycle_pulse_count, + COALESCE(m.cycle_rate_ppm, 0) AS cycle_rate_ppm, + ma.first_machine_activity, + CASE + WHEN o.odoo_is_started = true + AND ma.first_machine_activity IS NOT NULL + AND o.odoo_reference_start IS NOT NULL + THEN ROUND(EXTRACT(EPOCH FROM (ma.first_machine_activity - o.odoo_reference_start))::numeric / 60.0, 2) + ELSE NULL::numeric + END AS start_delay_min, + s.stop_count, + s.stop_min, + s.stop_cost_eur, + COALESCE(m.cycle_pulse_count, 0)::numeric AS real_cycles, + COALESCE(o.planned_cycles, o.qty_planned, 0)::numeric AS planned_cycles, + CASE + WHEN COALESCE(o.planned_cycles, o.qty_planned, 0) > 0 + THEN ROUND( + ( + COALESCE(m.cycle_pulse_count, 0)::numeric + / COALESCE(o.planned_cycles, o.qty_planned, 0)::numeric + ) * 100, + 2 + ) + ELSE 0::numeric + END AS cycle_completion_pct, + CASE + WHEN m.age_s IS NULL OR m.age_s > 120 THEN 'SIN_TELEMETRIA' + WHEN o.odoo_state = 'ready' AND COALESCE(m.machine_running, false) = true THEN 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA' + WHEN o.odoo_state = 'ready' AND COALESCE(m.machine_running, false) = false THEN 'ORDEN_PREPARADA_MAQUINA_PARADA' + WHEN o.odoo_state IN ('progress', 'in_progress') AND COALESCE(m.machine_running, false) = false THEN 'ORDEN_EN_CURSO_MAQUINA_PARADA' + ELSE 'OK' + END AS status_check +FROM odoo o +CROSS JOIN machine m +CROSS JOIN machine_activity ma +CROSS JOIN stops s; + +CREATE VIEW mv_reports_ucepsa_demo.odoo_discrepancies_demo AS +SELECT + now() AS checked_at, + odoo_order_ref, + product, + machine_id, + status_check, + CASE + WHEN status_check = 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA' + THEN 'La máquina está en marcha, pero la orden de Odoo está preparada o en espera, no iniciada.' + WHEN status_check = 'ORDEN_PREPARADA_MAQUINA_PARADA' + THEN 'La orden está preparada/en espera y la máquina está parada. No hay desviación productiva activa.' + WHEN status_check = 'ORDEN_EN_CURSO_MAQUINA_PARADA' + THEN 'La orden está en curso en Odoo, pero la máquina está parada.' + WHEN status_check = 'SIN_TELEMETRIA' + THEN 'No hay telemetría reciente de máquina.' + ELSE 'Sin discrepancia relevante.' + END AS descripcion, + start_delay_min, + stop_count, + stop_min, + stop_cost_eur, + cycle_completion_pct +FROM mv_reports_ucepsa_demo.odoo_vs_machine_demo; + +GRANT SELECT ON mv_reports_ucepsa_demo.odoo_current_order_demo TO grafana_ucepsa_ro; +GRANT SELECT ON mv_reports_ucepsa_demo.odoo_vs_machine_demo TO grafana_ucepsa_ro; +GRANT SELECT ON mv_reports_ucepsa_demo.odoo_discrepancies_demo TO grafana_ucepsa_ro;