--
-- PostgreSQL database dump
--

\restrict 1wX0I2K6nLSszbhqDMaBaJRF13jG1hT3a3HKImFGiykK1wx4riB6Rf5OY4lcf06

-- Dumped from database version 16.14
-- Dumped by pg_dump version 16.14

SET statement_timeout = 0;
SET lock_timeout = 0;
SET idle_in_transaction_session_timeout = 0;
SET client_encoding = 'UTF8';
SET standard_conforming_strings = on;
SELECT pg_catalog.set_config('search_path', '', false);
SET check_function_bodies = false;
SET xmloption = content;
SET client_min_messages = warning;
SET row_security = off;

--
-- Name: mv_edge_oee_ucepsa_demo; Type: SCHEMA; Schema: -; Owner: mesavault
--

CREATE SCHEMA mv_edge_oee_ucepsa_demo;


ALTER SCHEMA mv_edge_oee_ucepsa_demo OWNER TO mesavault;

--
-- Name: SCHEMA mv_edge_oee_ucepsa_demo; Type: COMMENT; Schema: -; Owner: mesavault
--

COMMENT ON SCHEMA mv_edge_oee_ucepsa_demo IS 'Capa normalizada de la demo Edge-OEE UCEPSA. Inicialmente contiene vistas puente hacia mv_hot.';


--
-- Name: mv_edge_oee_ucepsa_prod; Type: SCHEMA; Schema: -; Owner: mesavault
--

CREATE SCHEMA mv_edge_oee_ucepsa_prod;


ALTER SCHEMA mv_edge_oee_ucepsa_prod OWNER TO mesavault;

--
-- Name: mv_hot; Type: SCHEMA; Schema: -; Owner: mesavault
--

CREATE SCHEMA mv_hot;


ALTER SCHEMA mv_hot OWNER TO mesavault;

--
-- Name: mv_reports_ucepsa_demo; Type: SCHEMA; Schema: -; Owner: mesavault
--

CREATE SCHEMA mv_reports_ucepsa_demo;


ALTER SCHEMA mv_reports_ucepsa_demo OWNER TO mesavault;

--
-- Name: SCHEMA mv_reports_ucepsa_demo; Type: COMMENT; Schema: -; Owner: mesavault
--

COMMENT ON SCHEMA mv_reports_ucepsa_demo IS 'Capa de reporting para Grafana UCEPSA demo. Grafana debe consultar preferentemente este schema.';


--
-- Name: mv_reports_ucepsa_prod; Type: SCHEMA; Schema: -; Owner: mesavault
--

CREATE SCHEMA mv_reports_ucepsa_prod;


ALTER SCHEMA mv_reports_ucepsa_prod OWNER TO mesavault;

--
-- Name: oee_kpis(timestamp with time zone, timestamp with time zone, text, text); Type: FUNCTION; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE FUNCTION mv_reports_ucepsa_demo.oee_kpis(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text DEFAULT 'CORT-01'::text, p_asset text DEFAULT 'revpi_oee_node_01'::text) RETURNS TABLE(oee_pct numeric, availability_pct numeric, performance_pct numeric, quality_pct numeric)
    LANGUAGE sql STABLE
    AS $$
WITH dashboard_bounds AS (
    SELECT
        p_from AS dashboard_from,
        LEAST(p_to, now()) AS dashboard_to
),
telemetry_span AS (
    SELECT
        MIN(ingest_ts) AS first_ts,
        MAX(ingest_ts) AS last_ts
    FROM mv_hot.edge_oee_live_telemetry
    WHERE asset = p_asset
      AND ingest_ts >= (SELECT dashboard_from FROM dashboard_bounds)
      AND ingest_ts <= (SELECT dashboard_to FROM dashboard_bounds)
),
bounds AS (
    SELECT
        CASE
            WHEN first_ts IS NULL THEN dashboard_from
            ELSE GREATEST(dashboard_from, first_ts)
        END AS t_from,
        CASE
            WHEN last_ts IS NULL THEN dashboard_to
            ELSE LEAST(dashboard_to, last_ts)
        END AS t_to
    FROM dashboard_bounds
    CROSS JOIN telemetry_span
),
target AS (
    SELECT
        COALESCE((
            SELECT mt.target_cycle_rate_ppm
            FROM mv_hot.edge_oee_machine_targets mt
            WHERE mt.machine_id = p_machine_id
            LIMIT 1
        ), 10.00)::numeric AS target_cycle_rate_ppm,

        COALESCE((
            SELECT mt.quality_pct_default
            FROM mv_hot.edge_oee_machine_targets mt
            WHERE mt.machine_id = p_machine_id
            LIMIT 1
        ), 100.00)::numeric AS quality_pct_default
),
planned AS (
    SELECT
        GREATEST(EXTRACT(EPOCH FROM (t_to - t_from))::numeric, 0) AS planned_s
    FROM bounds
),
stops AS (
    SELECT
        COALESCE(
            SUM(
                GREATEST(
                    EXTRACT(EPOCH FROM (
                        LEAST(COALESCE(s.ended_at, b.t_to), b.t_to)
                        -
                        GREATEST(
                            CASE
                                WHEN s.started_at > s.created_at + interval '5 seconds'
                                    THEN s.created_at
                                ELSE s.started_at
                            END,
                            b.t_from
                        )
                    ))::numeric,
                    0
                )
            ) FILTER (
                WHERE s.started_at < b.t_to
                  AND COALESCE(s.ended_at, now()) > b.t_from
            ),
            0
        )::numeric AS stop_s
    FROM mv_hot.edge_oee_machine_stops s
    CROSS JOIN bounds b
    WHERE s.machine_id = p_machine_id
),
cycles AS (
    SELECT
        COALESCE(
            GREATEST(
                MAX(cycle_pulse_count) - MIN(cycle_pulse_count),
                0
            ),
            0
        )::numeric AS actual_cycles
    FROM mv_hot.edge_oee_live_telemetry l
    CROSS JOIN bounds b
    WHERE l.asset = p_asset
      AND l.ingest_ts >= b.t_from
      AND l.ingest_ts <= b.t_to
      AND l.cycle_pulse_count IS NOT NULL
),
calc AS (
    SELECT
        p.planned_s,
        st.stop_s,
        GREATEST(p.planned_s - st.stop_s, 0)::numeric AS running_s,
        c.actual_cycles,
        t.target_cycle_rate_ppm,
        t.quality_pct_default,

        CASE
            WHEN p.planned_s > 0
            THEN ROUND(((GREATEST(p.planned_s - st.stop_s, 0) / p.planned_s) * 100)::numeric, 2)
            ELSE 0
        END AS availability_pct,

        CASE
            WHEN GREATEST(p.planned_s - st.stop_s, 0) > 0
             AND t.target_cycle_rate_ppm > 0
            THEN ROUND(
                LEAST(
                    100::numeric,
                    (
                        c.actual_cycles
                        /
                        NULLIF(
                            t.target_cycle_rate_ppm * (GREATEST(p.planned_s - st.stop_s, 0) / 60.0),
                            0
                        )
                    ) * 100
                )::numeric,
                2
            )
            ELSE 0
        END AS performance_pct,

        t.quality_pct_default AS quality_pct
    FROM planned p
    CROSS JOIN stops st
    CROSS JOIN cycles c
    CROSS JOIN target t
)
SELECT
    ROUND(((calc.availability_pct * calc.performance_pct * calc.quality_pct) / 10000.0)::numeric, 2) AS oee_pct,
    calc.availability_pct,
    calc.performance_pct,
    calc.quality_pct
FROM calc;
$$;


ALTER FUNCTION mv_reports_ucepsa_demo.oee_kpis(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text) OWNER TO mesavault;

--
-- Name: oee_operational_data(timestamp with time zone, timestamp with time zone, text, text); Type: FUNCTION; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE FUNCTION mv_reports_ucepsa_demo.oee_operational_data(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text DEFAULT 'CORT-01'::text, p_asset text DEFAULT 'revpi_oee_node_01'::text) RETURNS TABLE(running_min numeric, stop_min numeric, actual_cycles numeric)
    LANGUAGE sql STABLE
    AS $$
WITH dashboard_bounds AS (
    SELECT
        p_from AS dashboard_from,
        LEAST(p_to, now()) AS dashboard_to
),
telemetry_span AS (
    SELECT
        MIN(ingest_ts) AS first_ts,
        MAX(ingest_ts) AS last_ts
    FROM mv_hot.edge_oee_live_telemetry
    WHERE asset = p_asset
      AND ingest_ts >= (SELECT dashboard_from FROM dashboard_bounds)
      AND ingest_ts <= (SELECT dashboard_to FROM dashboard_bounds)
),
bounds AS (
    SELECT
        CASE
            WHEN first_ts IS NULL THEN dashboard_from
            ELSE GREATEST(dashboard_from, first_ts)
        END AS t_from,
        CASE
            WHEN last_ts IS NULL THEN dashboard_to
            ELSE LEAST(dashboard_to, last_ts)
        END AS t_to
    FROM dashboard_bounds
    CROSS JOIN telemetry_span
),
planned AS (
    SELECT
        GREATEST(EXTRACT(EPOCH FROM (t_to - t_from))::numeric, 0) AS planned_s
    FROM bounds
),
stops AS (
    SELECT
        COALESCE(
            SUM(
                GREATEST(
                    EXTRACT(EPOCH FROM (
                        LEAST(COALESCE(s.ended_at, b.t_to), b.t_to)
                        -
                        GREATEST(
                            CASE
                                WHEN s.started_at > s.created_at + interval '5 seconds'
                                    THEN s.created_at
                                ELSE s.started_at
                            END,
                            b.t_from
                        )
                    ))::numeric,
                    0
                )
            ) FILTER (
                WHERE s.started_at < b.t_to
                  AND COALESCE(s.ended_at, now()) > b.t_from
            ),
            0
        )::numeric AS stop_s
    FROM mv_hot.edge_oee_machine_stops s
    CROSS JOIN bounds b
    WHERE s.machine_id = p_machine_id
),
cycles AS (
    SELECT
        COALESCE(
            GREATEST(
                MAX(cycle_pulse_count) - MIN(cycle_pulse_count),
                0
            ),
            0
        )::numeric AS actual_cycles
    FROM mv_hot.edge_oee_live_telemetry l
    CROSS JOIN bounds b
    WHERE l.asset = p_asset
      AND l.ingest_ts >= b.t_from
      AND l.ingest_ts <= b.t_to
      AND l.cycle_pulse_count IS NOT NULL
),
calc AS (
    SELECT
        p.planned_s,
        st.stop_s,
        GREATEST(p.planned_s - st.stop_s, 0)::numeric AS running_s,
        c.actual_cycles
    FROM planned p
    CROSS JOIN stops st
    CROSS JOIN cycles c
)
SELECT
    ROUND((running_s / 60.0)::numeric, 2) AS running_min,
    ROUND((stop_s / 60.0)::numeric, 2) AS stop_min,
    actual_cycles
FROM calc;
$$;


ALTER FUNCTION mv_reports_ucepsa_demo.oee_operational_data(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text) OWNER TO mesavault;

SET default_tablespace = '';

SET default_table_access_method = heap;

--
-- Name: data_quality_contract_rules; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.data_quality_contract_rules (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    rule_code text NOT NULL,
    rule_name text NOT NULL,
    domain text NOT NULL,
    dimension text NOT NULL,
    severity text NOT NULL,
    owner_area text NOT NULL,
    applies_to text NOT NULL,
    description text NOT NULL,
    expected_condition text NOT NULL,
    blocking_for text,
    is_active boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.data_quality_contract_rules OWNER TO mesavault;

--
-- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq OWNER TO mesavault;

--
-- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq OWNED BY mv_edge_oee_ucepsa_demo.data_quality_contract_rules.id;


--
-- Name: edge_oee_eastron_readings; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_eastron_readings (
    id bigint NOT NULL,
    ts timestamp with time zone DEFAULT now() NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    asset text DEFAULT 'revpi_eastron_demo'::text NOT NULL,
    source text DEFAULT 'eastron_reader'::text NOT NULL,
    meter_model text,
    meter_id text,
    machine_id text,
    order_id text,
    voltage_l1_v numeric(10,3),
    voltage_l2_v numeric(10,3),
    voltage_l3_v numeric(10,3),
    current_l1_a numeric(10,3),
    current_l2_a numeric(10,3),
    current_l3_a numeric(10,3),
    power_l1_kw numeric(10,3),
    power_l2_kw numeric(10,3),
    power_l3_kw numeric(10,3),
    power_total_kw numeric(10,3),
    frequency_hz numeric(10,3),
    import_kwh numeric(14,3),
    export_kwh numeric(14,3),
    comm_ok boolean DEFAULT true NOT NULL,
    error_text text,
    payload_json jsonb DEFAULT '{}'::jsonb NOT NULL,
    ingest_ts timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_hot.edge_oee_eastron_readings OWNER TO mesavault;

--
-- Name: edge_oee_eastron_latest; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_eastron_latest AS
 SELECT DISTINCT ON (asset) id,
    ts,
    tenant,
    site,
    asset,
    source,
    meter_model,
    meter_id,
    machine_id,
    order_id,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    power_l1_kw,
    power_l2_kw,
    power_l3_kw,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    payload_json,
    ingest_ts
   FROM mv_hot.edge_oee_eastron_readings
  ORDER BY asset, ingest_ts DESC;


ALTER VIEW mv_hot.edge_oee_eastron_latest OWNER TO mesavault;

--
-- Name: edge_oee_eastron_dashboard; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_eastron_dashboard AS
 SELECT ts,
    ingest_ts,
    GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) AS age_s,
    tenant,
    site,
    asset,
    meter_model,
    meter_id,
    machine_id,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
        CASE
            WHEN (comm_ok = false) THEN 2
            WHEN (GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) > 180) THEN 2
            WHEN (GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) > 60) THEN 1
            ELSE 0
        END AS comm_risk_level,
        CASE
            WHEN (comm_ok = false) THEN 'Sin comunicación Modbus'::text
            WHEN (GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) > 180) THEN 'Lectura antigua'::text
            WHEN (GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) > 60) THEN 'Lectura no reciente'::text
            ELSE 'Comunicación correcta'::text
        END AS comm_status
   FROM mv_hot.edge_oee_eastron_latest;


ALTER VIEW mv_hot.edge_oee_eastron_dashboard OWNER TO mesavault;

--
-- Name: eastron_dashboard; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.eastron_dashboard AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    meter_model,
    meter_id,
    machine_id,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    comm_risk_level,
    comm_status
   FROM mv_hot.edge_oee_eastron_dashboard;


ALTER VIEW mv_edge_oee_ucepsa_demo.eastron_dashboard OWNER TO mesavault;

--
-- Name: edge_oee_eastron_diagnosis_latest; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_eastron_diagnosis_latest AS
 SELECT 1 AS sort_order,
    'Comunicación'::text AS group_name,
    'Edad último dato'::text AS metric,
    (edge_oee_eastron_dashboard.age_s)::numeric AS value,
    's'::text AS unit,
        CASE
            WHEN (edge_oee_eastron_dashboard.comm_risk_level = 0) THEN 'OK'::text
            WHEN (edge_oee_eastron_dashboard.comm_risk_level = 1) THEN 'Warning'::text
            ELSE 'Peligro'::text
        END AS status,
        CASE
            WHEN (edge_oee_eastron_dashboard.comm_risk_level = 0) THEN 'Lectura reciente recibida por PostgreSQL'::text
            ELSE 'La lectura no es reciente o hay fallo de comunicación'::text
        END AS problem,
        CASE
            WHEN (edge_oee_eastron_dashboard.comm_risk_level = 0) THEN 'La captura industrial está viva'::text
            ELSE 'El dashboard puede estar mostrando un valor antiguo'::text
        END AS likely_impact,
        CASE
            WHEN (edge_oee_eastron_dashboard.comm_risk_level = 0) THEN 'Sin acción'::text
            ELSE 'Revisar RevPi, MQTT, sink, RS-485, SDM120-M y logs'::text
        END AS recommended_action
   FROM mv_hot.edge_oee_eastron_dashboard
UNION ALL
 SELECT 2 AS sort_order,
    'Energía'::text AS group_name,
    'Potencia total'::text AS metric,
    edge_oee_eastron_dashboard.power_total_kw AS value,
    'kW'::text AS unit,
        CASE
            WHEN (edge_oee_eastron_dashboard.power_total_kw IS NULL) THEN 'Warning'::text
            ELSE 'OK'::text
        END AS status,
        CASE
            WHEN (edge_oee_eastron_dashboard.power_total_kw IS NULL) THEN 'No hay potencia total disponible'::text
            ELSE 'Potencia total leída correctamente'::text
        END AS problem,
        CASE
            WHEN (edge_oee_eastron_dashboard.power_total_kw IS NULL) THEN 'No se puede validar carga eléctrica'::text
            ELSE 'Permite demostrar captura energética industrial'::text
        END AS likely_impact,
        CASE
            WHEN (edge_oee_eastron_dashboard.power_total_kw IS NULL) THEN 'Revisar mapa de registros Modbus'::text
            ELSE 'Sin acción'::text
        END AS recommended_action
   FROM mv_hot.edge_oee_eastron_dashboard;


ALTER VIEW mv_hot.edge_oee_eastron_diagnosis_latest OWNER TO mesavault;

--
-- Name: eastron_diagnosis_latest; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.eastron_diagnosis_latest AS
 SELECT sort_order,
    group_name,
    metric,
    value,
    unit,
    status,
    problem,
    likely_impact,
    recommended_action
   FROM mv_hot.edge_oee_eastron_diagnosis_latest;


ALTER VIEW mv_edge_oee_ucepsa_demo.eastron_diagnosis_latest OWNER TO mesavault;

--
-- Name: eastron_latest; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.eastron_latest AS
 SELECT id,
    ts,
    tenant,
    site,
    asset,
    source,
    meter_model,
    meter_id,
    machine_id,
    order_id,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    power_l1_kw,
    power_l2_kw,
    power_l3_kw,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    payload_json,
    ingest_ts
   FROM mv_hot.edge_oee_eastron_latest;


ALTER VIEW mv_edge_oee_ucepsa_demo.eastron_latest OWNER TO mesavault;

--
-- Name: eastron_readings; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.eastron_readings AS
 SELECT id,
    ts,
    tenant,
    site,
    asset,
    source,
    meter_model,
    meter_id,
    machine_id,
    order_id,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    power_l1_kw,
    power_l2_kw,
    power_l3_kw,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    payload_json,
    ingest_ts
   FROM mv_hot.edge_oee_eastron_readings;


ALTER VIEW mv_edge_oee_ucepsa_demo.eastron_readings OWNER TO mesavault;

--
-- Name: edge_oee_live_telemetry; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_live_telemetry AS
 SELECT ts,
    ingest_ts,
    GREATEST((EXTRACT(epoch FROM (now() - ingest_ts)))::integer, 0) AS age_s,
    tenant,
    site,
    asset,
    COALESCE(machine_id, (payload_json ->> 'machine_id'::text)) AS machine_id,
    COALESCE(order_id, (payload_json ->> 'order_id'::text)) AS order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
        CASE
            WHEN (payload_json ? 'machine_auto_signal'::text) THEN ((payload_json ->> 'machine_auto_signal'::text))::boolean
            ELSE NULL::boolean
        END AS machine_auto_signal,
        CASE
            WHEN (payload_json ? 'machine_running'::text) THEN ((payload_json ->> 'machine_running'::text))::boolean
            ELSE NULL::boolean
        END AS machine_running,
        CASE
            WHEN (payload_json ? 'cycle_pulse_count'::text) THEN ((payload_json ->> 'cycle_pulse_count'::text))::bigint
            ELSE NULL::bigint
        END AS cycle_pulse_count,
        CASE
            WHEN (payload_json ? 'cycle_rate_ppm'::text) THEN ((payload_json ->> 'cycle_rate_ppm'::text))::numeric
            ELSE NULL::numeric
        END AS cycle_rate_ppm,
        CASE
            WHEN ((payload_json ? 'last_cycle_age_s'::text) AND ((payload_json ->> 'last_cycle_age_s'::text) IS NOT NULL) AND ((payload_json ->> 'last_cycle_age_s'::text) <> 'null'::text)) THEN ((payload_json ->> 'last_cycle_age_s'::text))::numeric
            ELSE NULL::numeric
        END AS last_cycle_age_s,
    (payload_json -> 'digital_inputs'::text) AS digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_eastron_readings r
  WHERE (asset = 'revpi_oee_node_01'::text)
  ORDER BY ingest_ts DESC;


ALTER VIEW mv_hot.edge_oee_live_telemetry OWNER TO mesavault;

--
-- Name: edge_oee_latest_machine_snapshot; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_latest_machine_snapshot AS
 SELECT DISTINCT ON (asset) ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_live_telemetry
  ORDER BY asset, ingest_ts DESC;


ALTER VIEW mv_hot.edge_oee_latest_machine_snapshot OWNER TO mesavault;

--
-- Name: latest_machine_snapshot; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.latest_machine_snapshot AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_latest_machine_snapshot;


ALTER VIEW mv_edge_oee_ucepsa_demo.latest_machine_snapshot OWNER TO mesavault;

--
-- Name: live_telemetry; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.live_telemetry AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_live_telemetry;


ALTER VIEW mv_edge_oee_ucepsa_demo.live_telemetry OWNER TO mesavault;

--
-- Name: edge_oee_node_events; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_node_events (
    id bigint NOT NULL,
    received_at timestamp with time zone DEFAULT now() NOT NULL,
    event_ts timestamp with time zone NOT NULL,
    topic text NOT NULL,
    tenant text NOT NULL,
    site text NOT NULL,
    vertical text NOT NULL,
    asset text NOT NULL,
    machine_id text,
    order_id text,
    event_type text NOT NULL,
    event_name text NOT NULL,
    previous_auto_signal boolean,
    new_auto_signal boolean,
    machine_running boolean,
    reason_pending boolean,
    cycle_pulse_count bigint,
    cycle_rate_ppm numeric(10,2),
    last_cycle_age_s numeric(10,2),
    payload_json jsonb DEFAULT '{}'::jsonb NOT NULL
);


ALTER TABLE mv_hot.edge_oee_node_events OWNER TO mesavault;

--
-- Name: edge_oee_machine_state_latest; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_machine_state_latest AS
 SELECT DISTINCT ON (asset) received_at,
    (EXTRACT(epoch FROM (now() - received_at)))::integer AS age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s
   FROM mv_hot.edge_oee_node_events
  WHERE (event_type = 'machine_state_changed'::text)
  ORDER BY asset, event_ts DESC;


ALTER VIEW mv_hot.edge_oee_machine_state_latest OWNER TO mesavault;

--
-- Name: machine_state_latest; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.machine_state_latest AS
 SELECT received_at,
    age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s
   FROM mv_hot.edge_oee_machine_state_latest;


ALTER VIEW mv_edge_oee_ucepsa_demo.machine_state_latest OWNER TO mesavault;

--
-- Name: edge_oee_machine_stops; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_machine_stops (
    id bigint NOT NULL,
    tenant text NOT NULL,
    site text NOT NULL,
    vertical text NOT NULL,
    asset text NOT NULL,
    machine_id text,
    order_id text,
    started_at timestamp with time zone NOT NULL,
    ended_at timestamp with time zone,
    status text DEFAULT 'OPEN'::text NOT NULL,
    classification_status text DEFAULT 'PENDING'::text NOT NULL,
    cause_code text,
    operator_note text,
    value_hour_eur numeric(10,2) DEFAULT 36.00 NOT NULL,
    duration_s numeric(14,2),
    cost_eur numeric(14,2),
    start_event_name text,
    end_event_name text,
    start_payload_json jsonb DEFAULT '{}'::jsonb NOT NULL,
    end_payload_json jsonb DEFAULT '{}'::jsonb NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    updated_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_hot.edge_oee_machine_stops OWNER TO mesavault;

--
-- Name: machine_stops; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.machine_stops AS
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    ended_at,
    status,
    classification_status,
    cause_code,
    operator_note,
    value_hour_eur,
    duration_s,
    cost_eur,
    start_event_name,
    end_event_name,
    start_payload_json,
    end_payload_json,
    created_at,
    updated_at
   FROM mv_hot.edge_oee_machine_stops;


ALTER VIEW mv_edge_oee_ucepsa_demo.machine_stops OWNER TO mesavault;

--
-- Name: edge_oee_machine_targets; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_machine_targets (
    machine_id text NOT NULL,
    machine_name text NOT NULL,
    asset text NOT NULL,
    target_cycle_rate_ppm numeric(10,2) DEFAULT 10.00 NOT NULL,
    value_hour_eur numeric(10,2) DEFAULT 36.00 NOT NULL,
    quality_pct_default numeric(10,2) DEFAULT 100.00 NOT NULL,
    notes text
);


ALTER TABLE mv_hot.edge_oee_machine_targets OWNER TO mesavault;

--
-- Name: machine_targets; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.machine_targets AS
 SELECT machine_id,
    machine_name,
    asset,
    target_cycle_rate_ppm,
    value_hour_eur,
    quality_pct_default,
    notes
   FROM mv_hot.edge_oee_machine_targets;


ALTER VIEW mv_edge_oee_ucepsa_demo.machine_targets OWNER TO mesavault;

--
-- Name: margin_cost_parameters; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.margin_cost_parameters (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    scope_level text DEFAULT 'GLOBAL'::text NOT NULL,
    machine_id text,
    product_default_code text,
    energy_cost_eur_per_kwh numeric(14,6),
    material_cost_eur_per_kg numeric(14,6),
    machine_run_cost_eur_per_h numeric(14,4),
    labor_cost_eur_per_h numeric(14,4),
    overhead_cost_eur_per_h numeric(14,4),
    valid_from timestamp with time zone DEFAULT now() NOT NULL,
    valid_to timestamp with time zone,
    is_active boolean DEFAULT true NOT NULL,
    notes text,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.margin_cost_parameters OWNER TO mesavault;

--
-- Name: margin_cost_parameters_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.margin_cost_parameters_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.margin_cost_parameters_id_seq OWNER TO mesavault;

--
-- Name: margin_cost_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.margin_cost_parameters_id_seq OWNED BY mv_edge_oee_ucepsa_demo.margin_cost_parameters.id;


--
-- Name: node_events; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.node_events AS
 SELECT id,
    received_at,
    event_ts,
    topic,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    event_type,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    payload_json
   FROM mv_hot.edge_oee_node_events;


ALTER VIEW mv_edge_oee_ucepsa_demo.node_events OWNER TO mesavault;

--
-- Name: edge_oee_node_events_recent; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_node_events_recent AS
 SELECT received_at,
    (EXTRACT(epoch FROM (now() - received_at)))::integer AS age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    event_type,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    topic,
    payload_json
   FROM mv_hot.edge_oee_node_events
  ORDER BY event_ts DESC;


ALTER VIEW mv_hot.edge_oee_node_events_recent OWNER TO mesavault;

--
-- Name: node_events_recent; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.node_events_recent AS
 SELECT received_at,
    age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    event_type,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    topic,
    payload_json
   FROM mv_hot.edge_oee_node_events_recent;


ALTER VIEW mv_edge_oee_ucepsa_demo.node_events_recent OWNER TO mesavault;

--
-- Name: odoo_order_commercials; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.odoo_order_commercials (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    odoo_instance text NOT NULL,
    odoo_production_id integer NOT NULL,
    odoo_order_ref text NOT NULL,
    odoo_origin text,
    odoo_state text,
    product_id integer,
    product_default_code text,
    product_name text,
    product_uom text,
    product_standard_price numeric(14,4),
    product_list_price numeric(14,4),
    production_qty numeric(14,3),
    qty_producing numeric(14,3),
    production_uom text,
    sale_line_id integer,
    sale_order_id integer,
    sale_order_ref text,
    customer_id integer,
    customer_name text,
    sale_state text,
    sale_date_order timestamp with time zone,
    currency text,
    sale_line_qty numeric(14,3),
    sale_line_qty_delivered numeric(14,3),
    sale_price_unit numeric(14,4),
    sale_discount_pct numeric(10,2),
    revenue_net_eur numeric(14,4),
    revenue_total_eur numeric(14,4),
    raw_material_value_eur numeric(14,4),
    finished_value_eur numeric(14,4),
    material_cost_status text DEFAULT 'UNAVAILABLE'::text NOT NULL,
    stock_raw_moves_json jsonb DEFAULT '[]'::jsonb NOT NULL,
    stock_finished_moves_json jsonb DEFAULT '[]'::jsonb NOT NULL,
    raw_json jsonb DEFAULT '{}'::jsonb NOT NULL,
    snapshot_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.odoo_order_commercials OWNER TO mesavault;

--
-- Name: odoo_order_commercials_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.odoo_order_commercials_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_order_commercials_id_seq OWNER TO mesavault;

--
-- Name: odoo_order_commercials_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_order_commercials_id_seq OWNED BY mv_edge_oee_ucepsa_demo.odoo_order_commercials.id;


--
-- Name: odoo_workcenter_map; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.odoo_workcenter_map (
    id bigint NOT NULL,
    tenant text NOT NULL,
    site text NOT NULL,
    odoo_instance text NOT NULL,
    odoo_workcenter_id integer,
    odoo_workcenter_code text NOT NULL,
    odoo_workcenter_name text NOT NULL,
    machine_id text NOT NULL,
    asset text NOT NULL,
    is_active boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.odoo_workcenter_map OWNER TO mesavault;

--
-- Name: odoo_workcenter_map_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workcenter_map_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workcenter_map_id_seq OWNER TO mesavault;

--
-- Name: odoo_workcenter_map_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workcenter_map_id_seq OWNED BY mv_edge_oee_ucepsa_demo.odoo_workcenter_map.id;


--
-- Name: odoo_workorders_demo; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.odoo_workorders_demo (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    odoo_instance text DEFAULT 'odoo_demo'::text NOT NULL,
    odoo_workorder_id integer,
    odoo_production_id integer,
    odoo_order_ref text NOT NULL,
    odoo_state text NOT NULL,
    odoo_workcenter_code text NOT NULL,
    odoo_workcenter_name text NOT NULL,
    machine_id text NOT NULL,
    asset text NOT NULL,
    product text NOT NULL,
    qty_planned numeric(14,2),
    qty_done numeric(14,2),
    uom text,
    planned_cycles numeric(14,2),
    target_cycle_rate_ppm numeric(10,2),
    odoo_start timestamp with time zone NOT NULL,
    odoo_end timestamp with time zone,
    notes text,
    snapshot_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.odoo_workorders_demo OWNER TO mesavault;

--
-- Name: odoo_workorders_demo_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workorders_demo_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workorders_demo_id_seq OWNER TO mesavault;

--
-- Name: odoo_workorders_demo_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workorders_demo_id_seq OWNED BY mv_edge_oee_ucepsa_demo.odoo_workorders_demo.id;


--
-- Name: edge_oee_stop_causes; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_stop_causes (
    cause_code text NOT NULL,
    cause_name text NOT NULL,
    description text,
    is_planned boolean DEFAULT false NOT NULL,
    is_active boolean DEFAULT true NOT NULL,
    sort_order integer DEFAULT 100 NOT NULL
);


ALTER TABLE mv_hot.edge_oee_stop_causes OWNER TO mesavault;

--
-- Name: edge_oee_open_stops; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_open_stops AS
 WITH src AS (
         SELECT s_1.id,
            s_1.tenant,
            s_1.site,
            s_1.vertical,
            s_1.asset,
            s_1.machine_id,
            s_1.order_id,
            s_1.started_at,
            s_1.ended_at,
            s_1.status,
            s_1.classification_status,
            s_1.cause_code,
            s_1.operator_note,
            s_1.value_hour_eur,
            s_1.duration_s,
            s_1.cost_eur,
            s_1.start_event_name,
            s_1.end_event_name,
            s_1.start_payload_json,
            s_1.end_payload_json,
            s_1.created_at,
            s_1.updated_at,
                CASE
                    WHEN (s_1.started_at > (s_1.created_at + '00:00:05'::interval)) THEN s_1.created_at
                    ELSE s_1.started_at
                END AS effective_started_at
           FROM mv_hot.edge_oee_machine_stops s_1
        )
 SELECT s.id,
    s.tenant,
    s.site,
    s.vertical,
    s.asset,
    s.machine_id,
    s.order_id,
    s.started_at,
    (GREATEST(EXTRACT(epoch FROM (now() - s.effective_started_at)), (0)::numeric))::numeric(14,2) AS current_duration_s,
    round((GREATEST(EXTRACT(epoch FROM (now() - s.effective_started_at)), (0)::numeric) / 60.0), 2) AS current_duration_min,
    round(((GREATEST(EXTRACT(epoch FROM (now() - s.effective_started_at)), (0)::numeric) / 3600.0) * s.value_hour_eur), 2) AS current_cost_eur,
    s.status,
    s.classification_status,
    s.cause_code,
    c.cause_name,
    s.operator_note,
    s.value_hour_eur
   FROM (src s
     LEFT JOIN mv_hot.edge_oee_stop_causes c ON ((c.cause_code = s.cause_code)))
  WHERE (s.status = 'OPEN'::text)
  ORDER BY s.started_at DESC;


ALTER VIEW mv_hot.edge_oee_open_stops OWNER TO mesavault;

--
-- Name: open_stops; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.open_stops AS
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    current_duration_s,
    current_duration_min,
    current_cost_eur,
    status,
    classification_status,
    cause_code,
    cause_name,
    operator_note,
    value_hour_eur
   FROM mv_hot.edge_oee_open_stops;


ALTER VIEW mv_edge_oee_ucepsa_demo.open_stops OWNER TO mesavault;

--
-- Name: raw_material_cost_parameters; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    raw_product_default_code text NOT NULL,
    raw_product_name text,
    material_cost_eur_per_kg numeric(14,6) NOT NULL,
    source text DEFAULT 'MANUAL'::text NOT NULL,
    valid_from timestamp with time zone DEFAULT now() NOT NULL,
    valid_to timestamp with time zone,
    is_active boolean DEFAULT true NOT NULL,
    notes text,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters OWNER TO mesavault;

--
-- Name: raw_material_cost_parameters_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters_id_seq OWNER TO mesavault;

--
-- Name: raw_material_cost_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters_id_seq OWNED BY mv_edge_oee_ucepsa_demo.raw_material_cost_parameters.id;


--
-- Name: edge_oee_stop_cause_options; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_stop_cause_options AS
 SELECT cause_code,
    cause_name,
    description,
    is_planned,
    sort_order
   FROM mv_hot.edge_oee_stop_causes
  WHERE (is_active = true)
  ORDER BY sort_order, cause_name;


ALTER VIEW mv_hot.edge_oee_stop_cause_options OWNER TO mesavault;

--
-- Name: stop_cause_options; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.stop_cause_options AS
 SELECT cause_code,
    cause_name,
    description,
    is_planned,
    sort_order
   FROM mv_hot.edge_oee_stop_cause_options;


ALTER VIEW mv_edge_oee_ucepsa_demo.stop_cause_options OWNER TO mesavault;

--
-- Name: stop_causes; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.stop_causes AS
 SELECT cause_code,
    cause_name,
    description,
    is_planned,
    is_active,
    sort_order
   FROM mv_hot.edge_oee_stop_causes;


ALTER VIEW mv_edge_oee_ucepsa_demo.stop_causes OWNER TO mesavault;

--
-- Name: edge_oee_stop_summary_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_stop_summary_demo AS
 WITH src AS (
         SELECT s.id,
            s.tenant,
            s.site,
            s.vertical,
            s.asset,
            s.machine_id,
            s.order_id,
            s.started_at,
            s.ended_at,
            s.status,
            s.classification_status,
            s.cause_code,
            s.operator_note,
            s.value_hour_eur,
            s.duration_s,
            s.cost_eur,
            s.start_event_name,
            s.end_event_name,
            s.start_payload_json,
            s.end_payload_json,
            s.created_at,
            s.updated_at,
            c.cause_name,
                CASE
                    WHEN (s.started_at > (s.created_at + '00:00:05'::interval)) THEN s.created_at
                    ELSE s.started_at
                END AS effective_started_at
           FROM (mv_hot.edge_oee_machine_stops s
             LEFT JOIN mv_hot.edge_oee_stop_causes c ON ((c.cause_code = s.cause_code)))
        ), base AS (
         SELECT src.id,
            src.tenant,
            src.site,
            src.vertical,
            src.asset,
            src.machine_id,
            src.order_id,
            src.started_at,
            src.ended_at,
            src.status,
            src.classification_status,
            src.cause_code,
            src.operator_note,
            src.value_hour_eur,
            src.duration_s,
            src.cost_eur,
            src.start_event_name,
            src.end_event_name,
            src.start_payload_json,
            src.end_payload_json,
            src.created_at,
            src.updated_at,
            src.cause_name,
            src.effective_started_at,
                CASE
                    WHEN (src.duration_s IS NOT NULL) THEN GREATEST(src.duration_s, (0)::numeric)
                    WHEN (src.ended_at IS NOT NULL) THEN GREATEST(EXTRACT(epoch FROM (src.ended_at - src.effective_started_at)), (0)::numeric)
                    ELSE GREATEST(EXTRACT(epoch FROM (now() - src.effective_started_at)), (0)::numeric)
                END AS safe_duration_s
           FROM src
        )
 SELECT COALESCE(cause_name, 'Pendiente de clasificar'::text) AS cause_name,
    COALESCE(cause_code, 'pending'::text) AS cause_code,
    count(*) AS stop_count,
    round((sum(safe_duration_s) / 60.0), 2) AS total_min,
    round(sum(COALESCE(cost_eur, ((safe_duration_s / 3600.0) * value_hour_eur))), 2) AS total_cost_eur
   FROM base
  GROUP BY COALESCE(cause_name, 'Pendiente de clasificar'::text), COALESCE(cause_code, 'pending'::text)
  ORDER BY (round(sum(COALESCE(cost_eur, ((safe_duration_s / 3600.0) * value_hour_eur))), 2)) DESC;


ALTER VIEW mv_hot.edge_oee_stop_summary_demo OWNER TO mesavault;

--
-- Name: stop_summary; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.stop_summary AS
 SELECT cause_name,
    cause_code,
    stop_count,
    total_min,
    total_cost_eur
   FROM mv_hot.edge_oee_stop_summary_demo;


ALTER VIEW mv_edge_oee_ucepsa_demo.stop_summary OWNER TO mesavault;

--
-- Name: edge_oee_stops_recent; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_stops_recent AS
 WITH src AS (
         SELECT s.id,
            s.tenant,
            s.site,
            s.vertical,
            s.asset,
            s.machine_id,
            s.order_id,
            s.started_at,
            s.ended_at,
            s.status,
            s.classification_status,
            s.cause_code,
            s.operator_note,
            s.value_hour_eur,
            s.duration_s,
            s.cost_eur,
            s.start_event_name,
            s.end_event_name,
            s.start_payload_json,
            s.end_payload_json,
            s.created_at,
            s.updated_at,
            c.cause_name,
            c.is_planned,
                CASE
                    WHEN (s.started_at > (s.created_at + '00:00:05'::interval)) THEN s.created_at
                    ELSE s.started_at
                END AS effective_started_at
           FROM (mv_hot.edge_oee_machine_stops s
             LEFT JOIN mv_hot.edge_oee_stop_causes c ON ((c.cause_code = s.cause_code)))
        ), base AS (
         SELECT src.id,
            src.tenant,
            src.site,
            src.vertical,
            src.asset,
            src.machine_id,
            src.order_id,
            src.started_at,
            src.ended_at,
            src.status,
            src.classification_status,
            src.cause_code,
            src.operator_note,
            src.value_hour_eur,
            src.duration_s,
            src.cost_eur,
            src.start_event_name,
            src.end_event_name,
            src.start_payload_json,
            src.end_payload_json,
            src.created_at,
            src.updated_at,
            src.cause_name,
            src.is_planned,
            src.effective_started_at,
                CASE
                    WHEN (src.duration_s IS NOT NULL) THEN GREATEST(src.duration_s, (0)::numeric)
                    WHEN (src.ended_at IS NOT NULL) THEN GREATEST(EXTRACT(epoch FROM (src.ended_at - src.effective_started_at)), (0)::numeric)
                    ELSE GREATEST(EXTRACT(epoch FROM (now() - src.effective_started_at)), (0)::numeric)
                END AS safe_duration_s
           FROM src
        )
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    ended_at,
    (safe_duration_s)::numeric(14,2) AS duration_s,
    round((safe_duration_s / 60.0), 2) AS duration_min,
    COALESCE(cost_eur, round(((safe_duration_s / 3600.0) * value_hour_eur), 2)) AS cost_eur,
    status,
    classification_status,
    cause_code,
    cause_name,
    is_planned,
    operator_note,
    value_hour_eur,
    start_event_name,
    end_event_name,
    created_at,
    updated_at
   FROM base
  ORDER BY started_at DESC;


ALTER VIEW mv_hot.edge_oee_stops_recent OWNER TO mesavault;

--
-- Name: stops_recent; Type: VIEW; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_edge_oee_ucepsa_demo.stops_recent AS
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    ended_at,
    duration_s,
    duration_min,
    cost_eur,
    status,
    classification_status,
    cause_code,
    cause_name,
    is_planned,
    operator_note,
    value_hour_eur,
    start_event_name,
    end_event_name,
    created_at,
    updated_at
   FROM mv_hot.edge_oee_stops_recent;


ALTER VIEW mv_edge_oee_ucepsa_demo.stops_recent OWNER TO mesavault;

--
-- Name: data_quality_contract_rules; Type: TABLE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_prod.data_quality_contract_rules (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    rule_code text NOT NULL,
    rule_name text NOT NULL,
    domain text NOT NULL,
    dimension text NOT NULL,
    severity text NOT NULL,
    owner_area text NOT NULL,
    applies_to text NOT NULL,
    description text NOT NULL,
    expected_condition text NOT NULL,
    blocking_for text,
    is_active boolean DEFAULT true NOT NULL,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_prod.data_quality_contract_rules OWNER TO mesavault;

--
-- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_prod.data_quality_contract_rules_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_prod.data_quality_contract_rules_id_seq OWNER TO mesavault;

--
-- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_prod.data_quality_contract_rules_id_seq OWNED BY mv_edge_oee_ucepsa_prod.data_quality_contract_rules.id;


--
-- Name: margin_cost_parameters; Type: TABLE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_prod.margin_cost_parameters (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    scope_level text DEFAULT 'GLOBAL'::text NOT NULL,
    machine_id text,
    product_default_code text,
    energy_cost_eur_per_kwh numeric(14,6),
    material_cost_eur_per_kg numeric(14,6),
    machine_run_cost_eur_per_h numeric(14,4),
    labor_cost_eur_per_h numeric(14,4),
    overhead_cost_eur_per_h numeric(14,4),
    valid_from timestamp with time zone DEFAULT now() NOT NULL,
    valid_to timestamp with time zone,
    is_active boolean DEFAULT true NOT NULL,
    notes text,
    created_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_prod.margin_cost_parameters OWNER TO mesavault;

--
-- Name: margin_cost_parameters_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_prod.margin_cost_parameters_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_prod.margin_cost_parameters_id_seq OWNER TO mesavault;

--
-- Name: margin_cost_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_prod.margin_cost_parameters_id_seq OWNED BY mv_edge_oee_ucepsa_prod.margin_cost_parameters.id;


--
-- Name: odoo_order_commercials; Type: TABLE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_prod.odoo_order_commercials (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    odoo_instance text NOT NULL,
    odoo_production_id integer NOT NULL,
    odoo_order_ref text NOT NULL,
    odoo_origin text,
    odoo_state text,
    product_id integer,
    product_default_code text,
    product_name text,
    product_uom text,
    product_standard_price numeric(14,4),
    product_list_price numeric(14,4),
    production_qty numeric(14,3),
    qty_producing numeric(14,3),
    production_uom text,
    sale_line_id integer,
    sale_order_id integer,
    sale_order_ref text,
    customer_id integer,
    customer_name text,
    sale_state text,
    sale_date_order timestamp with time zone,
    currency text,
    sale_line_qty numeric(14,3),
    sale_line_qty_delivered numeric(14,3),
    sale_price_unit numeric(14,4),
    sale_discount_pct numeric(10,2),
    revenue_net_eur numeric(14,4),
    revenue_total_eur numeric(14,4),
    raw_material_value_eur numeric(14,4),
    finished_value_eur numeric(14,4),
    material_cost_status text DEFAULT 'UNAVAILABLE'::text NOT NULL,
    stock_raw_moves_json jsonb DEFAULT '[]'::jsonb NOT NULL,
    stock_finished_moves_json jsonb DEFAULT '[]'::jsonb NOT NULL,
    raw_json jsonb DEFAULT '{}'::jsonb NOT NULL,
    snapshot_at timestamp with time zone DEFAULT now() NOT NULL
);


ALTER TABLE mv_edge_oee_ucepsa_prod.odoo_order_commercials OWNER TO mesavault;

--
-- Name: odoo_order_commercials_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_prod.odoo_order_commercials_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_prod.odoo_order_commercials_id_seq OWNER TO mesavault;

--
-- Name: odoo_order_commercials_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_prod.odoo_order_commercials_id_seq OWNED BY mv_edge_oee_ucepsa_prod.odoo_order_commercials.id;


--
-- Name: raw_material_cost_parameters; Type: TABLE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE TABLE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters (
    id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'ucepsa_test'::text NOT NULL,
    raw_product_default_code text NOT NULL,
    raw_product_name text,
    material_cost_eur_per_kg numeric(14,6) NOT NULL,
    source text DEFAULT 'MANUAL'::text NOT NULL,
    valid_from timestamp with time zone DEFAULT now() NOT NULL,
    valid_to timestamp with time zone,
    is_active boolean DEFAULT true NOT NULL,
    notes text,
    created_at timestamp with time zone DEFAULT now() NOT NULL,
    raw_product_id integer,
    raw_uom text
);


ALTER TABLE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters OWNER TO mesavault;

--
-- Name: raw_material_cost_parameters_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE SEQUENCE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters_id_seq OWNER TO mesavault;

--
-- Name: raw_material_cost_parameters_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER SEQUENCE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters_id_seq OWNED BY mv_edge_oee_ucepsa_prod.raw_material_cost_parameters.id;


--
-- Name: edge_oee_loss_summary_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_loss_summary_demo (
    cause text NOT NULL,
    hours_month numeric(10,2) NOT NULL,
    value_hour_eur numeric(10,2) NOT NULL,
    monthly_cost_eur numeric(10,2) NOT NULL,
    recommended_action text NOT NULL,
    effort text,
    priority text,
    machine_focus text
);


ALTER TABLE mv_hot.edge_oee_loss_summary_demo OWNER TO mesavault;

--
-- Name: edge_oee_actions_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_actions_demo AS
 SELECT cause AS "Causa",
    monthly_cost_eur AS "Impacto estimado €/mes",
    effort AS "Esfuerzo",
    priority AS "Prioridad",
    recommended_action AS "Acción recomendada",
        CASE
            WHEN (cause = 'Ajuste de sellado'::text) THEN (4000)::numeric
            ELSE NULL::numeric
        END AS "Inversión ejemplo €",
        CASE
            WHEN (cause = 'Ajuste de sellado'::text) THEN round(((4000)::numeric / NULLIF(monthly_cost_eur, (0)::numeric)), 1)
            ELSE NULL::numeric
        END AS "Payback ejemplo meses"
   FROM mv_hot.edge_oee_loss_summary_demo
  ORDER BY monthly_cost_eur DESC;


ALTER VIEW mv_hot.edge_oee_actions_demo OWNER TO mesavault;

--
-- Name: edge_oee_data_quality_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_data_quality_demo (
    metric_id text NOT NULL,
    metric text NOT NULL,
    value_numeric numeric(10,2),
    value_text text,
    unit text,
    status text NOT NULL,
    problem text,
    likely_impact text,
    recommended_action text,
    sort_order integer NOT NULL
);


ALTER TABLE mv_hot.edge_oee_data_quality_demo OWNER TO mesavault;

--
-- Name: edge_oee_data_quality_dashboard_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_data_quality_dashboard_demo AS
 SELECT sort_order,
    metric AS "Indicador",
    COALESCE((value_numeric)::text, value_text) AS "Valor",
    unit AS "Unidad",
    status AS "Estado",
    problem AS "Qué está mal",
    likely_impact AS "Impacto probable",
    recommended_action AS "Qué revisar / acción"
   FROM mv_hot.edge_oee_data_quality_demo
  ORDER BY sort_order;


ALTER VIEW mv_hot.edge_oee_data_quality_dashboard_demo OWNER TO mesavault;

--
-- Name: edge_oee_eastron_readings_id_seq; Type: SEQUENCE; Schema: mv_hot; Owner: mesavault
--

CREATE SEQUENCE mv_hot.edge_oee_eastron_readings_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_hot.edge_oee_eastron_readings_id_seq OWNER TO mesavault;

--
-- Name: edge_oee_eastron_readings_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_hot; Owner: mesavault
--

ALTER SEQUENCE mv_hot.edge_oee_eastron_readings_id_seq OWNED BY mv_hot.edge_oee_eastron_readings.id;


--
-- Name: edge_oee_energy_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_energy_demo (
    ts timestamp with time zone NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    machine_id text NOT NULL,
    order_id text,
    power_kw numeric(10,3),
    kwh_total numeric(14,3),
    source text DEFAULT 'demo'::text,
    payload_json jsonb DEFAULT '{}'::jsonb
);


ALTER TABLE mv_hot.edge_oee_energy_demo OWNER TO mesavault;

--
-- Name: edge_oee_events_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_events_demo (
    event_id bigint NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    machine_id text NOT NULL,
    order_id text,
    event_type text NOT NULL,
    cause text NOT NULL,
    start_time timestamp with time zone NOT NULL,
    end_time timestamp with time zone NOT NULL,
    duration_min numeric(10,2) NOT NULL,
    cost_eur numeric(10,2) DEFAULT 0 NOT NULL,
    source text DEFAULT 'mesavault_demo'::text NOT NULL,
    notes text
);


ALTER TABLE mv_hot.edge_oee_events_demo OWNER TO mesavault;

--
-- Name: edge_oee_events_demo_event_id_seq; Type: SEQUENCE; Schema: mv_hot; Owner: mesavault
--

CREATE SEQUENCE mv_hot.edge_oee_events_demo_event_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_hot.edge_oee_events_demo_event_id_seq OWNER TO mesavault;

--
-- Name: edge_oee_events_demo_event_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_hot; Owner: mesavault
--

ALTER SEQUENCE mv_hot.edge_oee_events_demo_event_id_seq OWNED BY mv_hot.edge_oee_events_demo.event_id;


--
-- Name: edge_oee_executive_summary_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_executive_summary_demo AS
 WITH losses AS (
         SELECT sum(edge_oee_loss_summary_demo.hours_month) AS classified_loss_hours,
            sum(edge_oee_loss_summary_demo.monthly_cost_eur) AS estimated_loss_cost_eur
           FROM mv_hot.edge_oee_loss_summary_demo
        ), principal AS (
         SELECT edge_oee_loss_summary_demo.cause
           FROM mv_hot.edge_oee_loss_summary_demo
          ORDER BY edge_oee_loss_summary_demo.monthly_cost_eur DESC
         LIMIT 1
        )
 SELECT now() AS evaluated_at,
    816.0::numeric(10,1) AS hours_analyzed,
    losses.classified_loss_hours,
    losses.estimated_loss_cost_eur,
    principal.cause AS main_loss_cause,
    'Cortadora 2'::text AS machine_with_more_losses,
    5.0::numeric(10,1) AS unclassified_stop_hours,
    7 AS orders_with_odoo_machine_discrepancy
   FROM losses,
    principal;


ALTER VIEW mv_hot.edge_oee_executive_summary_demo OWNER TO mesavault;

--
-- Name: edge_oee_kpi_cards_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_kpi_cards_demo AS
 SELECT 1 AS sort_order,
    'Horas analizadas'::text AS kpi,
    edge_oee_executive_summary_demo.hours_analyzed AS value,
    'h'::text AS unit,
    'OK'::text AS status
   FROM mv_hot.edge_oee_executive_summary_demo
UNION ALL
 SELECT 2 AS sort_order,
    'Pérdidas clasificadas'::text AS kpi,
    edge_oee_executive_summary_demo.classified_loss_hours AS value,
    'h/mes'::text AS unit,
    'Warning'::text AS status
   FROM mv_hot.edge_oee_executive_summary_demo
UNION ALL
 SELECT 3 AS sort_order,
    'Coste estimado de pérdidas'::text AS kpi,
    edge_oee_executive_summary_demo.estimated_loss_cost_eur AS value,
    '€/mes'::text AS unit,
    'Warning'::text AS status
   FROM mv_hot.edge_oee_executive_summary_demo
UNION ALL
 SELECT 4 AS sort_order,
    'Paros sin causa'::text AS kpi,
    edge_oee_executive_summary_demo.unclassified_stop_hours AS value,
    'h/mes'::text AS unit,
    'Warning'::text AS status
   FROM mv_hot.edge_oee_executive_summary_demo
UNION ALL
 SELECT 5 AS sort_order,
    'Órdenes con discrepancia Odoo/máquina'::text AS kpi,
    edge_oee_executive_summary_demo.orders_with_odoo_machine_discrepancy AS value,
    'órdenes'::text AS unit,
    'Warning'::text AS status
   FROM mv_hot.edge_oee_executive_summary_demo;


ALTER VIEW mv_hot.edge_oee_kpi_cards_demo OWNER TO mesavault;

--
-- Name: edge_oee_machine_stops_backup_cort00_20260622_175800; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_machine_stops_backup_cort00_20260622_175800 (
    id bigint,
    tenant text,
    site text,
    vertical text,
    asset text,
    machine_id text,
    order_id text,
    started_at timestamp with time zone,
    ended_at timestamp with time zone,
    status text,
    classification_status text,
    cause_code text,
    operator_note text,
    value_hour_eur numeric(10,2),
    duration_s numeric(14,2),
    cost_eur numeric(14,2),
    start_event_name text,
    end_event_name text,
    start_payload_json jsonb,
    end_payload_json jsonb,
    created_at timestamp with time zone,
    updated_at timestamp with time zone
);


ALTER TABLE mv_hot.edge_oee_machine_stops_backup_cort00_20260622_175800 OWNER TO mesavault;

--
-- Name: edge_oee_machine_stops_id_seq; Type: SEQUENCE; Schema: mv_hot; Owner: mesavault
--

CREATE SEQUENCE mv_hot.edge_oee_machine_stops_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_hot.edge_oee_machine_stops_id_seq OWNER TO mesavault;

--
-- Name: edge_oee_machine_stops_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_hot; Owner: mesavault
--

ALTER SEQUENCE mv_hot.edge_oee_machine_stops_id_seq OWNED BY mv_hot.edge_oee_machine_stops.id;


--
-- Name: edge_oee_machines; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_machines (
    machine_id text NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    name text NOT NULL,
    area text DEFAULT 'corte'::text NOT NULL,
    machine_type text DEFAULT 'cortadora'::text NOT NULL,
    value_hour_eur numeric(10,2) NOT NULL,
    standard_kg_h numeric(10,2),
    sale_price_eur_kg numeric(10,2),
    transformation_cost_eur_kg numeric(10,2),
    raw_material_cost_eur_kg numeric(10,2),
    notes text
);


ALTER TABLE mv_hot.edge_oee_machines OWNER TO mesavault;

--
-- Name: edge_oee_node_events_id_seq; Type: SEQUENCE; Schema: mv_hot; Owner: mesavault
--

CREATE SEQUENCE mv_hot.edge_oee_node_events_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_hot.edge_oee_node_events_id_seq OWNER TO mesavault;

--
-- Name: edge_oee_node_events_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_hot; Owner: mesavault
--

ALTER SEQUENCE mv_hot.edge_oee_node_events_id_seq OWNED BY mv_hot.edge_oee_node_events.id;


--
-- Name: edge_oee_orders_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_orders_demo (
    order_id text NOT NULL,
    tenant text DEFAULT 'ucepsa'::text NOT NULL,
    site text DEFAULT 'demo_edge_oee'::text NOT NULL,
    machine_id text NOT NULL,
    product text NOT NULL,
    odoo_start timestamp with time zone NOT NULL,
    odoo_end timestamp with time zone NOT NULL,
    qty_planned numeric(14,2),
    qty_done numeric(14,2),
    scrap_qty numeric(14,2),
    uom text DEFAULT 'unidades'::text,
    commercial_note text
);


ALTER TABLE mv_hot.edge_oee_orders_demo OWNER TO mesavault;

--
-- Name: edge_oee_order_timeline_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_order_timeline_demo AS
 SELECT o.odoo_start AS "time",
    (o.odoo_start + '00:01:00'::interval) AS time_end,
    o.order_id,
    o.machine_id,
    m.name AS machine_name,
    o.product,
    'ODOO'::text AS source,
    'ODOO_START'::text AS state,
    'Odoo inicia la orden'::text AS detail,
    (0)::numeric AS duration_min,
    (0)::numeric AS cost_eur,
    1 AS sort_order
   FROM (mv_hot.edge_oee_orders_demo o
     JOIN mv_hot.edge_oee_machines m ON ((m.machine_id = o.machine_id)))
UNION ALL
 SELECT e.start_time AS "time",
    e.end_time AS time_end,
    e.order_id,
    e.machine_id,
    m.name AS machine_name,
    COALESCE(o.product, 'Sin orden activa'::text) AS product,
    'MESAVAULT'::text AS source,
    e.event_type AS state,
    e.cause AS detail,
    e.duration_min,
    e.cost_eur,
    2 AS sort_order
   FROM ((mv_hot.edge_oee_events_demo e
     JOIN mv_hot.edge_oee_machines m ON ((m.machine_id = e.machine_id)))
     LEFT JOIN mv_hot.edge_oee_orders_demo o ON ((o.order_id = e.order_id)))
UNION ALL
 SELECT o.odoo_end AS "time",
    (o.odoo_end + '00:01:00'::interval) AS time_end,
    o.order_id,
    o.machine_id,
    m.name AS machine_name,
    o.product,
    'ODOO'::text AS source,
    'ODOO_END'::text AS state,
    'Odoo finaliza la orden'::text AS detail,
    (0)::numeric AS duration_min,
    (0)::numeric AS cost_eur,
    3 AS sort_order
   FROM (mv_hot.edge_oee_orders_demo o
     JOIN mv_hot.edge_oee_machines m ON ((m.machine_id = o.machine_id)));


ALTER VIEW mv_hot.edge_oee_order_timeline_demo OWNER TO mesavault;

--
-- Name: edge_oee_pareto_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_pareto_demo AS
 SELECT rank() OVER (ORDER BY monthly_cost_eur DESC) AS ranking,
    cause,
    hours_month,
    value_hour_eur,
    monthly_cost_eur,
    recommended_action,
    effort,
    priority,
    machine_focus
   FROM mv_hot.edge_oee_loss_summary_demo
  ORDER BY monthly_cost_eur DESC;


ALTER VIEW mv_hot.edge_oee_pareto_demo OWNER TO mesavault;

--
-- Name: edge_oee_quality_cases_demo; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.edge_oee_quality_cases_demo (
    case_id text NOT NULL,
    order_id text,
    machine_id text,
    product text,
    claim text,
    sealing_adjustment_stops integer,
    sealing_adjustment_min numeric(10,2),
    microstops_count integer,
    scrap_pct numeric(10,2),
    energy_vs_avg_pct numeric(10,2),
    interpretation text,
    recommended_action text
);


ALTER TABLE mv_hot.edge_oee_quality_cases_demo OWNER TO mesavault;

--
-- Name: edge_oee_quality_case_demo; Type: VIEW; Schema: mv_hot; Owner: mesavault
--

CREATE VIEW mv_hot.edge_oee_quality_case_demo AS
 SELECT qc.case_id,
    qc.order_id,
    m.name AS machine_name,
    qc.product,
    qc.claim,
    qc.sealing_adjustment_stops,
    qc.sealing_adjustment_min,
    qc.microstops_count,
    qc.scrap_pct,
    qc.energy_vs_avg_pct,
    qc.interpretation,
    qc.recommended_action
   FROM (mv_hot.edge_oee_quality_cases_demo qc
     JOIN mv_hot.edge_oee_machines m ON ((m.machine_id = qc.machine_id)));


ALTER VIEW mv_hot.edge_oee_quality_case_demo OWNER TO mesavault;

--
-- Name: odoo_order_state_current; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.odoo_order_state_current (
    tenant text NOT NULL,
    site text NOT NULL,
    machine_id text NOT NULL,
    topic text,
    mqtt_ts timestamp with time zone,
    received_at timestamp with time zone DEFAULT now() NOT NULL,
    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
);


ALTER TABLE mv_hot.odoo_order_state_current OWNER TO mesavault;

--
-- Name: odoo_order_state_events; Type: TABLE; Schema: mv_hot; Owner: mesavault
--

CREATE TABLE mv_hot.odoo_order_state_events (
    id bigint NOT NULL,
    tenant text NOT NULL,
    site text NOT NULL,
    machine_id text NOT NULL,
    topic text,
    mqtt_ts timestamp with time zone,
    received_at timestamp with time zone DEFAULT now() NOT NULL,
    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
);


ALTER TABLE mv_hot.odoo_order_state_events OWNER TO mesavault;

--
-- Name: odoo_order_state_events_id_seq; Type: SEQUENCE; Schema: mv_hot; Owner: mesavault
--

CREATE SEQUENCE mv_hot.odoo_order_state_events_id_seq
    START WITH 1
    INCREMENT BY 1
    NO MINVALUE
    NO MAXVALUE
    CACHE 1;


ALTER SEQUENCE mv_hot.odoo_order_state_events_id_seq OWNER TO mesavault;

--
-- Name: odoo_order_state_events_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_hot; Owner: mesavault
--

ALTER SEQUENCE mv_hot.odoo_order_state_events_id_seq OWNED BY mv_hot.odoo_order_state_events.id;


--
-- Name: order_execution_report_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_report_v1 AS
 WITH orders AS (
         SELECT o_1.id,
            o_1.tenant,
            o_1.site,
            o_1.odoo_instance,
            o_1.odoo_workorder_id,
            o_1.odoo_production_id,
            o_1.odoo_order_ref,
            o_1.odoo_state,
            o_1.odoo_workcenter_code,
            o_1.odoo_workcenter_name,
            o_1.machine_id,
            o_1.asset,
            o_1.product,
            o_1.qty_planned,
            o_1.qty_done,
            o_1.uom,
            o_1.planned_cycles,
            o_1.target_cycle_rate_ppm,
            o_1.odoo_start,
            o_1.odoo_end,
            o_1.notes,
            o_1.snapshot_at,
            o_1.odoo_start AS start_ts,
                CASE
                    WHEN (o_1.odoo_state = ANY (ARRAY['done'::text, 'to_close'::text, 'cancel'::text])) THEN COALESCE(o_1.odoo_end, o_1.snapshot_at)
                    ELSE COALESCE(( SELECT max(r.ingest_ts) AS max
                       FROM mv_hot.edge_oee_eastron_readings r
                      WHERE ((r.machine_id = o_1.machine_id) AND (r.ingest_ts >= o_1.odoo_start) AND (r.comm_ok = true) AND (r.meter_model = 'Eastron SDM120-M'::text))), o_1.snapshot_at)
                END AS end_ts
           FROM mv_edge_oee_ucepsa_demo.odoo_workorders_demo o_1
          WHERE ((o_1.odoo_instance = 'odoo_ucepsa_test'::text) AND (o_1.machine_id IS NOT NULL) AND (o_1.odoo_start IS NOT NULL))
        ), energy AS (
         SELECT o_1.id AS order_row_id,
            count(r.id) AS energy_samples,
            min(r.ingest_ts) AS energy_first_ts,
            max(r.ingest_ts) AS energy_last_ts,
            min(r.import_kwh) AS start_import_kwh,
            max(r.import_kwh) AS end_import_kwh,
            round((max(r.import_kwh) - min(r.import_kwh)), 3) AS kwh_consumed,
            round(avg(r.power_total_kw), 3) AS avg_kw,
            round(max(r.power_total_kw), 3) AS max_kw
           FROM (orders o_1
             LEFT JOIN mv_hot.edge_oee_eastron_readings r ON (((r.machine_id = o_1.machine_id) AND (r.ingest_ts >= o_1.start_ts) AND (r.ingest_ts <= o_1.end_ts) AND (r.comm_ok = true) AND (r.meter_model = 'Eastron SDM120-M'::text))))
          GROUP BY o_1.id
        ), cycles AS (
         SELECT o_1.id AS order_row_id,
            count(r.id) AS telemetry_samples,
            min(r.ingest_ts) AS telemetry_first_ts,
            max(r.ingest_ts) AS telemetry_last_ts,
            min(((r.payload_json ->> 'cycle_pulse_count'::text))::bigint) AS min_cycle_pulse_count,
            max(((r.payload_json ->> 'cycle_pulse_count'::text))::bigint) AS max_cycle_pulse_count,
            GREATEST((max(((r.payload_json ->> 'cycle_pulse_count'::text))::bigint) - min(((r.payload_json ->> 'cycle_pulse_count'::text))::bigint)), (0)::bigint) AS real_cycle_delta,
            round(avg(((r.payload_json ->> 'cycle_rate_ppm'::text))::numeric), 2) AS avg_cycle_rate_ppm,
            round(avg(NULLIF(((r.payload_json ->> 'cycle_rate_ppm'::text))::numeric, (0)::numeric)), 2) AS avg_nonzero_cycle_rate_ppm
           FROM (orders o_1
             LEFT JOIN mv_hot.edge_oee_eastron_readings r ON (((r.machine_id = o_1.machine_id) AND (r.ingest_ts >= o_1.start_ts) AND (r.ingest_ts <= o_1.end_ts) AND (r.comm_ok = true) AND (r.meter_model = 'Eastron SDM120-M'::text) AND (r.payload_json ? 'cycle_pulse_count'::text))))
          GROUP BY o_1.id
        ), stops AS (
         SELECT o_1.id AS order_row_id,
            count(ms.id) AS stop_count,
            round((COALESCE(sum(GREATEST(EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, o_1.end_ts), o_1.end_ts) - GREATEST(ms.started_at, o_1.start_ts))), (0)::numeric)), (0)::numeric) / 60.0), 2) AS stop_min,
            count(ms.id) FILTER (WHERE (ms.classification_status = 'PENDING'::text)) AS pending_stops,
            count(ms.id) FILTER (WHERE (ms.classification_status = 'CLASSIFIED'::text)) AS classified_stops,
            round(COALESCE(sum(((GREATEST(EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, o_1.end_ts), o_1.end_ts) - GREATEST(ms.started_at, o_1.start_ts))), (0)::numeric) / 3600.0) * ms.value_hour_eur)), (0)::numeric), 2) AS stop_cost_eur
           FROM (orders o_1
             LEFT JOIN mv_hot.edge_oee_machine_stops ms ON (((ms.machine_id = o_1.machine_id) AND (ms.started_at < o_1.end_ts) AND (COALESCE(ms.ended_at, now()) > o_1.start_ts))))
          GROUP BY o_1.id
        )
 SELECT o.id AS order_row_id,
    o.tenant,
    o.site,
    o.odoo_instance,
    o.odoo_workorder_id,
    o.odoo_production_id,
    o.odoo_order_ref,
    o.odoo_state,
    o.odoo_workcenter_code,
    o.odoo_workcenter_name,
    o.machine_id,
    o.asset,
    o.product,
    o.qty_planned,
    o.qty_done,
    o.uom,
    o.planned_cycles,
    o.target_cycle_rate_ppm,
    o.start_ts,
    o.end_ts,
    round((EXTRACT(epoch FROM (o.end_ts - o.start_ts)) / 60.0), 2) AS window_min,
    COALESCE(c.telemetry_samples, (0)::bigint) AS telemetry_samples,
    c.telemetry_first_ts,
    c.telemetry_last_ts,
    COALESCE(c.min_cycle_pulse_count, (0)::bigint) AS min_cycle_pulse_count,
    COALESCE(c.max_cycle_pulse_count, (0)::bigint) AS max_cycle_pulse_count,
    COALESCE(c.real_cycle_delta, (0)::bigint) AS real_cycle_delta,
    c.avg_cycle_rate_ppm,
    c.avg_nonzero_cycle_rate_ppm,
    COALESCE(e.energy_samples, (0)::bigint) AS energy_samples,
    e.energy_first_ts,
    e.energy_last_ts,
    e.start_import_kwh,
    e.end_import_kwh,
    e.kwh_consumed,
    e.avg_kw,
    e.max_kw,
    COALESCE(s.stop_count, (0)::bigint) AS stop_count,
    COALESCE(s.stop_min, (0)::numeric) AS stop_min,
    COALESCE(s.classified_stops, (0)::bigint) AS classified_stops,
    COALESCE(s.pending_stops, (0)::bigint) AS pending_stops,
    COALESCE(s.stop_cost_eur, (0)::numeric) AS stop_cost_eur,
        CASE
            WHEN (COALESCE(c.telemetry_samples, (0)::bigint) = 0) THEN 'SIN_TELEMETRIA_EN_VENTANA'::text
            WHEN (COALESCE(e.energy_samples, (0)::bigint) = 0) THEN 'SIN_ENERGIA_EN_VENTANA'::text
            WHEN (o.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 'PARCIAL_ORDEN_EN_CURSO'::text
            WHEN (COALESCE(s.pending_stops, (0)::bigint) > 0) THEN 'PARCIAL_PAROS_PENDIENTES'::text
            ELSE 'CERRADO_CALCULABLE'::text
        END AS report_status,
        CASE
            WHEN (COALESCE(c.telemetry_samples, (0)::bigint) = 0) THEN 'No hay telemetría Edge-OEE dentro de la ventana de la orden.'::text
            WHEN (COALESCE(e.energy_samples, (0)::bigint) = 0) THEN 'No hay muestras energéticas válidas dentro de la ventana de la orden.'::text
            WHEN (o.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 'La orden sigue en curso. El informe es parcial.'::text
            WHEN (COALESCE(s.pending_stops, (0)::bigint) > 0) THEN 'Existen paros pendientes de clasificación.'::text
            ELSE 'Orden cerrada con datos suficientes para informe.'::text
        END AS report_status_description
   FROM (((orders o
     LEFT JOIN cycles c ON ((c.order_row_id = o.id)))
     LEFT JOIN energy e ON ((e.order_row_id = o.id)))
     LEFT JOIN stops s ON ((s.order_row_id = o.id)));


ALTER VIEW mv_reports_ucepsa_demo.order_execution_report_v1 OWNER TO mesavault;

--
-- Name: order_execution_energy_timeseries_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 AS
 WITH base AS (
         SELECT r.order_row_id,
            r.tenant,
            r.site,
            r.odoo_instance,
            r.odoo_workorder_id,
            r.odoo_production_id,
            r.odoo_order_ref,
            r.odoo_state,
            r.product,
            r.machine_id,
            r.asset,
            r.start_ts AS order_start_ts,
            r.end_ts AS order_end_ts,
            r.report_status,
            e.id AS reading_id,
            e.ts AS meter_ts,
            e.ingest_ts AS "time",
            e.voltage_l1_v,
            e.current_l1_a,
            e.power_total_kw,
            e.frequency_hz,
            e.import_kwh,
            e.export_kwh,
            e.comm_ok,
            e.error_text,
                CASE
                    WHEN (e.payload_json ? 'machine_running'::text) THEN ((e.payload_json ->> 'machine_running'::text))::boolean
                    ELSE NULL::boolean
                END AS machine_running,
                CASE
                    WHEN (e.payload_json ? 'machine_auto_signal'::text) THEN ((e.payload_json ->> 'machine_auto_signal'::text))::boolean
                    ELSE NULL::boolean
                END AS machine_auto_signal,
                CASE
                    WHEN (e.payload_json ? 'cycle_pulse_count'::text) THEN (NULLIF((e.payload_json ->> 'cycle_pulse_count'::text), ''::text))::bigint
                    ELSE NULL::bigint
                END AS cycle_pulse_count,
                CASE
                    WHEN (e.payload_json ? 'cycle_rate_ppm'::text) THEN (NULLIF((e.payload_json ->> 'cycle_rate_ppm'::text), ''::text))::numeric
                    ELSE NULL::numeric
                END AS cycle_rate_ppm,
                CASE
                    WHEN (e.payload_json ? 'last_cycle_age_s'::text) THEN (NULLIF((e.payload_json ->> 'last_cycle_age_s'::text), ''::text))::numeric
                    ELSE NULL::numeric
                END AS last_cycle_age_s,
            e.payload_json
           FROM (mv_reports_ucepsa_demo.order_execution_report_v1 r
             JOIN mv_hot.edge_oee_eastron_readings e ON (((e.machine_id = r.machine_id) AND (e.ingest_ts >= r.start_ts) AND (e.ingest_ts <= r.end_ts) AND (e.meter_model = 'Eastron SDM120-M'::text))))
        ), enriched AS (
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.product,
            b.machine_id,
            b.asset,
            b.order_start_ts,
            b.order_end_ts,
            b.report_status,
            b.reading_id,
            b.meter_ts,
            b."time",
            b.voltage_l1_v,
            b.current_l1_a,
            b.power_total_kw,
            b.frequency_hz,
            b.import_kwh,
            b.export_kwh,
            b.comm_ok,
            b.error_text,
            b.machine_running,
            b.machine_auto_signal,
            b.cycle_pulse_count,
            b.cycle_rate_ppm,
            b.last_cycle_age_s,
            b.payload_json,
            round((EXTRACT(epoch FROM (b."time" - b.order_start_ts)) / 60.0), 2) AS minute_from_order_start,
            round(EXTRACT(epoch FROM (b."time" - lag(b."time") OVER (PARTITION BY b.order_row_id ORDER BY b."time"))), 2) AS sample_gap_s,
            min(b.import_kwh) FILTER (WHERE ((b.comm_ok = true) AND (b.import_kwh IS NOT NULL))) OVER (PARTITION BY b.order_row_id) AS order_start_import_kwh,
            min(b.cycle_pulse_count) FILTER (WHERE (b.cycle_pulse_count IS NOT NULL)) OVER (PARTITION BY b.order_row_id) AS order_start_cycle_pulse_count
           FROM base b
        )
 SELECT order_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_workorder_id,
    odoo_production_id,
    odoo_order_ref,
    odoo_state,
    product,
    machine_id,
    asset,
    order_start_ts,
    order_end_ts,
    report_status,
    reading_id,
    meter_ts,
    "time",
    minute_from_order_start,
    sample_gap_s,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    round(GREATEST((import_kwh - order_start_import_kwh), (0)::numeric), 3) AS kwh_from_order_start,
    comm_ok,
    error_text,
    machine_running,
    machine_auto_signal,
    cycle_pulse_count,
    GREATEST((cycle_pulse_count - order_start_cycle_pulse_count), (0)::bigint) AS cycles_from_order_start,
    cycle_rate_ppm,
    last_cycle_age_s,
        CASE
            WHEN (comm_ok = false) THEN 'BAD_COMMUNICATION'::text
            WHEN ((sample_gap_s IS NOT NULL) AND (sample_gap_s > (30)::numeric)) THEN 'TELEMETRY_GAP'::text
            WHEN (power_total_kw IS NULL) THEN 'NO_POWER_VALUE'::text
            WHEN (import_kwh IS NULL) THEN 'NO_IMPORT_KWH'::text
            ELSE 'OK'::text
        END AS sample_quality_status,
    payload_json
   FROM enriched;


ALTER VIEW mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 OWNER TO mesavault;

--
-- Name: order_execution_data_quality_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_data_quality_v1 AS
 WITH base AS (
         SELECT r.order_row_id,
            r.tenant,
            r.site,
            r.odoo_instance,
            r.odoo_workorder_id,
            r.odoo_production_id,
            r.odoo_order_ref,
            r.odoo_state,
            r.odoo_workcenter_code,
            r.odoo_workcenter_name,
            r.machine_id,
            r.asset,
            r.product,
            r.qty_planned,
            r.qty_done,
            r.uom,
            r.planned_cycles,
            r.target_cycle_rate_ppm,
            r.start_ts,
            r.end_ts,
            r.window_min,
            r.telemetry_samples,
            r.telemetry_first_ts,
            r.telemetry_last_ts,
            r.min_cycle_pulse_count,
            r.max_cycle_pulse_count,
            r.real_cycle_delta,
            r.avg_cycle_rate_ppm,
            r.avg_nonzero_cycle_rate_ppm,
            r.energy_samples,
            r.energy_first_ts,
            r.energy_last_ts,
            r.start_import_kwh,
            r.end_import_kwh,
            r.kwh_consumed,
            r.avg_kw,
            r.max_kw,
            r.stop_count,
            r.stop_min,
            r.classified_stops,
            r.pending_stops,
            r.stop_cost_eur,
            r.report_status,
            r.report_status_description,
            GREATEST(((floor((EXTRACT(epoch FROM (r.end_ts - r.start_ts)) / 10.0)))::integer + 1), 1) AS expected_samples_10s
           FROM mv_reports_ucepsa_demo.order_execution_report_v1 r
        ), gap_stats AS (
         SELECT t.order_row_id,
            count(*) FILTER (WHERE ((t.sample_gap_s IS NOT NULL) AND (t.sample_gap_s > (30)::numeric))) AS telemetry_gap_count_30s,
            round(max(t.sample_gap_s), 2) AS max_sample_gap_s,
            round(avg(t.sample_gap_s) FILTER (WHERE (t.sample_gap_s IS NOT NULL)), 2) AS avg_sample_gap_s,
            count(*) FILTER (WHERE (t.sample_quality_status <> 'OK'::text)) AS non_ok_samples
           FROM mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 t
          GROUP BY t.order_row_id
        ), scored AS (
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.product,
            b.machine_id,
            b.asset,
            b.start_ts,
            b.end_ts,
            b.window_min,
            b.qty_planned,
            b.qty_done,
            b.uom,
            b.planned_cycles,
            b.target_cycle_rate_ppm,
            b.telemetry_samples,
            b.energy_samples,
            b.expected_samples_10s,
            round((((COALESCE(b.telemetry_samples, (0)::bigint))::numeric / (NULLIF(b.expected_samples_10s, 0))::numeric) * 100.0), 2) AS telemetry_sample_coverage_pct,
            b.telemetry_first_ts,
            b.telemetry_last_ts,
            b.energy_first_ts,
            b.energy_last_ts,
            b.real_cycle_delta,
            b.avg_cycle_rate_ppm,
            b.avg_nonzero_cycle_rate_ppm,
            b.kwh_consumed,
            b.avg_kw,
            b.max_kw,
            b.stop_count,
            b.stop_min,
            b.classified_stops,
            b.pending_stops,
            b.stop_cost_eur,
            COALESCE(g.telemetry_gap_count_30s, (0)::bigint) AS telemetry_gap_count_30s,
            COALESCE(g.max_sample_gap_s, (0)::numeric) AS max_sample_gap_s,
            COALESCE(g.avg_sample_gap_s, (0)::numeric) AS avg_sample_gap_s,
            COALESCE(g.non_ok_samples, (0)::bigint) AS non_ok_samples,
            b.report_status,
            b.report_status_description,
                CASE
                    WHEN (COALESCE(b.planned_cycles, (0)::numeric) <= (0)::numeric) THEN 'SIN_OBJETIVO_CICLOS'::text
                    WHEN ((COALESCE(b.real_cycle_delta, (0)::bigint) = 0) AND (COALESCE(b.qty_done, (0)::numeric) > (0)::numeric)) THEN 'CANTIDAD_ODOO_SIN_CICLOS_EDGE'::text
                    WHEN ((COALESCE(b.real_cycle_delta, (0)::bigint) > 0) AND (COALESCE(b.planned_cycles, (0)::numeric) > (0)::numeric) AND ((((COALESCE(b.real_cycle_delta, (0)::bigint))::numeric / NULLIF(b.planned_cycles, (0)::numeric)) >= 0.5) AND (((COALESCE(b.real_cycle_delta, (0)::bigint))::numeric / NULLIF(b.planned_cycles, (0)::numeric)) <= 1.5))) THEN 'CICLOS_COHERENTES_CON_OBJETIVO'::text
                    ELSE 'REVISAR_CONVERSION_ODOO_CICLOS'::text
                END AS production_conversion_status,
            GREATEST(0, (((((((100 -
                CASE
                    WHEN (COALESCE(b.telemetry_samples, (0)::bigint) = 0) THEN 60
                    ELSE 0
                END) -
                CASE
                    WHEN (COALESCE(b.energy_samples, (0)::bigint) = 0) THEN 50
                    ELSE 0
                END) -
                CASE
                    WHEN (b.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 20
                    ELSE 0
                END) -
                CASE
                    WHEN (COALESCE(b.pending_stops, (0)::bigint) > 0) THEN 20
                    ELSE 0
                END) -
                CASE
                    WHEN (COALESCE(g.telemetry_gap_count_30s, (0)::bigint) > 0) THEN LEAST(((COALESCE(g.telemetry_gap_count_30s, (0)::bigint))::integer * 2), 15)
                    ELSE 0
                END) -
                CASE
                    WHEN (COALESCE(g.max_sample_gap_s, (0)::numeric) > (60)::numeric) THEN 10
                    ELSE 0
                END) -
                CASE
                    WHEN (COALESCE(g.non_ok_samples, (0)::bigint) > 0) THEN 10
                    ELSE 0
                END)) AS technical_quality_score
           FROM (base b
             LEFT JOIN gap_stats g ON ((g.order_row_id = b.order_row_id)))
        )
 SELECT order_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_workorder_id,
    odoo_production_id,
    odoo_order_ref,
    odoo_state,
    product,
    machine_id,
    asset,
    start_ts,
    end_ts,
    window_min,
    qty_planned,
    qty_done,
    uom,
    planned_cycles,
    target_cycle_rate_ppm,
    telemetry_samples,
    energy_samples,
    expected_samples_10s,
    telemetry_sample_coverage_pct,
    telemetry_first_ts,
    telemetry_last_ts,
    energy_first_ts,
    energy_last_ts,
    real_cycle_delta,
    avg_cycle_rate_ppm,
    avg_nonzero_cycle_rate_ppm,
    kwh_consumed,
    avg_kw,
    max_kw,
    stop_count,
    stop_min,
    classified_stops,
    pending_stops,
    stop_cost_eur,
    telemetry_gap_count_30s,
    max_sample_gap_s,
    avg_sample_gap_s,
    non_ok_samples,
    report_status,
    report_status_description,
    production_conversion_status,
    technical_quality_score,
        CASE
            WHEN (technical_quality_score >= 90) THEN 'FIABLE'::text
            WHEN (technical_quality_score >= 70) THEN 'ACEPTABLE_CON_OBSERVACIONES'::text
            WHEN (technical_quality_score >= 40) THEN 'PARCIAL'::text
            ELSE 'NO_DEFENDIBLE'::text
        END AS technical_quality_level,
        CASE
            WHEN (COALESCE(telemetry_samples, (0)::bigint) = 0) THEN 'No hay telemetría Edge-OEE dentro de la ventana de la orden. El informe solo puede apoyarse en Odoo.'::text
            WHEN (COALESCE(energy_samples, (0)::bigint) = 0) THEN 'Faltan muestras energéticas válidas dentro de la ventana de la orden.'::text
            WHEN (odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 'La orden sigue abierta. El informe debe tratarse como parcial.'::text
            WHEN (COALESCE(pending_stops, (0)::bigint) > 0) THEN 'Hay paros pendientes de clasificación. Conviene clasificarlos antes de cerrar el informe.'::text
            WHEN (COALESCE(telemetry_gap_count_30s, (0)::bigint) > 0) THEN 'Hay gaps de telemetría superiores a 30 segundos. Revisar continuidad de señal.'::text
            WHEN (production_conversion_status = 'REVISAR_CONVERSION_ODOO_CICLOS'::text) THEN 'El informe técnico es válido para paros, energía y ciclos reales; revisar la conversión entre cantidad Odoo y ciclos/golpes.'::text
            ELSE 'Datos suficientes para generar informe técnico de orden.'::text
        END AS recommended_action
   FROM scored;


ALTER VIEW mv_reports_ucepsa_demo.order_execution_data_quality_v1 OWNER TO mesavault;

--
-- Name: order_execution_stops_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_stops_v1 AS
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.odoo_state,
    r.product,
    r.machine_id,
    r.asset,
    r.start_ts AS order_start_ts,
    r.end_ts AS order_end_ts,
    r.report_status AS order_report_status,
    ms.id AS stop_id,
    ms.started_at AS stop_started_at,
    ms.ended_at AS stop_ended_at,
    GREATEST(ms.started_at, r.start_ts) AS attributed_started_at,
    LEAST(COALESCE(ms.ended_at, r.end_ts), r.end_ts) AS attributed_ended_at,
    round(ms.duration_s, 2) AS original_duration_s,
    round((ms.duration_s / 60.0), 2) AS original_duration_min,
    round(EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, r.end_ts), r.end_ts) - GREATEST(ms.started_at, r.start_ts))), 2) AS attributed_duration_s,
    round((EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, r.end_ts), r.end_ts) - GREATEST(ms.started_at, r.start_ts))) / 60.0), 2) AS attributed_duration_min,
    ms.status AS stop_status,
    ms.classification_status,
    ms.cause_code,
    ms.operator_note,
    ms.value_hour_eur,
    round(((EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, r.end_ts), r.end_ts) - GREATEST(ms.started_at, r.start_ts))) / 3600.0) * ms.value_hour_eur), 2) AS attributed_cost_eur,
    ms.start_event_name,
    ms.end_event_name,
    ms.created_at,
    ms.updated_at,
        CASE
            WHEN (ms.status = 'OPEN'::text) THEN 'PARO_ABIERTO'::text
            WHEN (ms.classification_status = 'PENDING'::text) THEN 'PENDIENTE_CLASIFICACION'::text
            WHEN (ms.classification_status = 'CLASSIFIED'::text) THEN 'CLASIFICADO'::text
            ELSE 'SIN_ESTADO_CLARO'::text
        END AS stop_quality_status
   FROM (mv_reports_ucepsa_demo.order_execution_report_v1 r
     JOIN mv_hot.edge_oee_machine_stops ms ON (((ms.machine_id = r.machine_id) AND (ms.started_at < r.end_ts) AND (COALESCE(ms.ended_at, r.end_ts) > r.start_ts))))
  WHERE (LEAST(COALESCE(ms.ended_at, r.end_ts), r.end_ts) > GREATEST(ms.started_at, r.start_ts));


ALTER VIEW mv_reports_ucepsa_demo.order_execution_stops_v1 OWNER TO mesavault;

--
-- Name: order_execution_stop_causes_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_stop_causes_v1 AS
 SELECT order_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_workorder_id,
    odoo_production_id,
    odoo_order_ref,
    product,
    machine_id,
    cause_code,
    count(*) AS stop_count,
    round(sum(attributed_duration_min), 2) AS total_stop_min,
    round(sum(attributed_cost_eur), 2) AS total_stop_cost_eur,
    count(*) FILTER (WHERE (classification_status = 'CLASSIFIED'::text)) AS classified_stop_count,
    count(*) FILTER (WHERE (classification_status = 'PENDING'::text)) AS pending_stop_count,
    min(stop_started_at) AS first_stop_at,
    max(stop_ended_at) AS last_stop_at
   FROM mv_reports_ucepsa_demo.order_execution_stops_v1
  GROUP BY order_row_id, tenant, site, odoo_instance, odoo_workorder_id, odoo_production_id, odoo_order_ref, product, machine_id, cause_code;


ALTER VIEW mv_reports_ucepsa_demo.order_execution_stop_causes_v1 OWNER TO mesavault;

--
-- Name: order_execution_timeline_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_timeline_v1 AS
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.product,
    r.machine_id,
    r.asset,
    r.start_ts AS event_ts,
    'ORDER_START'::text AS event_type,
    'Inicio de orden'::text AS event_label,
    'INFO'::text AS severity,
    NULL::bigint AS stop_id,
    NULL::bigint AS node_event_id,
    NULL::text AS cause_code,
    NULL::numeric AS duration_min,
    NULL::numeric AS cost_eur,
    'Inicio de la ventana de ejecución de la orden según Odoo.'::text AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_report_v1', 'odoo_state', r.odoo_state, 'qty_planned', r.qty_planned, 'qty_done', r.qty_done, 'uom', r.uom) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_report_v1 r
  WHERE (r.start_ts IS NOT NULL)
UNION ALL
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.product,
    r.machine_id,
    r.asset,
    r.telemetry_first_ts AS event_ts,
    'FIRST_TELEMETRY'::text AS event_type,
    'Primera telemetría Edge-OEE'::text AS event_label,
    'INFO'::text AS severity,
    NULL::bigint AS stop_id,
    NULL::bigint AS node_event_id,
    NULL::text AS cause_code,
    NULL::numeric AS duration_min,
    NULL::numeric AS cost_eur,
    'Primera muestra de telemetría recibida dentro de la ventana de la orden.'::text AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_report_v1', 'telemetry_samples', r.telemetry_samples, 'energy_samples', r.energy_samples) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_report_v1 r
  WHERE (r.telemetry_first_ts IS NOT NULL)
UNION ALL
 SELECT s.order_row_id,
    s.tenant,
    s.site,
    s.odoo_instance,
    s.odoo_workorder_id,
    s.odoo_production_id,
    s.odoo_order_ref,
    s.product,
    s.machine_id,
    s.asset,
    s.attributed_started_at AS event_ts,
    'STOP_START'::text AS event_type,
    'Inicio de paro'::text AS event_label,
        CASE
            WHEN (s.classification_status = 'PENDING'::text) THEN 'WARNING'::text
            ELSE 'LOSS'::text
        END AS severity,
    s.stop_id,
    NULL::bigint AS node_event_id,
    s.cause_code,
    s.attributed_duration_min AS duration_min,
    s.attributed_cost_eur AS cost_eur,
    concat('Inicio de paro imputado a la orden. Causa: ', COALESCE(s.cause_code, 'sin clasificar'::text), '. Duración imputada: ', COALESCE((s.attributed_duration_min)::text, '0'::text), ' min.') AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_stops_v1', 'stop_id', s.stop_id, 'classification_status', s.classification_status, 'operator_note', s.operator_note, 'original_started_at', s.stop_started_at, 'original_ended_at', s.stop_ended_at) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_stops_v1 s
UNION ALL
 SELECT s.order_row_id,
    s.tenant,
    s.site,
    s.odoo_instance,
    s.odoo_workorder_id,
    s.odoo_production_id,
    s.odoo_order_ref,
    s.product,
    s.machine_id,
    s.asset,
    s.attributed_ended_at AS event_ts,
    'STOP_END'::text AS event_type,
    'Fin de paro'::text AS event_label,
        CASE
            WHEN (s.classification_status = 'PENDING'::text) THEN 'WARNING'::text
            ELSE 'INFO'::text
        END AS severity,
    s.stop_id,
    NULL::bigint AS node_event_id,
    s.cause_code,
    s.attributed_duration_min AS duration_min,
    s.attributed_cost_eur AS cost_eur,
    concat('Fin de paro imputado a la orden. Causa: ', COALESCE(s.cause_code, 'sin clasificar'::text), '. Coste imputado: ', COALESCE((s.attributed_cost_eur)::text, '0'::text), ' €.') AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_stops_v1', 'stop_id', s.stop_id, 'classification_status', s.classification_status, 'operator_note', s.operator_note, 'value_hour_eur', s.value_hour_eur) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_stops_v1 s
UNION ALL
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.product,
    r.machine_id,
    r.asset,
    r.telemetry_last_ts AS event_ts,
    'LAST_TELEMETRY'::text AS event_type,
    'Última telemetría Edge-OEE'::text AS event_label,
        CASE
            WHEN (r.report_status = 'PARCIAL_ORDEN_EN_CURSO'::text) THEN 'WARNING'::text
            ELSE 'INFO'::text
        END AS severity,
    NULL::bigint AS stop_id,
    NULL::bigint AS node_event_id,
    NULL::text AS cause_code,
    NULL::numeric AS duration_min,
    NULL::numeric AS cost_eur,
    'Última muestra de telemetría recibida dentro de la ventana analizada.'::text AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_report_v1', 'real_cycle_delta', r.real_cycle_delta, 'kwh_consumed', r.kwh_consumed, 'avg_kw', r.avg_kw, 'max_kw', r.max_kw) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_report_v1 r
  WHERE (r.telemetry_last_ts IS NOT NULL)
UNION ALL
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.product,
    r.machine_id,
    r.asset,
    r.end_ts AS event_ts,
        CASE
            WHEN (r.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 'REPORT_CUTOFF'::text
            ELSE 'ORDER_END'::text
        END AS event_type,
        CASE
            WHEN (r.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text])) THEN 'Corte provisional del informe'::text
            ELSE 'Fin de orden'::text
        END AS event_label,
        CASE
            WHEN (r.report_status = 'CERRADO_CALCULABLE'::text) THEN 'INFO'::text
            ELSE 'WARNING'::text
        END AS severity,
    NULL::bigint AS stop_id,
    NULL::bigint AS node_event_id,
    NULL::text AS cause_code,
    NULL::numeric AS duration_min,
    NULL::numeric AS cost_eur,
    r.report_status_description AS description,
    jsonb_build_object('source', 'mv_reports_ucepsa_demo.order_execution_report_v1', 'report_status', r.report_status, 'window_min', r.window_min, 'stop_count', r.stop_count, 'stop_min', r.stop_min, 'stop_cost_eur', r.stop_cost_eur) AS evidence_json
   FROM mv_reports_ucepsa_demo.order_execution_report_v1 r
  WHERE (r.end_ts IS NOT NULL);


ALTER VIEW mv_reports_ucepsa_demo.order_execution_timeline_v1 OWNER TO mesavault;

--
-- Name: order_execution_report_full_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_execution_report_full_v1 AS
 WITH stop_causes_json AS (
         SELECT order_execution_stop_causes_v1.order_row_id,
            jsonb_agg(jsonb_build_object('cause_code', order_execution_stop_causes_v1.cause_code, 'stop_count', order_execution_stop_causes_v1.stop_count, 'total_stop_min', order_execution_stop_causes_v1.total_stop_min, 'total_stop_cost_eur', order_execution_stop_causes_v1.total_stop_cost_eur, 'classified_stop_count', order_execution_stop_causes_v1.classified_stop_count, 'pending_stop_count', order_execution_stop_causes_v1.pending_stop_count, 'first_stop_at', order_execution_stop_causes_v1.first_stop_at, 'last_stop_at', order_execution_stop_causes_v1.last_stop_at) ORDER BY order_execution_stop_causes_v1.total_stop_min DESC) AS stop_causes_json,
            string_agg(concat(COALESCE(order_execution_stop_causes_v1.cause_code, 'sin_clasificar'::text), ': ', order_execution_stop_causes_v1.stop_count, ' paros / ', order_execution_stop_causes_v1.total_stop_min, ' min / ', order_execution_stop_causes_v1.total_stop_cost_eur, ' €'), '; '::text ORDER BY order_execution_stop_causes_v1.total_stop_min DESC) AS stop_causes_summary
           FROM mv_reports_ucepsa_demo.order_execution_stop_causes_v1
          GROUP BY order_execution_stop_causes_v1.order_row_id
        ), stops_json AS (
         SELECT order_execution_stops_v1.order_row_id,
            jsonb_agg(jsonb_build_object('stop_id', order_execution_stops_v1.stop_id, 'stop_started_at', order_execution_stops_v1.stop_started_at, 'stop_ended_at', order_execution_stops_v1.stop_ended_at, 'attributed_started_at', order_execution_stops_v1.attributed_started_at, 'attributed_ended_at', order_execution_stops_v1.attributed_ended_at, 'attributed_duration_min', order_execution_stops_v1.attributed_duration_min, 'cause_code', order_execution_stops_v1.cause_code, 'operator_note', order_execution_stops_v1.operator_note, 'classification_status', order_execution_stops_v1.classification_status, 'attributed_cost_eur', order_execution_stops_v1.attributed_cost_eur, 'stop_quality_status', order_execution_stops_v1.stop_quality_status) ORDER BY order_execution_stops_v1.attributed_started_at) AS stops_json
           FROM mv_reports_ucepsa_demo.order_execution_stops_v1
          GROUP BY order_execution_stops_v1.order_row_id
        ), timeline_json AS (
         SELECT order_execution_timeline_v1.order_row_id,
            jsonb_agg(jsonb_build_object('event_ts', order_execution_timeline_v1.event_ts, 'event_type', order_execution_timeline_v1.event_type, 'event_label', order_execution_timeline_v1.event_label, 'severity', order_execution_timeline_v1.severity, 'stop_id', order_execution_timeline_v1.stop_id, 'cause_code', order_execution_timeline_v1.cause_code, 'duration_min', order_execution_timeline_v1.duration_min, 'cost_eur', order_execution_timeline_v1.cost_eur, 'description', order_execution_timeline_v1.description) ORDER BY order_execution_timeline_v1.event_ts, order_execution_timeline_v1.event_type) AS timeline_json
           FROM mv_reports_ucepsa_demo.order_execution_timeline_v1
          GROUP BY order_execution_timeline_v1.order_row_id
        )
 SELECT r.order_row_id,
    r.tenant,
    r.site,
    r.odoo_instance,
    r.odoo_workorder_id,
    r.odoo_production_id,
    r.odoo_order_ref,
    r.odoo_state,
    r.odoo_workcenter_code,
    r.odoo_workcenter_name,
    r.machine_id,
    r.asset,
    r.product,
    r.qty_planned,
    r.qty_done,
    r.uom,
    r.planned_cycles,
    r.target_cycle_rate_ppm,
    r.start_ts,
    r.end_ts,
    r.window_min,
    GREATEST((r.window_min - r.stop_min), (0)::numeric) AS run_min,
        CASE
            WHEN (r.window_min > (0)::numeric) THEN round(((r.stop_min / r.window_min) * 100.0), 2)
            ELSE NULL::numeric
        END AS stop_pct,
        CASE
            WHEN (r.window_min > (0)::numeric) THEN round(((GREATEST((r.window_min - r.stop_min), (0)::numeric) / r.window_min) * 100.0), 2)
            ELSE NULL::numeric
        END AS availability_pct,
    r.telemetry_samples,
    r.telemetry_first_ts,
    r.telemetry_last_ts,
    r.energy_samples,
    r.energy_first_ts,
    r.energy_last_ts,
    r.start_import_kwh,
    r.end_import_kwh,
    r.kwh_consumed,
    r.avg_kw,
    r.max_kw,
    r.min_cycle_pulse_count,
    r.max_cycle_pulse_count,
    r.real_cycle_delta,
    r.avg_cycle_rate_ppm,
    r.avg_nonzero_cycle_rate_ppm,
        CASE
            WHEN (r.real_cycle_delta > 0) THEN round((r.kwh_consumed / (NULLIF(r.real_cycle_delta, 0))::numeric), 6)
            ELSE NULL::numeric
        END AS kwh_per_cycle,
        CASE
            WHEN (GREATEST((r.window_min - r.stop_min), (0)::numeric) > (0)::numeric) THEN round(((r.real_cycle_delta)::numeric / NULLIF(GREATEST((r.window_min - r.stop_min), (0)::numeric), (0)::numeric)), 2)
            ELSE NULL::numeric
        END AS cycles_per_run_min,
    r.stop_count,
    r.stop_min,
    r.classified_stops,
    r.pending_stops,
    r.stop_cost_eur,
    COALESCE(sc.stop_causes_summary, 'Sin paros imputados'::text) AS stop_causes_summary,
    COALESCE(sc.stop_causes_json, '[]'::jsonb) AS stop_causes_json,
    COALESCE(sj.stops_json, '[]'::jsonb) AS stops_json,
    COALESCE(tj.timeline_json, '[]'::jsonb) AS timeline_json,
    q.expected_samples_10s,
    q.telemetry_sample_coverage_pct,
    q.telemetry_gap_count_30s,
    q.max_sample_gap_s,
    q.avg_sample_gap_s,
    q.non_ok_samples,
    q.production_conversion_status,
    q.technical_quality_score,
    q.technical_quality_level,
    r.report_status,
    r.report_status_description,
    q.recommended_action,
        CASE
            WHEN ((r.report_status = 'CERRADO_CALCULABLE'::text) AND (q.technical_quality_level = 'FIABLE'::text) AND (q.production_conversion_status = 'CICLOS_COHERENTES_CON_OBJETIVO'::text)) THEN 'LISTO_INFORME_FINAL'::text
            WHEN ((r.report_status = 'CERRADO_CALCULABLE'::text) AND (q.technical_quality_level = 'FIABLE'::text) AND (q.production_conversion_status = 'REVISAR_CONVERSION_ODOO_CICLOS'::text)) THEN 'LISTO_TECNICO_REVISAR_CONVERSION'::text
            WHEN ((r.report_status = 'CERRADO_CALCULABLE'::text) AND (q.technical_quality_level = ANY (ARRAY['FIABLE'::text, 'ACEPTABLE_CON_OBSERVACIONES'::text]))) THEN 'LISTO_CON_OBSERVACIONES'::text
            WHEN (r.report_status = 'PARCIAL_ORDEN_EN_CURSO'::text) THEN 'INFORME_PARCIAL_ORDEN_EN_CURSO'::text
            WHEN (r.report_status = 'SIN_TELEMETRIA_EN_VENTANA'::text) THEN 'BLOQUEADO_SIN_TELEMETRIA'::text
            WHEN (r.report_status = 'SIN_ENERGIA_EN_VENTANA'::text) THEN 'BLOQUEADO_SIN_ENERGIA'::text
            WHEN (r.pending_stops > 0) THEN 'PENDIENTE_CLASIFICAR_PAROS'::text
            ELSE 'REVISAR'::text
        END AS final_report_status,
    concat('Orden ', r.odoo_order_ref, ' en ', r.machine_id, ': duración ', r.window_min, ' min; ciclos reales ', r.real_cycle_delta, '; energía ', COALESCE((r.kwh_consumed)::text, 'sin dato'::text), ' kWh; paros ', r.stop_count, ' (', r.stop_min, ' min); coste estimado ', r.stop_cost_eur, ' €. Estado técnico: ', q.technical_quality_level, '.') AS executive_summary
   FROM ((((mv_reports_ucepsa_demo.order_execution_report_v1 r
     LEFT JOIN mv_reports_ucepsa_demo.order_execution_data_quality_v1 q ON ((q.order_row_id = r.order_row_id)))
     LEFT JOIN stop_causes_json sc ON ((sc.order_row_id = r.order_row_id)))
     LEFT JOIN stops_json sj ON ((sj.order_row_id = r.order_row_id)))
     LEFT JOIN timeline_json tj ON ((tj.order_row_id = r.order_row_id)));


ALTER VIEW mv_reports_ucepsa_demo.order_execution_report_full_v1 OWNER TO mesavault;

--
-- Name: order_raw_material_costs_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_raw_material_costs_v1 AS
 WITH raw_moves AS (
         SELECT c.id AS commercial_row_id,
            c.tenant,
            c.site,
            c.odoo_instance,
            c.odoo_production_id,
            c.odoo_order_ref,
            c.sale_order_ref,
            c.customer_name,
            c.product_default_code AS finished_product_default_code,
            c.product_name AS finished_product_name,
            ((rm.raw_move ->> 'id'::text))::integer AS raw_move_id,
            (NULLIF(((rm.raw_move -> 'product_id'::text) ->> 0), ''::text))::integer AS raw_product_id,
            ((rm.raw_move -> 'product_id'::text) ->> 1) AS raw_product_name,
            "substring"(((rm.raw_move -> 'product_id'::text) ->> 1), '\[([^\]]+)\]'::text) AS raw_product_default_code,
            (NULLIF((rm.raw_move ->> 'product_uom_qty'::text), ''::text))::numeric AS planned_qty,
            (NULLIF((rm.raw_move ->> 'quantity'::text), ''::text))::numeric AS consumed_qty,
            ((rm.raw_move -> 'product_uom'::text) ->> 1) AS raw_uom,
            (NULLIF((rm.raw_move ->> 'price_unit'::text), ''::text))::numeric AS odoo_price_unit,
            (NULLIF((rm.raw_move ->> 'value'::text), ''::text))::numeric AS odoo_value,
            (rm.raw_move ->> 'state'::text) AS move_state,
            rm.raw_move AS raw_move_json
           FROM (mv_edge_oee_ucepsa_demo.odoo_order_commercials c
             CROSS JOIN LATERAL jsonb_array_elements(c.stock_raw_moves_json) rm(raw_move))
        ), costed AS (
         SELECT r.commercial_row_id,
            r.tenant,
            r.site,
            r.odoo_instance,
            r.odoo_production_id,
            r.odoo_order_ref,
            r.sale_order_ref,
            r.customer_name,
            r.finished_product_default_code,
            r.finished_product_name,
            r.raw_move_id,
            r.raw_product_id,
            r.raw_product_name,
            r.raw_product_default_code,
            r.planned_qty,
            r.consumed_qty,
            r.raw_uom,
            r.odoo_price_unit,
            r.odoo_value,
            r.move_state,
            r.raw_move_json,
            p.id AS raw_material_cost_parameter_id,
            p.material_cost_eur_per_kg,
            p.source AS raw_material_cost_source,
            p.notes AS raw_material_cost_notes,
                CASE
                    WHEN (COALESCE(r.odoo_value, (0)::numeric) <> (0)::numeric) THEN abs(r.odoo_value)
                    WHEN ((lower(COALESCE(r.raw_uom, ''::text)) = 'kg'::text) AND (p.material_cost_eur_per_kg IS NOT NULL) AND (r.consumed_qty IS NOT NULL)) THEN (r.consumed_qty * p.material_cost_eur_per_kg)
                    ELSE NULL::numeric
                END AS material_cost_estimated_eur,
                CASE
                    WHEN (COALESCE(r.odoo_value, (0)::numeric) <> (0)::numeric) THEN 'FROM_ODOO_STOCK_MOVE_VALUE'::text
                    WHEN (r.raw_product_default_code IS NULL) THEN 'MISSING_RAW_PRODUCT_CODE'::text
                    WHEN (lower(COALESCE(r.raw_uom, ''::text)) <> 'kg'::text) THEN 'UNSUPPORTED_RAW_UOM'::text
                    WHEN (p.material_cost_eur_per_kg IS NULL) THEN 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text
                    WHEN (r.consumed_qty IS NULL) THEN 'MISSING_CONSUMED_QTY'::text
                    ELSE 'FROM_RAW_MATERIAL_COST_PARAMETER'::text
                END AS material_cost_status
           FROM (raw_moves r
             LEFT JOIN LATERAL ( SELECT p_1.id,
                    p_1.tenant,
                    p_1.site,
                    p_1.raw_product_default_code,
                    p_1.raw_product_name,
                    p_1.material_cost_eur_per_kg,
                    p_1.source,
                    p_1.valid_from,
                    p_1.valid_to,
                    p_1.is_active,
                    p_1.notes,
                    p_1.created_at
                   FROM mv_edge_oee_ucepsa_demo.raw_material_cost_parameters p_1
                  WHERE ((p_1.tenant = r.tenant) AND (p_1.site = r.site) AND (p_1.is_active = true) AND (p_1.raw_product_default_code = r.raw_product_default_code) AND (p_1.valid_from <= now()) AND ((p_1.valid_to IS NULL) OR (p_1.valid_to > now())))
                  ORDER BY p_1.valid_from DESC, p_1.id DESC
                 LIMIT 1) p ON (true))
        )
 SELECT commercial_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_production_id,
    odoo_order_ref,
    sale_order_ref,
    customer_name,
    finished_product_default_code,
    finished_product_name,
    raw_move_id,
    raw_product_id,
    raw_product_name,
    raw_product_default_code,
    planned_qty,
    consumed_qty,
    raw_uom,
    odoo_price_unit,
    odoo_value,
    move_state,
    raw_move_json,
    raw_material_cost_parameter_id,
    material_cost_eur_per_kg,
    raw_material_cost_source,
    raw_material_cost_notes,
    material_cost_estimated_eur,
    material_cost_status,
    round(material_cost_estimated_eur, 4) AS material_cost_estimated_eur_rounded
   FROM costed;


ALTER VIEW mv_reports_ucepsa_demo.order_raw_material_costs_v1 OWNER TO mesavault;

--
-- Name: order_raw_material_costs_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_raw_material_costs_summary_v1 AS
 SELECT tenant,
    site,
    odoo_instance,
    odoo_production_id,
    odoo_order_ref,
    sale_order_ref,
    customer_name,
    finished_product_default_code,
    finished_product_name,
    count(*) AS raw_material_line_count,
    round(sum(COALESCE(consumed_qty, (0)::numeric)), 3) AS total_consumed_qty,
    string_agg(concat(COALESCE(raw_product_default_code, 'sin_codigo'::text), ' - ', COALESCE(raw_product_name, 'sin_nombre'::text), ': ', COALESCE((consumed_qty)::text, 'sin_cantidad'::text), ' ', COALESCE(raw_uom, ''::text)), '; '::text ORDER BY raw_product_default_code) AS raw_materials_summary,
    round(sum(COALESCE(material_cost_estimated_eur, (0)::numeric)), 4) AS material_cost_estimated_eur,
    count(*) FILTER (WHERE (material_cost_estimated_eur IS NOT NULL)) AS costed_raw_material_line_count,
    count(*) FILTER (WHERE ((material_cost_status <> 'FROM_RAW_MATERIAL_COST_PARAMETER'::text) AND (material_cost_status <> 'FROM_ODOO_STOCK_MOVE_VALUE'::text))) AS missing_or_invalid_raw_material_cost_count,
    string_agg(DISTINCT material_cost_status, ', '::text ORDER BY material_cost_status) AS material_cost_status_summary
   FROM mv_reports_ucepsa_demo.order_raw_material_costs_v1
  GROUP BY tenant, site, odoo_instance, odoo_production_id, odoo_order_ref, sale_order_ref, customer_name, finished_product_default_code, finished_product_name;


ALTER VIEW mv_reports_ucepsa_demo.order_raw_material_costs_summary_v1 OWNER TO mesavault;

--
-- Name: order_margin_report_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.order_margin_report_v1 AS
 WITH joined AS (
         SELECT r.order_row_id,
            r.tenant,
            r.site,
            r.odoo_instance,
            r.odoo_workorder_id,
            r.odoo_production_id,
            r.odoo_order_ref,
            r.odoo_state,
            r.machine_id,
            r.asset,
            r.product AS edge_product,
            r.start_ts,
            r.end_ts,
            r.window_min,
            r.run_min,
            r.stop_min,
            r.stop_cost_eur,
            r.real_cycle_delta,
            r.kwh_consumed,
            r.kwh_per_cycle,
            r.technical_quality_level,
            r.final_report_status,
            c.odoo_origin,
            c.sale_order_ref,
            c.customer_id,
            c.customer_name,
            c.sale_state,
            c.sale_date_order,
            c.currency,
            c.product_id,
            c.product_default_code,
            c.product_name,
            c.production_qty,
            c.qty_producing,
            c.production_uom,
            c.sale_line_id,
            c.sale_order_id,
            c.sale_line_qty,
            c.sale_line_qty_delivered,
            c.sale_price_unit,
            c.sale_discount_pct,
            c.revenue_net_eur,
            c.revenue_total_eur,
            c.product_standard_price,
            c.product_list_price,
            c.raw_material_value_eur,
            c.finished_value_eur,
            c.material_cost_status AS odoo_material_cost_status,
            c.snapshot_at AS commercial_snapshot_at,
            rms.raw_material_line_count,
            rms.total_consumed_qty AS raw_total_consumed_qty,
            rms.raw_materials_summary,
            rms.material_cost_estimated_eur AS raw_material_cost_estimated_eur,
            rms.costed_raw_material_line_count,
            rms.missing_or_invalid_raw_material_cost_count,
            rms.material_cost_status_summary AS raw_material_cost_status_summary
           FROM ((mv_reports_ucepsa_demo.order_execution_report_full_v1 r
             LEFT JOIN mv_edge_oee_ucepsa_demo.odoo_order_commercials c ON (((c.odoo_instance = r.odoo_instance) AND (c.odoo_production_id = r.odoo_production_id))))
             LEFT JOIN mv_reports_ucepsa_demo.order_raw_material_costs_summary_v1 rms ON (((rms.odoo_instance = r.odoo_instance) AND (rms.odoo_production_id = r.odoo_production_id))))
        ), with_params AS (
         SELECT j.order_row_id,
            j.tenant,
            j.site,
            j.odoo_instance,
            j.odoo_workorder_id,
            j.odoo_production_id,
            j.odoo_order_ref,
            j.odoo_state,
            j.machine_id,
            j.asset,
            j.edge_product,
            j.start_ts,
            j.end_ts,
            j.window_min,
            j.run_min,
            j.stop_min,
            j.stop_cost_eur,
            j.real_cycle_delta,
            j.kwh_consumed,
            j.kwh_per_cycle,
            j.technical_quality_level,
            j.final_report_status,
            j.odoo_origin,
            j.sale_order_ref,
            j.customer_id,
            j.customer_name,
            j.sale_state,
            j.sale_date_order,
            j.currency,
            j.product_id,
            j.product_default_code,
            j.product_name,
            j.production_qty,
            j.qty_producing,
            j.production_uom,
            j.sale_line_id,
            j.sale_order_id,
            j.sale_line_qty,
            j.sale_line_qty_delivered,
            j.sale_price_unit,
            j.sale_discount_pct,
            j.revenue_net_eur,
            j.revenue_total_eur,
            j.product_standard_price,
            j.product_list_price,
            j.raw_material_value_eur,
            j.finished_value_eur,
            j.odoo_material_cost_status,
            j.commercial_snapshot_at,
            j.raw_material_line_count,
            j.raw_total_consumed_qty,
            j.raw_materials_summary,
            j.raw_material_cost_estimated_eur,
            j.costed_raw_material_line_count,
            j.missing_or_invalid_raw_material_cost_count,
            j.raw_material_cost_status_summary,
            p.id AS cost_parameter_id,
            p.scope_level AS cost_parameter_scope_level,
            p.energy_cost_eur_per_kwh,
            p.material_cost_eur_per_kg AS fallback_material_cost_eur_per_kg,
            p.machine_run_cost_eur_per_h,
            p.labor_cost_eur_per_h,
            p.overhead_cost_eur_per_h,
            p.notes AS cost_parameter_notes
           FROM (joined j
             LEFT JOIN LATERAL ( SELECT p_1.id,
                    p_1.tenant,
                    p_1.site,
                    p_1.scope_level,
                    p_1.machine_id,
                    p_1.product_default_code,
                    p_1.energy_cost_eur_per_kwh,
                    p_1.material_cost_eur_per_kg,
                    p_1.machine_run_cost_eur_per_h,
                    p_1.labor_cost_eur_per_h,
                    p_1.overhead_cost_eur_per_h,
                    p_1.valid_from,
                    p_1.valid_to,
                    p_1.is_active,
                    p_1.notes,
                    p_1.created_at
                   FROM mv_edge_oee_ucepsa_demo.margin_cost_parameters p_1
                  WHERE ((p_1.is_active = true) AND (p_1.tenant = j.tenant) AND (p_1.site = j.site) AND (p_1.valid_from <= now()) AND ((p_1.valid_to IS NULL) OR (p_1.valid_to > now())) AND ((p_1.machine_id IS NULL) OR (p_1.machine_id = j.machine_id)) AND ((p_1.product_default_code IS NULL) OR (p_1.product_default_code = j.product_default_code)))
                  ORDER BY
                        CASE
                            WHEN ((p_1.product_default_code IS NOT NULL) AND (p_1.machine_id IS NOT NULL)) THEN 1
                            WHEN (p_1.product_default_code IS NOT NULL) THEN 2
                            WHEN (p_1.machine_id IS NOT NULL) THEN 3
                            ELSE 4
                        END, p_1.valid_from DESC, p_1.id DESC
                 LIMIT 1) p ON (true))
        ), costs AS (
         SELECT with_params.order_row_id,
            with_params.tenant,
            with_params.site,
            with_params.odoo_instance,
            with_params.odoo_workorder_id,
            with_params.odoo_production_id,
            with_params.odoo_order_ref,
            with_params.odoo_state,
            with_params.machine_id,
            with_params.asset,
            with_params.edge_product,
            with_params.start_ts,
            with_params.end_ts,
            with_params.window_min,
            with_params.run_min,
            with_params.stop_min,
            with_params.stop_cost_eur,
            with_params.real_cycle_delta,
            with_params.kwh_consumed,
            with_params.kwh_per_cycle,
            with_params.technical_quality_level,
            with_params.final_report_status,
            with_params.odoo_origin,
            with_params.sale_order_ref,
            with_params.customer_id,
            with_params.customer_name,
            with_params.sale_state,
            with_params.sale_date_order,
            with_params.currency,
            with_params.product_id,
            with_params.product_default_code,
            with_params.product_name,
            with_params.production_qty,
            with_params.qty_producing,
            with_params.production_uom,
            with_params.sale_line_id,
            with_params.sale_order_id,
            with_params.sale_line_qty,
            with_params.sale_line_qty_delivered,
            with_params.sale_price_unit,
            with_params.sale_discount_pct,
            with_params.revenue_net_eur,
            with_params.revenue_total_eur,
            with_params.product_standard_price,
            with_params.product_list_price,
            with_params.raw_material_value_eur,
            with_params.finished_value_eur,
            with_params.odoo_material_cost_status,
            with_params.commercial_snapshot_at,
            with_params.raw_material_line_count,
            with_params.raw_total_consumed_qty,
            with_params.raw_materials_summary,
            with_params.raw_material_cost_estimated_eur,
            with_params.costed_raw_material_line_count,
            with_params.missing_or_invalid_raw_material_cost_count,
            with_params.raw_material_cost_status_summary,
            with_params.cost_parameter_id,
            with_params.cost_parameter_scope_level,
            with_params.energy_cost_eur_per_kwh,
            with_params.fallback_material_cost_eur_per_kg,
            with_params.machine_run_cost_eur_per_h,
            with_params.labor_cost_eur_per_h,
            with_params.overhead_cost_eur_per_h,
            with_params.cost_parameter_notes,
            COALESCE(NULLIF(with_params.qty_producing, (0)::numeric), NULLIF(with_params.production_qty, (0)::numeric)) AS costing_qty_kg,
                CASE
                    WHEN ((with_params.raw_material_line_count > 0) AND (COALESCE(with_params.missing_or_invalid_raw_material_cost_count, (0)::bigint) = 0) AND (with_params.raw_material_cost_estimated_eur IS NOT NULL)) THEN with_params.raw_material_cost_estimated_eur
                    WHEN ((with_params.raw_material_line_count > 0) AND (COALESCE(with_params.missing_or_invalid_raw_material_cost_count, (0)::bigint) > 0)) THEN NULL::numeric
                    WHEN ((with_params.raw_material_value_eur IS NOT NULL) AND (with_params.raw_material_value_eur <> (0)::numeric)) THEN abs(with_params.raw_material_value_eur)
                    WHEN ((with_params.product_standard_price IS NOT NULL) AND (with_params.product_standard_price <> (0)::numeric) AND (COALESCE(NULLIF(with_params.qty_producing, (0)::numeric), NULLIF(with_params.production_qty, (0)::numeric)) IS NOT NULL)) THEN (with_params.product_standard_price * COALESCE(NULLIF(with_params.qty_producing, (0)::numeric), NULLIF(with_params.production_qty, (0)::numeric)))
                    WHEN ((with_params.fallback_material_cost_eur_per_kg IS NOT NULL) AND (COALESCE(NULLIF(with_params.qty_producing, (0)::numeric), NULLIF(with_params.production_qty, (0)::numeric)) IS NOT NULL)) THEN (with_params.fallback_material_cost_eur_per_kg * COALESCE(NULLIF(with_params.qty_producing, (0)::numeric), NULLIF(with_params.production_qty, (0)::numeric)))
                    ELSE NULL::numeric
                END AS material_cost_estimated_eur,
                CASE
                    WHEN ((with_params.raw_material_line_count > 0) AND (COALESCE(with_params.missing_or_invalid_raw_material_cost_count, (0)::bigint) = 0)) THEN 'FROM_RAW_MATERIAL_COSTS'::text
                    WHEN ((with_params.raw_material_line_count > 0) AND (COALESCE(with_params.missing_or_invalid_raw_material_cost_count, (0)::bigint) > 0)) THEN with_params.raw_material_cost_status_summary
                    WHEN ((with_params.raw_material_value_eur IS NOT NULL) AND (with_params.raw_material_value_eur <> (0)::numeric)) THEN 'FROM_ODOO_RAW_MATERIAL_VALUE'::text
                    WHEN ((with_params.product_standard_price IS NOT NULL) AND (with_params.product_standard_price <> (0)::numeric)) THEN 'FROM_PRODUCT_STANDARD_PRICE'::text
                    WHEN (with_params.fallback_material_cost_eur_per_kg IS NOT NULL) THEN 'FROM_FALLBACK_MARGIN_PARAMETER'::text
                    ELSE 'MISSING_MATERIAL_COST'::text
                END AS material_cost_source_status,
                CASE
                    WHEN ((with_params.kwh_consumed IS NOT NULL) AND (with_params.energy_cost_eur_per_kwh IS NOT NULL)) THEN (with_params.kwh_consumed * with_params.energy_cost_eur_per_kwh)
                    ELSE NULL::numeric
                END AS energy_cost_estimated_eur,
                CASE
                    WHEN ((with_params.run_min IS NOT NULL) AND (with_params.machine_run_cost_eur_per_h IS NOT NULL)) THEN ((with_params.run_min / 60.0) * with_params.machine_run_cost_eur_per_h)
                    ELSE NULL::numeric
                END AS machine_run_cost_estimated_eur,
                CASE
                    WHEN ((with_params.window_min IS NOT NULL) AND (with_params.labor_cost_eur_per_h IS NOT NULL)) THEN ((with_params.window_min / 60.0) * with_params.labor_cost_eur_per_h)
                    ELSE NULL::numeric
                END AS labor_cost_estimated_eur,
                CASE
                    WHEN ((with_params.window_min IS NOT NULL) AND (with_params.overhead_cost_eur_per_h IS NOT NULL)) THEN ((with_params.window_min / 60.0) * with_params.overhead_cost_eur_per_h)
                    ELSE NULL::numeric
                END AS overhead_cost_estimated_eur
           FROM with_params
        )
 SELECT order_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_workorder_id,
    odoo_production_id,
    odoo_order_ref,
    odoo_state,
    odoo_origin,
    sale_order_ref,
    customer_id,
    customer_name,
    sale_state,
    sale_date_order,
    currency,
    machine_id,
    asset,
    product_id,
    product_default_code,
    COALESCE(product_name, edge_product) AS product_name,
    production_qty,
    qty_producing,
    production_uom,
    costing_qty_kg,
    sale_line_id,
    sale_order_id,
    sale_line_qty,
    sale_line_qty_delivered,
    sale_price_unit,
    sale_discount_pct,
    revenue_net_eur,
    revenue_total_eur,
    start_ts,
    end_ts,
    window_min,
    run_min,
    stop_min,
    stop_cost_eur,
    real_cycle_delta,
    kwh_consumed,
    kwh_per_cycle,
    product_standard_price,
    product_list_price,
    raw_material_value_eur,
    finished_value_eur,
    odoo_material_cost_status,
    raw_material_line_count,
    raw_total_consumed_qty,
    raw_materials_summary,
    raw_material_cost_status_summary,
    costed_raw_material_line_count,
    missing_or_invalid_raw_material_cost_count,
    cost_parameter_id,
    cost_parameter_scope_level,
    energy_cost_eur_per_kwh,
    fallback_material_cost_eur_per_kg,
    machine_run_cost_eur_per_h,
    labor_cost_eur_per_h,
    overhead_cost_eur_per_h,
    round(material_cost_estimated_eur, 4) AS material_cost_estimated_eur,
    material_cost_source_status,
    round(energy_cost_estimated_eur, 4) AS energy_cost_estimated_eur,
    round(machine_run_cost_estimated_eur, 4) AS machine_run_cost_estimated_eur,
    round(labor_cost_estimated_eur, 4) AS labor_cost_estimated_eur,
    round(overhead_cost_estimated_eur, 4) AS overhead_cost_estimated_eur,
    round((((((COALESCE(material_cost_estimated_eur, (0)::numeric) + COALESCE(energy_cost_estimated_eur, (0)::numeric)) + COALESCE(machine_run_cost_estimated_eur, (0)::numeric)) + COALESCE(labor_cost_estimated_eur, (0)::numeric)) + COALESCE(overhead_cost_estimated_eur, (0)::numeric)) + COALESCE(stop_cost_eur, (0)::numeric)), 4) AS known_or_estimated_cost_eur,
    round(
        CASE
            WHEN (revenue_net_eur IS NOT NULL) THEN (revenue_net_eur - (((((COALESCE(material_cost_estimated_eur, (0)::numeric) + COALESCE(energy_cost_estimated_eur, (0)::numeric)) + COALESCE(machine_run_cost_estimated_eur, (0)::numeric)) + COALESCE(labor_cost_estimated_eur, (0)::numeric)) + COALESCE(overhead_cost_estimated_eur, (0)::numeric)) + COALESCE(stop_cost_eur, (0)::numeric)))
            ELSE NULL::numeric
        END, 4) AS partial_margin_after_known_costs_eur,
    round(
        CASE
            WHEN ((revenue_net_eur IS NOT NULL) AND (material_cost_estimated_eur IS NOT NULL)) THEN (revenue_net_eur - (((((COALESCE(material_cost_estimated_eur, (0)::numeric) + COALESCE(energy_cost_estimated_eur, (0)::numeric)) + COALESCE(machine_run_cost_estimated_eur, (0)::numeric)) + COALESCE(labor_cost_estimated_eur, (0)::numeric)) + COALESCE(overhead_cost_estimated_eur, (0)::numeric)) + COALESCE(stop_cost_eur, (0)::numeric)))
            ELSE NULL::numeric
        END, 4) AS estimated_margin_eur,
    round(
        CASE
            WHEN ((revenue_net_eur IS NOT NULL) AND (revenue_net_eur <> (0)::numeric) AND (material_cost_estimated_eur IS NOT NULL)) THEN (((revenue_net_eur - (((((COALESCE(material_cost_estimated_eur, (0)::numeric) + COALESCE(energy_cost_estimated_eur, (0)::numeric)) + COALESCE(machine_run_cost_estimated_eur, (0)::numeric)) + COALESCE(labor_cost_estimated_eur, (0)::numeric)) + COALESCE(overhead_cost_estimated_eur, (0)::numeric)) + COALESCE(stop_cost_eur, (0)::numeric))) / revenue_net_eur) * 100.0)
            ELSE NULL::numeric
        END, 2) AS estimated_margin_pct,
        CASE
            WHEN (revenue_net_eur IS NULL) THEN 'NO_REVENUE_LINKED'::text
            ELSE 'REVENUE_LINKED'::text
        END AS revenue_status,
        CASE
            WHEN ((raw_material_line_count > 0) AND (COALESCE(missing_or_invalid_raw_material_cost_count, (0)::bigint) > 0)) THEN 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text
            WHEN (material_cost_estimated_eur IS NULL) THEN 'MISSING_MATERIAL_COST'::text
            WHEN (energy_cost_eur_per_kwh IS NULL) THEN 'MISSING_ENERGY_COST'::text
            WHEN (machine_run_cost_eur_per_h IS NULL) THEN 'MISSING_MACHINE_RUN_COST'::text
            ELSE 'COST_PARAMETERS_AVAILABLE'::text
        END AS cost_status,
        CASE
            WHEN (revenue_net_eur IS NULL) THEN 'NO_MARGIN_WITHOUT_REVENUE'::text
            WHEN ((raw_material_line_count > 0) AND (COALESCE(missing_or_invalid_raw_material_cost_count, (0)::bigint) > 0)) THEN 'PARTIAL_MARGIN_MISSING_RAW_MATERIAL_COST'::text
            WHEN (material_cost_estimated_eur IS NULL) THEN 'PARTIAL_MARGIN_MISSING_MATERIAL'::text
            ELSE 'ESTIMATED_MARGIN_AVAILABLE'::text
        END AS margin_status,
    technical_quality_level,
    final_report_status,
    commercial_snapshot_at
   FROM costs;


ALTER VIEW mv_reports_ucepsa_demo.order_margin_report_v1 OWNER TO mesavault;

--
-- Name: cost_readiness_orders_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.cost_readiness_orders_v1 AS
 WITH base AS (
         SELECT m.order_row_id,
            m.tenant,
            m.site,
            m.odoo_instance,
            m.odoo_workorder_id,
            m.odoo_production_id,
            m.odoo_order_ref,
            m.odoo_state,
            m.odoo_origin,
            m.sale_order_ref,
            m.customer_id,
            m.customer_name,
            m.sale_state,
            m.sale_date_order,
            m.currency,
            m.machine_id,
            m.asset,
            m.product_id,
            m.product_default_code,
            m.product_name,
            m.production_qty,
            m.qty_producing,
            m.production_uom,
            m.costing_qty_kg,
            m.sale_line_id,
            m.sale_order_id,
            m.sale_line_qty,
            m.sale_line_qty_delivered,
            m.sale_price_unit,
            m.sale_discount_pct,
            m.revenue_net_eur,
            m.revenue_total_eur,
            m.start_ts,
            m.end_ts,
            m.window_min,
            m.run_min,
            m.stop_min,
            m.stop_cost_eur,
            m.real_cycle_delta,
            m.kwh_consumed,
            m.kwh_per_cycle,
            m.product_standard_price,
            m.product_list_price,
            m.raw_material_value_eur,
            m.finished_value_eur,
            m.odoo_material_cost_status,
            m.raw_material_line_count,
            m.raw_total_consumed_qty,
            m.raw_materials_summary,
            m.raw_material_cost_status_summary,
            m.costed_raw_material_line_count,
            m.missing_or_invalid_raw_material_cost_count,
            m.cost_parameter_id,
            m.cost_parameter_scope_level,
            m.energy_cost_eur_per_kwh,
            m.fallback_material_cost_eur_per_kg,
            m.machine_run_cost_eur_per_h,
            m.labor_cost_eur_per_h,
            m.overhead_cost_eur_per_h,
            m.material_cost_estimated_eur,
            m.material_cost_source_status,
            m.energy_cost_estimated_eur,
            m.machine_run_cost_estimated_eur,
            m.labor_cost_estimated_eur,
            m.overhead_cost_estimated_eur,
            m.known_or_estimated_cost_eur,
            m.partial_margin_after_known_costs_eur,
            m.estimated_margin_eur,
            m.estimated_margin_pct,
            m.revenue_status,
            m.cost_status,
            m.margin_status,
            m.technical_quality_level,
            m.final_report_status,
            m.commercial_snapshot_at,
                CASE
                    WHEN (m.revenue_net_eur IS NOT NULL) THEN true
                    ELSE false
                END AS has_revenue,
                CASE
                    WHEN (NULLIF(TRIM(BOTH FROM COALESCE(m.customer_name, ''::text)), ''::text) IS NOT NULL) THEN true
                    ELSE false
                END AS has_customer,
                CASE
                    WHEN (NULLIF(TRIM(BOTH FROM COALESCE(m.sale_order_ref, ''::text)), ''::text) IS NOT NULL) THEN true
                    ELSE false
                END AS has_sale_order,
                CASE
                    WHEN (COALESCE(m.raw_material_line_count, (0)::bigint) > 0) THEN true
                    ELSE false
                END AS has_raw_materials,
                CASE
                    WHEN ((COALESCE(m.raw_material_line_count, (0)::bigint) > 0) AND (COALESCE(m.missing_or_invalid_raw_material_cost_count, (0)::bigint) = 0) AND (m.material_cost_estimated_eur IS NOT NULL)) THEN true
                    ELSE false
                END AS has_raw_material_cost,
                CASE
                    WHEN (m.technical_quality_level = ANY (ARRAY['FIABLE'::text, 'ACEPTABLE_CON_OBSERVACIONES'::text])) THEN true
                    ELSE false
                END AS has_usable_technical_data,
                CASE
                    WHEN (m.final_report_status = ANY (ARRAY['LISTO_INFORME_FINAL'::text, 'LISTO_TECNICO_REVISAR_CONVERSION'::text, 'LISTO_CON_OBSERVACIONES'::text])) THEN true
                    ELSE false
                END AS has_closed_or_usable_order_report,
                CASE
                    WHEN ((m.kwh_consumed IS NULL) OR (m.energy_cost_eur_per_kwh IS NOT NULL)) THEN true
                    ELSE false
                END AS has_energy_cost_parameter,
                CASE
                    WHEN ((m.run_min IS NULL) OR (m.machine_run_cost_eur_per_h IS NOT NULL)) THEN true
                    ELSE false
                END AS has_machine_cost_parameter
           FROM mv_reports_ucepsa_demo.order_margin_report_v1 m
        ), scored AS (
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.odoo_origin,
            b.sale_order_ref,
            b.customer_id,
            b.customer_name,
            b.sale_state,
            b.sale_date_order,
            b.currency,
            b.machine_id,
            b.asset,
            b.product_id,
            b.product_default_code,
            b.product_name,
            b.production_qty,
            b.qty_producing,
            b.production_uom,
            b.costing_qty_kg,
            b.sale_line_id,
            b.sale_order_id,
            b.sale_line_qty,
            b.sale_line_qty_delivered,
            b.sale_price_unit,
            b.sale_discount_pct,
            b.revenue_net_eur,
            b.revenue_total_eur,
            b.start_ts,
            b.end_ts,
            b.window_min,
            b.run_min,
            b.stop_min,
            b.stop_cost_eur,
            b.real_cycle_delta,
            b.kwh_consumed,
            b.kwh_per_cycle,
            b.product_standard_price,
            b.product_list_price,
            b.raw_material_value_eur,
            b.finished_value_eur,
            b.odoo_material_cost_status,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.costed_raw_material_line_count,
            b.missing_or_invalid_raw_material_cost_count,
            b.cost_parameter_id,
            b.cost_parameter_scope_level,
            b.energy_cost_eur_per_kwh,
            b.fallback_material_cost_eur_per_kg,
            b.machine_run_cost_eur_per_h,
            b.labor_cost_eur_per_h,
            b.overhead_cost_eur_per_h,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_estimated_eur,
            b.machine_run_cost_estimated_eur,
            b.labor_cost_estimated_eur,
            b.overhead_cost_estimated_eur,
            b.known_or_estimated_cost_eur,
            b.partial_margin_after_known_costs_eur,
            b.estimated_margin_eur,
            b.estimated_margin_pct,
            b.revenue_status,
            b.cost_status,
            b.margin_status,
            b.technical_quality_level,
            b.final_report_status,
            b.commercial_snapshot_at,
            b.has_revenue,
            b.has_customer,
            b.has_sale_order,
            b.has_raw_materials,
            b.has_raw_material_cost,
            b.has_usable_technical_data,
            b.has_closed_or_usable_order_report,
            b.has_energy_cost_parameter,
            b.has_machine_cost_parameter,
            GREATEST(0, (((((((((100 -
                CASE
                    WHEN (b.has_revenue = false) THEN 35
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_customer = false) THEN 5
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_sale_order = false) THEN 5
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_usable_technical_data = false) THEN 25
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_closed_or_usable_order_report = false) THEN 15
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_raw_materials = false) THEN 20
                    ELSE 0
                END) -
                CASE
                    WHEN ((b.has_raw_materials = true) AND (b.has_raw_material_cost = false)) THEN 35
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_energy_cost_parameter = false) THEN 5
                    ELSE 0
                END) -
                CASE
                    WHEN (b.has_machine_cost_parameter = false) THEN 5
                    ELSE 0
                END)) AS cost_readiness_score,
            concat_ws('; '::text,
                CASE
                    WHEN (b.has_revenue = false) THEN 'Falta ingreso de venta vinculado'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_customer = false) THEN 'Falta cliente'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_sale_order = false) THEN 'Falta pedido de venta'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_usable_technical_data = false) THEN 'Datos técnicos no defendibles'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_closed_or_usable_order_report = false) THEN 'Informe técnico parcial o bloqueado'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_raw_materials = false) THEN 'No se detecta materia prima consumida'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN ((b.has_raw_materials = true) AND (b.has_raw_material_cost = false)) THEN 'Falta coste de materia prima'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_energy_cost_parameter = false) THEN 'Falta coste €/kWh'::text
                    ELSE NULL::text
                END,
                CASE
                    WHEN (b.has_machine_cost_parameter = false) THEN 'Falta coste hora máquina'::text
                    ELSE NULL::text
                END) AS cost_readiness_blockers
           FROM base b
        )
 SELECT order_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_order_ref,
    odoo_state,
    sale_order_ref,
    customer_name,
    product_default_code,
    product_name,
    machine_id,
    revenue_net_eur,
    revenue_total_eur,
    raw_material_line_count,
    raw_total_consumed_qty,
    raw_materials_summary,
    raw_material_cost_status_summary,
    missing_or_invalid_raw_material_cost_count,
    material_cost_estimated_eur,
    material_cost_source_status,
    stop_cost_eur,
    kwh_consumed,
    run_min,
    window_min,
    technical_quality_level,
    final_report_status,
    margin_status,
    has_revenue,
    has_customer,
    has_sale_order,
    has_raw_materials,
    has_raw_material_cost,
    has_usable_technical_data,
    has_closed_or_usable_order_report,
    has_energy_cost_parameter,
    has_machine_cost_parameter,
    cost_readiness_score,
        CASE
            WHEN (has_revenue = false) THEN 'BLOQUEADO_SIN_INGRESO'::text
            WHEN (has_usable_technical_data = false) THEN 'BLOQUEADO_DATOS_TECNICOS'::text
            WHEN (has_closed_or_usable_order_report = false) THEN 'PARCIAL_INFORME_TECNICO'::text
            WHEN (has_raw_materials = false) THEN 'BLOQUEADO_SIN_MATERIA_PRIMA'::text
            WHEN ((has_raw_materials = true) AND (has_raw_material_cost = false)) THEN 'BLOQUEADO_FALTA_COSTE_MATERIA_PRIMA'::text
            WHEN ((has_energy_cost_parameter = false) OR (has_machine_cost_parameter = false)) THEN 'PARCIAL_FALTAN_COSTES_OPERATIVOS'::text
            ELSE 'LISTO_PARA_MARGEN'::text
        END AS cost_readiness_status,
        CASE
            WHEN (cost_readiness_blockers = ''::text) THEN 'Orden lista para cálculo de margen estimado.'::text
            ELSE cost_readiness_blockers
        END AS cost_readiness_description
   FROM scored;


ALTER VIEW mv_reports_ucepsa_demo.cost_readiness_orders_v1 OWNER TO mesavault;

--
-- Name: cost_readiness_raw_materials_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.cost_readiness_raw_materials_v1 AS
 SELECT tenant,
    site,
    raw_product_default_code,
    raw_product_name,
    raw_uom,
    count(DISTINCT odoo_order_ref) AS affected_order_count,
    string_agg(DISTINCT odoo_order_ref, ', '::text ORDER BY odoo_order_ref) AS affected_orders,
    string_agg(DISTINCT COALESCE(sale_order_ref, 'sin_pedido_venta'::text), ', '::text ORDER BY COALESCE(sale_order_ref, 'sin_pedido_venta'::text)) AS affected_sale_orders,
    string_agg(DISTINCT COALESCE(customer_name, 'sin_cliente'::text), ', '::text ORDER BY COALESCE(customer_name, 'sin_cliente'::text)) AS affected_customers,
    round(sum(COALESCE(consumed_qty, (0)::numeric)), 3) AS total_consumed_qty,
    count(*) AS raw_material_line_count,
    count(*) FILTER (WHERE (material_cost_status = 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text)) AS missing_cost_line_count,
    max(material_cost_eur_per_kg) AS current_material_cost_eur_per_kg,
        CASE
            WHEN (count(*) FILTER (WHERE (material_cost_status = 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text)) > 0) THEN 'PENDIENTE_COSTE_MATERIA_PRIMA'::text
            ELSE 'COSTE_DISPONIBLE'::text
        END AS raw_material_readiness_status,
        CASE
            WHEN (count(*) FILTER (WHERE (material_cost_status = 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text)) > 0) THEN concat('Falta coste €/kg para ', COALESCE(raw_product_default_code, 'sin_codigo'::text), ' - ', COALESCE(raw_product_name, 'sin_nombre'::text))
            ELSE 'Coste de materia prima disponible.'::text
        END AS recommended_action
   FROM mv_reports_ucepsa_demo.order_raw_material_costs_v1
  GROUP BY tenant, site, raw_product_default_code, raw_product_name, raw_uom;


ALTER VIEW mv_reports_ucepsa_demo.cost_readiness_raw_materials_v1 OWNER TO mesavault;

--
-- Name: cost_readiness_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.cost_readiness_summary_v1 AS
 SELECT tenant,
    site,
    count(*) AS total_orders,
    count(*) FILTER (WHERE (has_revenue = true)) AS orders_with_revenue,
    count(*) FILTER (WHERE (has_revenue = false)) AS orders_without_revenue,
    count(*) FILTER (WHERE (has_raw_materials = true)) AS orders_with_raw_materials,
    count(*) FILTER (WHERE (has_raw_materials = false)) AS orders_without_raw_materials,
    count(*) FILTER (WHERE ((has_raw_materials = true) AND (has_raw_material_cost = false))) AS orders_missing_raw_material_cost,
    count(*) FILTER (WHERE (has_usable_technical_data = false)) AS orders_with_bad_technical_data,
    count(*) FILTER (WHERE (cost_readiness_status = 'LISTO_PARA_MARGEN'::text)) AS orders_ready_for_margin,
    count(*) FILTER (WHERE (cost_readiness_status = 'BLOQUEADO_FALTA_COSTE_MATERIA_PRIMA'::text)) AS orders_blocked_missing_raw_material_cost,
    count(*) FILTER (WHERE (cost_readiness_status = 'BLOQUEADO_SIN_INGRESO'::text)) AS orders_blocked_no_revenue,
    round(avg(cost_readiness_score), 2) AS avg_cost_readiness_score,
    min(cost_readiness_score) AS min_cost_readiness_score,
    max(cost_readiness_score) AS max_cost_readiness_score
   FROM mv_reports_ucepsa_demo.cost_readiness_orders_v1
  GROUP BY tenant, site;


ALTER VIEW mv_reports_ucepsa_demo.cost_readiness_summary_v1 OWNER TO mesavault;

--
-- Name: cycle_rate_timeseries; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.cycle_rate_timeseries AS
 SELECT ts AS "time",
    cycle_rate_ppm,
    10.0 AS target_cycle_rate_ppm
   FROM mv_hot.edge_oee_live_telemetry
  WHERE ((asset = 'revpi_oee_node_01'::text) AND (cycle_rate_ppm IS NOT NULL))
  ORDER BY ts;


ALTER VIEW mv_reports_ucepsa_demo.cycle_rate_timeseries OWNER TO mesavault;

--
-- Name: data_quality_contract_order_checks_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1 AS
 WITH raw_stats AS (
         SELECT order_raw_material_costs_v1.odoo_instance,
            order_raw_material_costs_v1.odoo_production_id,
            count(*) AS raw_line_count,
            count(*) FILTER (WHERE ((order_raw_material_costs_v1.raw_product_default_code IS NULL) OR (TRIM(BOTH FROM order_raw_material_costs_v1.raw_product_default_code) = ''::text))) AS raw_missing_code_count,
            string_agg(DISTINCT concat(COALESCE([REDACTED], 'sin_codigo'::text), ' - ', COALESCE(order_raw_material_costs_v1.raw_product_name, 'sin_nombre'::text)), '; '::text ORDER BY (concat(COALESCE([REDACTED], 'sin_codigo'::text), ' - ', COALESCE(order_raw_material_costs_v1.raw_product_name, 'sin_nombre'::text)))) AS raw_materials_detected
           FROM mv_reports_ucepsa_demo.order_raw_material_costs_v1
          GROUP BY order_raw_material_costs_v1.odoo_instance, order_raw_material_costs_v1.odoo_production_id
        ), base AS (
         SELECT m.order_row_id,
            m.tenant,
            m.site,
            m.odoo_instance,
            m.odoo_workorder_id,
            m.odoo_production_id,
            m.odoo_order_ref,
            m.odoo_state,
            m.sale_order_ref,
            m.customer_name,
            m.revenue_net_eur,
            m.machine_id,
            m.asset,
            m.product_default_code,
            m.product_name,
            m.raw_material_line_count,
            m.raw_total_consumed_qty,
            m.raw_materials_summary,
            m.raw_material_cost_status_summary,
            m.missing_or_invalid_raw_material_cost_count,
            m.material_cost_estimated_eur,
            m.material_cost_source_status,
            m.energy_cost_eur_per_kwh,
            m.machine_run_cost_eur_per_h,
            m.kwh_consumed,
            m.run_min,
            m.stop_cost_eur,
            m.technical_quality_level,
            m.final_report_status,
            m.margin_status,
            r_1.pending_stops,
            r_1.production_conversion_status,
            COALESCE(rs.raw_line_count, (0)::bigint) AS dqc_raw_line_count,
            COALESCE(rs.raw_missing_code_count, (0)::bigint) AS dqc_raw_missing_code_count,
            rs.raw_materials_detected
           FROM ((mv_reports_ucepsa_demo.order_margin_report_v1 m
             LEFT JOIN mv_reports_ucepsa_demo.order_execution_report_full_v1 r_1 ON ((r_1.order_row_id = m.order_row_id)))
             LEFT JOIN raw_stats rs ON (((rs.odoo_instance = m.odoo_instance) AND (rs.odoo_production_id = m.odoo_production_id))))
        ), evaluations AS (
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-ODOO-001'::text AS rule_code,
                CASE
                    WHEN ((b.odoo_order_ref IS NOT NULL) AND (b.odoo_production_id IS NOT NULL)) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN ((b.odoo_order_ref IS NOT NULL) AND (b.odoo_production_id IS NOT NULL)) THEN 'Orden de fabricación correctamente identificada.'::text
                    ELSE 'Falta referencia de orden o identificador de producción Odoo.'::text
                END AS finding,
                CASE
                    WHEN ((b.odoo_order_ref IS NOT NULL) AND (b.odoo_production_id IS NOT NULL)) THEN 'Sin acción.'::text
                    ELSE 'Revisar sincronización de mrp.production / mrp.workorder desde Odoo.'::text
                END AS recommended_action,
            jsonb_build_object('odoo_order_ref', b.odoo_order_ref, 'odoo_production_id', b.odoo_production_id) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-ODOO-002'::text AS rule_code,
                CASE
                    WHEN ((b.machine_id IS NOT NULL) AND (TRIM(BOTH FROM b.machine_id) <> ''::text)) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN ((b.machine_id IS NOT NULL) AND (TRIM(BOTH FROM b.machine_id) <> ''::text)) THEN 'Centro de trabajo mapeado a máquina MESAVAULT.'::text
                    ELSE 'Falta machine_id o mapeo de centro de trabajo.'::text
                END AS finding,
                CASE
                    WHEN ((b.machine_id IS NOT NULL) AND (TRIM(BOTH FROM b.machine_id) <> ''::text)) THEN 'Sin acción.'::text
                    ELSE 'Revisar tabla de mapeo Odoo workcenter → machine_id.'::text
                END AS recommended_action,
            jsonb_build_object('machine_id', b.machine_id, 'asset', b.asset) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-ODOO-003'::text AS rule_code,
                CASE
                    WHEN (COALESCE(NULLIF(TRIM(BOTH FROM b.product_name), ''::text), NULLIF(TRIM(BOTH FROM b.product_default_code), ''::text)) IS NULL) THEN 'FAIL'::text
                    WHEN ((b.product_default_code IS NULL) OR (TRIM(BOTH FROM b.product_default_code) = ''::text)) THEN 'WARN'::text
                    ELSE 'PASS'::text
                END AS check_status,
                CASE
                    WHEN (COALESCE(NULLIF(TRIM(BOTH FROM b.product_name), ''::text), NULLIF(TRIM(BOTH FROM b.product_default_code), ''::text)) IS NULL) THEN 'Falta identificación del producto.'::text
                    WHEN ((b.product_default_code IS NULL) OR (TRIM(BOTH FROM b.product_default_code) = ''::text)) THEN 'Producto identificado por nombre, pero sin código interno.'::text
                    ELSE 'Producto identificado con nombre y código interno.'::text
                END AS finding,
                CASE
                    WHEN (COALESCE(NULLIF(TRIM(BOTH FROM b.product_name), ''::text), NULLIF(TRIM(BOTH FROM b.product_default_code), ''::text)) IS NULL) THEN 'Revisar maestro de producto en Odoo.'::text
                    WHEN ((b.product_default_code IS NULL) OR (TRIM(BOTH FROM b.product_default_code) = ''::text)) THEN 'Completar código interno/default_code del producto en Odoo.'::text
                    ELSE 'Sin acción.'::text
                END AS recommended_action,
            jsonb_build_object('product_default_code', b.product_default_code, 'product_name', b.product_name) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-SALES-001'::text AS rule_code,
                CASE
                    WHEN ((b.sale_order_ref IS NOT NULL) AND (b.revenue_net_eur IS NOT NULL)) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN ((b.sale_order_ref IS NOT NULL) AND (b.revenue_net_eur IS NOT NULL)) THEN 'Ingreso de venta vinculado a la orden.'::text
                    ELSE 'La orden no tiene ingreso de venta vinculado.'::text
                END AS finding,
                CASE
                    WHEN ((b.sale_order_ref IS NOT NULL) AND (b.revenue_net_eur IS NOT NULL)) THEN 'Sin acción.'::text
                    ELSE 'Revisar sale_line_id, pedido de venta u origen de la orden de fabricación.'::text
                END AS recommended_action,
            jsonb_build_object('sale_order_ref', b.sale_order_ref, 'revenue_net_eur', b.revenue_net_eur) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-SALES-002'::text AS rule_code,
                CASE
                    WHEN (b.sale_order_ref IS NULL) THEN 'NOT_APPLICABLE'::text
                    WHEN ((b.customer_name IS NOT NULL) AND (TRIM(BOTH FROM b.customer_name) <> ''::text)) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.sale_order_ref IS NULL) THEN 'No aplica porque no hay pedido de venta vinculado.'::text
                    WHEN ((b.customer_name IS NOT NULL) AND (TRIM(BOTH FROM b.customer_name) <> ''::text)) THEN 'Cliente vinculado correctamente.'::text
                    ELSE 'Hay pedido de venta, pero falta cliente.'::text
                END AS finding,
                CASE
                    WHEN (b.sale_order_ref IS NULL) THEN 'Resolver primero el vínculo de venta.'::text
                    WHEN ((b.customer_name IS NOT NULL) AND (TRIM(BOTH FROM b.customer_name) <> ''::text)) THEN 'Sin acción.'::text
                    ELSE 'Revisar partner_id del pedido de venta en Odoo.'::text
                END AS recommended_action,
            jsonb_build_object('sale_order_ref', b.sale_order_ref, 'customer_name', b.customer_name) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-RAW-001'::text AS rule_code,
                CASE
                    WHEN (COALESCE(b.raw_material_line_count, (0)::bigint) > 0) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (COALESCE(b.raw_material_line_count, (0)::bigint) > 0) THEN 'Materia prima consumida detectada.'::text
                    ELSE 'No se detecta materia prima consumida para la orden.'::text
                END AS finding,
                CASE
                    WHEN (COALESCE(b.raw_material_line_count, (0)::bigint) > 0) THEN 'Sin acción.'::text
                    ELSE 'Revisar movimientos de stock/MRP asociados a la orden.'::text
                END AS recommended_action,
            jsonb_build_object('raw_material_line_count', b.raw_material_line_count, 'raw_materials_summary', b.raw_materials_summary) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-RAW-002'::text AS rule_code,
                CASE
                    WHEN (COALESCE(b.dqc_raw_line_count, (0)::bigint) = 0) THEN 'NOT_APPLICABLE'::text
                    WHEN (COALESCE(b.dqc_raw_missing_code_count, (0)::bigint) = 0) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (COALESCE(b.dqc_raw_line_count, (0)::bigint) = 0) THEN 'No aplica porque no hay materia prima detectada.'::text
                    WHEN (COALESCE(b.dqc_raw_missing_code_count, (0)::bigint) = 0) THEN 'Todas las materias primas detectadas tienen código identificable.'::text
                    ELSE 'Hay materias primas sin código identificable.'::text
                END AS finding,
                CASE
                    WHEN (COALESCE(b.dqc_raw_line_count, (0)::bigint) = 0) THEN 'Resolver primero la detección de materia prima.'::text
                    WHEN (COALESCE(b.dqc_raw_missing_code_count, (0)::bigint) = 0) THEN 'Sin acción.'::text
                    ELSE 'Completar código interno/default_code de materias primas en Odoo.'::text
                END AS recommended_action,
            jsonb_build_object('raw_line_count', b.dqc_raw_line_count, 'raw_missing_code_count', b.dqc_raw_missing_code_count, 'raw_materials_detected', b.raw_materials_detected) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-COST-001'::text AS rule_code,
                CASE
                    WHEN (b.material_cost_estimated_eur IS NOT NULL) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.material_cost_estimated_eur IS NOT NULL) THEN 'Coste de materia prima disponible.'::text
                    ELSE 'Falta coste de materia prima.'::text
                END AS finding,
                CASE
                    WHEN (b.material_cost_estimated_eur IS NOT NULL) THEN 'Sin acción.'::text
                    ELSE COALESCE(concat('Cargar coste €/kg para materia prima: ', b.raw_materials_summary), 'Cargar coste de materia prima o revisar valoración en Odoo.'::text)
                END AS recommended_action,
            jsonb_build_object('material_cost_estimated_eur', b.material_cost_estimated_eur, 'material_cost_source_status', b.material_cost_source_status, 'raw_materials_summary', b.raw_materials_summary) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-COST-002'::text AS rule_code,
                CASE
                    WHEN (b.kwh_consumed IS NULL) THEN 'NOT_APPLICABLE'::text
                    WHEN (b.energy_cost_eur_per_kwh IS NOT NULL) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.kwh_consumed IS NULL) THEN 'No aplica porque no hay consumo energético medido.'::text
                    WHEN (b.energy_cost_eur_per_kwh IS NOT NULL) THEN 'Coste energético parametrizado.'::text
                    ELSE 'Hay consumo energético, pero falta coste €/kWh.'::text
                END AS finding,
                CASE
                    WHEN (b.kwh_consumed IS NULL) THEN 'Sin acción.'::text
                    WHEN (b.energy_cost_eur_per_kwh IS NOT NULL) THEN 'Sin acción.'::text
                    ELSE 'Cargar coste €/kWh en margin_cost_parameters.'::text
                END AS recommended_action,
            jsonb_build_object('kwh_consumed', b.kwh_consumed, 'energy_cost_eur_per_kwh', b.energy_cost_eur_per_kwh) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-COST-003'::text AS rule_code,
                CASE
                    WHEN (b.run_min IS NULL) THEN 'NOT_APPLICABLE'::text
                    WHEN (b.machine_run_cost_eur_per_h IS NOT NULL) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.run_min IS NULL) THEN 'No aplica porque no hay tiempo de máquina utilizable.'::text
                    WHEN (b.machine_run_cost_eur_per_h IS NOT NULL) THEN 'Coste hora máquina parametrizado.'::text
                    ELSE 'Hay tiempo de máquina, pero falta coste hora máquina.'::text
                END AS finding,
                CASE
                    WHEN (b.run_min IS NULL) THEN 'Sin acción.'::text
                    WHEN (b.machine_run_cost_eur_per_h IS NOT NULL) THEN 'Sin acción.'::text
                    ELSE 'Cargar coste hora máquina para la máquina correspondiente.'::text
                END AS recommended_action,
            jsonb_build_object('machine_id', b.machine_id, 'run_min', b.run_min, 'machine_run_cost_eur_per_h', b.machine_run_cost_eur_per_h) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-EDGE-001'::text AS rule_code,
                CASE
                    WHEN (b.technical_quality_level = ANY (ARRAY['FIABLE'::text, 'ACEPTABLE_CON_OBSERVACIONES'::text])) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.technical_quality_level = ANY (ARRAY['FIABLE'::text, 'ACEPTABLE_CON_OBSERVACIONES'::text])) THEN 'Datos técnicos defendibles.'::text
                    ELSE 'Datos técnicos no defendibles para análisis.'::text
                END AS finding,
                CASE
                    WHEN (b.technical_quality_level = ANY (ARRAY['FIABLE'::text, 'ACEPTABLE_CON_OBSERVACIONES'::text])) THEN 'Sin acción.'::text
                    ELSE 'Revisar telemetría, cobertura Edge-OEE y calidad del informe técnico.'::text
                END AS recommended_action,
            jsonb_build_object('technical_quality_level', b.technical_quality_level) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-EDGE-002'::text AS rule_code,
                CASE
                    WHEN (b.final_report_status = ANY (ARRAY['LISTO_INFORME_FINAL'::text, 'LISTO_TECNICO_REVISAR_CONVERSION'::text, 'LISTO_CON_OBSERVACIONES'::text])) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (b.final_report_status = ANY (ARRAY['LISTO_INFORME_FINAL'::text, 'LISTO_TECNICO_REVISAR_CONVERSION'::text, 'LISTO_CON_OBSERVACIONES'::text])) THEN 'Informe técnico cerrado o utilizable.'::text
                    ELSE 'Informe técnico parcial o bloqueado.'::text
                END AS finding,
                CASE
                    WHEN (b.final_report_status = ANY (ARRAY['LISTO_INFORME_FINAL'::text, 'LISTO_TECNICO_REVISAR_CONVERSION'::text, 'LISTO_CON_OBSERVACIONES'::text])) THEN 'Sin acción.'::text
                    ELSE 'Cerrar orden, revisar telemetría o completar clasificación antes de análisis económico final.'::text
                END AS recommended_action,
            jsonb_build_object('final_report_status', b.final_report_status) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-STOPS-001'::text AS rule_code,
                CASE
                    WHEN (COALESCE(b.pending_stops, (0)::bigint) = 0) THEN 'PASS'::text
                    ELSE 'FAIL'::text
                END AS check_status,
                CASE
                    WHEN (COALESCE(b.pending_stops, (0)::bigint) = 0) THEN 'No hay paros pendientes de clasificación.'::text
                    ELSE 'Hay paros pendientes de clasificación.'::text
                END AS finding,
                CASE
                    WHEN (COALESCE(b.pending_stops, (0)::bigint) = 0) THEN 'Sin acción.'::text
                    ELSE 'Clasificar paros pendientes desde la consola de paros.'::text
                END AS recommended_action,
            jsonb_build_object('pending_stops', b.pending_stops) AS evidence_json
           FROM base b
        UNION ALL
         SELECT b.order_row_id,
            b.tenant,
            b.site,
            b.odoo_instance,
            b.odoo_workorder_id,
            b.odoo_production_id,
            b.odoo_order_ref,
            b.odoo_state,
            b.sale_order_ref,
            b.customer_name,
            b.revenue_net_eur,
            b.machine_id,
            b.asset,
            b.product_default_code,
            b.product_name,
            b.raw_material_line_count,
            b.raw_total_consumed_qty,
            b.raw_materials_summary,
            b.raw_material_cost_status_summary,
            b.missing_or_invalid_raw_material_cost_count,
            b.material_cost_estimated_eur,
            b.material_cost_source_status,
            b.energy_cost_eur_per_kwh,
            b.machine_run_cost_eur_per_h,
            b.kwh_consumed,
            b.run_min,
            b.stop_cost_eur,
            b.technical_quality_level,
            b.final_report_status,
            b.margin_status,
            b.pending_stops,
            b.production_conversion_status,
            b.dqc_raw_line_count,
            b.dqc_raw_missing_code_count,
            b.raw_materials_detected,
            'DQC-CONV-001'::text AS rule_code,
                CASE
                    WHEN (b.production_conversion_status = 'CICLOS_COHERENTES_CON_OBJETIVO'::text) THEN 'PASS'::text
                    WHEN (b.production_conversion_status = 'CANTIDAD_ODOO_SIN_CICLOS_EDGE'::text) THEN 'FAIL'::text
                    ELSE 'WARN'::text
                END AS check_status,
                CASE
                    WHEN (b.production_conversion_status = 'CICLOS_COHERENTES_CON_OBJETIVO'::text) THEN 'Conversión producción-ciclos coherente.'::text
                    WHEN (b.production_conversion_status = 'CANTIDAD_ODOO_SIN_CICLOS_EDGE'::text) THEN 'Odoo muestra cantidad producida, pero Edge no detecta ciclos.'::text
                    ELSE 'Conversión producción-ciclos pendiente de revisión o no concluyente.'::text
                END AS finding,
                CASE
                    WHEN (b.production_conversion_status = 'CICLOS_COHERENTES_CON_OBJETIVO'::text) THEN 'Sin acción.'::text
                    ELSE 'Validar relación entre kg, bolsas, unidad comercial y ciclos/golpes.'::text
                END AS recommended_action,
            jsonb_build_object('production_conversion_status', b.production_conversion_status) AS evidence_json
           FROM base b
        )
 SELECT e.order_row_id,
    e.tenant,
    e.site,
    e.odoo_instance,
    e.odoo_workorder_id,
    e.odoo_production_id,
    e.odoo_order_ref,
    e.odoo_state,
    e.sale_order_ref,
    e.customer_name,
    e.product_default_code,
    e.product_name,
    e.machine_id,
    r.rule_code,
    r.rule_name,
    r.domain,
    r.dimension,
    r.severity,
    r.owner_area,
    r.applies_to,
    r.blocking_for,
    e.check_status,
        CASE
            WHEN (e.check_status = 'PASS'::text) THEN true
            WHEN (e.check_status = 'NOT_APPLICABLE'::text) THEN NULL::boolean
            ELSE false
        END AS check_passed,
    e.finding,
    e.recommended_action,
    e.evidence_json,
        CASE
            WHEN ((e.check_status = 'FAIL'::text) AND (r.severity = 'CRITICAL'::text)) THEN 100
            WHEN ((e.check_status = 'FAIL'::text) AND (r.severity = 'HIGH'::text)) THEN 75
            WHEN ((e.check_status = 'FAIL'::text) AND (r.severity = 'MEDIUM'::text)) THEN 50
            WHEN ((e.check_status = 'WARN'::text) AND (r.severity = 'CRITICAL'::text)) THEN 60
            WHEN ((e.check_status = 'WARN'::text) AND (r.severity = 'HIGH'::text)) THEN 45
            WHEN ((e.check_status = 'WARN'::text) AND (r.severity = 'MEDIUM'::text)) THEN 30
            ELSE 0
        END AS issue_score
   FROM (evaluations e
     JOIN mv_edge_oee_ucepsa_demo.data_quality_contract_rules r ON (((r.tenant = e.tenant) AND (r.site = e.site) AND (r.rule_code = e.rule_code) AND (r.is_active = true))));


ALTER VIEW mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1 OWNER TO mesavault;

--
-- Name: data_quality_contract_order_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1 AS
 WITH checks AS (
         SELECT data_quality_contract_order_checks_v1.order_row_id,
            data_quality_contract_order_checks_v1.tenant,
            data_quality_contract_order_checks_v1.site,
            data_quality_contract_order_checks_v1.odoo_instance,
            data_quality_contract_order_checks_v1.odoo_workorder_id,
            data_quality_contract_order_checks_v1.odoo_production_id,
            data_quality_contract_order_checks_v1.odoo_order_ref,
            data_quality_contract_order_checks_v1.odoo_state,
            data_quality_contract_order_checks_v1.sale_order_ref,
            data_quality_contract_order_checks_v1.customer_name,
            data_quality_contract_order_checks_v1.product_default_code,
            data_quality_contract_order_checks_v1.product_name,
            data_quality_contract_order_checks_v1.machine_id,
            data_quality_contract_order_checks_v1.rule_code,
            data_quality_contract_order_checks_v1.rule_name,
            data_quality_contract_order_checks_v1.domain,
            data_quality_contract_order_checks_v1.dimension,
            data_quality_contract_order_checks_v1.severity,
            data_quality_contract_order_checks_v1.owner_area,
            data_quality_contract_order_checks_v1.applies_to,
            data_quality_contract_order_checks_v1.blocking_for,
            data_quality_contract_order_checks_v1.check_status,
            data_quality_contract_order_checks_v1.check_passed,
            data_quality_contract_order_checks_v1.finding,
            data_quality_contract_order_checks_v1.recommended_action,
            data_quality_contract_order_checks_v1.evidence_json,
            data_quality_contract_order_checks_v1.issue_score
           FROM mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1
        ), agg AS (
         SELECT checks.order_row_id,
            checks.tenant,
            checks.site,
            checks.odoo_instance,
            checks.odoo_workorder_id,
            checks.odoo_production_id,
            checks.odoo_order_ref,
            checks.odoo_state,
            checks.sale_order_ref,
            checks.customer_name,
            checks.product_default_code,
            checks.product_name,
            checks.machine_id,
            count(*) AS total_rules,
            count(*) FILTER (WHERE (checks.check_status = 'PASS'::text)) AS passed_rules,
            count(*) FILTER (WHERE (checks.check_status = 'FAIL'::text)) AS failed_rules,
            count(*) FILTER (WHERE (checks.check_status = 'WARN'::text)) AS warn_rules,
            count(*) FILTER (WHERE (checks.check_status = 'NOT_APPLICABLE'::text)) AS not_applicable_rules,
            count(*) FILTER (WHERE ((checks.check_status = 'FAIL'::text) AND (checks.severity = 'CRITICAL'::text))) AS critical_failures,
            count(*) FILTER (WHERE ((checks.check_status = 'FAIL'::text) AND (checks.severity = 'HIGH'::text))) AS high_failures,
            count(*) FILTER (WHERE ((checks.check_status = 'FAIL'::text) AND (checks.severity = 'MEDIUM'::text))) AS medium_failures,
            count(*) FILTER (WHERE ((checks.check_status = 'WARN'::text) AND (checks.severity = 'CRITICAL'::text))) AS critical_warnings,
            count(*) FILTER (WHERE ((checks.check_status = 'WARN'::text) AND (checks.severity = 'HIGH'::text))) AS high_warnings,
            count(*) FILTER (WHERE ((checks.check_status = 'WARN'::text) AND (checks.severity = 'MEDIUM'::text))) AS medium_warnings,
            COALESCE(sum(checks.issue_score), (0)::bigint) AS total_issue_score,
            max(checks.issue_score) AS max_issue_score
           FROM checks
          GROUP BY checks.order_row_id, checks.tenant, checks.site, checks.odoo_instance, checks.odoo_workorder_id, checks.odoo_production_id, checks.odoo_order_ref, checks.odoo_state, checks.sale_order_ref, checks.customer_name, checks.product_default_code, checks.product_name, checks.machine_id
        ), main_issue AS (
         SELECT DISTINCT ON (checks.order_row_id) checks.order_row_id,
            checks.rule_code AS main_blocker_rule_code,
            checks.rule_name AS main_blocker_rule_name,
            checks.domain AS main_blocker_domain,
            checks.severity AS main_blocker_severity,
            checks.owner_area AS owner_area_to_act,
            checks.blocking_for,
            checks.check_status AS main_blocker_status,
            checks.finding AS main_blocker_finding,
            checks.recommended_action AS main_recommended_action,
            checks.issue_score AS main_issue_score
           FROM checks
          WHERE (checks.check_status = ANY (ARRAY['FAIL'::text, 'WARN'::text]))
          ORDER BY checks.order_row_id, checks.issue_score DESC,
                CASE checks.severity
                    WHEN 'CRITICAL'::text THEN 1
                    WHEN 'HIGH'::text THEN 2
                    WHEN 'MEDIUM'::text THEN 3
                    ELSE 4
                END, checks.rule_code
        )
 SELECT a.order_row_id,
    a.tenant,
    a.site,
    a.odoo_instance,
    a.odoo_workorder_id,
    a.odoo_production_id,
    a.odoo_order_ref,
    a.odoo_state,
    a.sale_order_ref,
    a.customer_name,
    a.product_default_code,
    a.product_name,
    a.machine_id,
    a.total_rules,
    a.passed_rules,
    a.failed_rules,
    a.warn_rules,
    a.not_applicable_rules,
    a.critical_failures,
    a.high_failures,
    a.medium_failures,
    a.critical_warnings,
    a.high_warnings,
    a.medium_warnings,
    a.total_issue_score,
    a.max_issue_score,
    GREATEST((0)::bigint, (100 - LEAST(a.total_issue_score, (100)::bigint))) AS contract_score,
        CASE
            WHEN (a.critical_failures > 0) THEN 'BLOQUEADO_CRITICO'::text
            WHEN (a.high_failures > 0) THEN 'BLOQUEADO_ALTO'::text
            WHEN (a.medium_failures > 0) THEN 'BLOQUEADO_MEDIO'::text
            WHEN (a.warn_rules > 0) THEN 'VALIDO_CON_OBSERVACIONES'::text
            WHEN ((a.failed_rules = 0) AND (a.warn_rules = 0)) THEN 'CONTRATO_CUMPLIDO'::text
            ELSE 'REVISAR'::text
        END AS contract_status,
    mi.main_blocker_rule_code,
    mi.main_blocker_rule_name,
    mi.main_blocker_domain,
    mi.main_blocker_severity,
    mi.owner_area_to_act,
    mi.blocking_for,
    mi.main_blocker_status,
    mi.main_blocker_finding,
    mi.main_recommended_action,
    mi.main_issue_score,
        CASE
            WHEN (a.critical_failures > 0) THEN concat('Contrato bloqueado por fallo crítico: ', COALESCE(mi.main_blocker_finding, 'sin detalle'::text))
            WHEN (a.high_failures > 0) THEN concat('Contrato bloqueado por fallo alto: ', COALESCE(mi.main_blocker_finding, 'sin detalle'::text))
            WHEN (a.medium_failures > 0) THEN concat('Contrato bloqueado por fallo medio: ', COALESCE(mi.main_blocker_finding, 'sin detalle'::text))
            WHEN (a.warn_rules > 0) THEN concat('Contrato válido con observaciones: ', COALESCE(mi.main_blocker_finding, 'sin detalle'::text))
            ELSE 'Contrato de datos cumplido para esta orden.'::text
        END AS contract_summary
   FROM (agg a
     LEFT JOIN main_issue mi ON ((mi.order_row_id = a.order_row_id)));


ALTER VIEW mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1 OWNER TO mesavault;

--
-- Name: data_quality_contract_owner_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1 AS
 SELECT tenant,
    site,
    owner_area,
    count(*) FILTER (WHERE (check_status = 'FAIL'::text)) AS failed_checks,
    count(*) FILTER (WHERE (check_status = 'WARN'::text)) AS warn_checks,
    count(*) FILTER (WHERE ((check_status = 'FAIL'::text) AND (severity = 'CRITICAL'::text))) AS critical_failed_checks,
    count(*) FILTER (WHERE ((check_status = 'FAIL'::text) AND (severity = 'HIGH'::text))) AS high_failed_checks,
    count(DISTINCT odoo_order_ref) FILTER (WHERE (check_status = ANY (ARRAY['FAIL'::text, 'WARN'::text]))) AS affected_orders,
    sum(issue_score) FILTER (WHERE (check_status = ANY (ARRAY['FAIL'::text, 'WARN'::text]))) AS total_issue_score,
    string_agg(DISTINCT rule_code, ', '::text ORDER BY rule_code) FILTER (WHERE (check_status = ANY (ARRAY['FAIL'::text, 'WARN'::text]))) AS affected_rules,
    string_agg(DISTINCT odoo_order_ref, ', '::text ORDER BY odoo_order_ref) FILTER (WHERE (check_status = ANY (ARRAY['FAIL'::text, 'WARN'::text]))) AS affected_order_refs
   FROM mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1
  GROUP BY tenant, site, owner_area;


ALTER VIEW mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1 OWNER TO mesavault;

--
-- Name: energy_3phase_timeseries; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_3phase_timeseries AS
 SELECT ingest_ts AS ts,
    ingest_ts,
    tenant,
    site,
    asset,
    machine_id,
    (EXTRACT(epoch FROM (now() - ingest_ts)))::double precision AS age_s,
    comm_ok,
        CASE
            WHEN (lower((payload_json ->> 'sample_valid'::text)) = ANY (ARRAY['true'::text, 't'::text, '1'::text, 'yes'::text])) THEN true
            WHEN (lower((payload_json ->> 'sample_valid'::text)) = ANY (ARRAY['false'::text, 'f'::text, '0'::text, 'no'::text])) THEN false
            ELSE NULL::boolean
        END AS sample_valid,
    (payload_json ->> 'energy_meter_model'::text) AS energy_meter_model,
    (payload_json ->> 'energy_map'::text) AS energy_map,
    voltage_l1_v,
    (NULLIF((payload_json ->> 'voltage_l2_v'::text), ''::text))::double precision AS voltage_l2_v,
    (NULLIF((payload_json ->> 'voltage_l3_v'::text), ''::text))::double precision AS voltage_l3_v,
    current_l1_a,
    (NULLIF((payload_json ->> 'current_l2_a'::text), ''::text))::double precision AS current_l2_a,
    (NULLIF((payload_json ->> 'current_l3_a'::text), ''::text))::double precision AS current_l3_a,
    (NULLIF((payload_json ->> 'active_power_l1_w'::text), ''::text))::double precision AS active_power_l1_w,
    (NULLIF((payload_json ->> 'active_power_l2_w'::text), ''::text))::double precision AS active_power_l2_w,
    (NULLIF((payload_json ->> 'active_power_l3_w'::text), ''::text))::double precision AS active_power_l3_w,
    COALESCE((NULLIF((payload_json ->> 'active_power_w'::text), ''::text))::double precision, ((power_total_kw * 1000.0))::double precision) AS active_power_w,
    power_total_kw,
    (NULLIF((payload_json ->> 'apparent_power_va'::text), ''::text))::double precision AS apparent_power_va,
    (NULLIF((payload_json ->> 'reactive_power_var'::text), ''::text))::double precision AS reactive_power_var,
    (NULLIF((payload_json ->> 'power_factor'::text), ''::text))::double precision AS power_factor,
    frequency_hz,
    import_kwh,
    (NULLIF((payload_json ->> 'export_kwh'::text), ''::text))::double precision AS export_kwh,
    (NULLIF((payload_json ->> 'total_active_energy_kwh'::text), ''::text))::double precision AS total_active_energy_kwh,
    payload_json
   FROM mv_hot.edge_oee_eastron_readings r;


ALTER VIEW mv_reports_ucepsa_demo.energy_3phase_timeseries OWNER TO mesavault;

--
-- Name: energy_3phase_latest; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_3phase_latest AS
 SELECT DISTINCT ON (machine_id) ts,
    ingest_ts,
    tenant,
    site,
    asset,
    machine_id,
    age_s,
    comm_ok,
    sample_valid,
    energy_meter_model,
    energy_map,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    active_power_l1_w,
    active_power_l2_w,
    active_power_l3_w,
    active_power_w,
    power_total_kw,
    apparent_power_va,
    reactive_power_var,
    power_factor,
    frequency_hz,
    import_kwh,
    export_kwh,
    total_active_energy_kwh,
    payload_json
   FROM mv_reports_ucepsa_demo.energy_3phase_timeseries
  WHERE (site = 'ucepsa_onpremise'::text)
  ORDER BY machine_id, ingest_ts DESC;


ALTER VIEW mv_reports_ucepsa_demo.energy_3phase_latest OWNER TO mesavault;

--
-- Name: energy_diagnosis; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_diagnosis AS
 SELECT sort_order,
    group_name,
    metric,
    value,
    unit,
    status,
    problem,
    likely_impact,
    recommended_action
   FROM mv_hot.edge_oee_eastron_diagnosis_latest;


ALTER VIEW mv_reports_ucepsa_demo.energy_diagnosis OWNER TO mesavault;

--
-- Name: energy_import_timeseries; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_import_timeseries AS
 SELECT ingest_ts AS "time",
    round((import_kwh * (1000)::numeric), 2) AS import_wh
   FROM mv_hot.edge_oee_eastron_readings
  WHERE (asset = 'revpi_oee_node_01'::text)
  ORDER BY ingest_ts;


ALTER VIEW mv_reports_ucepsa_demo.energy_import_timeseries OWNER TO mesavault;

--
-- Name: energy_latest; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_latest AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    meter_model,
    meter_id,
    machine_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    comm_risk_level,
    comm_status
   FROM mv_hot.edge_oee_eastron_dashboard
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.energy_latest OWNER TO mesavault;

--
-- Name: energy_power_timeseries; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.energy_power_timeseries AS
 SELECT ingest_ts AS "time",
    round((power_total_kw * (1000)::numeric), 2) AS power_w
   FROM mv_hot.edge_oee_eastron_readings
  WHERE (asset = 'revpi_oee_node_01'::text)
  ORDER BY ingest_ts;


ALTER VIEW mv_reports_ucepsa_demo.energy_power_timeseries OWNER TO mesavault;

--
-- Name: latest_machine_snapshot; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.latest_machine_snapshot AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_latest_machine_snapshot
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.latest_machine_snapshot OWNER TO mesavault;

--
-- Name: latest_machine_state_fast; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.latest_machine_state_fast AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_reports_ucepsa_demo.latest_machine_snapshot;


ALTER VIEW mv_reports_ucepsa_demo.latest_machine_state_fast OWNER TO mesavault;

--
-- Name: live_telemetry; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.live_telemetry AS
 SELECT ts,
    ingest_ts,
    age_s,
    tenant,
    site,
    asset,
    machine_id,
    order_id,
    voltage_l1_v,
    current_l1_a,
    power_total_kw,
    frequency_hz,
    import_kwh,
    export_kwh,
    comm_ok,
    error_text,
    machine_auto_signal,
    machine_running,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    digital_inputs,
    payload_json
   FROM mv_hot.edge_oee_live_telemetry
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.live_telemetry OWNER TO mesavault;

--
-- Name: odoo_current_order_demo; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.odoo_current_order_demo AS
 WITH latest AS (
         SELECT w.id,
            w.tenant,
            w.site,
            w.odoo_instance,
            w.odoo_workorder_id,
            w.odoo_production_id,
            w.odoo_order_ref,
            w.odoo_state,
            w.odoo_workcenter_code,
            w.odoo_workcenter_name,
            w.machine_id,
            w.asset,
            w.product,
            w.qty_planned,
            w.qty_done,
            w.uom,
            w.planned_cycles,
            w.target_cycle_rate_ppm,
            w.odoo_start,
            w.odoo_end,
            w.notes,
            w.snapshot_at,
            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'::text) AND (w.machine_id = 'CORT-01'::text))
        ), candidates AS (
         SELECT latest.id,
            latest.tenant,
            latest.site,
            latest.odoo_instance,
            latest.odoo_workorder_id,
            latest.odoo_production_id,
            latest.odoo_order_ref,
            latest.odoo_state,
            latest.odoo_workcenter_code,
            latest.odoo_workcenter_name,
            latest.machine_id,
            latest.asset,
            latest.product,
            latest.qty_planned,
            latest.qty_done,
            latest.uom,
            latest.planned_cycles,
            latest.target_cycle_rate_ppm,
            latest.odoo_start,
            latest.odoo_end,
            latest.notes,
            latest.snapshot_at,
            latest.rn
           FROM latest
          WHERE ((latest.rn = 1) AND (COALESCE(latest.odoo_state, ''::text) <> ALL (ARRAY['done'::text, 'cancel'::text, 'cancelled'::text])))
        )
 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 = ANY (ARRAY['progress'::text, 'in_progress'::text, 'done'::text])) THEN true
            ELSE false
        END AS odoo_is_started,
    odoo_end,
    notes,
    snapshot_at
   FROM candidates
  ORDER BY
        CASE
            WHEN (odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text])) THEN 1
            WHEN (odoo_state = 'ready'::text) THEN 2
            WHEN (odoo_state = ANY (ARRAY['waiting'::text, 'pending'::text, 'confirmed'::text, 'planned'::text])) THEN 3
            ELSE 9
        END, COALESCE(odoo_start, snapshot_at) DESC
 LIMIT 1;


ALTER VIEW mv_reports_ucepsa_demo.odoo_current_order_demo OWNER TO mesavault;

--
-- Name: stops_recent; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.stops_recent AS
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    ended_at,
    duration_s,
    duration_min,
    cost_eur,
    status,
    classification_status,
    cause_code,
    cause_name,
    is_planned,
    operator_note,
    value_hour_eur,
    start_event_name,
    end_event_name,
    created_at,
    updated_at
   FROM mv_hot.edge_oee_stops_recent
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.stops_recent OWNER TO mesavault;

--
-- Name: odoo_vs_machine_demo; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.odoo_vs_machine_demo AS
 WITH odoo AS (
         SELECT odoo_current_order_demo.id,
            odoo_current_order_demo.tenant,
            odoo_current_order_demo.site,
            odoo_current_order_demo.odoo_instance,
            odoo_current_order_demo.odoo_workorder_id,
            odoo_current_order_demo.odoo_production_id,
            odoo_current_order_demo.odoo_order_ref,
            odoo_current_order_demo.odoo_state,
            odoo_current_order_demo.odoo_workcenter_code,
            odoo_current_order_demo.odoo_workcenter_name,
            odoo_current_order_demo.machine_id,
            odoo_current_order_demo.asset,
            odoo_current_order_demo.product,
            odoo_current_order_demo.qty_planned,
            odoo_current_order_demo.qty_done,
            odoo_current_order_demo.uom,
            odoo_current_order_demo.planned_cycles,
            odoo_current_order_demo.target_cycle_rate_ppm,
            odoo_current_order_demo.odoo_start,
            odoo_current_order_demo.odoo_reference_start,
            odoo_current_order_demo.odoo_is_started,
            odoo_current_order_demo.odoo_end,
            odoo_current_order_demo.notes,
            odoo_current_order_demo.snapshot_at
           FROM mv_reports_ucepsa_demo.odoo_current_order_demo
        ), machine AS (
         SELECT latest_machine_state_fast.ts,
            latest_machine_state_fast.ingest_ts,
            latest_machine_state_fast.age_s,
            latest_machine_state_fast.tenant,
            latest_machine_state_fast.site,
            latest_machine_state_fast.asset,
            latest_machine_state_fast.machine_id,
            latest_machine_state_fast.order_id,
            latest_machine_state_fast.voltage_l1_v,
            latest_machine_state_fast.current_l1_a,
            latest_machine_state_fast.power_total_kw,
            latest_machine_state_fast.frequency_hz,
            latest_machine_state_fast.import_kwh,
            latest_machine_state_fast.export_kwh,
            latest_machine_state_fast.comm_ok,
            latest_machine_state_fast.error_text,
            latest_machine_state_fast.machine_auto_signal,
            latest_machine_state_fast.machine_running,
            latest_machine_state_fast.cycle_pulse_count,
            latest_machine_state_fast.cycle_rate_ppm,
            latest_machine_state_fast.last_cycle_age_s,
            latest_machine_state_fast.digital_inputs,
            latest_machine_state_fast.payload_json
           FROM mv_reports_ucepsa_demo.latest_machine_state_fast
          WHERE (latest_machine_state_fast.machine_id = 'CORT-01'::text)
          ORDER BY latest_machine_state_fast.ingest_ts DESC
         LIMIT 1
        ), stops AS (
         SELECT o_1.odoo_workorder_id,
            (count(s_1.*))::integer AS stop_count,
            COALESCE(round(sum(s_1.duration_min), 2), (0)::numeric) AS stop_min,
            COALESCE(round(sum(s_1.cost_eur), 2), (0)::numeric) AS stop_cost_eur
           FROM (odoo o_1
             LEFT JOIN mv_reports_ucepsa_demo.stops_recent s_1 ON (((s_1.machine_id = o_1.machine_id) AND (s_1.started_at >= COALESCE(o_1.odoo_reference_start, o_1.odoo_start, o_1.snapshot_at)) AND (s_1.started_at <= COALESCE(o_1.odoo_end, now())))))
          GROUP BY o_1.odoo_workorder_id
        )
 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)::bigint) AS cycle_pulse_count,
    COALESCE(m.cycle_rate_ppm, (0)::numeric) AS cycle_rate_ppm,
    ma.first_machine_activity,
        CASE
            WHEN ((o.odoo_is_started = true) AND (ma.first_machine_activity IS NOT NULL) AND (COALESCE(o.odoo_reference_start, o.odoo_start) IS NOT NULL)) THEN round((GREATEST(EXTRACT(epoch FROM (ma.first_machine_activity - COALESCE(o.odoo_reference_start, o.odoo_start))), (0)::numeric) / 60.0), 2)
            ELSE NULL::numeric
        END AS start_delay_min,
    COALESCE(s.stop_count, 0) AS stop_count,
    COALESCE(s.stop_min, (0)::numeric) AS stop_min,
    COALESCE(s.stop_cost_eur, (0)::numeric) AS stop_cost_eur,
    (COALESCE(m.cycle_pulse_count, (0)::bigint))::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)::numeric) > (0)::numeric) THEN round((((COALESCE(m.cycle_pulse_count, (0)::bigint))::numeric / COALESCE(o.planned_cycles, o.qty_planned, (0)::numeric)) * (100)::numeric), 2)
            ELSE (0)::numeric
        END AS cycle_completion_pct,
        CASE
            WHEN ((m.age_s IS NULL) OR (m.age_s > 120)) THEN 'SIN_TELEMETRIA'::text
            WHEN ((o.odoo_state = 'ready'::text) AND (COALESCE(m.machine_running, false) = true)) THEN 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA'::text
            WHEN ((o.odoo_state = 'ready'::text) AND (COALESCE(m.machine_running, false) = false)) THEN 'ORDEN_PREPARADA_MAQUINA_PARADA'::text
            WHEN ((o.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text])) AND (COALESCE(m.machine_running, false) = false)) THEN 'ORDEN_EN_CURSO_MAQUINA_PARADA'::text
            ELSE 'OK'::text
        END AS status_check
   FROM (((odoo o
     LEFT JOIN machine m ON (true))
     LEFT JOIN LATERAL ( SELECT min(r.ingest_ts) AS first_machine_activity
           FROM mv_hot.edge_oee_eastron_readings r
          WHERE ((r.machine_id = o.machine_id) AND (((r.payload_json ->> 'machine_running'::text))::boolean = true) AND (r.ingest_ts >= COALESCE(o.odoo_reference_start, o.odoo_start, o.snapshot_at)) AND (r.ingest_ts <= COALESCE(o.odoo_end, now())))) ma ON (true))
     LEFT JOIN stops s ON ((s.odoo_workorder_id = o.odoo_workorder_id)));


ALTER VIEW mv_reports_ucepsa_demo.odoo_vs_machine_demo OWNER TO mesavault;

--
-- Name: open_stops; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.open_stops AS
 SELECT id,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    started_at,
    current_duration_s,
    current_duration_min,
    current_cost_eur,
    status,
    classification_status,
    cause_code,
    cause_name,
    operator_note,
    value_hour_eur
   FROM mv_hot.edge_oee_open_stops
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.open_stops OWNER TO mesavault;

--
-- Name: loss_events_current; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.loss_events_current AS
 WITH open_stop_losses AS (
         SELECT now() AS detected_at,
            s.machine_id,
            COALESCE(s.asset, ''::text) AS asset,
            COALESCE(s.order_id, ''::text) AS order_ref,
            'OPEN_STOP'::text AS loss_type,
                CASE
                    WHEN (COALESCE(s.current_duration_min, (0)::numeric) >= (15)::numeric) THEN 'ACTION_REQUIRED'::text
                    WHEN (COALESCE(s.current_duration_min, (0)::numeric) >= (5)::numeric) THEN 'ATTENTION'::text
                    ELSE 'INFO'::text
                END AS severity,
                CASE
                    WHEN (COALESCE(s.current_duration_min, (0)::numeric) >= (15)::numeric) THEN 80
                    WHEN (COALESCE(s.current_duration_min, (0)::numeric) >= (5)::numeric) THEN 55
                    ELSE 30
                END AS severity_score,
            COALESCE(s.current_duration_min, (0)::numeric) AS duration_min,
            COALESCE(s.current_cost_eur, (0)::numeric) AS cost_eur,
            COALESCE(s.status, 'OPEN'::text) AS status,
            'Paro abierto pendiente de cierre o clasificación.'::text AS description,
            'Comprobar causa en máquina y clasificar el paro desde la consola.'::text AS recommended_action,
            jsonb_build_object('stop_id', s.id, 'classification_status', s.classification_status, 'cause_name', s.cause_name, 'started_at', s.started_at, 'source', 'mv_reports_ucepsa_demo.open_stops') AS evidence_json
           FROM mv_reports_ucepsa_demo.open_stops s
        ), unclassified_closed_stop_losses AS (
         SELECT now() AS detected_at,
            s.machine_id,
            COALESCE(s.asset, ''::text) AS asset,
            COALESCE(s.order_id, ''::text) AS order_ref,
            'UNCLASSIFIED_STOP'::text AS loss_type,
                CASE
                    WHEN (COALESCE(s.duration_min, (0)::numeric) >= (15)::numeric) THEN 'ACTION_REQUIRED'::text
                    ELSE 'ATTENTION'::text
                END AS severity,
                CASE
                    WHEN (COALESCE(s.duration_min, (0)::numeric) >= (15)::numeric) THEN 75
                    ELSE 55
                END AS severity_score,
            COALESCE(s.duration_min, (0)::numeric) AS duration_min,
            COALESCE(s.cost_eur, (0)::numeric) AS cost_eur,
            COALESCE(s.status, 'CLOSED'::text) AS status,
            'Paro cerrado pendiente de clasificación.'::text AS description,
            'Asignar causa para evitar pérdida sin explicación.'::text AS recommended_action,
            jsonb_build_object('stop_id', s.id, 'classification_status', s.classification_status, 'cause_name', s.cause_name, 'started_at', s.started_at, 'ended_at', s.ended_at, 'source', 'mv_reports_ucepsa_demo.stops_recent') AS evidence_json
           FROM mv_reports_ucepsa_demo.stops_recent s
          WHERE ((s.status = 'CLOSED'::text) AND (s.classification_status = 'PENDING'::text))
        ), odoo_machine_losses AS (
         SELECT now() AS detected_at,
            o.machine_id,
            COALESCE(o.asset, ''::text) AS asset,
            COALESCE(o.odoo_order_ref, ''::text) AS order_ref,
            o.status_check AS loss_type,
                CASE
                    WHEN (o.status_check = ANY (ARRAY['ORDEN_EN_CURSO_MAQUINA_PARADA'::text, 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA'::text])) THEN 'ACTION_REQUIRED'::text
                    WHEN (o.status_check = 'SIN_TELEMETRIA'::text) THEN 'ATTENTION'::text
                    ELSE 'INFO'::text
                END AS severity,
                CASE
                    WHEN (o.status_check = 'ORDEN_EN_CURSO_MAQUINA_PARADA'::text) THEN 85
                    WHEN (o.status_check = 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA'::text) THEN 75
                    WHEN (o.status_check = 'SIN_TELEMETRIA'::text) THEN 60
                    ELSE 20
                END AS severity_score,
            COALESCE(o.stop_min, (0)::numeric) AS duration_min,
            COALESCE(o.stop_cost_eur, (0)::numeric) AS cost_eur,
            o.status_check AS status,
                CASE
                    WHEN (o.status_check = 'ORDEN_EN_CURSO_MAQUINA_PARADA'::text) THEN 'Odoo indica orden en curso, pero la máquina está parada.'::text
                    WHEN (o.status_check = 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA'::text) THEN 'La máquina está en marcha, pero la orden no aparece iniciada en Odoo.'::text
                    WHEN (o.status_check = 'SIN_TELEMETRIA'::text) THEN 'No hay telemetría reciente para contrastar Odoo contra máquina.'::text
                    ELSE 'Sin discrepancia relevante.'::text
                END AS description,
                CASE
                    WHEN (o.status_check = 'ORDEN_EN_CURSO_MAQUINA_PARADA'::text) THEN 'Revisar paro real, operario, causa pendiente y estado de máquina.'::text
                    WHEN (o.status_check = 'MAQUINA_EN_MARCHA_SIN_ORDEN_INICIADA'::text) THEN 'Revisar disciplina de inicio de orden en Odoo o desfase de sincronización.'::text
                    WHEN (o.status_check = 'SIN_TELEMETRIA'::text) THEN 'Revisar RevPi, MQTT, VPN/red, contador y sink.'::text
                    ELSE 'Sin acción.'::text
                END AS recommended_action,
            jsonb_build_object('odoo_order_ref', o.odoo_order_ref, 'odoo_state', o.odoo_state, 'machine_running', o.machine_running, 'telemetry_age_s', o.telemetry_age_s, 'real_cycles', o.real_cycles, 'planned_cycles', o.planned_cycles, 'cycle_completion_pct', o.cycle_completion_pct, 'source', 'mv_reports_ucepsa_demo.odoo_vs_machine_demo') AS evidence_json
           FROM mv_reports_ucepsa_demo.odoo_vs_machine_demo o
          WHERE (o.status_check IS DISTINCT FROM 'OK'::text)
        ), telemetry_losses AS (
         SELECT now() AS detected_at,
            l.machine_id,
            COALESCE(l.asset, ''::text) AS asset,
            COALESCE(l.order_id, ''::text) AS order_ref,
            'STALE_OR_BAD_TELEMETRY'::text AS loss_type,
                CASE
                    WHEN (COALESCE(l.comm_ok, false) = false) THEN 'ACTION_REQUIRED'::text
                    WHEN (COALESCE(l.age_s, 999999) > 120) THEN 'ACTION_REQUIRED'::text
                    WHEN (COALESCE(l.age_s, 999999) > 30) THEN 'ATTENTION'::text
                    ELSE 'INFO'::text
                END AS severity,
                CASE
                    WHEN (COALESCE(l.comm_ok, false) = false) THEN 80
                    WHEN (COALESCE(l.age_s, 999999) > 120) THEN 75
                    WHEN (COALESCE(l.age_s, 999999) > 30) THEN 45
                    ELSE 10
                END AS severity_score,
            (0)::numeric AS duration_min,
            (0)::numeric AS cost_eur,
                CASE
                    WHEN (COALESCE(l.comm_ok, false) = false) THEN 'BAD_COMMUNICATION'::text
                    WHEN (COALESCE(l.age_s, 999999) > 120) THEN 'STALE_TELEMETRY'::text
                    WHEN (COALESCE(l.age_s, 999999) > 30) THEN 'DELAYED_TELEMETRY'::text
                    ELSE 'OK'::text
                END AS status,
                CASE
                    WHEN (COALESCE(l.comm_ok, false) = false) THEN 'La RevPi publica, pero la lectura Modbus no es válida.'::text
                    WHEN (COALESCE(l.age_s, 999999) > 120) THEN 'No hay telemetría reciente de máquina.'::text
                    WHEN (COALESCE(l.age_s, 999999) > 30) THEN 'La telemetría llega con retraso.'::text
                    ELSE 'Telemetría correcta.'::text
                END AS description,
                CASE
                    WHEN (COALESCE(l.comm_ok, false) = false) THEN 'Revisar RS-485, SDM120-M, alimentación del contador y logs de la RevPi.'::text
                    WHEN (COALESCE(l.age_s, 999999) > 120) THEN 'Revisar RevPi, red/VPN, Mosquitto y sink MQTT.'::text
                    WHEN (COALESCE(l.age_s, 999999) > 30) THEN 'Revisar estabilidad de red y frecuencia de publicación.'::text
                    ELSE 'Sin acción.'::text
                END AS recommended_action,
            jsonb_build_object('age_s', l.age_s, 'comm_ok', l.comm_ok, 'error_text', l.error_text, 'ingest_ts', l.ingest_ts, 'source', 'mv_reports_ucepsa_demo.latest_machine_state_fast') AS evidence_json
           FROM mv_reports_ucepsa_demo.latest_machine_state_fast l
          WHERE ((COALESCE(l.comm_ok, false) = false) OR (COALESCE(l.age_s, 999999) > 30))
        ), low_cycle_rate_losses AS (
         SELECT now() AS detected_at,
            l.machine_id,
            COALESCE(l.asset, ''::text) AS asset,
            COALESCE(o.odoo_order_ref, ''::text) AS order_ref,
            'LOW_CYCLE_RATE'::text AS loss_type,
                CASE
                    WHEN (COALESCE(l.cycle_rate_ppm, (0)::numeric) <= (0)::numeric) THEN 'ATTENTION'::text
                    WHEN (COALESCE(l.cycle_rate_ppm, (0)::numeric) < (7)::numeric) THEN 'ATTENTION'::text
                    ELSE 'INFO'::text
                END AS severity,
                CASE
                    WHEN (COALESCE(l.cycle_rate_ppm, (0)::numeric) <= (0)::numeric) THEN 50
                    WHEN (COALESCE(l.cycle_rate_ppm, (0)::numeric) < (7)::numeric) THEN 40
                    ELSE 10
                END AS severity_score,
            (0)::numeric AS duration_min,
            (0)::numeric AS cost_eur,
            'LOW_RATE'::text AS status,
            'La máquina aparece en marcha, pero la velocidad de ciclos/golpes es baja respecto al objetivo inicial.'::text AS description,
            'Revisar golpes reales, sensor I_2, velocidad programada, material, ajuste de máquina y criterio de bolsas por golpe.'::text AS recommended_action,
            jsonb_build_object('cycle_rate_ppm', l.cycle_rate_ppm, 'cycle_pulse_count', l.cycle_pulse_count, 'machine_running', l.machine_running, 'target_cycle_rate_ppm_assumed', 10, 'odoo_order_ref', o.odoo_order_ref, 'source', 'mv_reports_ucepsa_demo.latest_machine_state_fast') AS evidence_json
           FROM (mv_reports_ucepsa_demo.latest_machine_state_fast l
             LEFT JOIN mv_reports_ucepsa_demo.odoo_current_order_demo o ON ((o.machine_id = l.machine_id)))
          WHERE ((COALESCE(l.age_s, 999999) <= 120) AND (COALESCE(l.machine_running, false) = true) AND (COALESCE(l.cycle_rate_ppm, (0)::numeric) < (7)::numeric))
        )
 SELECT open_stop_losses.detected_at,
    open_stop_losses.machine_id,
    open_stop_losses.asset,
    open_stop_losses.order_ref,
    open_stop_losses.loss_type,
    open_stop_losses.severity,
    open_stop_losses.severity_score,
    open_stop_losses.duration_min,
    open_stop_losses.cost_eur,
    open_stop_losses.status,
    open_stop_losses.description,
    open_stop_losses.recommended_action,
    open_stop_losses.evidence_json
   FROM open_stop_losses
UNION ALL
 SELECT unclassified_closed_stop_losses.detected_at,
    unclassified_closed_stop_losses.machine_id,
    unclassified_closed_stop_losses.asset,
    unclassified_closed_stop_losses.order_ref,
    unclassified_closed_stop_losses.loss_type,
    unclassified_closed_stop_losses.severity,
    unclassified_closed_stop_losses.severity_score,
    unclassified_closed_stop_losses.duration_min,
    unclassified_closed_stop_losses.cost_eur,
    unclassified_closed_stop_losses.status,
    unclassified_closed_stop_losses.description,
    unclassified_closed_stop_losses.recommended_action,
    unclassified_closed_stop_losses.evidence_json
   FROM unclassified_closed_stop_losses
UNION ALL
 SELECT odoo_machine_losses.detected_at,
    odoo_machine_losses.machine_id,
    odoo_machine_losses.asset,
    odoo_machine_losses.order_ref,
    odoo_machine_losses.loss_type,
    odoo_machine_losses.severity,
    odoo_machine_losses.severity_score,
    odoo_machine_losses.duration_min,
    odoo_machine_losses.cost_eur,
    odoo_machine_losses.status,
    odoo_machine_losses.description,
    odoo_machine_losses.recommended_action,
    odoo_machine_losses.evidence_json
   FROM odoo_machine_losses
UNION ALL
 SELECT telemetry_losses.detected_at,
    telemetry_losses.machine_id,
    telemetry_losses.asset,
    telemetry_losses.order_ref,
    telemetry_losses.loss_type,
    telemetry_losses.severity,
    telemetry_losses.severity_score,
    telemetry_losses.duration_min,
    telemetry_losses.cost_eur,
    telemetry_losses.status,
    telemetry_losses.description,
    telemetry_losses.recommended_action,
    telemetry_losses.evidence_json
   FROM telemetry_losses
UNION ALL
 SELECT low_cycle_rate_losses.detected_at,
    low_cycle_rate_losses.machine_id,
    low_cycle_rate_losses.asset,
    low_cycle_rate_losses.order_ref,
    low_cycle_rate_losses.loss_type,
    low_cycle_rate_losses.severity,
    low_cycle_rate_losses.severity_score,
    low_cycle_rate_losses.duration_min,
    low_cycle_rate_losses.cost_eur,
    low_cycle_rate_losses.status,
    low_cycle_rate_losses.description,
    low_cycle_rate_losses.recommended_action,
    low_cycle_rate_losses.evidence_json
   FROM low_cycle_rate_losses;


ALTER VIEW mv_reports_ucepsa_demo.loss_events_current OWNER TO mesavault;

--
-- Name: loss_priority_board; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.loss_priority_board AS
 WITH active_orders AS (
         SELECT DISTINCT odoo_current_order_demo.machine_id
           FROM mv_reports_ucepsa_demo.odoo_current_order_demo
        ), filtered AS (
         SELECT e.detected_at,
            e.machine_id,
            e.asset,
            e.order_ref,
            e.loss_type,
            e.severity,
            e.severity_score,
            e.duration_min,
            e.cost_eur,
            e.status,
            e.description,
            e.recommended_action,
            e.evidence_json
           FROM mv_reports_ucepsa_demo.loss_events_current e
          WHERE ((NOT ((e.loss_type = ANY (ARRAY['STALE_OR_BAD_TELEMETRY'::text, 'LOW_CYCLE_RATE'::text])) AND (NOT (EXISTS ( SELECT 1
                   FROM active_orders a
                  WHERE (a.machine_id = e.machine_id)))))) AND (NOT ((e.loss_type = 'STALE_OR_BAD_TELEMETRY'::text) AND (EXISTS ( SELECT 1
                   FROM mv_reports_ucepsa_demo.loss_events_current x
                  WHERE ((x.machine_id = e.machine_id) AND (x.loss_type = 'SIN_TELEMETRIA'::text)))))))
        )
 SELECT row_number() OVER (ORDER BY ((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) DESC, detected_at DESC) AS priority_rank,
    ((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) AS priority_score,
        CASE
            WHEN (((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) >= 90) THEN 'CRÍTICA'::text
            WHEN (((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) >= 60) THEN 'ALTA'::text
            WHEN (((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) >= 35) THEN 'MEDIA'::text
            ELSE 'BAJA'::text
        END AS priority_level,
    detected_at,
    machine_id,
    asset,
    order_ref,
    loss_type,
    severity,
    duration_min,
    cost_eur,
    status,
    description,
    recommended_action,
    evidence_json
   FROM filtered
  ORDER BY ((severity_score + (LEAST((COALESCE(cost_eur, (0)::numeric) * (10)::numeric), (50)::numeric))::integer) + (LEAST((COALESCE(duration_min, (0)::numeric) * (2)::numeric), (40)::numeric))::integer) DESC, detected_at DESC;


ALTER VIEW mv_reports_ucepsa_demo.loss_priority_board OWNER TO mesavault;

--
-- Name: machine_state_latest; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.machine_state_latest AS
 SELECT received_at,
    age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s
   FROM mv_hot.edge_oee_machine_state_latest
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.machine_state_latest OWNER TO mesavault;

--
-- Name: machine_state_latest_multi; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.machine_state_latest_multi AS
 SELECT ingest_ts,
    ts,
    tenant,
    site,
    asset,
    machine_id,
    age_s,
    comm_ok,
    sample_valid,
    energy_map,
        CASE
            WHEN (lower((payload_json ->> 'machine_running'::text)) = ANY (ARRAY['true'::text, 't'::text, '1'::text, 'yes'::text])) THEN true
            WHEN (lower((payload_json ->> 'machine_running'::text)) = ANY (ARRAY['false'::text, 'f'::text, '0'::text, 'no'::text])) THEN false
            ELSE false
        END AS machine_running,
    COALESCE(((NULLIF((payload_json ->> 'cycle_pulse_count'::text), ''::text))::numeric)::bigint, (0)::bigint) AS cycle_pulse_count,
    COALESCE((NULLIF((payload_json ->> 'cycle_rate_ppm'::text), ''::text))::double precision, (0.0)::double precision) AS cycle_rate_ppm,
    ((NULLIF((payload_json ->> 'wise_cycle_counter_raw'::text), ''::text))::numeric)::bigint AS wise_cycle_counter_raw,
        CASE
            WHEN (lower((payload_json ->> 'cycle_input_state'::text)) = ANY (ARRAY['true'::text, 't'::text, '1'::text, 'yes'::text])) THEN true
            WHEN (lower((payload_json ->> 'cycle_input_state'::text)) = ANY (ARRAY['false'::text, 'f'::text, '0'::text, 'no'::text])) THEN false
            ELSE NULL::boolean
        END AS cycle_input_state,
    (payload_json -> 'digital_inputs'::text) AS digital_inputs,
    voltage_l1_v,
    voltage_l2_v,
    voltage_l3_v,
    current_l1_a,
    current_l2_a,
    current_l3_a,
    active_power_l1_w,
    active_power_l2_w,
    active_power_l3_w,
    power_total_kw,
    frequency_hz,
    import_kwh,
    payload_json
   FROM mv_reports_ucepsa_demo.energy_3phase_latest l;


ALTER VIEW mv_reports_ucepsa_demo.machine_state_latest_multi OWNER TO mesavault;

--
-- Name: machine_stops_grafana; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.machine_stops_grafana AS
 WITH base AS (
         SELECT s.id,
            s.tenant,
            s.site,
            s.vertical,
            s.asset,
            s.machine_id,
            s.order_id,
            s.started_at,
            s.ended_at,
            s.status,
            s.classification_status,
            s.cause_code,
            s.operator_note,
            s.value_hour_eur,
            s.duration_s,
            s.cost_eur,
            s.start_event_name,
            s.end_event_name,
            s.start_payload_json,
            s.end_payload_json,
            s.created_at,
            s.updated_at,
            to_jsonb(s.*) AS sj,
            COALESCE((to_jsonb(s.*) ->> 'cause_code'::text), (to_jsonb(s.*) ->> 'stop_cause_code'::text), (to_jsonb(s.*) ->> 'reason_code'::text)) AS raw_cause_code,
            COALESCE((to_jsonb(s.*) ->> 'cause_id'::text), (to_jsonb(s.*) ->> 'stop_cause_id'::text), (to_jsonb(s.*) ->> 'reason_id'::text)) AS raw_cause_id,
            COALESCE((to_jsonb(s.*) ->> 'cause_name'::text), (to_jsonb(s.*) ->> 'stop_cause_name'::text), (to_jsonb(s.*) ->> 'reason_name'::text)) AS raw_cause_name
           FROM mv_hot.edge_oee_machine_stops s
        ), base_with_cause AS (
         SELECT b_1.id,
            b_1.tenant,
            b_1.site,
            b_1.vertical,
            b_1.asset,
            b_1.machine_id,
            b_1.order_id,
            b_1.started_at,
            b_1.ended_at,
            b_1.status,
            b_1.classification_status,
            b_1.cause_code,
            b_1.operator_note,
            b_1.value_hour_eur,
            b_1.duration_s,
            b_1.cost_eur,
            b_1.start_event_name,
            b_1.end_event_name,
            b_1.start_payload_json,
            b_1.end_payload_json,
            b_1.created_at,
            b_1.updated_at,
            b_1.sj,
            b_1.raw_cause_code,
            b_1.raw_cause_id,
            b_1.raw_cause_name,
            cause.cj AS cause_json
           FROM (base b_1
             LEFT JOIN LATERAL ( SELECT to_jsonb(sc.*) AS cj
                   FROM mv_hot.edge_oee_stop_causes sc
                  WHERE (((b_1.raw_cause_id IS NOT NULL) AND ((to_jsonb(sc.*) ->> 'id'::text) = b_1.raw_cause_id)) OR ((b_1.raw_cause_code IS NOT NULL) AND (((to_jsonb(sc.*) ->> 'code'::text) = b_1.raw_cause_code) OR ((to_jsonb(sc.*) ->> 'cause_code'::text) = b_1.raw_cause_code) OR ((to_jsonb(sc.*) ->> 'name'::text) = b_1.raw_cause_code))))
                 LIMIT 1) cause ON (true))
        )
 SELECT id,
    machine_id,
    started_at,
    ended_at,
    COALESCE(ended_at, now()) AS effective_ended_at,
    status,
    classification_status,
    start_event_name,
    end_event_name,
    COALESCE(duration_s, EXTRACT(epoch FROM (COALESCE(ended_at, now()) - started_at))) AS duration_s_current,
    round((COALESCE(duration_s, EXTRACT(epoch FROM (COALESCE(ended_at, now()) - started_at))) / 60.0), 2) AS duration_min,
    COALESCE(cost_eur, (0)::numeric) AS cost_eur,
    COALESCE(NULLIF(raw_cause_code, ''::text), NULLIF((cause_json ->> 'code'::text), ''::text), NULLIF((cause_json ->> 'cause_code'::text), ''::text),
        CASE
            WHEN (classification_status = 'PENDING'::text) THEN 'PENDIENTE'::text
            ELSE 'SIN_CAUSA'::text
        END) AS cause_code,
    COALESCE(NULLIF(raw_cause_name, ''::text), NULLIF((cause_json ->> 'name'::text), ''::text), NULLIF((cause_json ->> 'description'::text), ''::text), NULLIF((cause_json ->> 'label'::text), ''::text),
        CASE COALESCE(NULLIF(raw_cause_code, ''::text), NULLIF((cause_json ->> 'code'::text), ''::text))
            WHEN 'cambio_bobina'::text THEN 'Cambio de bobina'::text
            WHEN 'espera_instrucciones'::text THEN 'Espera de instrucciones'::text
            WHEN 'fallo_empalme'::text THEN 'Fallo de empalme'::text
            WHEN 'falta_material'::text THEN 'Falta de material'::text
            WHEN 'ajuste_sellado'::text THEN 'Ajuste de sellado'::text
            ELSE NULL::text
        END,
        CASE
            WHEN (classification_status = 'PENDING'::text) THEN 'Pendiente de clasificar'::text
            ELSE 'Sin causa registrada'::text
        END) AS cause_name,
    (sj ->> 'operator_note'::text) AS operator_note,
    (sj ->> 'classified_by'::text) AS classified_by,
    (sj ->> 'classified_at'::text) AS classified_at,
    (sj ->> 'order_ref'::text) AS order_ref,
    (sj ->> 'production_order'::text) AS production_order,
        CASE
            WHEN (status = 'OPEN'::text) THEN true
            ELSE false
        END AS is_open,
        CASE
            WHEN (classification_status = 'PENDING'::text) THEN true
            ELSE false
        END AS is_pending_classification,
        CASE
            WHEN (status = 'OPEN'::text) THEN 'ABIERTO'::text
            WHEN (classification_status = 'PENDING'::text) THEN 'CERRADO SIN CLASIFICAR'::text
            WHEN (classification_status = 'CLASSIFIED'::text) THEN 'CLASIFICADO'::text
            ELSE COALESCE(status, 'SIN_ESTADO'::text)
        END AS stop_status_label,
        CASE
            WHEN (status = 'OPEN'::text) THEN 3
            WHEN (classification_status = 'PENDING'::text) THEN 2
            WHEN (classification_status = 'CLASSIFIED'::text) THEN 1
            ELSE 0
        END AS stop_priority_score
   FROM base_with_cause b;


ALTER VIEW mv_reports_ucepsa_demo.machine_stops_grafana OWNER TO mesavault;

--
-- Name: machine_targets; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.machine_targets AS
 SELECT machine_id,
    machine_name,
    asset,
    target_cycle_rate_ppm,
    value_hour_eur,
    quality_pct_default,
    notes
   FROM mv_hot.edge_oee_machine_targets
  WHERE (machine_id = 'CORT-01'::text);


ALTER VIEW mv_reports_ucepsa_demo.machine_targets OWNER TO mesavault;

--
-- Name: node_events_recent; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.node_events_recent AS
 SELECT received_at,
    age_s,
    event_ts,
    tenant,
    site,
    vertical,
    asset,
    machine_id,
    order_id,
    event_type,
    event_name,
    previous_auto_signal,
    new_auto_signal,
    machine_running,
    reason_pending,
    cycle_pulse_count,
    cycle_rate_ppm,
    last_cycle_age_s,
    topic,
    payload_json
   FROM mv_hot.edge_oee_node_events_recent
  WHERE (asset = 'revpi_oee_node_01'::text);


ALTER VIEW mv_reports_ucepsa_demo.node_events_recent OWNER TO mesavault;

--
-- Name: odoo_discrepancies_demo; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

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'::text) THEN 'La máquina está en marcha, pero la orden de Odoo está preparada o en espera, no iniciada.'::text
            WHEN (status_check = 'ORDEN_PREPARADA_MAQUINA_PARADA'::text) THEN 'La orden está preparada/en espera y la máquina está parada. No hay desviación productiva activa.'::text
            WHEN (status_check = 'ORDEN_EN_CURSO_MAQUINA_PARADA'::text) THEN 'La orden está en curso en Odoo, pero la máquina está parada.'::text
            WHEN (status_check = 'SIN_TELEMETRIA'::text) THEN 'No hay telemetría reciente de máquina.'::text
            ELSE 'Sin discrepancia relevante.'::text
        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;


ALTER VIEW mv_reports_ucepsa_demo.odoo_discrepancies_demo OWNER TO mesavault;

--
-- Name: odoo_workorders_reality_history; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.odoo_workorders_reality_history AS
 WITH orders AS (
         SELECT o_1.id,
            o_1.tenant,
            o_1.site,
            o_1.odoo_instance,
            o_1.odoo_workorder_id,
            o_1.odoo_production_id,
            o_1.odoo_order_ref,
            o_1.odoo_state,
            o_1.odoo_workcenter_code,
            o_1.odoo_workcenter_name,
            o_1.machine_id,
            o_1.asset,
            o_1.product,
            o_1.qty_planned,
            o_1.qty_done,
            o_1.uom,
            o_1.planned_cycles,
            o_1.target_cycle_rate_ppm,
            o_1.odoo_start,
            o_1.odoo_end,
            o_1.notes,
            o_1.snapshot_at,
                CASE
                    WHEN ((o_1.odoo_state = ANY (ARRAY['progress'::text, 'in_progress'::text, 'started'::text, 'done'::text, 'to_close'::text])) AND (o_1.odoo_start IS NOT NULL)) THEN true
                    ELSE false
                END AS odoo_is_started_calc,
            COALESCE(o_1.odoo_end, now()) AS analysis_end
           FROM mv_edge_oee_ucepsa_demo.odoo_workorders_demo o_1
          WHERE ((o_1.machine_id = 'CORT-01'::text) AND (o_1.odoo_instance = 'odoo_demo'::text) AND (o_1.odoo_workorder_id IS NOT NULL))
        ), first_activity AS (
         SELECT o_1.id AS order_row_id,
            min(l.ingest_ts) AS first_machine_activity
           FROM (orders o_1
             LEFT JOIN mv_reports_ucepsa_demo.live_telemetry l ON (((o_1.odoo_is_started_calc = true) AND (l.asset = o_1.asset) AND (l.ingest_ts >= o_1.odoo_start) AND (l.ingest_ts <= o_1.analysis_end) AND ((l.machine_running = true) OR (COALESCE(l.cycle_pulse_count, (0)::bigint) > 0)))))
          GROUP BY o_1.id
        ), cycle_calc AS (
         SELECT o_1.id AS order_row_id,
            (COALESCE(GREATEST((max(l.cycle_pulse_count) - min(l.cycle_pulse_count)), (0)::bigint), (0)::bigint))::numeric AS real_cycles
           FROM (orders o_1
             LEFT JOIN mv_reports_ucepsa_demo.live_telemetry l ON (((o_1.odoo_is_started_calc = true) AND (l.asset = o_1.asset) AND (l.ingest_ts >= o_1.odoo_start) AND (l.ingest_ts <= o_1.analysis_end) AND (l.cycle_pulse_count IS NOT NULL))))
          GROUP BY o_1.id
        ), stop_calc AS (
         SELECT o_1.id AS order_row_id,
            count(s.stop_id) AS stop_count,
            round((COALESCE(sum(s.overlap_s), (0)::numeric) / 60.0), 2) AS stop_min,
            round(COALESCE(sum(((s.overlap_s / 3600.0) * s.value_hour_eur)), (0)::numeric), 2) AS stop_cost_eur
           FROM (orders o_1
             LEFT JOIN LATERAL ( SELECT ms.id AS stop_id,
                    ms.value_hour_eur,
                    GREATEST(EXTRACT(epoch FROM (LEAST(COALESCE(ms.ended_at, o_1.analysis_end), o_1.analysis_end) - GREATEST(
                        CASE
                            WHEN (ms.started_at > (ms.created_at + '00:00:05'::interval)) THEN ms.created_at
                            ELSE ms.started_at
                        END, o_1.odoo_start))), (0)::numeric) AS overlap_s
                   FROM mv_hot.edge_oee_machine_stops ms
                  WHERE ((o_1.odoo_is_started_calc = true) AND (ms.machine_id = o_1.machine_id) AND (
                        CASE
                            WHEN (ms.started_at > (ms.created_at + '00:00:05'::interval)) THEN ms.created_at
                            ELSE ms.started_at
                        END < o_1.analysis_end) AND (COALESCE(ms.ended_at, now()) > o_1.odoo_start))) s ON (true))
          GROUP BY o_1.id
        )
 SELECT o.id,
    o.tenant,
    o.site,
    o.odoo_instance,
    o.odoo_workorder_id,
    o.odoo_production_id,
    o.odoo_order_ref,
    o.odoo_state,
    o.odoo_workcenter_code,
    o.odoo_workcenter_name,
    o.machine_id,
    o.asset,
    o.product,
    o.qty_planned,
    o.qty_done,
    o.uom,
    o.planned_cycles,
    o.target_cycle_rate_ppm,
    o.odoo_start,
    o.odoo_end,
    o.snapshot_at,
    o.odoo_is_started_calc AS odoo_is_started,
    fa.first_machine_activity,
        CASE
            WHEN (o.odoo_is_started_calc = false) THEN NULL::numeric
            WHEN (fa.first_machine_activity IS NULL) THEN NULL::numeric
            ELSE round((EXTRACT(epoch FROM (fa.first_machine_activity - o.odoo_start)) / 60.0), 2)
        END AS start_delay_min,
    COALESCE(sc.stop_count, (0)::bigint) AS stop_count,
    COALESCE(sc.stop_min, (0)::numeric) AS stop_min,
    COALESCE(sc.stop_cost_eur, (0)::numeric) AS stop_cost_eur,
        CASE
            WHEN (o.odoo_is_started_calc = true) THEN COALESCE(cc.real_cycles, (0)::numeric)
            ELSE (0)::numeric
        END AS real_cycles,
        CASE
            WHEN ((o.odoo_is_started_calc = true) AND (o.planned_cycles > (0)::numeric)) THEN round(((COALESCE(cc.real_cycles, (0)::numeric) / o.planned_cycles) * (100)::numeric), 2)
            WHEN (o.odoo_is_started_calc = false) THEN (0)::numeric
            ELSE NULL::numeric
        END AS cycle_completion_pct,
        CASE
            WHEN (o.odoo_state = ANY (ARRAY['ready'::text, 'waiting'::text])) THEN 'ORDEN_NO_INICIADA'::text
            WHEN ((o.odoo_is_started_calc = true) AND (fa.first_machine_activity IS NULL)) THEN 'ORDEN_SIN_ACTIVIDAD_REAL'::text
            WHEN ((o.odoo_is_started_calc = true) AND (COALESCE(sc.stop_count, (0)::bigint) > 0)) THEN 'OK_CON_PAROS'::text
            WHEN (o.odoo_is_started_calc = true) THEN 'OK'::text
            ELSE 'SIN_EVALUAR'::text
        END AS status_check,
        CASE
            WHEN (o.odoo_state = ANY (ARRAY['ready'::text, 'waiting'::text])) THEN 'Orden preparada o en espera. Todavía no debe imputar ciclos, paros ni retrasos.'::text
            WHEN ((o.odoo_is_started_calc = true) AND (fa.first_machine_activity IS NULL)) THEN 'La orden está iniciada/cerrada en Odoo, pero no se detectó actividad real de máquina en su ventana.'::text
            WHEN ((o.odoo_is_started_calc = true) AND (COALESCE(sc.stop_count, (0)::bigint) > 0)) THEN 'La orden tuvo actividad real y paros imputados durante su ventana.'::text
            WHEN (o.odoo_is_started_calc = true) THEN 'La orden tuvo actividad real sin paros imputados.'::text
            ELSE 'Orden sin evaluación suficiente.'::text
        END AS descripcion
   FROM (((orders o
     LEFT JOIN first_activity fa ON ((fa.order_row_id = o.id)))
     LEFT JOIN cycle_calc cc ON ((cc.order_row_id = o.id)))
     LEFT JOIN stop_calc sc ON ((sc.order_row_id = o.id)))
  ORDER BY COALESCE(o.odoo_end, o.odoo_start, o.snapshot_at) DESC, o.odoo_workorder_id DESC;


ALTER VIEW mv_reports_ucepsa_demo.odoo_workorders_reality_history OWNER TO mesavault;

--
-- Name: odoo_last_finished_order_demo; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.odoo_last_finished_order_demo AS
 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_end,
    snapshot_at,
    odoo_is_started,
    first_machine_activity,
    start_delay_min,
    stop_count,
    stop_min,
    stop_cost_eur,
    real_cycles,
    cycle_completion_pct,
    status_check,
    descripcion
   FROM mv_reports_ucepsa_demo.odoo_workorders_reality_history
  WHERE (odoo_state = ANY (ARRAY['done'::text, 'to_close'::text]))
  ORDER BY COALESCE(odoo_end, snapshot_at) DESC
 LIMIT 1;


ALTER VIEW mv_reports_ucepsa_demo.odoo_last_finished_order_demo OWNER TO mesavault;

--
-- Name: odoo_order_state_machine_grafana; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

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'::text
            WHEN (EXTRACT(epoch FROM (now() - o.received_at)) > (30)::numeric) THEN 'ODOO_STATE_ANTIGUO'::text
            WHEN (o.odoo_state = 'multiple_loaded_orders'::text) THEN 'MULTIPLES_ORDENES_EN_PROGRESS'::text
            WHEN ((o.order_present = true) AND (o.order_coherent = true) AND (COALESCE(m.machine_running, false) = true)) THEN 'ORDEN_CARGADA_MAQUINA_EN_MARCHA'::text
            WHEN ((o.order_present = true) AND (o.order_coherent = true) AND (COALESCE(m.machine_running, false) = false)) THEN 'ORDEN_CARGADA_MAQUINA_PARADA'::text
            WHEN ((COALESCE(o.order_present, false) = false) AND (COALESCE(m.machine_running, false) = true)) THEN 'MAQUINA_EN_MARCHA_SIN_ORDEN_ODOO'::text
            WHEN ((COALESCE(o.order_present, false) = false) AND (COALESCE(m.machine_running, false) = false)) THEN 'SIN_ORDEN_MAQUINA_PARADA'::text
            ELSE 'REVISAR'::text
        END AS edge_odoo_status,
    o.payload_json AS odoo_payload_json
   FROM (mv_reports_ucepsa_demo.machine_state_latest_multi m
     FULL JOIN mv_hot.odoo_order_state_current o ON (((o.tenant = 'ucepsa'::text) AND (o.site = 'ucepsa_onpremise'::text) AND (o.machine_id = m.machine_id))))
  WHERE (COALESCE(m.site, o.site) = 'ucepsa_onpremise'::text);


ALTER VIEW mv_reports_ucepsa_demo.odoo_order_state_machine_grafana OWNER TO mesavault;

--
-- Name: stop_summary; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_demo.stop_summary AS
 SELECT cause_name,
    cause_code,
    stop_count,
    total_min,
    total_cost_eur
   FROM mv_hot.edge_oee_stop_summary_demo;


ALTER VIEW mv_reports_ucepsa_demo.stop_summary OWNER TO mesavault;

--
-- Name: current_order_margin_readiness_v1; Type: VIEW; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_prod.current_order_margin_readiness_v1 AS
 WITH current_orders AS (
         SELECT odoo_order_state_current.tenant,
            odoo_order_state_current.site,
            odoo_order_state_current.machine_id,
            odoo_order_state_current.workcenter_id,
            odoo_order_state_current.workcenter_name,
            odoo_order_state_current.order_present,
            odoo_order_state_current.order_coherent,
            odoo_order_state_current.odoo_state AS order_state_from_shopfloor,
            odoo_order_state_current.workorder_id AS odoo_workorder_id,
            odoo_order_state_current.production_order AS odoo_order_ref,
            odoo_order_state_current.product AS order_state_product,
            odoo_order_state_current.waiting_count,
            odoo_order_state_current.ready_count,
            odoo_order_state_current.progress_count,
            odoo_order_state_current.mqtt_ts,
            odoo_order_state_current.received_at,
            odoo_order_state_current.payload_json,
            (NULLIF((odoo_order_state_current.payload_json ->> 'production_id'::text), ''::text))::integer AS odoo_production_id,
            (NULLIF((odoo_order_state_current.payload_json ->> 'product_id'::text), ''::text))::integer AS order_state_product_id,
            (NULLIF((odoo_order_state_current.payload_json ->> 'qty_production'::text), ''::text))::numeric AS order_state_qty_production,
            (odoo_order_state_current.payload_json ->> 'date_start'::text) AS order_state_date_start,
            (odoo_order_state_current.payload_json ->> 'date_finished'::text) AS order_state_date_finished
           FROM mv_hot.odoo_order_state_current
          WHERE (odoo_order_state_current.site = 'ucepsa_onpremise'::text)
        ), commercial AS (
         SELECT odoo_order_commercials.id,
            odoo_order_commercials.tenant,
            odoo_order_commercials.site,
            odoo_order_commercials.odoo_instance,
            odoo_order_commercials.odoo_production_id,
            odoo_order_commercials.odoo_order_ref,
            odoo_order_commercials.odoo_origin,
            odoo_order_commercials.odoo_state,
            odoo_order_commercials.product_id,
            odoo_order_commercials.product_default_code,
            odoo_order_commercials.product_name,
            odoo_order_commercials.product_uom,
            odoo_order_commercials.product_standard_price,
            odoo_order_commercials.product_list_price,
            odoo_order_commercials.production_qty,
            odoo_order_commercials.qty_producing,
            odoo_order_commercials.production_uom,
            odoo_order_commercials.sale_line_id,
            odoo_order_commercials.sale_order_id,
            odoo_order_commercials.sale_order_ref,
            odoo_order_commercials.customer_id,
            odoo_order_commercials.customer_name,
            odoo_order_commercials.sale_state,
            odoo_order_commercials.sale_date_order,
            odoo_order_commercials.currency,
            odoo_order_commercials.sale_line_qty,
            odoo_order_commercials.sale_line_qty_delivered,
            odoo_order_commercials.sale_price_unit,
            odoo_order_commercials.sale_discount_pct,
            odoo_order_commercials.revenue_net_eur,
            odoo_order_commercials.revenue_total_eur,
            odoo_order_commercials.raw_material_value_eur,
            odoo_order_commercials.finished_value_eur,
            odoo_order_commercials.material_cost_status,
            odoo_order_commercials.stock_raw_moves_json,
            odoo_order_commercials.stock_finished_moves_json,
            odoo_order_commercials.raw_json,
            odoo_order_commercials.snapshot_at
           FROM mv_edge_oee_ucepsa_prod.odoo_order_commercials
          WHERE ((odoo_order_commercials.site = 'ucepsa_onpremise'::text) AND (odoo_order_commercials.odoo_instance = 'odoo_ucepsa_prod'::text))
        ), joined AS (
         SELECT co.tenant,
            co.site,
            co.machine_id,
            co.workcenter_id,
            co.workcenter_name,
            co.order_present,
            co.order_coherent,
            co.order_state_from_shopfloor,
            co.odoo_workorder_id,
            co.odoo_production_id,
            co.odoo_order_ref,
            co.order_state_product,
            co.order_state_product_id,
            co.order_state_qty_production,
            co.waiting_count,
            co.ready_count,
            co.progress_count,
            co.mqtt_ts,
            co.received_at,
            c.odoo_instance,
            c.odoo_state AS production_state,
            c.odoo_origin,
            c.product_id,
            c.product_default_code,
            COALESCE(c.product_name, co.order_state_product) AS product_name,
            c.product_uom,
            c.production_qty,
            c.qty_producing,
            c.production_uom,
            c.sale_line_id,
            c.sale_order_id,
            c.sale_order_ref,
            c.customer_id,
            c.customer_name,
            c.sale_state,
            c.sale_date_order,
            c.currency,
            c.sale_line_qty,
            c.sale_line_qty_delivered,
            c.sale_price_unit,
            c.sale_discount_pct,
            c.revenue_net_eur,
            c.revenue_total_eur,
            c.raw_material_value_eur,
            c.finished_value_eur,
            c.material_cost_status,
            jsonb_array_length(COALESCE(c.stock_raw_moves_json, '[]'::jsonb)) AS raw_material_line_count,
            jsonb_array_length(COALESCE(c.stock_finished_moves_json, '[]'::jsonb)) AS finished_move_line_count,
            c.stock_raw_moves_json,
            c.stock_finished_moves_json,
            c.snapshot_at AS commercial_snapshot_at
           FROM (current_orders co
             LEFT JOIN commercial c ON ((c.odoo_production_id = co.odoo_production_id)))
        )
 SELECT tenant,
    site,
    machine_id,
    workcenter_id,
    workcenter_name,
    order_present,
    order_coherent,
    order_state_from_shopfloor,
    odoo_workorder_id,
    odoo_production_id,
    odoo_order_ref,
    order_state_product,
    order_state_product_id,
    order_state_qty_production,
    waiting_count,
    ready_count,
    progress_count,
    mqtt_ts,
    received_at,
    odoo_instance,
    production_state,
    odoo_origin,
    product_id,
    product_default_code,
    product_name,
    product_uom,
    production_qty,
    qty_producing,
    production_uom,
    sale_line_id,
    sale_order_id,
    sale_order_ref,
    customer_id,
    customer_name,
    sale_state,
    sale_date_order,
    currency,
    sale_line_qty,
    sale_line_qty_delivered,
    sale_price_unit,
    sale_discount_pct,
    revenue_net_eur,
    revenue_total_eur,
    raw_material_value_eur,
    finished_value_eur,
    material_cost_status,
    raw_material_line_count,
    finished_move_line_count,
    stock_raw_moves_json,
    stock_finished_moves_json,
    commercial_snapshot_at,
        CASE
            WHEN (order_present IS FALSE) THEN 'NO_ORDER_LOADED'::text
            WHEN (order_coherent IS FALSE) THEN 'ODOO_ORDER_INCOHERENT'::text
            WHEN (odoo_production_id IS NULL) THEN 'MISSING_PRODUCTION_ID_FROM_ORDER_STATE'::text
            WHEN (odoo_instance IS NULL) THEN 'MISSING_COMMERCIAL_SNAPSHOT'::text
            WHEN ((sale_order_ref IS NULL) OR (revenue_net_eur IS NULL)) THEN 'MISSING_REVENUE_LINK'::text
            WHEN (customer_name IS NULL) THEN 'MISSING_CUSTOMER'::text
            WHEN (raw_material_line_count = 0) THEN 'MISSING_RAW_MATERIALS'::text
            WHEN (material_cost_status = 'UNAVAILABLE_OR_ZERO'::text) THEN 'MISSING_MATERIAL_COST'::text
            ELSE 'READY_FOR_MARGIN_BASE'::text
        END AS margin_readiness_status,
        CASE
            WHEN (order_present IS FALSE) THEN 'No hay orden cargada en Odoo Shop Floor para esta máquina.'::text
            WHEN (order_coherent IS FALSE) THEN 'Hay estado Odoo incoherente para esta máquina.'::text
            WHEN (odoo_production_id IS NULL) THEN 'El order_state no trae production_id; revisar publicador Odoo.'::text
            WHEN (odoo_instance IS NULL) THEN 'La orden existe en order_state, pero aún no tiene snapshot comercial en Edge-OEE.'::text
            WHEN ((sale_order_ref IS NULL) OR (revenue_net_eur IS NULL)) THEN 'Falta vínculo económico con pedido/línea de venta.'::text
            WHEN (customer_name IS NULL) THEN 'Falta cliente asociado al pedido de venta.'::text
            WHEN (raw_material_line_count = 0) THEN 'No se detectan movimientos de materia prima para la orden.'::text
            WHEN (material_cost_status = 'UNAVAILABLE_OR_ZERO'::text) THEN 'Hay materia prima, pero Odoo no aporta valoración económica útil. Cargar coste €/kg o corregir valoración.'::text
            ELSE 'Datos comerciales mínimos disponibles para calcular margen base.'::text
        END AS margin_readiness_description,
    ((((((
        CASE
            WHEN (order_present IS TRUE) THEN 20
            ELSE 0
        END +
        CASE
            WHEN (order_coherent IS TRUE) THEN 15
            ELSE 0
        END) +
        CASE
            WHEN (odoo_instance IS NOT NULL) THEN 15
            ELSE 0
        END) +
        CASE
            WHEN ((sale_order_ref IS NOT NULL) AND (revenue_net_eur IS NOT NULL)) THEN 20
            ELSE 0
        END) +
        CASE
            WHEN (customer_name IS NOT NULL) THEN 10
            ELSE 0
        END) +
        CASE
            WHEN (raw_material_line_count > 0) THEN 10
            ELSE 0
        END) +
        CASE
            WHEN (material_cost_status <> 'UNAVAILABLE_OR_ZERO'::text) THEN 10
            ELSE 0
        END) AS margin_readiness_score
   FROM joined;


ALTER VIEW mv_reports_ucepsa_prod.current_order_margin_readiness_v1 OWNER TO mesavault;

--
-- Name: order_raw_material_costs_v1; Type: VIEW; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_prod.order_raw_material_costs_v1 AS
 WITH raw_moves AS (
         SELECT c.id AS commercial_row_id,
            c.tenant,
            c.site,
            c.odoo_instance,
            c.odoo_production_id,
            c.odoo_order_ref,
            c.sale_order_ref,
            c.customer_name,
            c.product_default_code AS finished_product_default_code,
            c.product_name AS finished_product_name,
            (NULLIF((rm.raw_move ->> 'id'::text), ''::text))::integer AS raw_move_id,
            (NULLIF(((rm.raw_move -> 'product_id'::text) ->> 0), ''::text))::integer AS raw_product_id,
            ((rm.raw_move -> 'product_id'::text) ->> 1) AS raw_product_name,
            "substring"(((rm.raw_move -> 'product_id'::text) ->> 1), '\[([^\]]+)\]'::text) AS raw_product_default_code,
            (NULLIF((rm.raw_move ->> 'product_uom_qty'::text), ''::text))::numeric AS planned_qty,
            (NULLIF((rm.raw_move ->> 'quantity'::text), ''::text))::numeric AS consumed_qty,
            ((rm.raw_move -> 'product_uom'::text) ->> 1) AS raw_uom,
            (NULLIF((rm.raw_move ->> 'price_unit'::text), ''::text))::numeric AS odoo_price_unit,
            (NULLIF((rm.raw_move ->> 'value'::text), ''::text))::numeric AS odoo_value,
            (rm.raw_move ->> 'state'::text) AS move_state,
            rm.raw_move AS raw_move_json
           FROM (mv_edge_oee_ucepsa_prod.odoo_order_commercials c
             CROSS JOIN LATERAL jsonb_array_elements(c.stock_raw_moves_json) rm(raw_move))
        ), costed AS (
         SELECT r.commercial_row_id,
            r.tenant,
            r.site,
            r.odoo_instance,
            r.odoo_production_id,
            r.odoo_order_ref,
            r.sale_order_ref,
            r.customer_name,
            r.finished_product_default_code,
            r.finished_product_name,
            r.raw_move_id,
            r.raw_product_id,
            r.raw_product_name,
            r.raw_product_default_code,
            r.planned_qty,
            r.consumed_qty,
            r.raw_uom,
            r.odoo_price_unit,
            r.odoo_value,
            r.move_state,
            r.raw_move_json,
            p.id AS raw_material_cost_parameter_id,
            p.material_cost_eur_per_kg,
            p.source AS raw_material_cost_source,
            p.notes AS raw_material_cost_notes,
                CASE
                    WHEN (COALESCE(r.odoo_value, (0)::numeric) <> (0)::numeric) THEN abs(r.odoo_value)
                    WHEN ((lower(COALESCE(r.raw_uom, ''::text)) = 'kg'::text) AND (p.material_cost_eur_per_kg IS NOT NULL) AND (r.consumed_qty IS NOT NULL)) THEN (r.consumed_qty * p.material_cost_eur_per_kg)
                    ELSE NULL::numeric
                END AS material_cost_estimated_eur,
                CASE
                    WHEN (COALESCE(r.odoo_value, (0)::numeric) <> (0)::numeric) THEN 'FROM_ODOO_STOCK_MOVE_VALUE'::text
                    WHEN (r.raw_product_id IS NULL) THEN 'MISSING_RAW_PRODUCT_ID'::text
                    WHEN (lower(COALESCE(r.raw_uom, ''::text)) <> 'kg'::text) THEN 'UNSUPPORTED_RAW_UOM'::text
                    WHEN (p.material_cost_eur_per_kg IS NULL) THEN 'MISSING_RAW_MATERIAL_COST_PARAMETER'::text
                    WHEN (r.consumed_qty IS NULL) THEN 'MISSING_CONSUMED_QTY'::text
                    ELSE 'FROM_RAW_MATERIAL_COST_PARAMETER'::text
                END AS material_cost_status
           FROM (raw_moves r
             LEFT JOIN LATERAL ( SELECT p1.id,
                    p1.tenant,
                    p1.site,
                    p1.raw_product_default_code,
                    p1.raw_product_name,
                    p1.material_cost_eur_per_kg,
                    p1.source,
                    p1.valid_from,
                    p1.valid_to,
                    p1.is_active,
                    p1.notes,
                    p1.created_at,
                    p1.raw_product_id,
                    p1.raw_uom
                   FROM mv_edge_oee_ucepsa_prod.raw_material_cost_parameters p1
                  WHERE ((p1.tenant = r.tenant) AND (p1.site = r.site) AND (p1.is_active = true) AND (p1.valid_from <= now()) AND ((p1.valid_to IS NULL) OR (p1.valid_to > now())) AND (((p1.raw_product_id IS NOT NULL) AND (p1.raw_product_id = r.raw_product_id)) OR ((p1.raw_product_id IS NULL) AND (p1.raw_product_default_code IS NOT NULL) AND (p1.raw_product_default_code = r.raw_product_default_code)) OR ((p1.raw_product_id IS NULL) AND (p1.raw_product_default_code IS NULL) AND (p1.raw_product_name IS NOT NULL) AND (p1.raw_product_name = r.raw_product_name))))
                  ORDER BY
                        CASE
                            WHEN ((p1.raw_product_id IS NOT NULL) AND (p1.raw_product_id = r.raw_product_id)) THEN 1
                            WHEN ((p1.raw_product_default_code IS NOT NULL) AND (p1.raw_product_default_code = r.raw_product_default_code)) THEN 2
                            WHEN ((p1.raw_product_name IS NOT NULL) AND (p1.raw_product_name = r.raw_product_name)) THEN 3
                            ELSE 9
                        END, p1.valid_from DESC, p1.id DESC
                 LIMIT 1) p ON (true))
        )
 SELECT commercial_row_id,
    tenant,
    site,
    odoo_instance,
    odoo_production_id,
    odoo_order_ref,
    sale_order_ref,
    customer_name,
    finished_product_default_code,
    finished_product_name,
    raw_move_id,
    raw_product_id,
    raw_product_name,
    raw_product_default_code,
    planned_qty,
    consumed_qty,
    raw_uom,
    odoo_price_unit,
    odoo_value,
    move_state,
    raw_material_cost_parameter_id,
    material_cost_eur_per_kg,
    raw_material_cost_source,
    raw_material_cost_notes,
    material_cost_estimated_eur,
    round(material_cost_estimated_eur, 4) AS material_cost_estimated_eur_rounded,
    material_cost_status,
    raw_move_json
   FROM costed;


ALTER VIEW mv_reports_ucepsa_prod.order_raw_material_costs_v1 OWNER TO mesavault;

--
-- Name: order_raw_material_costs_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_prod.order_raw_material_costs_summary_v1 AS
 SELECT tenant,
    site,
    odoo_instance,
    odoo_production_id,
    odoo_order_ref,
    sale_order_ref,
    customer_name,
    finished_product_default_code,
    finished_product_name,
    count(*) AS raw_material_line_count,
    round(sum(COALESCE(consumed_qty, (0)::numeric)), 3) AS total_consumed_qty,
    string_agg(concat(COALESCE(raw_product_default_code, (raw_product_id)::text, 'sin_codigo'::text), ' - ', COALESCE(raw_product_name, 'sin_nombre'::text), ': ', COALESCE((consumed_qty)::text, 'sin_cantidad'::text), ' ', COALESCE(raw_uom, ''::text)), '; '::text ORDER BY raw_product_name) AS raw_materials_summary,
    round(sum(COALESCE(material_cost_estimated_eur, (0)::numeric)), 4) AS material_cost_estimated_eur,
    count(*) FILTER (WHERE (material_cost_estimated_eur IS NOT NULL)) AS costed_raw_material_line_count,
    count(*) FILTER (WHERE ((material_cost_status <> 'FROM_RAW_MATERIAL_COST_PARAMETER'::text) AND (material_cost_status <> 'FROM_ODOO_STOCK_MOVE_VALUE'::text))) AS missing_or_invalid_raw_material_cost_count,
    string_agg(DISTINCT material_cost_status, ', '::text ORDER BY material_cost_status) AS material_cost_status_summary
   FROM mv_reports_ucepsa_prod.order_raw_material_costs_v1
  GROUP BY tenant, site, odoo_instance, odoo_production_id, odoo_order_ref, sale_order_ref, customer_name, finished_product_default_code, finished_product_name;


ALTER VIEW mv_reports_ucepsa_prod.order_raw_material_costs_summary_v1 OWNER TO mesavault;

--
-- Name: raw_material_cost_requirements_v1; Type: VIEW; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

CREATE VIEW mv_reports_ucepsa_prod.raw_material_cost_requirements_v1 AS
 SELECT tenant,
    site,
    raw_product_id,
    raw_product_default_code,
    raw_product_name,
    raw_uom,
    count(*) AS affected_order_lines,
    count(DISTINCT odoo_order_ref) AS affected_orders,
    string_agg(DISTINCT odoo_order_ref, ', '::text ORDER BY odoo_order_ref) AS affected_order_refs,
    round(sum(COALESCE(consumed_qty, (0)::numeric)), 3) AS total_consumed_qty,
    string_agg(DISTINCT customer_name, ', '::text ORDER BY customer_name) AS affected_customers,
    max(material_cost_status) AS current_status,
    'Cargar coste €/kg en mv_edge_oee_ucepsa_prod.raw_material_cost_parameters'::text AS recommended_action
   FROM mv_reports_ucepsa_prod.order_raw_material_costs_v1
  WHERE (material_cost_status = ANY (ARRAY['MISSING_RAW_MATERIAL_COST_PARAMETER'::text, 'MISSING_RAW_PRODUCT_ID'::text, 'MISSING_CONSUMED_QTY'::text, 'UNSUPPORTED_RAW_UOM'::text]))
  GROUP BY tenant, site, raw_product_id, raw_product_default_code, raw_product_name, raw_uom;


ALTER VIEW mv_reports_ucepsa_prod.raw_material_cost_requirements_v1 OWNER TO mesavault;

--
-- Name: data_quality_contract_rules id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.data_quality_contract_rules ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq'::regclass);


--
-- Name: margin_cost_parameters id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.margin_cost_parameters ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.margin_cost_parameters_id_seq'::regclass);


--
-- Name: odoo_order_commercials id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_order_commercials ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.odoo_order_commercials_id_seq'::regclass);


--
-- Name: odoo_workcenter_map id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workcenter_map ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.odoo_workcenter_map_id_seq'::regclass);


--
-- Name: odoo_workorders_demo id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workorders_demo ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.odoo_workorders_demo_id_seq'::regclass);


--
-- Name: raw_material_cost_parameters id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.raw_material_cost_parameters ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_demo.raw_material_cost_parameters_id_seq'::regclass);


--
-- Name: data_quality_contract_rules id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.data_quality_contract_rules ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_prod.data_quality_contract_rules_id_seq'::regclass);


--
-- Name: margin_cost_parameters id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.margin_cost_parameters ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_prod.margin_cost_parameters_id_seq'::regclass);


--
-- Name: odoo_order_commercials id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.odoo_order_commercials ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_prod.odoo_order_commercials_id_seq'::regclass);


--
-- Name: raw_material_cost_parameters id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.raw_material_cost_parameters ALTER COLUMN id SET DEFAULT nextval('mv_edge_oee_ucepsa_prod.raw_material_cost_parameters_id_seq'::regclass);


--
-- Name: edge_oee_eastron_readings id; Type: DEFAULT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_eastron_readings ALTER COLUMN id SET DEFAULT nextval('mv_hot.edge_oee_eastron_readings_id_seq'::regclass);


--
-- Name: edge_oee_events_demo event_id; Type: DEFAULT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_events_demo ALTER COLUMN event_id SET DEFAULT nextval('mv_hot.edge_oee_events_demo_event_id_seq'::regclass);


--
-- Name: edge_oee_machine_stops id; Type: DEFAULT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_machine_stops ALTER COLUMN id SET DEFAULT nextval('mv_hot.edge_oee_machine_stops_id_seq'::regclass);


--
-- Name: edge_oee_node_events id; Type: DEFAULT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_node_events ALTER COLUMN id SET DEFAULT nextval('mv_hot.edge_oee_node_events_id_seq'::regclass);


--
-- Name: odoo_order_state_events id; Type: DEFAULT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.odoo_order_state_events ALTER COLUMN id SET DEFAULT nextval('mv_hot.odoo_order_state_events_id_seq'::regclass);


--
-- Name: data_quality_contract_rules data_quality_contract_rules_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.data_quality_contract_rules
    ADD CONSTRAINT data_quality_contract_rules_pkey PRIMARY KEY (id);


--
-- Name: margin_cost_parameters margin_cost_parameters_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.margin_cost_parameters
    ADD CONSTRAINT margin_cost_parameters_pkey PRIMARY KEY (id);


--
-- Name: odoo_order_commercials odoo_order_commercials_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_order_commercials
    ADD CONSTRAINT odoo_order_commercials_pkey PRIMARY KEY (id);


--
-- Name: odoo_workcenter_map odoo_workcenter_map_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workcenter_map
    ADD CONSTRAINT odoo_workcenter_map_pkey PRIMARY KEY (id);


--
-- Name: odoo_workcenter_map odoo_workcenter_map_tenant_site_machine_id_key; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workcenter_map
    ADD CONSTRAINT odoo_workcenter_map_tenant_site_machine_id_key UNIQUE (tenant, site, machine_id);


--
-- Name: odoo_workcenter_map odoo_workcenter_map_tenant_site_odoo_instance_odoo_workcent_key; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workcenter_map
    ADD CONSTRAINT odoo_workcenter_map_tenant_site_odoo_instance_odoo_workcent_key UNIQUE (tenant, site, odoo_instance, odoo_workcenter_code);


--
-- Name: odoo_workorders_demo odoo_workorders_demo_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_workorders_demo
    ADD CONSTRAINT odoo_workorders_demo_pkey PRIMARY KEY (id);


--
-- Name: raw_material_cost_parameters raw_material_cost_parameters_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.raw_material_cost_parameters
    ADD CONSTRAINT raw_material_cost_parameters_pkey PRIMARY KEY (id);


--
-- Name: data_quality_contract_rules ux_data_quality_contract_rules_code; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.data_quality_contract_rules
    ADD CONSTRAINT ux_data_quality_contract_rules_code UNIQUE (tenant, site, rule_code);


--
-- Name: odoo_order_commercials ux_odoo_order_commercials_instance_production; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.odoo_order_commercials
    ADD CONSTRAINT ux_odoo_order_commercials_instance_production UNIQUE (odoo_instance, odoo_production_id);


--
-- Name: data_quality_contract_rules data_quality_contract_rules_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.data_quality_contract_rules
    ADD CONSTRAINT data_quality_contract_rules_pkey PRIMARY KEY (id);


--
-- Name: data_quality_contract_rules data_quality_contract_rules_tenant_site_rule_code_key; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.data_quality_contract_rules
    ADD CONSTRAINT data_quality_contract_rules_tenant_site_rule_code_key UNIQUE (tenant, site, rule_code);


--
-- Name: margin_cost_parameters margin_cost_parameters_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.margin_cost_parameters
    ADD CONSTRAINT margin_cost_parameters_pkey PRIMARY KEY (id);


--
-- Name: odoo_order_commercials odoo_order_commercials_odoo_instance_odoo_production_id_key; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.odoo_order_commercials
    ADD CONSTRAINT odoo_order_commercials_odoo_instance_odoo_production_id_key UNIQUE (odoo_instance, odoo_production_id);


--
-- Name: odoo_order_commercials odoo_order_commercials_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.odoo_order_commercials
    ADD CONSTRAINT odoo_order_commercials_pkey PRIMARY KEY (id);


--
-- Name: raw_material_cost_parameters raw_material_cost_parameters_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

ALTER TABLE ONLY mv_edge_oee_ucepsa_prod.raw_material_cost_parameters
    ADD CONSTRAINT raw_material_cost_parameters_pkey PRIMARY KEY (id);


--
-- Name: edge_oee_data_quality_demo edge_oee_data_quality_demo_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_data_quality_demo
    ADD CONSTRAINT edge_oee_data_quality_demo_pkey PRIMARY KEY (metric_id);


--
-- Name: edge_oee_eastron_readings edge_oee_eastron_readings_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_eastron_readings
    ADD CONSTRAINT edge_oee_eastron_readings_pkey PRIMARY KEY (id);


--
-- Name: edge_oee_events_demo edge_oee_events_demo_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_events_demo
    ADD CONSTRAINT edge_oee_events_demo_pkey PRIMARY KEY (event_id);


--
-- Name: edge_oee_loss_summary_demo edge_oee_loss_summary_demo_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_loss_summary_demo
    ADD CONSTRAINT edge_oee_loss_summary_demo_pkey PRIMARY KEY (cause);


--
-- Name: edge_oee_machine_stops edge_oee_machine_stops_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_machine_stops
    ADD CONSTRAINT edge_oee_machine_stops_pkey PRIMARY KEY (id);


--
-- Name: edge_oee_machine_targets edge_oee_machine_targets_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_machine_targets
    ADD CONSTRAINT edge_oee_machine_targets_pkey PRIMARY KEY (machine_id);


--
-- Name: edge_oee_machines edge_oee_machines_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_machines
    ADD CONSTRAINT edge_oee_machines_pkey PRIMARY KEY (machine_id);


--
-- Name: edge_oee_node_events edge_oee_node_events_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_node_events
    ADD CONSTRAINT edge_oee_node_events_pkey PRIMARY KEY (id);


--
-- Name: edge_oee_orders_demo edge_oee_orders_demo_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_orders_demo
    ADD CONSTRAINT edge_oee_orders_demo_pkey PRIMARY KEY (order_id);


--
-- Name: edge_oee_quality_cases_demo edge_oee_quality_cases_demo_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_quality_cases_demo
    ADD CONSTRAINT edge_oee_quality_cases_demo_pkey PRIMARY KEY (case_id);


--
-- Name: edge_oee_stop_causes edge_oee_stop_causes_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_stop_causes
    ADD CONSTRAINT edge_oee_stop_causes_pkey PRIMARY KEY (cause_code);


--
-- Name: odoo_order_state_current odoo_order_state_current_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.odoo_order_state_current
    ADD CONSTRAINT odoo_order_state_current_pkey PRIMARY KEY (tenant, site, machine_id);


--
-- Name: odoo_order_state_events odoo_order_state_events_pkey; Type: CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.odoo_order_state_events
    ADD CONSTRAINT odoo_order_state_events_pkey PRIMARY KEY (id);


--
-- Name: idx_data_quality_contract_rules_active; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_data_quality_contract_rules_active ON mv_edge_oee_ucepsa_demo.data_quality_contract_rules USING btree (tenant, site, is_active, domain, severity);


--
-- Name: idx_margin_cost_parameters_scope; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_margin_cost_parameters_scope ON mv_edge_oee_ucepsa_demo.margin_cost_parameters USING btree (tenant, site, is_active, machine_id, product_default_code);


--
-- Name: idx_odoo_order_commercials_customer; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_odoo_order_commercials_customer ON mv_edge_oee_ucepsa_demo.odoo_order_commercials USING btree (customer_name);


--
-- Name: idx_odoo_order_commercials_order_ref; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_odoo_order_commercials_order_ref ON mv_edge_oee_ucepsa_demo.odoo_order_commercials USING btree (odoo_order_ref);


--
-- Name: idx_odoo_order_commercials_sale_order_ref; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_odoo_order_commercials_sale_order_ref ON mv_edge_oee_ucepsa_demo.odoo_order_commercials USING btree (sale_order_ref);


--
-- Name: idx_odoo_workorders_demo_machine_time; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_odoo_workorders_demo_machine_time ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo USING btree (machine_id, odoo_start DESC);


--
-- Name: idx_odoo_workorders_demo_state; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_odoo_workorders_demo_state ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo USING btree (odoo_state);


--
-- Name: idx_raw_material_cost_parameters_lookup; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE INDEX idx_raw_material_cost_parameters_lookup ON mv_edge_oee_ucepsa_demo.raw_material_cost_parameters USING btree (tenant, site, raw_product_default_code, is_active, valid_from DESC);


--
-- Name: ux_odoo_workcenter_map_instance_workcenter; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE UNIQUE INDEX ux_odoo_workcenter_map_instance_workcenter ON mv_edge_oee_ucepsa_demo.odoo_workcenter_map USING btree (odoo_instance, odoo_workcenter_id);


--
-- Name: ux_odoo_workcenter_map_tenant_site_instance_workcenter; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE UNIQUE INDEX ux_odoo_workcenter_map_tenant_site_instance_workcenter ON mv_edge_oee_ucepsa_demo.odoo_workcenter_map USING btree (tenant, site, odoo_instance, odoo_workcenter_id);


--
-- Name: ux_odoo_workorders_demo_instance_workorder; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE UNIQUE INDEX ux_odoo_workorders_demo_instance_workorder ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo USING btree (odoo_instance, odoo_workorder_id);


--
-- Name: ux_odoo_workorders_demo_tenant_site_instance_workorder; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

CREATE UNIQUE INDEX ux_odoo_workorders_demo_tenant_site_instance_workorder ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo USING btree (tenant, site, odoo_instance, odoo_workorder_id);


--
-- Name: data_quality_contract_rules_tenant_site_is_active_domain_se_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX data_quality_contract_rules_tenant_site_is_active_domain_se_idx ON mv_edge_oee_ucepsa_prod.data_quality_contract_rules USING btree (tenant, site, is_active, domain, severity);


--
-- Name: idx_raw_material_cost_params_prod_code; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX idx_raw_material_cost_params_prod_code ON mv_edge_oee_ucepsa_prod.raw_material_cost_parameters USING btree (raw_product_default_code);


--
-- Name: idx_raw_material_cost_params_prod_name; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX idx_raw_material_cost_params_prod_name ON mv_edge_oee_ucepsa_prod.raw_material_cost_parameters USING btree (raw_product_name);


--
-- Name: idx_raw_material_cost_params_prod_product_id; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX idx_raw_material_cost_params_prod_product_id ON mv_edge_oee_ucepsa_prod.raw_material_cost_parameters USING btree (raw_product_id);


--
-- Name: margin_cost_parameters_tenant_site_is_active_machine_id_pro_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX margin_cost_parameters_tenant_site_is_active_machine_id_pro_idx ON mv_edge_oee_ucepsa_prod.margin_cost_parameters USING btree (tenant, site, is_active, machine_id, product_default_code);


--
-- Name: odoo_order_commercials_customer_name_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX odoo_order_commercials_customer_name_idx ON mv_edge_oee_ucepsa_prod.odoo_order_commercials USING btree (customer_name);


--
-- Name: odoo_order_commercials_odoo_order_ref_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX odoo_order_commercials_odoo_order_ref_idx ON mv_edge_oee_ucepsa_prod.odoo_order_commercials USING btree (odoo_order_ref);


--
-- Name: odoo_order_commercials_sale_order_ref_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX odoo_order_commercials_sale_order_ref_idx ON mv_edge_oee_ucepsa_prod.odoo_order_commercials USING btree (sale_order_ref);


--
-- Name: raw_material_cost_parameters_tenant_site_raw_product_defaul_idx; Type: INDEX; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

CREATE INDEX raw_material_cost_parameters_tenant_site_raw_product_defaul_idx ON mv_edge_oee_ucepsa_prod.raw_material_cost_parameters USING btree (tenant, site, raw_product_default_code, is_active, valid_from DESC);


--
-- Name: idx_edge_oee_eastron_readings_asset_ts; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_eastron_readings_asset_ts ON mv_hot.edge_oee_eastron_readings USING btree (asset, ts DESC);


--
-- Name: idx_edge_oee_eastron_readings_ts; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_eastron_readings_ts ON mv_hot.edge_oee_eastron_readings USING btree (ts DESC);


--
-- Name: idx_edge_oee_energy_demo_time; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_energy_demo_time ON mv_hot.edge_oee_energy_demo USING btree (ts DESC);


--
-- Name: idx_edge_oee_events_demo_machine_time; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_events_demo_machine_time ON mv_hot.edge_oee_events_demo USING btree (machine_id, start_time DESC);


--
-- Name: idx_edge_oee_events_demo_time; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_events_demo_time ON mv_hot.edge_oee_events_demo USING btree (start_time DESC);


--
-- Name: idx_edge_oee_machine_stops_asset_status; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_machine_stops_asset_status ON mv_hot.edge_oee_machine_stops USING btree (asset, status);


--
-- Name: idx_edge_oee_machine_stops_machine_started; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_machine_stops_machine_started ON mv_hot.edge_oee_machine_stops USING btree (machine_id, started_at DESC);


--
-- Name: idx_edge_oee_machine_stops_started_at; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_machine_stops_started_at ON mv_hot.edge_oee_machine_stops USING btree (started_at DESC);


--
-- Name: idx_edge_oee_node_events_asset_ts; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_node_events_asset_ts ON mv_hot.edge_oee_node_events USING btree (asset, event_ts DESC);


--
-- Name: idx_edge_oee_node_events_event_ts; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_node_events_event_ts ON mv_hot.edge_oee_node_events USING btree (event_ts DESC);


--
-- Name: idx_edge_oee_node_events_machine_ts; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_node_events_machine_ts ON mv_hot.edge_oee_node_events USING btree (machine_id, event_ts DESC);


--
-- Name: idx_edge_oee_node_events_received_at; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE INDEX idx_edge_oee_node_events_received_at ON mv_hot.edge_oee_node_events USING btree (received_at DESC);


--
-- Name: ux_odoo_order_state_events_state_hash; Type: INDEX; Schema: mv_hot; Owner: mesavault
--

CREATE UNIQUE INDEX ux_odoo_order_state_events_state_hash ON mv_hot.odoo_order_state_events USING btree (tenant, site, machine_id, payload_hash);


--
-- Name: edge_oee_energy_demo edge_oee_energy_demo_machine_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_energy_demo
    ADD CONSTRAINT edge_oee_energy_demo_machine_id_fkey FOREIGN KEY (machine_id) REFERENCES mv_hot.edge_oee_machines(machine_id);


--
-- Name: edge_oee_energy_demo edge_oee_energy_demo_order_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_energy_demo
    ADD CONSTRAINT edge_oee_energy_demo_order_id_fkey FOREIGN KEY (order_id) REFERENCES mv_hot.edge_oee_orders_demo(order_id);


--
-- Name: edge_oee_events_demo edge_oee_events_demo_machine_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_events_demo
    ADD CONSTRAINT edge_oee_events_demo_machine_id_fkey FOREIGN KEY (machine_id) REFERENCES mv_hot.edge_oee_machines(machine_id);


--
-- Name: edge_oee_events_demo edge_oee_events_demo_order_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_events_demo
    ADD CONSTRAINT edge_oee_events_demo_order_id_fkey FOREIGN KEY (order_id) REFERENCES mv_hot.edge_oee_orders_demo(order_id);


--
-- Name: edge_oee_machine_stops edge_oee_machine_stops_cause_code_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_machine_stops
    ADD CONSTRAINT edge_oee_machine_stops_cause_code_fkey FOREIGN KEY (cause_code) REFERENCES mv_hot.edge_oee_stop_causes(cause_code);


--
-- Name: edge_oee_orders_demo edge_oee_orders_demo_machine_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_orders_demo
    ADD CONSTRAINT edge_oee_orders_demo_machine_id_fkey FOREIGN KEY (machine_id) REFERENCES mv_hot.edge_oee_machines(machine_id);


--
-- Name: edge_oee_quality_cases_demo edge_oee_quality_cases_demo_machine_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_quality_cases_demo
    ADD CONSTRAINT edge_oee_quality_cases_demo_machine_id_fkey FOREIGN KEY (machine_id) REFERENCES mv_hot.edge_oee_machines(machine_id);


--
-- Name: edge_oee_quality_cases_demo edge_oee_quality_cases_demo_order_id_fkey; Type: FK CONSTRAINT; Schema: mv_hot; Owner: mesavault
--

ALTER TABLE ONLY mv_hot.edge_oee_quality_cases_demo
    ADD CONSTRAINT edge_oee_quality_cases_demo_order_id_fkey FOREIGN KEY (order_id) REFERENCES mv_hot.edge_oee_orders_demo(order_id);


--
-- Name: SCHEMA mv_edge_oee_ucepsa_demo; Type: ACL; Schema: -; Owner: mesavault
--

GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_demo TO grafana_ucepsa_ro;
GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_demo TO edge_oee_odoo_sync_writer;
GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_demo TO edge_oee_operator_writer;


--
-- Name: SCHEMA mv_edge_oee_ucepsa_prod; Type: ACL; Schema: -; Owner: mesavault
--

GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_prod TO grafana_ucepsa_ro;
GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_prod TO edge_oee_odoo_sync_writer;


--
-- Name: SCHEMA mv_hot; Type: ACL; Schema: -; Owner: mesavault
--

GRANT USAGE ON SCHEMA mv_hot TO grafana_ucepsa_ro;
GRANT USAGE ON SCHEMA mv_hot TO edge_oee_odoo_sync_writer;
GRANT USAGE ON SCHEMA mv_hot TO edge_oee_operator_writer;


--
-- Name: SCHEMA mv_reports_ucepsa_demo; Type: ACL; Schema: -; Owner: mesavault
--

GRANT USAGE ON SCHEMA mv_reports_ucepsa_demo TO grafana_ucepsa_ro;
GRANT USAGE ON SCHEMA mv_reports_ucepsa_demo TO edge_oee_odoo_sync_writer;
GRANT USAGE ON SCHEMA mv_reports_ucepsa_demo TO edge_oee_operator_writer;


--
-- Name: SCHEMA mv_reports_ucepsa_prod; Type: ACL; Schema: -; Owner: mesavault
--

GRANT USAGE ON SCHEMA mv_reports_ucepsa_prod TO grafana_ucepsa_ro;


--
-- Name: FUNCTION oee_kpis(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text); Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON FUNCTION mv_reports_ucepsa_demo.oee_kpis(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text) TO grafana_ucepsa_ro;


--
-- Name: FUNCTION oee_operational_data(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text); Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON FUNCTION mv_reports_ucepsa_demo.oee_operational_data(p_from timestamp with time zone, p_to timestamp with time zone, p_machine_id text, p_asset text) TO grafana_ucepsa_ro;


--
-- Name: TABLE data_quality_contract_rules; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.data_quality_contract_rules TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.data_quality_contract_rules TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE data_quality_contract_rules_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE edge_oee_eastron_readings; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_readings TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_readings TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_readings TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_eastron_latest; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_latest TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_eastron_dashboard; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_dashboard TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_dashboard TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_dashboard TO edge_oee_operator_writer;


--
-- Name: TABLE eastron_dashboard; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_dashboard TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.eastron_dashboard TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_dashboard TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_eastron_diagnosis_latest; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_diagnosis_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_diagnosis_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_eastron_diagnosis_latest TO edge_oee_operator_writer;


--
-- Name: TABLE eastron_diagnosis_latest; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_diagnosis_latest TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.eastron_diagnosis_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_diagnosis_latest TO edge_oee_operator_writer;


--
-- Name: TABLE eastron_latest; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_latest TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.eastron_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_latest TO edge_oee_operator_writer;


--
-- Name: TABLE eastron_readings; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_readings TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.eastron_readings TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.eastron_readings TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_live_telemetry; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_live_telemetry TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_live_telemetry TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_live_telemetry TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_latest_machine_snapshot; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_latest_machine_snapshot TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_latest_machine_snapshot TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_latest_machine_snapshot TO edge_oee_operator_writer;


--
-- Name: TABLE latest_machine_snapshot; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.latest_machine_snapshot TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.latest_machine_snapshot TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.latest_machine_snapshot TO edge_oee_operator_writer;


--
-- Name: TABLE live_telemetry; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.live_telemetry TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.live_telemetry TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.live_telemetry TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_node_events; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_node_events TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_node_events TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_node_events TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_machine_state_latest; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_machine_state_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_state_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_state_latest TO edge_oee_operator_writer;


--
-- Name: TABLE machine_state_latest; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_state_latest TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.machine_state_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_state_latest TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_machine_stops; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_machine_stops TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_stops TO edge_oee_odoo_sync_writer;
GRANT SELECT,UPDATE ON TABLE mv_hot.edge_oee_machine_stops TO edge_oee_operator_writer;


--
-- Name: TABLE machine_stops; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_stops TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.machine_stops TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_stops TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_machine_targets; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_machine_targets TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_targets TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_targets TO edge_oee_operator_writer;


--
-- Name: TABLE machine_targets; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_targets TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.machine_targets TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.machine_targets TO edge_oee_operator_writer;


--
-- Name: TABLE margin_cost_parameters; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.margin_cost_parameters TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.margin_cost_parameters TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE margin_cost_parameters_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.margin_cost_parameters_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE node_events; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.node_events TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.node_events TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.node_events TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_node_events_recent; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_node_events_recent TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_node_events_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_node_events_recent TO edge_oee_operator_writer;


--
-- Name: TABLE node_events_recent; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.node_events_recent TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.node_events_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.node_events_recent TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_order_commercials; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.odoo_order_commercials TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.odoo_order_commercials TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE odoo_order_commercials_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.odoo_order_commercials_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE odoo_workcenter_map; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.odoo_workcenter_map TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.odoo_workcenter_map TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.odoo_workcenter_map TO edge_oee_operator_writer;


--
-- Name: SEQUENCE odoo_workcenter_map_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workcenter_map_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE odoo_workorders_demo; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.odoo_workorders_demo TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.odoo_workorders_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.odoo_workorders_demo TO edge_oee_operator_writer;


--
-- Name: SEQUENCE odoo_workorders_demo_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.odoo_workorders_demo_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE edge_oee_stop_causes; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_stop_causes TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_causes TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_causes TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_open_stops; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_open_stops TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_open_stops TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_open_stops TO edge_oee_operator_writer;


--
-- Name: TABLE open_stops; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.open_stops TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.open_stops TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.open_stops TO edge_oee_operator_writer;


--
-- Name: TABLE raw_material_cost_parameters; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE raw_material_cost_parameters_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_demo.raw_material_cost_parameters_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE edge_oee_stop_cause_options; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_stop_cause_options TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_cause_options TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_cause_options TO edge_oee_operator_writer;


--
-- Name: TABLE stop_cause_options; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_cause_options TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.stop_cause_options TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_cause_options TO edge_oee_operator_writer;


--
-- Name: TABLE stop_causes; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_causes TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.stop_causes TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_causes TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_stop_summary_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_stop_summary_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_summary_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_stop_summary_demo TO edge_oee_operator_writer;


--
-- Name: TABLE stop_summary; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_summary TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.stop_summary TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stop_summary TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_stops_recent; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_stops_recent TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_stops_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_stops_recent TO edge_oee_operator_writer;


--
-- Name: TABLE stops_recent; Type: ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stops_recent TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_demo.stops_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_edge_oee_ucepsa_demo.stops_recent TO edge_oee_operator_writer;


--
-- Name: TABLE data_quality_contract_rules; Type: ACL; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_prod.data_quality_contract_rules TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_prod.data_quality_contract_rules TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE margin_cost_parameters; Type: ACL; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_prod.margin_cost_parameters TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_prod.margin_cost_parameters TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE odoo_order_commercials; Type: ACL; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_prod.odoo_order_commercials TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_prod.odoo_order_commercials TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE odoo_order_commercials_id_seq; Type: ACL; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_edge_oee_ucepsa_prod.odoo_order_commercials_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE raw_material_cost_parameters; Type: ACL; Schema: mv_edge_oee_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters TO grafana_ucepsa_ro;
GRANT SELECT,INSERT,DELETE,UPDATE ON TABLE mv_edge_oee_ucepsa_prod.raw_material_cost_parameters TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE edge_oee_loss_summary_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_loss_summary_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_loss_summary_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_loss_summary_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_actions_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_actions_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_actions_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_actions_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_data_quality_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_data_quality_dashboard_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_dashboard_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_dashboard_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_data_quality_dashboard_demo TO edge_oee_operator_writer;


--
-- Name: SEQUENCE edge_oee_eastron_readings_id_seq; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_hot.edge_oee_eastron_readings_id_seq TO edge_oee_odoo_sync_writer;
GRANT ALL ON SEQUENCE mv_hot.edge_oee_eastron_readings_id_seq TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_energy_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_energy_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_energy_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_energy_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_events_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_events_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_events_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_events_demo TO edge_oee_operator_writer;


--
-- Name: SEQUENCE edge_oee_events_demo_event_id_seq; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_hot.edge_oee_events_demo_event_id_seq TO edge_oee_odoo_sync_writer;
GRANT ALL ON SEQUENCE mv_hot.edge_oee_events_demo_event_id_seq TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_executive_summary_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_executive_summary_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_executive_summary_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_executive_summary_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_kpi_cards_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_kpi_cards_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_kpi_cards_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_kpi_cards_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_machine_stops_backup_cort00_20260622_175800; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_machine_stops_backup_cort00_20260622_175800 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_machine_stops_backup_cort00_20260622_175800 TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE edge_oee_machine_stops_id_seq; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_hot.edge_oee_machine_stops_id_seq TO edge_oee_odoo_sync_writer;
GRANT ALL ON SEQUENCE mv_hot.edge_oee_machine_stops_id_seq TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_machines; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_machines TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_machines TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_machines TO edge_oee_operator_writer;


--
-- Name: SEQUENCE edge_oee_node_events_id_seq; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_hot.edge_oee_node_events_id_seq TO edge_oee_odoo_sync_writer;
GRANT ALL ON SEQUENCE mv_hot.edge_oee_node_events_id_seq TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_orders_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_orders_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_orders_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_orders_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_order_timeline_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_order_timeline_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_order_timeline_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_order_timeline_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_pareto_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_pareto_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_pareto_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_pareto_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_quality_cases_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_quality_cases_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_quality_cases_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_quality_cases_demo TO edge_oee_operator_writer;


--
-- Name: TABLE edge_oee_quality_case_demo; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.edge_oee_quality_case_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.edge_oee_quality_case_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_hot.edge_oee_quality_case_demo TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_order_state_current; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.odoo_order_state_current TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.odoo_order_state_current TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE odoo_order_state_events; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT SELECT ON TABLE mv_hot.odoo_order_state_events TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_hot.odoo_order_state_events TO edge_oee_odoo_sync_writer;


--
-- Name: SEQUENCE odoo_order_state_events_id_seq; Type: ACL; Schema: mv_hot; Owner: mesavault
--

GRANT ALL ON SEQUENCE mv_hot.odoo_order_state_events_id_seq TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_report_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_report_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_report_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_energy_timeseries_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_data_quality_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_data_quality_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_data_quality_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_stops_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_stops_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_stops_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_stop_causes_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_stop_causes_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_stop_causes_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_timeline_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_timeline_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_timeline_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_execution_report_full_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_report_full_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_execution_report_full_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_raw_material_costs_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_raw_material_costs_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_raw_material_costs_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_raw_material_costs_summary_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_raw_material_costs_summary_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_raw_material_costs_summary_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE order_margin_report_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_margin_report_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.order_margin_report_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE cost_readiness_orders_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_orders_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_orders_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE cost_readiness_raw_materials_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_raw_materials_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_raw_materials_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE cost_readiness_summary_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_summary_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cost_readiness_summary_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE cycle_rate_timeseries; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cycle_rate_timeseries TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cycle_rate_timeseries TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.cycle_rate_timeseries TO edge_oee_operator_writer;


--
-- Name: TABLE data_quality_contract_order_checks_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE data_quality_contract_order_summary_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE data_quality_contract_owner_summary_v1; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1 TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1 TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE energy_3phase_timeseries; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_3phase_timeseries TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_3phase_timeseries TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE energy_3phase_latest; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_3phase_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_3phase_latest TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE energy_diagnosis; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_diagnosis TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_diagnosis TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_diagnosis TO edge_oee_operator_writer;


--
-- Name: TABLE energy_import_timeseries; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_import_timeseries TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_import_timeseries TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_import_timeseries TO edge_oee_operator_writer;


--
-- Name: TABLE energy_latest; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_latest TO edge_oee_operator_writer;


--
-- Name: TABLE energy_power_timeseries; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_power_timeseries TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_power_timeseries TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.energy_power_timeseries TO edge_oee_operator_writer;


--
-- Name: TABLE latest_machine_snapshot; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_snapshot TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_snapshot TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_snapshot TO edge_oee_operator_writer;


--
-- Name: TABLE latest_machine_state_fast; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_state_fast TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_state_fast TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.latest_machine_state_fast TO edge_oee_operator_writer;


--
-- Name: TABLE live_telemetry; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.live_telemetry TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.live_telemetry TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.live_telemetry TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_current_order_demo; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_current_order_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_current_order_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_current_order_demo TO edge_oee_operator_writer;


--
-- Name: TABLE stops_recent; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stops_recent TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stops_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stops_recent TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_vs_machine_demo; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_vs_machine_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_vs_machine_demo TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE open_stops; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.open_stops TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.open_stops TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.open_stops TO edge_oee_operator_writer;


--
-- Name: TABLE loss_events_current; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.loss_events_current TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.loss_events_current TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE loss_priority_board; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.loss_priority_board TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.loss_priority_board TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE machine_state_latest; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_state_latest TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_state_latest TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_state_latest TO edge_oee_operator_writer;


--
-- Name: TABLE machine_state_latest_multi; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_state_latest_multi TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_state_latest_multi TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE machine_stops_grafana; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_stops_grafana TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_stops_grafana TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE machine_targets; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_targets TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_targets TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.machine_targets TO edge_oee_operator_writer;


--
-- Name: TABLE node_events_recent; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.node_events_recent TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.node_events_recent TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.node_events_recent TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_discrepancies_demo; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_discrepancies_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_discrepancies_demo TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE odoo_workorders_reality_history; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_workorders_reality_history TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_workorders_reality_history TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_workorders_reality_history TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_last_finished_order_demo; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_last_finished_order_demo TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_last_finished_order_demo TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_last_finished_order_demo TO edge_oee_operator_writer;


--
-- Name: TABLE odoo_order_state_machine_grafana; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_order_state_machine_grafana TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.odoo_order_state_machine_grafana TO edge_oee_odoo_sync_writer;


--
-- Name: TABLE stop_summary; Type: ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stop_summary TO grafana_ucepsa_ro;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stop_summary TO edge_oee_odoo_sync_writer;
GRANT SELECT ON TABLE mv_reports_ucepsa_demo.stop_summary TO edge_oee_operator_writer;


--
-- Name: TABLE current_order_margin_readiness_v1; Type: ACL; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_prod.current_order_margin_readiness_v1 TO grafana_ucepsa_ro;


--
-- Name: TABLE order_raw_material_costs_v1; Type: ACL; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_prod.order_raw_material_costs_v1 TO grafana_ucepsa_ro;


--
-- Name: TABLE order_raw_material_costs_summary_v1; Type: ACL; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_prod.order_raw_material_costs_summary_v1 TO grafana_ucepsa_ro;


--
-- Name: TABLE raw_material_cost_requirements_v1; Type: ACL; Schema: mv_reports_ucepsa_prod; Owner: mesavault
--

GRANT SELECT ON TABLE mv_reports_ucepsa_prod.raw_material_cost_requirements_v1 TO grafana_ucepsa_ro;


--
-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_edge_oee_ucepsa_demo GRANT ALL ON SEQUENCES TO edge_oee_odoo_sync_writer;


--
-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: mv_edge_oee_ucepsa_demo; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_edge_oee_ucepsa_demo GRANT SELECT ON TABLES TO grafana_ucepsa_ro;
ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_edge_oee_ucepsa_demo GRANT SELECT,INSERT,DELETE,UPDATE ON TABLES TO edge_oee_odoo_sync_writer;


--
-- Name: DEFAULT PRIVILEGES FOR SEQUENCES; Type: DEFAULT ACL; Schema: mv_hot; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_hot GRANT ALL ON SEQUENCES TO edge_oee_odoo_sync_writer;


--
-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: mv_hot; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_hot GRANT SELECT ON TABLES TO grafana_ucepsa_ro;
ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_hot GRANT SELECT ON TABLES TO edge_oee_odoo_sync_writer;


--
-- Name: DEFAULT PRIVILEGES FOR FUNCTIONS; Type: DEFAULT ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_reports_ucepsa_demo GRANT ALL ON FUNCTIONS TO grafana_ucepsa_ro;


--
-- Name: DEFAULT PRIVILEGES FOR TABLES; Type: DEFAULT ACL; Schema: mv_reports_ucepsa_demo; Owner: mesavault
--

ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_reports_ucepsa_demo GRANT SELECT ON TABLES TO grafana_ucepsa_ro;
ALTER DEFAULT PRIVILEGES FOR ROLE mesavault IN SCHEMA mv_reports_ucepsa_demo GRANT SELECT ON TABLES TO edge_oee_odoo_sync_writer;


--
-- PostgreSQL database dump complete
--

\unrestrict 1wX0I2K6nLSszbhqDMaBaJRF13jG1hT3a3HKImFGiykK1wx4riB6Rf5OY4lcf06

