CREATE TABLE IF NOT EXISTS mv_hot.odoo_order_state_current ( tenant text NOT NULL, site text NOT NULL, machine_id text NOT NULL, topic text, mqtt_ts timestamptz, received_at timestamptz NOT NULL DEFAULT now(), source text, workcenter_id bigint, workcenter_name text, workcenter_display_name text, order_present boolean, order_coherent boolean, odoo_state text, reason text, workorder_id text, production_order text, product text, waiting_count integer, ready_count integer, progress_count integer, payload_hash text, payload_json jsonb NOT NULL, PRIMARY KEY (tenant, site, machine_id) ); CREATE TABLE IF NOT EXISTS mv_hot.odoo_order_state_events ( id bigserial PRIMARY KEY, tenant text NOT NULL, site text NOT NULL, machine_id text NOT NULL, topic text, mqtt_ts timestamptz, received_at timestamptz NOT NULL DEFAULT now(), odoo_state text, order_present boolean, order_coherent boolean, production_order text, product text, reason text, waiting_count integer, ready_count integer, progress_count integer, payload_hash text NOT NULL, payload_json jsonb NOT NULL ); CREATE UNIQUE INDEX IF NOT EXISTS ux_odoo_order_state_events_state_hash ON mv_hot.odoo_order_state_events (tenant, site, machine_id, payload_hash); DROP VIEW IF EXISTS mv_reports_ucepsa_demo.odoo_order_state_machine_grafana; CREATE VIEW mv_reports_ucepsa_demo.odoo_order_state_machine_grafana AS SELECT COALESCE(m.machine_id, o.machine_id) AS machine_id, o.received_at AS odoo_state_received_at, o.mqtt_ts AS odoo_state_ts, EXTRACT(EPOCH FROM (now() - o.received_at))::double precision AS order_age_s, o.workcenter_id, o.workcenter_name, o.workcenter_display_name, o.production_order AS order_ref, o.product AS product_name, o.odoo_state, o.order_present, o.order_coherent, o.reason, o.waiting_count, o.ready_count, o.progress_count, m.ingest_ts AS telemetry_ingest_ts, m.age_s AS telemetry_age_s, m.comm_ok, m.sample_valid, m.machine_running, m.cycle_rate_ppm, m.cycle_pulse_count, m.digital_inputs, CASE WHEN o.machine_id IS NULL THEN 'SIN_ESTADO_ODOO' WHEN EXTRACT(EPOCH FROM (now() - o.received_at)) > 30 THEN 'ODOO_STATE_ANTIGUO' WHEN o.odoo_state = 'multiple_loaded_orders' THEN 'MULTIPLES_ORDENES_EN_PROGRESS' WHEN o.order_present = true AND o.order_coherent = true AND COALESCE(m.machine_running, false) = true THEN 'ORDEN_CARGADA_MAQUINA_EN_MARCHA' WHEN o.order_present = true AND o.order_coherent = true AND COALESCE(m.machine_running, false) = false THEN 'ORDEN_CARGADA_MAQUINA_PARADA' WHEN COALESCE(o.order_present, false) = false AND COALESCE(m.machine_running, false) = true THEN 'MAQUINA_EN_MARCHA_SIN_ORDEN_ODOO' WHEN COALESCE(o.order_present, false) = false AND COALESCE(m.machine_running, false) = false THEN 'SIN_ORDEN_MAQUINA_PARADA' ELSE 'REVISAR' END AS edge_odoo_status, o.payload_json AS odoo_payload_json FROM mv_reports_ucepsa_demo.machine_state_latest_multi m FULL OUTER JOIN mv_hot.odoo_order_state_current o ON o.tenant = 'ucepsa' AND o.site = 'ucepsa_onpremise' AND o.machine_id = m.machine_id WHERE COALESCE(m.site, o.site) = 'ucepsa_onpremise'; GRANT SELECT ON mv_hot.odoo_order_state_current TO grafana_ucepsa_ro; GRANT SELECT ON mv_hot.odoo_order_state_events TO grafana_ucepsa_ro; GRANT SELECT ON mv_reports_ucepsa_demo.odoo_order_state_machine_grafana TO grafana_ucepsa_ro;