157 lines
5.5 KiB
SQL
157 lines
5.5 KiB
SQL
CREATE SCHEMA IF NOT EXISTS mv_hot;
|
|
|
|
CREATE TABLE IF NOT EXISTS mv_hot.edge_oee_stop_causes (
|
|
cause_code TEXT PRIMARY KEY,
|
|
cause_name TEXT NOT NULL,
|
|
description TEXT,
|
|
is_planned BOOLEAN NOT NULL DEFAULT false,
|
|
is_active BOOLEAN NOT NULL DEFAULT true,
|
|
sort_order INT NOT NULL DEFAULT 100
|
|
);
|
|
|
|
INSERT INTO mv_hot.edge_oee_stop_causes
|
|
(cause_code, cause_name, description, is_planned, sort_order)
|
|
VALUES
|
|
('cambio_bobina', 'Cambio de bobina', 'Paro por cambio de bobina o material.', false, 10),
|
|
('fallo_empalme', 'Fallo en empalme', 'Paro por fallo o ajuste en empalme de material.', false, 20),
|
|
('ajuste_sellado', 'Ajuste de sellado', 'Paro por ajuste de mordazas, temperatura, presión o teflón.', false, 30),
|
|
('falta_material', 'Falta de material', 'Paro por ausencia de bobina, material no preparado o espera logística.', false, 40),
|
|
('limpieza_fotocelula', 'Limpieza fotocélula', 'Paro por limpieza o ajuste de sensor/fotocélula.', false, 50),
|
|
('cambio_formato', 'Cambio de formato', 'Paro por cambio de medidas, producto o configuración.', false, 60),
|
|
('averia_mecanica', 'Avería mecánica', 'Paro por fallo mecánico de la máquina.', false, 70),
|
|
('espera_instrucciones', 'Espera de instrucciones', 'Paro por falta de definición, autorización o instrucción.', false, 80),
|
|
('pausa_cafe', 'Pausa café', 'Pausa del operario o descanso.', true, 90),
|
|
('otro', 'Otro', 'Causa no clasificada en el catálogo principal.', false, 999)
|
|
ON CONFLICT (cause_code) DO UPDATE SET
|
|
cause_name = EXCLUDED.cause_name,
|
|
description = EXCLUDED.description,
|
|
is_planned = EXCLUDED.is_planned,
|
|
sort_order = EXCLUDED.sort_order;
|
|
|
|
CREATE TABLE IF NOT EXISTS mv_hot.edge_oee_machine_stops (
|
|
id BIGSERIAL PRIMARY KEY,
|
|
|
|
tenant TEXT NOT NULL,
|
|
site TEXT NOT NULL,
|
|
vertical TEXT NOT NULL,
|
|
asset TEXT NOT NULL,
|
|
|
|
machine_id TEXT,
|
|
order_id TEXT,
|
|
|
|
started_at TIMESTAMPTZ NOT NULL,
|
|
ended_at TIMESTAMPTZ,
|
|
|
|
status TEXT NOT NULL DEFAULT 'OPEN',
|
|
classification_status TEXT NOT NULL DEFAULT 'PENDING',
|
|
|
|
cause_code TEXT REFERENCES mv_hot.edge_oee_stop_causes(cause_code),
|
|
operator_note TEXT,
|
|
|
|
value_hour_eur NUMERIC(10,2) NOT NULL DEFAULT 36.00,
|
|
duration_s NUMERIC(14,2),
|
|
cost_eur NUMERIC(14,2),
|
|
|
|
start_event_name TEXT,
|
|
end_event_name TEXT,
|
|
|
|
start_payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
end_payload_json JSONB NOT NULL DEFAULT '{}'::jsonb,
|
|
|
|
created_at TIMESTAMPTZ NOT NULL DEFAULT now(),
|
|
updated_at TIMESTAMPTZ NOT NULL DEFAULT now()
|
|
);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_edge_oee_machine_stops_asset_status
|
|
ON mv_hot.edge_oee_machine_stops(asset, status);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_edge_oee_machine_stops_started_at
|
|
ON mv_hot.edge_oee_machine_stops(started_at DESC);
|
|
|
|
CREATE INDEX IF NOT EXISTS idx_edge_oee_machine_stops_machine_started
|
|
ON mv_hot.edge_oee_machine_stops(machine_id, started_at DESC);
|
|
|
|
CREATE OR REPLACE VIEW mv_hot.edge_oee_open_stops AS
|
|
SELECT
|
|
s.id,
|
|
s.tenant,
|
|
s.site,
|
|
s.vertical,
|
|
s.asset,
|
|
s.machine_id,
|
|
s.order_id,
|
|
s.started_at,
|
|
EXTRACT(EPOCH FROM (now() - s.started_at))::numeric(14,2) AS current_duration_s,
|
|
ROUND((EXTRACT(EPOCH FROM (now() - s.started_at)) / 60.0)::numeric, 2) AS current_duration_min,
|
|
ROUND(((EXTRACT(EPOCH FROM (now() - s.started_at)) / 3600.0) * s.value_hour_eur)::numeric, 2) AS current_cost_eur,
|
|
s.status,
|
|
s.classification_status,
|
|
s.cause_code,
|
|
c.cause_name,
|
|
s.operator_note,
|
|
s.value_hour_eur
|
|
FROM mv_hot.edge_oee_machine_stops s
|
|
LEFT JOIN mv_hot.edge_oee_stop_causes c ON c.cause_code = s.cause_code
|
|
WHERE s.status = 'OPEN'
|
|
ORDER BY s.started_at DESC;
|
|
|
|
CREATE OR REPLACE VIEW mv_hot.edge_oee_stops_recent AS
|
|
SELECT
|
|
s.id,
|
|
s.tenant,
|
|
s.site,
|
|
s.vertical,
|
|
s.asset,
|
|
s.machine_id,
|
|
s.order_id,
|
|
s.started_at,
|
|
s.ended_at,
|
|
COALESCE(
|
|
s.duration_s,
|
|
EXTRACT(EPOCH FROM (now() - s.started_at))::numeric(14,2)
|
|
) AS duration_s,
|
|
ROUND((
|
|
COALESCE(s.duration_s, EXTRACT(EPOCH FROM (now() - s.started_at))::numeric) / 60.0
|
|
)::numeric, 2) AS duration_min,
|
|
COALESCE(
|
|
s.cost_eur,
|
|
ROUND(((EXTRACT(EPOCH FROM (now() - s.started_at)) / 3600.0) * s.value_hour_eur)::numeric, 2)
|
|
) AS cost_eur,
|
|
s.status,
|
|
s.classification_status,
|
|
s.cause_code,
|
|
c.cause_name,
|
|
c.is_planned,
|
|
s.operator_note,
|
|
s.value_hour_eur,
|
|
s.start_event_name,
|
|
s.end_event_name,
|
|
s.created_at,
|
|
s.updated_at
|
|
FROM mv_hot.edge_oee_machine_stops s
|
|
LEFT JOIN mv_hot.edge_oee_stop_causes c ON c.cause_code = s.cause_code
|
|
ORDER BY s.started_at DESC;
|
|
|
|
CREATE OR REPLACE VIEW mv_hot.edge_oee_stop_summary_demo AS
|
|
SELECT
|
|
COALESCE(c.cause_name, 'Pendiente de clasificar') AS cause_name,
|
|
COALESCE(s.cause_code, 'pending') AS cause_code,
|
|
COUNT(*) AS stop_count,
|
|
ROUND(SUM(COALESCE(s.duration_s, EXTRACT(EPOCH FROM (now() - s.started_at))::numeric)) / 60.0, 2) AS total_min,
|
|
ROUND(SUM(COALESCE(s.cost_eur, ((EXTRACT(EPOCH FROM (now() - s.started_at)) / 3600.0) * s.value_hour_eur)))::numeric, 2) AS total_cost_eur
|
|
FROM mv_hot.edge_oee_machine_stops s
|
|
LEFT JOIN mv_hot.edge_oee_stop_causes c ON c.cause_code = s.cause_code
|
|
GROUP BY COALESCE(c.cause_name, 'Pendiente de clasificar'), COALESCE(s.cause_code, 'pending')
|
|
ORDER BY total_cost_eur DESC;
|
|
|
|
CREATE OR REPLACE VIEW mv_hot.edge_oee_stop_cause_options AS
|
|
SELECT
|
|
cause_code,
|
|
cause_name,
|
|
description,
|
|
is_planned,
|
|
sort_order
|
|
FROM mv_hot.edge_oee_stop_causes
|
|
WHERE is_active = true
|
|
ORDER BY sort_order, cause_name;
|