Add UCEPSA order execution report SQL views
This commit is contained in:
parent
90a0da730b
commit
0ed753587b
@ -0,0 +1,885 @@
|
||||
-- MESAVAULT Edge-OEE UCEPSA
|
||||
-- Order execution report views
|
||||
-- Generated from validated PostgreSQL views.
|
||||
-- Contains no data and no secrets.
|
||||
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_report_full_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_data_quality_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_timeline_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_stop_causes_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_stops_v1;
|
||||
DROP VIEW IF EXISTS mv_reports_ucepsa_demo.order_execution_report_v1;
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump
|
||||
--
|
||||
|
||||
\restrict YbA0VcRIrZ1kSDSxIf4zctoL9eu8TYoJ5cvkbSD5WkFTQ1jRyH26snWSZehz5VJ
|
||||
|
||||
-- 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: order_execution_report_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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)));
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_energy_timeseries_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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;
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_data_quality_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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;
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_stops_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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));
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_stop_causes_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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;
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_timeline_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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);
|
||||
|
||||
|
||||
--
|
||||
-- Name: order_execution_report_full_v1; Type: VIEW; Schema: mv_reports_ucepsa_demo; Owner: -
|
||||
--
|
||||
|
||||
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)));
|
||||
|
||||
|
||||
--
|
||||
-- PostgreSQL database dump complete
|
||||
--
|
||||
|
||||
\unrestrict YbA0VcRIrZ1kSDSxIf4zctoL9eu8TYoJ5cvkbSD5WkFTQ1jRyH26snWSZehz5VJ
|
||||
|
||||
|
||||
GRANT USAGE ON SCHEMA mv_reports_ucepsa_demo TO grafana_ucepsa_ro;
|
||||
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_report_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_stops_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_stop_causes_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_timeline_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_energy_timeseries_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_data_quality_v1 TO grafana_ucepsa_ro;
|
||||
GRANT SELECT ON mv_reports_ucepsa_demo.order_execution_report_full_v1 TO grafana_ucepsa_ro;
|
||||
Loading…
x
Reference in New Issue
Block a user