-- MESAVAULT Edge-OEE UCEPSA -- Data Quality Contract Odoo-MESAVAULT -- Schema + seed rules. -- No secrets. DROP VIEW IF EXISTS mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1; DROP VIEW IF EXISTS mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1; DROP VIEW IF EXISTS mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1; DROP TABLE IF EXISTS mv_edge_oee_ucepsa_demo.data_quality_contract_rules; -- -- PostgreSQL database dump -- \restrict Jszr4ruwRiCXF4itba8oT9UnTRsL1bJGSsYnj9UgpfOpaiQUSblgKdozAITLZdr -- 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; SET default_tablespace = ''; SET default_table_access_method = heap; -- -- Name: data_quality_contract_rules; Type: TABLE; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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 ); -- -- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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; -- -- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE OWNED BY; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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: data_quality_contract_order_checks_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: - -- 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(order_raw_material_costs_v1.raw_product_default_code, 'sin_codigo'::text), ' - ', COALESCE(order_raw_material_costs_v1.raw_product_name, 'sin_nombre'::text)), '; '::text ORDER BY (concat(COALESCE(order_raw_material_costs_v1.raw_product_default_code, '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)))); -- -- Name: data_quality_contract_order_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: - -- 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))); -- -- Name: data_quality_contract_owner_summary_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: - -- 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; -- -- Name: data_quality_contract_rules id; Type: DEFAULT; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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: data_quality_contract_rules data_quality_contract_rules_pkey; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- ALTER TABLE ONLY mv_edge_oee_ucepsa_demo.data_quality_contract_rules ADD CONSTRAINT data_quality_contract_rules_pkey PRIMARY KEY (id); -- -- Name: data_quality_contract_rules ux_data_quality_contract_rules_code; Type: CONSTRAINT; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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: idx_data_quality_contract_rules_active; Type: INDEX; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- 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); -- -- PostgreSQL database dump complete -- \unrestrict Jszr4ruwRiCXF4itba8oT9UnTRsL1bJGSsYnj9UgpfOpaiQUSblgKdozAITLZdr -- Seed rules -- -- PostgreSQL database dump -- \restrict 0GULSAN6PrEX9eK1oI9gTcg4MdETx9P93tGMaONyYc1oC6UFbi5FCS1yjEVkVNx -- 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; -- -- Data for Name: data_quality_contract_rules; Type: TABLE DATA; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (1, 'ucepsa', 'ucepsa_test', 'DQC-ODOO-001', 'Orden de fabricación identificada', 'ODOO', 'COMPLETENESS', 'CRITICAL', 'Odoo / Producción', 'Manufacturing Order', 'La orden debe tener referencia de fabricación e identificador de producción Odoo.', 'odoo_order_ref y odoo_production_id deben existir.', 'order_report', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (2, 'ucepsa', 'ucepsa_test', 'DQC-ODOO-002', 'Centro de trabajo mapeado a máquina MESAVAULT', 'ODOO', 'TRACEABILITY', 'CRITICAL', 'Odoo / MESAVAULT', 'Workcenter / Machine', 'El centro de trabajo de Odoo debe estar asociado a un machine_id MESAVAULT.', 'machine_id debe existir y estar mapeado.', 'edge_oee_report', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (3, 'ucepsa', 'ucepsa_test', 'DQC-ODOO-003', 'Producto identificado', 'ODOO', 'COMPLETENESS', 'HIGH', 'Odoo / Maestro de producto', 'Product', 'El producto debe estar identificado con nombre y, cuando aplique, código interno.', 'product_name o product deben existir; product_default_code recomendable.', 'product_margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (4, 'ucepsa', 'ucepsa_test', 'DQC-SALES-001', 'Ingreso de venta vinculado', 'SALES', 'TRACEABILITY', 'CRITICAL', 'Ventas / Odoo', 'Sale Order', 'La orden debe estar vinculada a una línea de venta para poder calcular margen.', 'sale_order_ref y revenue_net_eur deben existir.', 'margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (5, 'ucepsa', 'ucepsa_test', 'DQC-SALES-002', 'Cliente vinculado', 'SALES', 'COMPLETENESS', 'HIGH', 'Ventas / Odoo', 'Customer', 'La orden debe tener cliente asociado cuando exista pedido de venta.', 'customer_name debe existir si hay sale_order_ref.', 'customer_margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (6, 'ucepsa', 'ucepsa_test', 'DQC-RAW-001', 'Materia prima consumida detectada', 'MATERIAL', 'TRACEABILITY', 'CRITICAL', 'Producción / Almacén / Odoo', 'Raw Material', 'La orden debe tener materia prima consumida o movimiento de material asociado.', 'raw_material_line_count debe ser mayor que cero.', 'material_cost', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (7, 'ucepsa', 'ucepsa_test', 'DQC-RAW-002', 'Materia prima con código identificable', 'MATERIAL', 'COMPLETENESS', 'HIGH', 'Maestro de producto / Odoo', 'Raw Material', 'La materia prima debe tener código interno para poder asignar costes y analizar histórico.', 'raw_product_default_code debe existir.', 'material_cost', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (8, 'ucepsa', 'ucepsa_test', 'DQC-COST-001', 'Coste de materia prima disponible', 'COST', 'COMPLETENESS', 'CRITICAL', 'Compras / Administración / Odoo', 'Raw Material Cost', 'La materia prima debe tener coste €/kg o valoración Odoo para calcular margen.', 'material_cost_estimated_eur debe existir o la materia prima debe tener coste parametrizado.', 'margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (9, 'ucepsa', 'ucepsa_test', 'DQC-COST-002', 'Coste energético parametrizado', 'COST', 'COMPLETENESS', 'MEDIUM', 'Administración / MESAVAULT', 'Energy Cost', 'Si se usa energía en el margen, debe existir coste €/kWh.', 'energy_cost_eur_per_kwh debe existir cuando kwh_consumed exista.', 'full_margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (10, 'ucepsa', 'ucepsa_test', 'DQC-COST-003', 'Coste hora máquina parametrizado', 'COST', 'COMPLETENESS', 'MEDIUM', 'Producción / Administración / MESAVAULT', 'Machine Cost', 'Si se imputa coste de máquina, debe existir coste horario para la máquina.', 'machine_run_cost_eur_per_h debe existir cuando run_min exista.', 'full_margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (11, 'ucepsa', 'ucepsa_test', 'DQC-EDGE-001', 'Datos técnicos defendibles', 'EDGE', 'QUALITY', 'CRITICAL', 'MESAVAULT / Producción', 'Telemetry', 'La orden debe tener datos técnicos suficientes para un informe defendible.', 'technical_quality_level debe ser FIABLE o ACEPTABLE_CON_OBSERVACIONES.', 'technical_report', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (12, 'ucepsa', 'ucepsa_test', 'DQC-EDGE-002', 'Informe técnico cerrado o utilizable', 'EDGE', 'TIMELINESS', 'HIGH', 'MESAVAULT / Producción', 'Order Execution Report', 'La orden debe tener informe técnico cerrado o utilizable antes de análisis económico final.', 'final_report_status debe estar en estado listo o con observaciones.', 'margin', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (13, 'ucepsa', 'ucepsa_test', 'DQC-STOPS-001', 'Paros clasificados', 'LOSSES', 'COMPLETENESS', 'HIGH', 'Producción', 'Stops', 'Los paros imputados a una orden deben estar clasificados para explicar pérdidas.', 'pending_stops debe ser cero.', 'loss_analysis', true, '2026-05-30 20:18:18.616748+02'); INSERT INTO mv_edge_oee_ucepsa_demo.data_quality_contract_rules (id, tenant, site, rule_code, rule_name, domain, dimension, severity, owner_area, applies_to, description, expected_condition, blocking_for, is_active, created_at) VALUES (14, 'ucepsa', 'ucepsa_test', 'DQC-CONV-001', 'Conversión producción-ciclos revisada', 'PRODUCTION', 'CONSISTENCY', 'MEDIUM', 'Odoo / Producción / MESAVAULT', 'Production Conversion', 'La relación entre cantidad Odoo, kg, bolsas y ciclos debe estar validada antes de usar métricas unitarias.', 'production_conversion_status debe ser coherente o marcado como pendiente.', 'unit_margin', true, '2026-05-30 20:18:18.616748+02'); -- -- Name: data_quality_contract_rules_id_seq; Type: SEQUENCE SET; Schema: mv_edge_oee_ucepsa_demo; Owner: - -- SELECT pg_catalog.setval('mv_edge_oee_ucepsa_demo.data_quality_contract_rules_id_seq', 14, true); -- -- PostgreSQL database dump complete -- \unrestrict 0GULSAN6PrEX9eK1oI9gTcg4MdETx9P93tGMaONyYc1oC6UFbi5FCS1yjEVkVNx -- Read-only grants GRANT USAGE ON SCHEMA mv_edge_oee_ucepsa_demo TO grafana_ucepsa_ro; GRANT USAGE ON SCHEMA mv_reports_ucepsa_demo TO grafana_ucepsa_ro; GRANT SELECT ON mv_edge_oee_ucepsa_demo.data_quality_contract_rules TO grafana_ucepsa_ro; GRANT SELECT ON mv_reports_ucepsa_demo.data_quality_contract_order_checks_v1 TO grafana_ucepsa_ro; GRANT SELECT ON mv_reports_ucepsa_demo.data_quality_contract_order_summary_v1 TO grafana_ucepsa_ro; GRANT SELECT ON mv_reports_ucepsa_demo.data_quality_contract_owner_summary_v1 TO grafana_ucepsa_ro;