266 lines
6.9 KiB
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;
|
|
|
|
|