40-clients/ucepsa/edge-oee-demo/sql/060_odoo_shadow_layer_demo.sql

266 lines
6.9 KiB
SQL

CREATE TABLE IF NOT EXISTS mv_edge_oee_ucepsa_demo.odoo_workorders_demo (
id BIGSERIAL PRIMARY KEY,
tenant TEXT NOT NULL DEFAULT 'ucepsa',
site TEXT NOT NULL DEFAULT 'demo_edge_oee',
odoo_instance TEXT NOT NULL DEFAULT 'odoo_demo',
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 TIMESTAMPTZ NOT NULL,
odoo_end TIMESTAMPTZ,
notes TEXT,
snapshot_at TIMESTAMPTZ NOT NULL DEFAULT now()
);
CREATE INDEX IF NOT EXISTS idx_odoo_workorders_demo_machine_time
ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo(machine_id, odoo_start DESC);
CREATE INDEX IF NOT EXISTS idx_odoo_workorders_demo_state
ON mv_edge_oee_ucepsa_demo.odoo_workorders_demo(odoo_state);
DELETE FROM mv_edge_oee_ucepsa_demo.odoo_workorders_demo
WHERE tenant = 'ucepsa'
AND site = 'demo_edge_oee'
AND odoo_instance = 'odoo_demo';
INSERT INTO mv_edge_oee_ucepsa_demo.odoo_workorders_demo (
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,
notes
)
VALUES
(
'OF-DEMO-001',
'in_progress',
'CORT-01',
'Cortadora 01',
'CORT-01',
'revpi_oee_node_01',
'Bolsa 300x400',
50000,
0,
'unidades',
500,
10,
now() - interval '20 minutes',
now() + interval '40 minutes',
'Orden demo activa para cruce Odoo vs máquina.'
),
(
'OF-DEMO-002',
'planned',
'CORT-01',
'Cortadora 01',
'CORT-01',
'revpi_oee_node_01',
'Bolsa 250x350',
42000,
0,
'unidades',
420,
10,
now() + interval '60 minutes',
now() + interval '120 minutes',
'Orden demo planificada.'
),
(
'OF-DEMO-000',
'done',
'CORT-01',
'Cortadora 01',
'CORT-01',
'revpi_oee_node_01',
'Bolsa 300x400',
52000,
51000,
'unidades',
520,
10,
now() - interval '3 hours',
now() - interval '2 hours',
'Orden demo ya cerrada.'
);
CREATE OR REPLACE VIEW mv_reports_ucepsa_demo.odoo_current_order_demo AS
SELECT
o.id,
o.tenant,
o.site,
o.odoo_instance,
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.notes,
o.snapshot_at
FROM mv_edge_oee_ucepsa_demo.odoo_workorders_demo o
WHERE o.machine_id = 'CORT-01'
AND o.odoo_state IN ('in_progress', 'progress', 'started')
ORDER BY o.odoo_start DESC
LIMIT 1;
CREATE OR REPLACE VIEW mv_reports_ucepsa_demo.odoo_vs_machine_demo AS
WITH current_order AS (
SELECT *
FROM mv_reports_ucepsa_demo.odoo_current_order_demo
),
machine AS (
SELECT *
FROM mv_reports_ucepsa_demo.latest_machine_state_fast
),
first_real_activity AS (
SELECT
MIN(l.ingest_ts) AS first_machine_activity
FROM mv_reports_ucepsa_demo.live_telemetry l
CROSS JOIN current_order o
WHERE l.asset = o.asset
AND l.ingest_ts >= o.odoo_start
AND (
l.machine_running = true
OR COALESCE(l.cycle_pulse_count, 0) > 0
)
),
stops_in_order AS (
SELECT
COUNT(*) AS stop_count,
ROUND(COALESCE(SUM(s.duration_min), 0)::numeric, 2) AS stop_min,
ROUND(COALESCE(SUM(s.cost_eur), 0)::numeric, 2) AS stop_cost_eur
FROM mv_reports_ucepsa_demo.stops_recent s
CROSS JOIN current_order o
WHERE s.machine_id = o.machine_id
AND s.started_at >= o.odoo_start
AND s.started_at <= COALESCE(o.odoo_end, now())
),
cycles_in_order AS (
SELECT
COALESCE(
GREATEST(MAX(l.cycle_pulse_count) - MIN(l.cycle_pulse_count), 0),
0
)::numeric AS real_cycles
FROM mv_reports_ucepsa_demo.live_telemetry l
CROSS JOIN current_order o
WHERE l.asset = o.asset
AND l.ingest_ts >= o.odoo_start
AND l.ingest_ts <= COALESCE(o.odoo_end, now())
AND l.cycle_pulse_count IS NOT NULL
)
SELECT
o.odoo_order_ref,
o.odoo_state,
o.product,
o.machine_id,
o.asset,
o.odoo_start,
o.odoo_end,
m.machine_running,
m.age_s AS telemetry_age_s,
m.cycle_pulse_count,
m.cycle_rate_ppm,
f.first_machine_activity,
CASE
WHEN f.first_machine_activity IS NULL THEN NULL
ELSE ROUND((EXTRACT(EPOCH FROM (f.first_machine_activity - o.odoo_start)) / 60.0)::numeric, 2)
END AS start_delay_min,
s.stop_count,
s.stop_min,
s.stop_cost_eur,
c.real_cycles,
o.planned_cycles,
CASE
WHEN o.planned_cycles > 0
THEN ROUND(((c.real_cycles / o.planned_cycles) * 100)::numeric, 2)
ELSE NULL
END AS cycle_completion_pct,
CASE
WHEN m.age_s > 30 THEN 'SIN_TELEMETRIA'
WHEN o.odoo_state IN ('in_progress', 'progress', 'started') AND m.machine_running = false THEN 'ORDEN_ACTIVA_MAQUINA_PARADA'
WHEN o.odoo_state IN ('in_progress', 'progress', 'started') AND f.first_machine_activity IS NULL THEN 'ORDEN_ACTIVA_SIN_ACTIVIDAD_REAL'
WHEN f.first_machine_activity IS NOT NULL
AND EXTRACT(EPOCH FROM (f.first_machine_activity - o.odoo_start)) > 600 THEN 'ARRANQUE_REAL_TARDIO'
ELSE 'OK'
END AS status_check
FROM current_order o
LEFT JOIN machine m ON m.asset = o.asset
LEFT JOIN first_real_activity f ON true
LEFT JOIN stops_in_order s ON true
LEFT JOIN cycles_in_order c ON true;
CREATE OR REPLACE 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 = 'SIN_TELEMETRIA' THEN 'No hay telemetría reciente de la RevPi.'
WHEN status_check = 'ORDEN_ACTIVA_MAQUINA_PARADA' THEN 'Odoo tiene una orden activa, pero la máquina aparece parada.'
WHEN status_check = 'ORDEN_ACTIVA_SIN_ACTIVIDAD_REAL' THEN 'Odoo tiene una orden activa, pero no se detecta actividad real de máquina.'
WHEN status_check = 'ARRANQUE_REAL_TARDIO' THEN 'La primera actividad real de máquina llega más de 10 minutos después del inicio Odoo.'
ELSE 'Sin discrepancia relevante.'
END AS descripcion,
start_delay_min,
stop_count,
stop_min,
stop_cost_eur,
cycle_completion_pct
FROM mv_reports_ucepsa_demo.odoo_vs_machine_demo;
GRANT SELECT ON
mv_edge_oee_ucepsa_demo.odoo_workorders_demo,
mv_reports_ucepsa_demo.odoo_current_order_demo,
mv_reports_ucepsa_demo.odoo_vs_machine_demo,
mv_reports_ucepsa_demo.odoo_discrepancies_demo
TO grafana_ucepsa_ro;