Digital Team Board and CIC Board

Di seguito il documento di specifica di Franke:

Digital Team Board and CIC Board

La struttura delle location prevederà:

Azienda -> Area -> Plant

Team (Reparti) -> Luoghi e linee di produzione

Al fine di importare le location da un database di un determinato stabilimento per aggiungerle ai relativi TEAM, si procede come segue:

Si seleziona la lista delle ubicazioni che si vogliono importare dallo stabilimento

Si richiama la setcentubi dell'agente centubi

Per il p.to 1 è necessario usare l'agentdb definito nella tabella dbubi in corrispondenza dello stabilimento (tiposet='S') relativo all'elemento selezionato. Cosi si può estrarre la lista di tutte le linee di produzione ordinate in modo alfabetico. Successivamente si può richiamare la seguente per inviare al centubi che copierà i dati:

Safety Pages

Selezionando un elemento della gerarchia a partire dal Team (Reparto) in poi viene abilitata una delle funzioni di inserimento dati presenti ai paragrafi:

1.2.2, 1.2.3, 1.2.4

Strutture dati

Le strutture dati utilizzate sono quelle relativa al sistema EEM ovvero:

objiter: ogni oggetto della safety è un objiter abbiamo i seguenti tipi di oggetti:

Near Miss (N)

Accident (A)

Long time 5S (S)

Long time TMP (J)

Short time 5S/TMP (Y)

Audit Checklist (P)

project: ogni oggetto trova i dati di dettaglio nel project

objteam: team interessato dall'attività

Per quanto riguarda oggetti di tipo N, A, S, J, Y viene considerato il project solo come definizione di eventi e attività da svolgere; un'attività è svolta quando l'objiter.state='A' (approvato/chiuso).
Mentre per quanto riguarda il tipo P, si dovrà generare la checklist (clista) e registrare l'esito del voto direttamente in curans.
Near Miss, Accident, Long time 5S, Long time TMP sono gestiti dalla pagina al paragrafo 1.2.4, mentre Short time 5S/TPM sono gestiti dalla pagina 1.2.2. I flussi operativi sono esattamente gli stessi, ma quando si crea un progetto con la 1.2.2 si dovrà assegnare anche un project.codequip.
Una struttura completa del database la troviamo ai seguenti paragrafi:

Objiter

Checklist

Project

Near Miss, Accident, long time S5 e TPM, short time TPM

Il flusso generale della gestione dei suddetti objects è il seguente:

newobjiter (tipo=N,A,S,J,Y): crea il nuovo objiter e restituisce il codice

insert into project (codice,descrizio,codubi): inserisce in project con la descrizio ed il codubi (vedi sotto le query da svolgere)

initteam: inizializza il team, nel caso specifico individua "chi" dovrà eseguire l'eventuale contromisura

sendobjiter: pianifica l'objiter per lo svolgimento

approve: dichiara lo svolgimento eseguito dell'objiter

L'inserimento del progetto deve procedere svolgendo esattamente le seguenti query, sostituendo opportunamente il codice del progetto con il codice del objiter create (le tre query vanno fatte in un colpo solo):

INSERT INTO PROJECT (codice,descrizio,codubi) VALUES (8,'descrizione di prova','000000098'); -- (alloca il progetto) INSERT INTO PRJMATGAP (CODPRJ,CODGRP,CODAREA,CODPROC) VALUES (7,1,1,1); -- (necessario per la gestione delle checklist) INSERT INTO PRJCAT (codprj,codcat) SELECT 7,category.codice FROM category; -- (necessario per la gestione delle checklist)

Le tabelle coinvolte dai movimenti sono le seguenti:

objiter: contiene la tipologia ed i riferimenti principali

project: contiene alcune informazioni di dettaglio (descrizio, codubi, altro...)

objteam: contiene il team (chi) che deve svolgere; il team avrà objteam.tipo=A

iter: contiene le date di previsto svolgimento (tmsend) ed infine di svolgimento (tmfeed)

L'objiter cambia stato in funzione delle operazioni:

appena inserito è in objiter.state=N

dopo la sendobjiter è in objiter.state=S

dopo l'approve è in objiter.state=A (stato di chiusura dell'operazione)

Di seguito le chiamate da effettuare ad i rispettivi agenti:

newobjiter (nel nume va il tm di creazione dell'oggetto, se 0 prende il tm attuale)

initteam: nel caso di modifica del team è sufficiente reinviare il team con nume=1 (il team verrà cancellato e ripristinato, al limite si fa una select dell'owner e si invia anche l'owner; in tal caso si dovrà aggiungere un campo al rec con il nome "owners" e mettere il codoper opportuno)

sendobjiter (nel nume va il tm di creazione dell'oggetto, se 0 prende il tm attuale)

approve (nel nume va il tm di creazione dell'oggetto, se 0 prende il tm attuale)

La seguente immagine illustra il flusso dall'inizializzazione del team alla chiusura dell'oggetto nella grafica proposta da Franke.
Mentre i short time TPM/5S sono gestiti dalla seguente ove è indicato il flusso:

Short time TPM/5S REJECT

Dallo schema del short time TPM/5S è evidente come in corrispodenza di una determinata riga, vi sia una ripianificazione di una attività.
In questo caso specifico, l'operatore deve avere la possibilità di eseguire i seguenti passi:

reject: una reject in corrispondenza della ITER che non è stata svolta

sendobjiter: una sendobjiter per creare la nuova ITER da svolgere

La prima sendobjiter crea il primo iter con lo stato = 'N' (vedi sotto).
A partire dal calendario possiamo prevedere le seguenti funzionalità:

conferma svolgimento (approve)

attività non svolta (reject)

La conferma corrisponde alla chiamata approve già vista sopra, mentre la reject è la seguente.
Funziona esattamente come la approve ma l'effetto su iter è il seguente.

su iter

su objiter

Se rigettiamo una attività, abbiamo la possibilità di riprogrammarla richiamando nuovamente la sendobjiter con una nuova data. Effettuando questa operazione otteniamo quanto segue:

su iter

su objiter

Si può iterare questo flusso finchè si rigetta definitivamente (objiter resta nello stato R) oppure si approva (objiter nello stato A).
Interrogando la tabella iter si può ricavare una sorta di calendario delle varie pianificazioni effettuate.

Short time TPM/5S Eventi periodici

E' possibile pianificare eventi con una cadenza periodica a tal fine si stabilisce:

data di inizio pianificazione (project.tmstart)

data di fine pianificazione (project.tmend)

tipo di periodo (project.tipoper): W=settimanale, D=giornaliero

durata del periodo in unita' di tipoper (project.n): ogni 2 giorni => tipoper=D, n=2

In questo caso si dovranno utilizzare apposite chiamate per gestire gli objiter periodici che sono le seguenti:

pianificazione: sendobjiterperiodic

annulla piano: undosendobjiterperiodic

approve di una iter: approveiterperiodic

reject di una iter: rejectiterperiodic

undo di una iter: undoiter (con nume=1)

Di seguito la sendobjiterperiodic.
Di seguito la undosendobjiterperiodic.
Mentre le altre chiamate sono identiche alle rispettive per il caso di eventi non periodici, con l'aggiunta del codice dell'iterazione nel rec nel campo coditer.
Se si rettifica la periodicità del piano è necessario innanzitutto esegure una undosendobjiterperiodic

Gestione delle checklist (S5 - AUDIT)

Il flusso generale della gestione del suddetto object è il seguente:

newobjiter (tipo=P): crea il nuovo objiter e restituisce il codice

insert into project (codice,descrizio,codubi): inserisce in project con la descrizio ed il codubi (vedi sotto le query da svolgere)

initteam: inizializza il team, nel caso specifico individua "chi" dovrà eseguire la compilazione

generate: genera la checklist

answer: registra la risposta di ogni elemento della checklist

approve (da valutare se lo gestiremo): dichiara lo svolgimento eseguito dell'objiter

L'inserimento del progetto deve procedere svolgendo esattamente le seguenti query, sostituendo opportunamente il codice del progetto con il codice del objiter create (le tre query vanno fatte in un colpo solo):

INSERT INTO PROJECT (codice,descrizio,codubi) VALUES (8,'descrizione di prova','000000098'); -- (alloca il progetto) INSERT INTO PRJMATGAP (CODPRJ,CODGRP,CODAREA,CODPROC) VALUES (7,1,1,1); -- (necessario per la gestione delle checklist) INSERT INTO PRJCAT (codprj,codcat) SELECT 7,category.codice FROM category; -- (necessario per la gestione delle checklist)

Le tabelle coinvolte dai movimenti sono le seguenti:

objiter: contiene la tipologia ed i riferimenti principali

project: contiene alcune informazioni di dettaglio (descrizio, codubi, altro...)

objteam: contiene il team (chi) che deve svolgere; il team avrà objteam.tipo=A

iter: contiene le date di previsto svolgimento (tmsend) ed infine di svolgimento (tmfeed)

prjtask: tabella intermedia dei task che collega l'istanza di checklist al progetto

clista: contiene le checklist e le risposte correnti

answer: contiene i commenti di ogni singola risposta e l'esito della risposta

Di seguito uno schema commentato della pagina degli Audit.
I passi 1, 2, 3, 6 sono svolti come indicato nel paragrafo precedente, mentre i passi 4, 5 come segue:

generate

answer

Green Cross

Le Green Cross prevedono la visualizzazione di eventi di tipo:

near miss (objiter.tipo='N'): colore giallo

accident (objiter.tipo='A'): colore rosso

Oltre alla visualizzazione giornaliera dei dati viene anche indicata la data ed il luogo dell'ultimo incidente e dell'ultimo near miss (tabella a destra).
Al fine di avere un valore iniziale relativamente alla data ultimo incidente e data ultimo near miss, utilizziamo due campi aggiuntivi di ubicaz:

ubicaz.tminc: tm dell'ultimo incidente

ubicaz.tmnm: tm ultimo near miss

ALTER TABLE ubicaz ADD COLUMN tminc FLOAT, ADD COLUMN tmnm FLOAT; comment ON COLUMN ubicaz.tminc IS 'tm dell''ultimo incidente'; comment ON COLUMN ubicaz.tmnm IS 'tm dell''ultimo near miss';

L'AgenteDigCIC si occuperà di considerare questi valori, insieme a quelli derivanti dagli objiter creati, per fornire i dati alla GUI secondo gli schemi descritti di seguito.
La chiamata per ottenere i dati delle green cross è la seguente (greencross).
L'agente elabora le greencross di ogni location sottostante e restituisce la seguente lista.

Quality

Action plan Quality

L'Action plan Quality ha la medesima impostazione degli Action plan definiti per la safety in particolare per la Near Miss, Accident, long time S5 e TPM, short time TPM. Il flusso è il medesimo definito per i tipi N,A,S,J; aggiungiamo un nuovo tipo che chiamiamo Q. Il resto del processo è esattamente lo stesso come pure la pagina cui si fa riferimento (vedi sotto).

Grafici della qualità

Vengono definite 2 strutture basate su grafici per visualizzare i dati della qualità:

la prima visualizza, in un grafico a barre, la frazione di scarti/ripassi per ogni mese; inoltre, per ogni settimana, presenta una tabella, ove le colonne sono i giorni della settimana (lun, mar, ...) e le righe sono le macchine appartenenti al team; ogni cella contiene il numero di pezzi giornaliero di scarti/ripassi (2 tabelle)

la seconda visualizza il Pareto delle cause/numero di scarti/ripassi; in un unico grafico vengono affiancate sia le barre dei ripassi che quelle degli scarti con colore differente

Q1

Al fine di gestire le soglie di scarti/ripassi per location-turno (presenti nelle tabelle settimanali) viene creata la relazione ubiturso (soglie ubicaz-turnidet). Di seguito il file contenente la struttura e lo schema ER.

ubiturso.sql

Al fine di inserire i dati nella ubiturso, l'utente potrà selezionare l'icona indicata sotto solo in corrispondenza di una specifica location di tipo linea di produzione.
I dati relativi al report Q1 possono essere richiesti all'AgentDigCICSup attraverso la seguente chiamata:
Ove in p1, troviamo il codice della location a partire dalla quale si desidera sviluppare il report e l'anno di riferimento. L'agente ritorna un REC contenente 3 campi che sono oggetti JSON:

mensile: grafico dei dati mensili

settimanale_scarti: tabella settimanale degli scarti contenente tutte le settimane dell'anno

settimanale_ripassi: tabella settimanale dei ripassi contenente tutte le settimane dell'anno

Di seguito il JSON di "mensile".
Di seguito il JSON di "settimanale_scarti" (il JSON di settimanale_ripassi è uguale).
@ Nel JSON Settimanale è stato integrato un campo aggiuntivo per ubicazione-turno che si chiama "soglia"; tale campo rappresenta la soglia giornaliera in termini di numero di scarti o ripassi (ubiturso.nsca, ubiturso.nrip).

Q2

E' possibile estrarre la statistica Q2 tramite l'AgentDigCICSup con la seguente richiesta, riferita ad una specifica codubi e ad un intervallo temporale.
La risposta è un rec contenente per ogni causale identificata di scarto il numero di scarti (scarti) ed il numero di ripassi (ripassi), oltre al codice e descrizione della causale di scarto/ripasso.

Quality Alarms

Di seguito lo schema da realizzare per i quality alarms.
Verrà inserito come objiter di tipo X, e viene allocata una nuova tabella relazionata alla project secondo il seguente schema.
L'oggetto non sarà soggetto ad iterazioni e non richiede la costruzione del team. Il seguente file crea la actionplan:

actionplan.sql

Costs

Il modulo Costs presenta le seguenti funzioni:

C1 - OEE

C2 - STOPPAGE

C3 - CHANGEOVER

C4 - ACTION PLAN

Il modulo C4 - Action Plan sarà gestito come gli altri action plan con tipo='O'.

C1 - OEE

Al fine di realizzare il grafico C1 sarà necessario attivare per lo specifico plant il calcolo dell'OEE per turno per ogni location del plant. In particolare si dovrà tenere in conto la seguente raccomandazione da verificare prima dell'avviamento:

LE LINEE DEL PLANT SONO SOGGETTE A CAMBIO DEL TURNO: in tal caso si dovrà prevedere, al momento del caricamento del plant, la possibilità di modificare il turno in OEECONF per le linee (da sviluppare solo durante l'eventual estensione)

Il grafico sopra ha il medesimo schema del grafico Q1 della qualità. A sx abbiamo l'andamento mensile totale, mentre a dx abbiamo calendari settimanali per macchina/turno ove sono indicati i valori dell'OEE e le relative soglie.
I dati sono forniti allo stesso modo dall'AgentDigCICSup attraverso la seguente chiamata.
L'agente risponde con un rec contenete i due campi seguenti:

mensile: array JSON con la lista dei mesi dell'anno e l'OEE + soglia di ogni mese

oee_settimana: array JSON contenente le settimane dell'anno (woy=1..53) ed un campo data

il campo data a sua volta contiene un array JSON come segue

C2 - STOPPAGES

Si tratta di un semplice Pareto delle fermate accessibile da qualsiasi livello della gerarchia. Per ottenere i dati è sufficiente inoltrare all'AgentDigCICSup, la seguente chiamata.
L'agente risponde con la seguente semplice struttura (rec).

C3 - Changeover

La pagina del Changover dovrà presentare un blocco dati per ogni linea appartenente ad un determinato Team; in un pagina si dovranno presentare massimo 4 linee alla volta, con la possibilità di poter scorrere manualmente oppure automaticamente.
I dati saranno prodotti dall'AgentDigCICSup, in base al codice del Team (codubi) ed ad un intervallo temporale (tmin, tmfi). L'agente produce un rec contenente tutti i dati ordinati per codubi delle linee di produzione e per tm.
Di seguito uno schema dell'interfaccia.
I dati presenti in ogni blocchetto macchina sono i seguenti:

nome della linea/macchina

numero di eventi di changeover (numero di righe del rec ritornato riferiti alla linea)

quantità media ordini del periodo (presente nella colonna qtameop del rec dell'agente)

durata totale changover (somma dei tmdiff presenti nel rec per la linea)

durata media changeover (media dei tmdiff presenti nel rec per la linea)

mediana della durata di changeover (mediana dei tmdiff presenti nel rec per la linea)

grafico

serie 1: x = tm del rec per la linea, y = tmdiff del rec per la linea

serie 2: y = media

serie 3: y = mediana

dati aggiuntivi: data inizio, fine, codice e descrizione dell'articolo in lavorazione (questi ultimi si trovano nel rec per la linea, come JSON nel campo "catego" della riga corrispondente)

Di seguito la richiesta da inviare all'AgentDigCICSup.
La risposta dell'agente è la seguente.

Delivery

Il modulo Delivery presenta le seguenti funzioni:

D1 - Order achievement

D2 - Pareto Order achievement / losses

D3 - ???

D4 - ACTION PLAN

Il modulo D4 - Action Plan sarà gestito come gli altri action plan con tipo='D'.

D1 - Order Achievement

La logica di funzionamento di questa tabella è la medesima della tabella dell'OEE in C1; l'unica differenza è che le soglie sono soglie giornaliere e per macchina/turno. Questo sarà gestito nel rec ritornato dall'agente.
La chiamata all'agente restituisce direttamente un rec con la coppia:

woy: numero della settimana dell'anno (per tutto l'anno)

data: JSON contenente i dati della settimana

La richiesta all'AgentDigCICSup è la seguente.
La risposta dell'agente ha la medesima struttura della parte "settimanale" del report C1. Da notare che in ogni giorno della settimana (0, 1, .., 6), questa volta troviamo due numeri interi divisi da una virgola:

il primo numero intero è il numero di pezzi prodotto nel turno

il secondo numero intero è il target del turno in base al takt time delle lavorazioni effettuate

D2 - Pareto Order achievement / losses

Semplice pareto delle cause di speed-losses, riferito ad uno specifico Team (codubi in generale) ed ad uno specifico intervallo temporale (tmin, tmfi).
A tale scopo si può chiedere all'AgentDigCICSup la seguente ask.
A cui l'agente risponde fornendo la lista delle cause di speedlosses riscontrate nel periodo (INRA) con la somma del numero di pezzi persi, l'elenco è già ordinato in modo decrescente di numero di pezzi persi.

D4 - SERVICE LEVEL

Aggiungere in ubicaz i campi:

thmonslev, thdayslev con relaviti commenti

Gestire l'inserimento di queste soglie ed anche delle soglie thmonscrap e thmonrip, in una pagina di configurazione associata al plant.

ALTER TABLE ubicaz ADD COLUMN thmonslev DOUBLE PRECISION; ALTER TABLE ubicaz ADD COLUMN thdayslev DOUBLE PRECISION; comment ON COLUMN ubicaz.thmonslev IS 'Soglia mensile Service Level'; comment ON COLUMN ubicaz.thdayslev IS 'Soglia giornaliera Service Level';

Mobile App

Di seguito la pagina di accesso all'APP.
Dopo aver selezionato la location si accede alla pagina di registrazione dell'osservazione.
Aggiungere la scelta del tipo di evento per default "Mobile app observation".

Accesso all'App

Si prevede un nuovo QR-CODE che sarà possibile stampare direttamente dall'applicazione e che contiene il link per l'accesso. Questo QR-CODE potrà essere stampato dalla seguente funzione accessibile per tiposet='S' o tiposet='R'.

L'accesso può essere svolto attraverso una delle seguenti modalità:

per ogni QR-CODE della location, si aggiunge sulla stampa un piccolo QR-CODE per accedere all'App (contiene il link)

in varie posizioni nel plant è presente il QR-CODE per l'accesso all'applicazione indipendentemente dal QR-CODE della zona

scaricare da Google Play store l'apk solo per android ed usare l'apk

digitare manualmente nel browser il link di accesso

Login all'app

Una volta acceduto all'App essa richiede sempre il login. Attraverso un apposito parametro di accesso l'applicazione può permettere il login come Guest; in questo modo anche utenti esterni e non registrati potranno accedere all'applicazione e registrare osservazioni.

Scelta manuale della location

Condizione 1 - Guest

Il Guest entra in una sessione di scelta che poi lo porterà nella pagina di compilazione esattamente come fa la lettura del qr-code.
La pagina di scelta e' fatta come segue:

ha una riga di ricerca (lente)

sotto ha una lista di location

L'applicazione svolge la seguente sequenza di operazioni:

al primo ingresso le location sono i plant (tiposet='S')

se clicco su un plant entro nel livello sotto team (tiposet='R')

se clicco sul team entro nel livello linea (tipset='P')

se clicco sulla linea entro in compilazione

Condizione 2 - Operatore loggato

Tutto come condizione 1, ma l'operatore loggato entra nella lista dei plant visualizzando solo i plant a lui associati, se in workpla ha piu' di un plant, mentre se ha un solo plant associato allora entra direttamente nei teams. Se non ha alcun plant associato allora parte da tutti i plant (o non vede nulla ?).

3 tipi di Observation

Aggiungere i seguenti campi.

ALTER TABLE project ADD COLUMN safetype VARCHAR(2),ADD COLUMN whathappen VARCHAR(1024),ADD COLUMN potinj VARCHAR(1024), ADD COLUMN gravity VARCHAR(2), ADD COLUMN pertype VARCHAR(1024); comment ON COLUMN project.safetype IS 'relativo a objiter.tipo=''N'', indica: N=near miss,A=unsafe action,C=unsafe condition,E=unsafe equipement'; comment ON COLUMN project.whathappen IS 'relativo a objiter.tipo=''N'', indica: what happen'; comment ON COLUMN project.safetype IS 'relativo a objiter.tipo=''N'', indica: potenziali incidenti'; comment ON COLUMN project.gravity IS 'relativo a objiter.tipo=''N'', indica: R=red,Y=yellow,G=green'; comment ON COLUMN project.pertype IS 'relativo a objiter.tipo=''5S'' oppure ''TPM'', indica: Performance Type';

Aggiungere inoltre la seguente tabella da utilizzare per la pagina di safety.

CREATE TABLE public.prjunsafe ( codprj INTEGER NOT NULL, pos INTEGER NOT NULL, descrizio CHARACTER VARYING(1024) ); COMMENT ON TABLE public.prjunsafe IS 'How can we prevent the occurrence/unsafe situation?'; COMMENT ON COLUMN public.prjunsafe.codprj IS 'codice progetto'; COMMENT ON COLUMN public.prjunsafe.pos IS 'sequenza per un dato progetto'; ALTER TABLE ONLY public.prjunsafe ADD CONSTRAINT ix_prjunsafe_key PRIMARY KEY (codprj, pos); ALTER TABLE ONLY public.prjunsafe ADD CONSTRAINT ix_prjunsafe_codprj FOREIGN KEY (codprj) REFERENCES public.project(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Aggiungere alle anags la tipologia di unsafe

INSERT INTO public.anags VALUES ('it', 'unsafe-type', 'A', 'Unsafe Action', 1, '', ''); INSERT INTO public.anags VALUES ('it', 'unsafe-type', 'C', 'Unsafe Condition', 2, '', ''); INSERT INTO public.anags VALUES ('it', 'unsafe-type', 'E', 'Unsafe Equipment', 3, '', ''); INSERT INTO public.anags VALUES ('it', 'unsafe-type', 'N', 'Near Miss', 4, '', ''); INSERT INTO public.anags VALUES ('en', 'unsafe-type', 'A', 'Unsafe Action', 1, '', ''); INSERT INTO public.anags VALUES ('en', 'unsafe-type', 'C', 'Unsafe Condition', 2, '', ''); INSERT INTO public.anags VALUES ('en', 'unsafe-type', 'E', 'Unsafe Equipment', 3, '', ''); INSERT INTO public.anags VALUES ('en', 'unsafe-type', 'N', 'Near Miss', 4, '', ''); INSERT INTO public.anags VALUES ('de', 'unsafe-type', 'A', 'Unsafe Action', 1, '', ''); INSERT INTO public.anags VALUES ('de', 'unsafe-type', 'C', 'Unsafe Condition', 2, '', ''); INSERT INTO public.anags VALUES ('de', 'unsafe-type', 'E', 'Unsafe Equipment', 3, '', ''); INSERT INTO public.anags VALUES ('de', 'unsafe-type', 'N', 'Near Miss', 4, '', ''); INSERT INTO public.anags VALUES ('pl', 'unsafe-type', 'A', 'Unsafe Action', 1, '', ''); INSERT INTO public.anags VALUES ('pl', 'unsafe-type', 'C', 'Unsafe Condition', 2, '', ''); INSERT INTO public.anags VALUES ('pl', 'unsafe-type', 'E', 'Unsafe Equipment', 3, '', ''); INSERT INTO public.anags VALUES ('pl', 'unsafe-type', 'N', 'Near Miss', 4, '', '');

L'app permette di selezionare una tra le seguenti funzioni:

Observation: apre la pagina delle osservazioni già realizzata

Safety: apre la pagina safety vedi sotto

TPM: apre la pagina TPM vedi sotto

5S: apre la pagina 5S vedi sotto

CIC

Safety

S1 - Safety Cross

E' necessario integrare il record senza infortuni e la data da cui comincia il record, a tal fine aggiungiamo la possibilità di poter inserire nell'anagrafica ubicaz i seguenti campi:

ALTER TABLE ubicaz ADD COLUMN hrecnr INTEGER, ADD COLUMN hrecgg CHARACTER VARYING(9); comment ON COLUMN ubicaz.hrecnr IS 'Record in termini di numero di giorni senza infortuni per il Team tipsoet=''R'''; comment ON COLUMN ubicaz.hrecgg IS 'Data di inizio del record senza infortuni';

L'agente restituirà per ogni green-cross due campi aggiuntivi:

hrecnr: numero di giorni senza infortuni

hrecgg: data di inizio del record

Questi dati dovranno essere visualizzati a destra come segue.
Un unico BOX riferito all'oggetto (codubi) sul quale stiamo lavorando.
L'AgentDigCICSup ritorna i vlaori necessari, vedi sotto.
E' necessario configurare i dati necessari al calcolo del record infortuni di seguito.
Aggiungere a tale scopo l'icona di accesso alla apposita scheda come segue.
L'ulteriore campo visibile è la data di avvio della location necessario per il calcolo dei record; questo dovrà essere associato all'elemento selezionato e dovrà essere editabile, una volta modificato va su ubicaz.datareg.

S3 - TPM / 5S Assessment (Kami Shabai)

Si tratta di pianificazione kami shabai (modello da lean manufacturing). In pratica si pianificano una serie di attività che hanno certi obiettivi definiti dalla carta delle attività. Le attività vengono assegnate a un team e vengono pianificate nel tempo con una certa frequenza (settimanali, giornaliere, altro...).
Il tipo di objiter dedicato ai kami shabai è K ([K]ami shabai).
Il team viene inserito tra gli owner, il team leader viene inserito come objiter.codoper ed anche nel objteam con tipo='O'; gli altri partecipanti al team vanno inseriti solo in objteam.
A partire da un calendario mensile è possibile vedere giornalmente la pianificazione di queste attività. Un auditor ha il compito di selezionare una cella in cui è presente una attività e visualizzare la T-CARD. La T-CARD è una carta che descrive alcune informazioni dell'attività. L'auditor ha il compito di ispezionare l'area interessata dall'attività e vedere se trova proprietà corrispondenti a quelle previste dalla T-CARD; se c'è corrispondenza allora da un feedback positivo (MEET=1) e la card si colora di verde, altrimenti da un feedback negativo (MEET=0) e la card si colora di rosso. Cliccando sulla cella è possibile visionare tutte le T-CARD colorate che sono già state assegnate a tale area con il rispettivo esito.
Quando l'auditor clicca su una cella, viene automaticamente inserito nel team di approver per l'objiter interessato, se non è già presente; in questo modo l'utente dall'auditor potrà approvare/rigettare la specifica iter.
I tipi di attività che si vedono dal calendario dell'esempio sono:

QA

C

FPS

Safety

Quando si alloca una nuova card di un certo tipo, si dovrà applicare un contatore di card di quel tipo e incrementarlo. A tale scopo la CARD va creata direttamente tramite AgentDigCICSup; l'agente riceve in ingresso i dati della newobjiter piu' il tipo di card ed avrà il compito di svolgere tutte le operazioni di inizializzazione dell'objiter e del project con l'assegnazione dell'ID card. Di seguito la modalità di comunicazione.
La seguente tabella contiene la lista delle attività con relative frequenze ed inoltre visualizza due T-CARD QA2 una negativa (rossa) e l'altra positiva (verde).
Quindi gli utenti devono innanzitutto compilare la tabella a destra. Tale tabella alimenta il seguente calendario.
Nel calendario si vedono in grigio le celle associate ad una CARD, cliccando si può:

visionare l'elenco delle card già create

creare una nuova card con un esito

Come si vede le card gestiscono i seguenti dati descrittivi che vanno inseriti manualmente per la predisposizione della riga:

Business excellence

Requisiti

Chiarimento/Spiegazione

Prova di conformità

Frequenza

Responsabile

Valutazione

Tutti questi campi andranno inseriti in project.
Per la procedura di gestione dell'informazione e la calendarizzazione sarà svolta come al seguente punto

Short time TPM5S nel sottoparagrafo degli eventi periodici

Ogni T-CARD corrisponderà ad una specifica ITER che può essere approved (meet=1) oppure rejected (meet=0), nel primo caso l'attività si chiude nel secondo si può creare una nuova card per lo stesso specifico evento.
Per poter creare una nuova T-CARD (iter) per uno specifico evento sarà necessario allocarla con un tm che ricada nel medesimo giorno, ma che sia maggiore della ITER precedente.
In base a quanto descritto aggiungiamo i seguenti campi alla struttura project.

ALTER TABLE project ADD COLUMN buex VARCHAR(1024), ADD COLUMN req VARCHAR(1024), ADD COLUMN spie VARCHAR(1024), ADD COLUMN cotest VARCHAR(1024), ADD COLUMN valdesc VARCHAR(1024), ADD COLUMN tipocar VARCHAR(101), ADD COLUMN idcar INTEGER; comment ON COLUMN project.buex IS 'Business exellence (vedi tabella kami shabai)'; comment ON COLUMN project.req IS 'Requisiti (vedi tabella kami shabai)'; comment ON COLUMN project.spie IS 'Chiarimento/Spiegazione (vedi tabella kami shabai)'; comment ON COLUMN project.cotest IS 'Test di conformità (vedi tabella kami shabai)'; comment ON COLUMN project.valdesc IS 'Valutazione (vedi tabella kami shabai)'; comment ON COLUMN project.tipocar IS 'Tipo carta (vedi tabella kami shabai)'; comment ON COLUMN project.idcar IS 'Numero progressivo della carta (vedi tabella kami shabai)';

Query per aggiungere le anags di tipocard per il Kami Shabai:

DELETE FROM anags WHERE tag='ks-tipocard'; INSERT INTO public.anags VALUES ('it', 'ks-tipocard', 'QA', 'QA', 1, '', ''); INSERT INTO public.anags VALUES ('it', 'ks-tipocard', 'C', 'C', 2, '', ''); INSERT INTO public.anags VALUES ('it', 'ks-tipocard', 'FPS', 'FPS', 3, '', ''); INSERT INTO public.anags VALUES ('it', 'ks-tipocard', 'Safety', 'Safety', 4, '', ''); INSERT INTO public.anags VALUES ('en', 'ks-tipocard', 'QA', 'QA', 1, '', ''); INSERT INTO public.anags VALUES ('en', 'ks-tipocard', 'C', 'C', 2, '', ''); INSERT INTO public.anags VALUES ('en', 'ks-tipocard', 'FPS', 'FPS', 3, '', ''); INSERT INTO public.anags VALUES ('en', 'ks-tipocard', 'Safety', 'Safety', 4, '', ''); INSERT INTO public.anags VALUES ('de', 'ks-tipocard', 'QA', 'QA', 1, '', ''); INSERT INTO public.anags VALUES ('de', 'ks-tipocard', 'C', 'C', 2, '', ''); INSERT INTO public.anags VALUES ('de', 'ks-tipocard', 'FPS', 'FPS', 3, '', ''); INSERT INTO public.anags VALUES ('de', 'ks-tipocard', 'Safety', 'Safety', 4, '', ''); INSERT INTO public.anags VALUES ('pl', 'ks-tipocard', 'QA', 'QA', 1, '', ''); INSERT INTO public.anags VALUES ('pl', 'ks-tipocard', 'C', 'C', 2, '', ''); INSERT INTO public.anags VALUES ('pl', 'ks-tipocard', 'FPS', 'FPS', 3, '', ''); INSERT INTO public.anags VALUES ('pl', 'ks-tipocard', 'Safety', 'Safety', 4, '', '');

S4 - Audit

Stessa struttura usata per gli AUDIT, ma solo in visualizzazione, non è possibile modificare.

Meeting Standard

CREATE TABLE public.protocol ( codice INTEGER NOT NULL, codubi CHARACTER VARYING(51), frequency CHARACTER VARYING(51), DAY CHARACTER VARYING(101), TIME CHARACTER VARYING(10), purpose CHARACTER VARYING(3000), actionplan CHARACTER VARYING(3000), leader CHARACTER VARYING(101), timekeeper CHARACTER VARYING(101), partecipants CHARACTER VARYING(3000), warnimage CHARACTER VARYING(101) ); ALTER TABLE public.protocol OWNER TO postgres; COMMENT ON TABLE public.protocol IS 'Tabella dei Meeting Protocols'; COMMENT ON COLUMN public.protocol.codubi IS 'Codice del luogo'; COMMENT ON COLUMN public.protocol.frequency IS 'Frequenza del meeting'; COMMENT ON COLUMN public.protocol.day IS 'Giorni della settimana del meeting'; COMMENT ON COLUMN public.protocol.time IS 'Orario del meeting'; COMMENT ON COLUMN public.protocol.purpose IS 'Scopo del meeting'; COMMENT ON COLUMN public.protocol.actionplan IS 'Actionplan del meeting'; COMMENT ON COLUMN public.protocol.leader IS 'Leader del meeting'; COMMENT ON COLUMN public.protocol.timekeeper IS 'Timekeeper del meeting'; COMMENT ON COLUMN public.protocol.partecipants IS 'Partecipanti al meeting'; COMMENT ON COLUMN public.protocol.warnimage IS 'Immagine warning di anteprima'; ALTER TABLE ONLY public.protocol ADD CONSTRAINT ix_protocol_codice PRIMARY KEY (codice); ALTER TABLE ONLY public.protocol ADD CONSTRAINT ix_protocol_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE RESTRICT; CREATE TABLE public.agenda ( codprot INTEGER NOT NULL, pos INTEGER, descrizio CHARACTER VARYING(256), responsible CHARACTER VARYING(101), TIME FLOAT ); ALTER TABLE public.agenda OWNER TO postgres; COMMENT ON TABLE public.agenda IS 'Tabella agenda per i meeting protocols'; COMMENT ON COLUMN public.agenda.codprot IS 'Codice riferimento protocollo'; COMMENT ON COLUMN public.agenda.pos IS 'Ordine degli argomenti in agenda'; COMMENT ON COLUMN public.agenda.descrizio IS 'Descrizione'; COMMENT ON COLUMN public.agenda.responsible IS 'Responsabile - ruolo che ricopre'; COMMENT ON COLUMN public.agenda.time IS 'durata del punto in agenda'; ALTER TABLE ONLY public.agenda ADD CONSTRAINT ix_agenda_codprot FOREIGN KEY (codprot) REFERENCES public.protocol(codice) ON UPDATE CASCADE ON DELETE CASCADE; CREATE TABLE public.protrules ( codprot INTEGER NOT NULL, pos INTEGER, descrizio CHARACTER VARYING(256) ); ALTER TABLE public.protrules OWNER TO postgres; COMMENT ON TABLE public.protrules IS 'Tabella agenda per i meeting protocols'; COMMENT ON COLUMN public.protrules.codprot IS 'Codice riferimento protocollo'; COMMENT ON COLUMN public.protrules.pos IS 'Ordine degli argomenti in agenda'; COMMENT ON COLUMN public.protrules.descrizio IS 'Descrizione'; ALTER TABLE ONLY public.protrules ADD CONSTRAINT ix_protrules_codprot FOREIGN KEY (codprot) REFERENCES public.protocol(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Aggiunta dei campi al meeting protocol

ALTER TABLE protocol ADD COLUMN kpisafety VARCHAR(51); ALTER TABLE protocol ADD COLUMN kpiquality VARCHAR(51); ALTER TABLE protocol ADD COLUMN kpidelivery VARCHAR(51); ALTER TABLE protocol ADD COLUMN kpicost VARCHAR(51); ALTER TABLE protocol ADD COLUMN warnimage VARCHAR(101);

Safety Report

CREATE TABLE public.safetyreport ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(101), zord INTEGER, tipodato VARCHAR(2) ); ALTER TABLE public.safetyreport OWNER TO postgres; COMMENT ON TABLE public.safetyreport IS 'Tabella tematica dei safety report'; ALTER TABLE ONLY public.safetyreport ADD CONSTRAINT ix_safetyreport_codice PRIMARY KEY (codice); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (1, 'Accident Description', 1); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (2, 'Interim Containment Actions', 2); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (3, 'Root Cause Analysis', 3); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (4, 'Preventive Actions', 4); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (5, 'Verifications of Corrective Actions', 5); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (6, 'Lost Time (days)', 6); INSERT INTO safetyreport (codice, descrizio, zord) VALUES (7, 'Report Closed', 7); CREATE TABLE public.safprj ( codsafety INTEGER, codprj INTEGER, codoper VARCHAR(51), descrizio VARCHAR(512), tmfin FLOAT ); ALTER TABLE public.safprj OWNER TO postgres; COMMENT ON TABLE public.safprj IS 'Associazione i project di tipo safety e i temi del safety report'; ALTER TABLE ONLY public.safprj ADD CONSTRAINT ix_safprj_codsafety FOREIGN KEY (codsafety) REFERENCES public.safetyreport(codice) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE ONLY public.safprj ADD CONSTRAINT ix_safprj_codprj FOREIGN KEY (codprj) REFERENCES public.project(codice) ON UPDATE CASCADE ON DELETE CASCADE; ALTER TABLE ONLY public.safprj ADD CONSTRAINT ix_safprj_codoper FOREIGN KEY (codoper) REFERENCES public.operato(codice) ON UPDATE CASCADE ON DELETE RESTRICT;

FPS ACHIVEMENT

CREATE TABLE fpsachievement ( codubi CHARACTER VARYING(51), MONTH INTEGER, YEAR INTEGER, actual FLOAT, target FLOAT, forecast FLOAT ); ALTER TABLE ONLY public.fpsachievement ADD CONSTRAINT ix_fpsachievement_pkey PRIMARY KEY (codubi, MONTH, YEAR); ALTER TABLE ONLY public.fpsachievement ADD CONSTRAINT ix_fpsachievement_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Inserimento manuale dati per le risorse che non sono connesse con sistema OEE Next

Per alcune teamboards è stata data la possibilità di aggiungere manualmente dei KPIs relativi su qualità, costo e delivery. In particolare per "Scraps & Reworks Pareto", "Downtime Pareto" e "Order Achivement Pareto". Questa tabella per gestire gli inserimenti manuali:

CREATE TABLE public.kpispareto ( codubi CHARACTER VARYING(101), causa CHARACTER VARYING(101), tm DOUBLE PRECISION, nr INTEGER, codoper CHARACTER VARYING(101), TYPE CHARACTER VARYING(5), DATA CHARACTER VARYING(9), codice INTEGER NOT NULL ); COMMENT ON COLUMN public.kpispareto.tm IS 'tm di registrazione'; COMMENT ON COLUMN public.kpispareto.type IS 'D = Downtime Pareto, S = Scraps & Rework pareto, O = Order Achivment Pareto'; COMMENT ON COLUMN public.kpispareto.data IS 'Data di registrazione'; ALTER TABLE ONLY public.kpispareto ADD CONSTRAINT ix_kpispareto_pk PRIMARY KEY (codice); ALTER TABLE ONLY public.kpispareto ADD CONSTRAINT ix_kpispareto_codoper FOREIGN KEY (codoper) REFERENCES public.operato(codice) ON UPDATE CASCADE ON DELETE CASCADE; ALTER TABLE ONLY public.kpispareto ADD CONSTRAINT ix_kpispareto_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Per abilitare quali risorse dovrenno utilizzare la pagina di inserimento manuale è stato messo su wip-settings la seguente chiave:

manualkpis:{ list:[ {k:'150121', v:'Others Fabricated (DAN)'}, {k:'FIMDIP03', v:'TB Fabricated Upstream'}, {k:'FIMDIP04', v:'TB Fabricated Downstream'}, ] }

I codici presenti in lista avranno accesso alla pagina di inserimento manuale dei dati nei pareto. Le altre risorse invece accederanno alla vista di default, con i dati collegati a OEE

Proactive KPIs

AgentGraphSup configurazione

<agent lib="/usr/lib/libdigcic.so.0.0.0" create="agentGraphSup" live="1" name="graph">
<param name="agps" value="prepstat"/>
</agent>

Safety Actions

Per gestire alcuni KPIs sulle actions abbiamo dovuto introdurre il concetto di "Safety Action".
Una Safety Action è un action generica che può essere associata a diversi tipi di oggetto (objiter), in particolare a:
- Job Safety Observations -> objiter.tipo='H'
- Safety Report -> objiter.tipo='A|N|B|F|R'
- Risk Assessmebr -> objiter.tipo='U' (nuovo oggetto che può essere gestito in modo simile a un JSO)

Per implementare utilizzando i dati che storicamente sono stati inseriti, vengono trasformate in "safety actions" i seguenti oggetti per tipo:
Job Safety Observation -> ogni suggestion di una JSO diventa una safety action. Le suggestion dei JSO sono salvate nella tabella prjunsafe
Safety Report -> nel safety report ci sono configurare 2 action (safprj.codsafety = 2 e safprj.codsafey = 4). Ognuna di queste action diventano una safety action.

Struttura di una safety action:

CREATE TABLE public.actionstype ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(51), tipo CHARACTER VARYING(51), zord INTEGER ); ALTER TABLE public.actionstype OWNER TO postgres; COMMENT ON TABLE public.actionstype IS 'Tabella che contiene la tipologia delle azioni legate al safety (Safety Report, Job Safety Observation, Risk)'; COMMENT ON COLUMN public.actionstype.tipo IS 'Tipologia di tipi di azione. RA -> Risk Assessment, SR -> Safety Report & JSO'; ALTER TABLE ONLY public.actionstype ADD CONSTRAINT ix_actionstype_pk PRIMARY KEY (codice); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (1, 'Azioni di contenimento provvisorie', 'SR', 1); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (2, 'Azioni preventive', 'SR', 2); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (3, 'Building', 'RA', 1); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (4, 'Installation', 'RA', 2); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (5, 'Zoning', 'RA', 3); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (6, 'PPE', 'RA', 4); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (7, 'Tools', 'RA', 5); INSERT INTO actionstype (codice, descrizio, tipo, zord) VALUES (8, 'Another', 'RA', 6); CREATE TABLE public.safetyactions ( codprj INTEGER, descrizio CHARACTER VARYING(1000), tmcre DOUBLE PRECISION, tmtarget DOUBLE PRECISION, tmclosed DOUBLE PRECISION, acttype INTEGER, STATUS CHARACTER VARYING(2), codoper CHARACTER VARYING(51), zord INTEGER ); ALTER TABLE public.safetyactions OWNER TO postgres; COMMENT ON TABLE public.safetyactions IS 'Tabella che contiene tutte le azioni preventive e correttive legate al safety (Safety Report, Job Safety Observation, Risk)'; COMMENT ON COLUMN public.safetyactions.codprj IS 'project.codice'; COMMENT ON COLUMN public.safetyactions.tmcre IS 'tm di creazione dell''azione'; COMMENT ON COLUMN public.safetyactions.tmtarget IS 'tm di prevista chiusura azione'; COMMENT ON COLUMN public.safetyactions.tmclosed IS 'tm chiusura effettiva dell''azione'; COMMENT ON COLUMN public.safetyactions.status IS 'O = Open, C = Close'; COMMENT ON COLUMN public.safetyactions.zord IS 'Posizione'; ALTER TABLE ONLY public.safetyactions ADD CONSTRAINT ix_safetyactions_acttype FOREIGN KEY (acttype) REFERENCES public.actionstype(codice) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE ONLY public.safetyactions ADD CONSTRAINT ix_safetyactions_codoper FOREIGN KEY (codoper) REFERENCES public.operato(codice) ON UPDATE CASCADE ON DELETE CASCADE; ALTER TABLE ONLY public.safetyactions ADD CONSTRAINT ix_safetyactions_codprj FOREIGN KEY (codprj) REFERENCES public.project(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Query per modificare e trasformare in safety actions le informazioni dei JSO e dei Safety Report esistenti:

INSERT INTO safetyactions SELECT safprj.codprj, safprj.descrizio, objiter.tmcre AS tmcre, tmfin AS tmtarget, tmfeed AS tmclosed, '1' AS acttype, 'C' AS STATUS, safprj.codoper, '1' AS zord FROM safprj JOIN objiter ON safprj.codprj = objiter.codice JOIN iter ON objiter.codice = iter.codobj WHERE objiter.state = 'A' AND safprj.codsafety = 2; INSERT INTO safetyactions SELECT safprj.codprj, safprj.descrizio, objiter.tmcre AS tmcre, tmfin AS tmtarget, NULL AS tmclosed, '1' AS acttype, 'O' AS STATUS, safprj.codoper, '1' AS zord FROM safprj JOIN objiter ON safprj.codprj = objiter.codice JOIN iter ON objiter.codice = iter.codobj WHERE objiter.state <> 'A' AND safprj.codsafety = 2; INSERT INTO safetyactions SELECT safprj.codprj, safprj.descrizio, objiter.tmcre AS tmcre, tmfin AS tmtarget, tmfeed AS tmclosed, '2' AS acttype, 'C' AS STATUS, safprj.codoper, '1' AS zord FROM safprj JOIN objiter ON safprj.codprj = objiter.codice JOIN iter ON objiter.codice = iter.codobj WHERE objiter.state = 'A' AND safprj.codsafety = 4; INSERT INTO safetyactions SELECT safprj.codprj, safprj.descrizio, objiter.tmcre AS tmcre, tmfin AS tmtarget, NULL AS tmclosed, '2' AS acttype, 'O' AS STATUS, safprj.codoper, '1' AS zord FROM safprj JOIN objiter ON safprj.codprj = objiter.codice JOIN iter ON objiter.codice = iter.codobj WHERE objiter.state <> 'A' AND safprj.codsafety = 4; DELETE FROM safprj WHERE codsafety = 2; DELETE FROM safetyreport WHERE codice = 2; DELETE FROM safprj WHERE codsafety = 4; DELETE FROM safetyreport WHERE codice = 4; UPDATE safetyreport SET codice = 2, zord = 2 WHERE codice = 3; UPDATE safetyreport SET codice = 3, zord = 3 WHERE codice = 5; UPDATE safetyreport SET codice = 4, zord = 4 WHERE codice = 6; UPDATE safetyreport SET codice = 5, zord = 5 WHERE codice = 7; INSERT INTO safetyactions SELECT prjunsafe.codprj, prjunsafe.descrizio, objiter.tmcre, NULL AS tmtarget, tmfeed AS tmclosed, NULL AS acttype, 'C' AS STATUS, NULL AS codoper, pos AS zord FROM prjunsafe JOIN objiter ON prjunsafe.codprj = objiter.codice LEFT JOIN iter ON objiter.codice = iter.codobj WHERE objiter.tipo = 'H' AND objiter.state = 'A'; DELETE FROM objiter WHERE codice = 15456; INSERT INTO safetyactions SELECT prjunsafe.codprj, prjunsafe.descrizio, objiter.tmcre, NULL AS tmtarget, NULL AS tmclosed, NULL AS acttype, 'O' AS STATUS, NULL AS codoper, pos AS zord FROM prjunsafe JOIN objiter ON prjunsafe.codprj = objiter.codice LEFT JOIN iter ON objiter.codice = iter.codobj WHERE objiter.tipo = 'H' AND objiter.state <> 'A';

KPI #4 - 5S Score

1 - Plant Level:
Come periodo di riferimento si prende gli ultimi 365 giorni (in 12 mesi). Il plant rate è una media pesata per il numero di persone che lavora ad ogni asset dei vari 5s audit fatti.

2 - Organization Level:
Come periodo di riferimento si prende gli ultimi 365 giorni. Viene mostrato il plant rate medio del periodo selezionato, data una singola organizzazione.

3 - Franke Level:
Come periodo di riferimento si prende gli ultimi 365 giorni. Viene mostrata la media di tutti i plant rate medio per ogni organizzazione.

NB I target devono essere messi a livello di ubicaz e rappresenterà una linea orizzontale sopra il grafico.

Query per estrarre lo score (media voto delle 5 risposte dell'audit) del singolo audit. Ogni riga corrisponde ad un audit con il suo score medio. Se il codubi dell'audit è di tiposet 'P' allora abbiamo in mancost il numero di operatori che lavorano su quell'asset. Questo mancost ci servirà per fare la media pesata.

WITH RECURSIVE treeubi AS (SELECT u.* FROM ubicaz u WHERE u.codice = 'FKT' UNION ALL SELECT u.* FROM ubicaz u, treeubi WHERE u.codubib = treeubi.codice), sinans AS (SELECT codoper, MAX(codice) AS codice, codclista FROM answer GROUP BY codoper, codclista) SELECT objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, operato.nominati AS creator, treeubi.descrizio AS asset, treeubi.tiposet, treeubi.mancost, project.codubi, AVG(answer.value::NUMERIC) AS score FROM objiter INNER JOIN project ON objiter.codice = project.codice INNER JOIN operato ON objiter.codoper = operato.codice INNER JOIN treeubi ON project.codubi = treeubi.codice JOIN prjtask ON prjtask.codprj = objiter.codice JOIN clista ON clista.codptask = prjtask.codice JOIN sinans ON clista.codice = sinans.codclista JOIN answer ON sinans.codice = answer.codice WHERE objiter.tipo='P' AND objiter.tmcre >= 1672527600 AND objiter.tmcre <= 1704063599 GROUP BY objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, creator, asset, tiposet, mancost, project.codubi ORDER BY tmcre DESC

Dato che in precedenza gli audit venivano fatti a livello di teamboard (tiposet 'R') e questa specifica è cambiata negli ultimi due mesi proprio per gestire il numero di operatori per asset, è possibile che se un audit è stato precedentemente fatto a livello di teamboard non abbia mancost per fare la media pesata. In questo caso potremmo gestire ciò (a tendere non ci saranno più audit a livello di teamboard ma solo a livello di asset) sommando tutti gli operatori di tutti gli asset di ogni teamboard e facendo la media pesata con questo valore.

SELECT t.codice, SUM(a.mancost) FROM ubicaz t JOIN ubicaz a ON t.codice = a.codubib WHERE t.tiposet = 'R' GROUP BY t.codice

QUERY PER I GRAFICI
Questa query prende in ingresso un codubi (codice del plant), un fromtm ed un totm. I tm vengono utilizzati come filtro sul cambo objiter.tmcre, che dovrà essere incluso tra i due tm passati. Per default i due tm devono essere gli ultimi 12 mesi, escluso il mese corrente. Esempio, sono a gennaio 2024, il fromtm deve essere il 01/01/2023 ed il totm 31/12/2023

WITH RECURSIVE treeubi AS (SELECT u.* FROM ubicaz u WHERE u.codice = 'FKT' UNION ALL SELECT u.* FROM ubicaz u, treeubi WHERE u.codubib = treeubi.codice), sinans AS (SELECT codoper, MAX(codice) AS codice, codclista FROM answer GROUP BY codoper, codclista), scores AS (SELECT objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, operato.nominati AS creator, treeubi.descrizio AS asset, treeubi.tiposet, treeubi.mancost, project.codubi, AVG(answer.value::NUMERIC) AS score FROM objiter INNER JOIN project ON objiter.codice = project.codice INNER JOIN operato ON objiter.codoper = operato.codice INNER JOIN treeubi ON project.codubi = treeubi.codice JOIN prjtask ON prjtask.codprj = objiter.codice JOIN clista ON clista.codptask = prjtask.codice JOIN sinans ON clista.codice = sinans.codclista JOIN answer ON sinans.codice = answer.codice WHERE objiter.tipo='P' AND objiter.tmcre >= 1676502000 AND objiter.tmcre <= 1705391447 AND mancost IS NOT NULL AND mancost > 0 GROUP BY objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, creator, asset, tiposet, mancost, project.codubi ORDER BY tmcre DESC), totoper AS (SELECT SUM(mancost) AS total, MONTH, YEAR FROM scores GROUP BY MONTH, YEAR) SELECT 'FKT' AS resource, scores.year, scores.month AS xasys, SUM((mancost*score))/totoper.total AS v_fivesrate FROM scores JOIN totoper ON scores.year = totoper.year AND scores.month = totoper.month GROUP BY scores.year, scores.month, totoper.total, resource ORDER BY resource, scores.year DESC, scores.month DESC

Questa query, per FKT, ritorna per ogni mese il 5s rating, che è proprio il valore che serve a disegnare il grafico:
La seguente query è sufficiente sia per l'organization che per franke level, basta passare un codubi di organization o il codubi di franke

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke001' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), sinans AS ( SELECT codoper, MAX(codice) AS codice, codclista FROM answer GROUP BY codoper, codclista ), scores AS ( SELECT ancestors, ancestorscode, objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, operato.nominati AS creator, treeubi.descrizio AS asset, treeubi.tiposet, treeubi.mancost, project.codubi, AVG(answer.value::NUMERIC) AS score FROM objiter INNER JOIN project ON objiter.codice = project.codice INNER JOIN operato ON objiter.codoper = operato.codice INNER JOIN treeubi ON project.codubi = treeubi.codice JOIN prjtask ON prjtask.codprj = objiter.codice JOIN clista ON clista.codptask = prjtask.codice JOIN sinans ON clista.codice = sinans.codclista JOIN answer ON sinans.codice = answer.codice WHERE objiter.tipo='P' AND mancost IS NOT NULL AND mancost > 0 AND objiter.tmcre >= 1676502000 AND objiter.tmcre <= 1705391447 GROUP BY ancestors, ancestorscode, objiter.codice, objiter.tmcre, objiter.tipo, objiter.dayofmonth, objiter.month, objiter.year, project.descrizio, creator, asset, tiposet, mancost, project.codubi ORDER BY tmcre DESC ), totoper AS ( SELECT SUM(mancost) AS total, MONTH, YEAR FROM scores GROUP BY MONTH, YEAR ) SELECT REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), ' ', '') AS resource, REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', '') AS xasys, scores.year, scores.month, SUM((mancost*score))/totoper.total AS v_fivesrate FROM scores JOIN totoper ON scores.year = totoper.year AND scores.month = totoper.month GROUP BY scores.year, scores.month, totoper.total, resource, xasys ORDER BY resource, scores.year DESC, scores.month DESC;

Chiamata Agent KPI #4
PLANT level:

Nome dell'agente: graph

ask

request: fivescore

p1: rec(codubi,fromtm,totm,tiposet)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

tiposet = tipo settore (S)

retv: rec(resource,year,xasys,v_fivesrate) ESEMPIO:

resource = "FKT"

year = 2023

xasys = 12

v_fivesrate = 2.6

ORGANIZATIONAL and FRANKE level:

Nome dell'agente: graph

ask

request: fivescore

p1: rec(codubi,fromtm,totm,tiposet)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

tiposet = tipo settore (A o W)

retv: rec(resource,xasys,year,month,v_fivesrate) ESEMPIO:

resource = "CICBoardPlantFKTSwitzerlandAarburg"

xasys = "FKT"

year = 2023

month = 12

v_fivesrate = 0.2

KPI #5 - Nr. of deviations/Safety visits

Andrebbe aggiunto al DSFM un nuovo elemento, la gemba walk observaion. È un report che viene fatto dai manager e dai supervisori che vanno in visita nel processo. Dato che di fatto sarebbero identiche alle Job Safety Observations, con Bladimir abbiamo concordato di aggiungere un flag agli oggetti JSO per identificare quelli che sono JSO e quelli che sono Gemba Wolk Observation Report.
Per questo KPI si considereranno quindi tutti i JSO che hanno il flag "Gemba Walk Observation Report", ed in particolare le safety actions relative.
I "nr. of deviations" di un gemba walk sarebbero le azioni legate al gembra walk stesso.

ALTER TABLE project ADD COLUMN sogw INTEGER DEFAULT 0; COMMENT ON COLUMN project.sogw IS '0 -> classico JSO, 1 -> Safety Observation Gemba Walk.';

Nuovo campo sogw nella tabella project, se 1 -> Gemba Walk Observation, se 0, classico JSO. Quindi per questo KPI vanno prese in considerazione tutte e sole le action degli objiter di tipo 'H', legate ai project con sogw = 1.

Le safety visits sono dati che a tendere andremo ad imporarci da un file excel che ci metteranno a disposizione ogni mese, e deriva da uniestrazione dal loro cognos ibm. Al momento diamo loro la possibilità di inserire manualmente questi valori. Comunque andranno salvati in una tabella. Le safety visits sono per mese per plant.

CREATE TABLE public.kpiubiext ( codubi CHARACTER VARYING(51) NOT NULL, MONTH INTEGER NOT NULL, YEAR INTEGER NOT NULL, fte INTEGER ); COMMENT ON COLUMN kpiubiext.fte IS 'il numero di executed walks per mese da parte del business'; ALTER TABLE public.kpiubiext OWNER TO postgres; ALTER TABLE ONLY public.kpiubiext ADD CONSTRAINT ix_kpiubiext_pkey PRIMARY KEY (codubi, MONTH, YEAR); ALTER TABLE ONLY public.kpiubiext ADD CONSTRAINT ix_kpiubiext_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE CASCADE;

QUERY PER I GRAFICI

WITH RECURSIVE treeubi AS (SELECT u.* FROM ubicaz u WHERE u.codice = 'FKT' UNION ALL SELECT u.* FROM ubicaz u, treeubi WHERE u.codubib = treeubi.codice), kpiext AS (SELECT * FROM kpiubiext WHERE codubi = 'FKT') SELECT 'FKT' AS resource, objiter.month, objiter.year, COUNT(safetyactions.*) AS tasks, kpiext.fte, COUNT(safetyactions.*)::FLOAT/fte AS rate FROM objiter JOIN project ON objiter.codice = project.codice JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj JOIN kpiext ON objiter.month = kpiext.month AND objiter.year = kpiext.year WHERE tipo = 'H' AND project.sogw = 1 AND objiter.tmcre >= 1676502000 AND objiter.tmcre <= 1705391447 GROUP BY resource, objiter.month, objiter.year, fte ORDER BY YEAR DESC, MONTH DESC

Questa query, per FKT, ritorna per ogni mese rate del numero di actions sul numero di safety visits (kpiubiext.fte):
- A livello di Organization sarà la somma di tutte le actions del periodo stabilito sulla somma del numero FTE del periodo stabilito (per ogni plant dell'organization)

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke001' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), kpiext AS (SELECT kpiubiext.* FROM kpiubiext JOIN treeubi ON kpiubiext.codubi = treeubi.codice), base AS ( SELECT REPLACE(REPLACE(SPLIT_PART(treeubi.ancestors::text, ',', 2), '{',''), '"', '') AS resource, REPLACE(SPLIT_PART(treeubi.ancestorscode::text, ',', 2), '{', '') AS rescode, objiter.month, objiter.year, COUNT(safetyactions.*) AS tasks, kpiext.fte, COUNT(safetyactions.*)::FLOAT/fte AS rate FROM objiter JOIN project ON objiter.codice = project.codice JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj JOIN kpiext ON objiter.month = kpiext.month AND objiter.year = kpiext.year WHERE tipo = 'H' AND project.sogw = 1 AND objiter.tmcre >= 1676502000 AND objiter.tmcre <= 1705391447 AND REPLACE(SPLIT_PART(treeubi.ancestorscode::text, ',', 2), '{', '') = kpiext.codubi GROUP BY resource, rescode, objiter.month, objiter.year, fte ORDER BY YEAR DESC, MONTH DESC) SELECT base.resource, base.rescode AS xasys, SUM(tasks) AS v_task, SUM(fte) AS v_fte, SUM(tasks)::FLOAT/SUM(fte) AS v_rate FROM base GROUP BY resource, xasys

- A livello di Franke sarà la somma di tutte le actions del periodo stabilito sulla somma del numero FTE del periodo stabilito (per ogni organization Franke)

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), kpiext AS (SELECT kpiubiext.* FROM kpiubiext JOIN treeubi ON kpiubiext.codubi = treeubi.codice), base AS ( SELECT REPLACE(REPLACE(SPLIT_PART(treeubi.ancestors::text, ',', 2), '{',''), '"', '') AS resource, REPLACE(SPLIT_PART(treeubi.ancestorscode::text, ',', 2), '{', '') AS rescode, objiter.month, objiter.year, COUNT(safetyactions.*) AS tasks, kpiext.fte, COUNT(safetyactions.*)::FLOAT/fte AS rate FROM objiter JOIN project ON objiter.codice = project.codice JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj JOIN kpiext ON objiter.month = kpiext.month AND objiter.year = kpiext.year WHERE tipo = 'H' AND project.sogw = 1 AND objiter.tmcre >= 1676502000 AND objiter.tmcre <= 1705391447 AND REPLACE(SPLIT_PART(treeubi.ancestorscode::text, ',', 3), '{', '') = kpiext.codubi GROUP BY resource, rescode, objiter.month, objiter.year, fte ORDER BY YEAR DESC, MONTH DESC) SELECT base.resource, base.rescode AS xasys, SUM(tasks) AS v_sumtask, SUM(fte) AS v_sumfte, SUM(tasks)::FLOAT/SUM(fte) AS v_rate FROM base GROUP BY resource, xasys

Chiamata Agent KPI #5
PLANT level:

Nome dell'agente: graph

ask

request: deviations

p1: rec(codubi,fromtm,totm,tiposet)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

tiposet = tipo settore (S)

retv: rec(resource,year,xasys,v_task,v_fte,v_rate) ESEMPIO:

resource = "FKT"

year = 2024

xasys = 1

v_task = 5

v_fte = 14

v_rate = 0.35714285714285715

ORGANIZATIONAL level:

Nome dell'agente: prepstat

ask

request: kpi5.organization

p1: rec(codubi,fromtm,totm)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

retv: rec(resource,xasys,v_task,v_fte,v_rate) ESEMPIO:

resource = "CIC Board Plant FBS Germany Bad Säkingen"

xasys: "FBS"

v_task = 1

v_fte = 9

v_rate = 0.1111111111111111

FRANKE level:

Nome dell'agente: prepstat

ask

request: kpi5.franke

p1: rec(codubi,fromtm,totm)

codubi = codice ubicaz

fromtm = tm di inzio

fromtm = tm di fine

retv: rec(resource,xasys,v_sumtask,v_sumfte,v_rate) ESEMPIO:

resource = "Sinks"

xasys= "franke001"

v_sumtask = 134

v_sumfte = 197

v_rate = 0.6802030456852792

KPI #6 - Maturity Assessment Score

CREATE TABLE public.malevels ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(51), score INTEGER, bgcolor CHARACTER VARYING(51), fgcolor CHARACTER VARYING(51) ); ALTER TABLE public.malevels OWNER TO postgres; INSERT INTO public.malevels VALUES (1, 'Pathologic', 1, 'red', '#FFFFFF'); INSERT INTO public.malevels VALUES (2, 'Reactive', 2, 'orange', '#FFFFFF'); INSERT INTO public.malevels VALUES (3, 'Calculative', 3, 'yellow', '#000000'); INSERT INTO public.malevels VALUES (4, 'Proactive', 4, 'blue', '#FFFFFF'); INSERT INTO public.malevels VALUES (5, 'Innovative', 5, 'green', '#FFFFFF'); ALTER TABLE ONLY public.malevels ADD CONSTRAINT ix_malevels_pk PRIMARY KEY (codice); CREATE TABLE public.matopics ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(51), zord INTEGER ); ALTER TABLE public.matopics OWNER TO postgres; INSERT INTO public.matopics VALUES (1, 'Safety Culture', 1); INSERT INTO public.matopics VALUES (2, 'Governance, communication and training', 2); INSERT INTO public.matopics VALUES (3, 'Risk management', 3); INSERT INTO public.matopics VALUES (4, 'Task level instruction', 4); INSERT INTO public.matopics VALUES (5, 'Infrastructure', 5); INSERT INTO public.matopics VALUES (6, 'Driver for safety', 6); INSERT INTO public.matopics VALUES (7, 'Bradley curve', 7); INSERT INTO public.matopics VALUES (8, 'Safety Ambition', 8); ALTER TABLE ONLY public.matopics ADD CONSTRAINT ix_matopics_pk PRIMARY KEY (codice); CREATE TABLE public.mamatrix ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(1001), codlevel INTEGER, codtopic INTEGER ); ALTER TABLE public.mamatrix OWNER TO postgres; COMMENT ON COLUMN public.mamatrix.codlevel IS 'Riferimento a malevels.codice'; COMMENT ON COLUMN public.mamatrix.codtopic IS 'Riferimento a matopics.codice'; INSERT INTO public.mamatrix VALUES (1, 'Re-active safety culture, shortcomings not always addressed', 1, 1); INSERT INTO public.mamatrix VALUES (2, 'Re-active safety culture, shortcomings trigger action', 2, 1); INSERT INTO public.mamatrix VALUES (3, 'Re-active safety culture with some pro-active elements in place', 3, 1); INSERT INTO public.mamatrix VALUES (4, 'Pro-active safety culture at all levels. Elements of autonomous teams in place', 4, 1); INSERT INTO public.mamatrix VALUES (5, 'Fully effective pro-active safety culture at all levels of the organisation', 5, 1); INSERT INTO public.mamatrix VALUES (6, 'Governance, communication & training on an ad hoc basis', 1, 2); INSERT INTO public.mamatrix VALUES (7, 'Governance, communication & training processes initiated', 2, 2); INSERT INTO public.mamatrix VALUES (8, 'Governance, communication & training processes in place, training is being applied', 3, 2); INSERT INTO public.mamatrix VALUES (9, 'PDCA applied on governance, communication & training', 4, 2); INSERT INTO public.mamatrix VALUES (10, 'GOvernance, communication & training fully effective', 5, 2); INSERT INTO public.mamatrix VALUES (11, 'Ad hoc risk management approach, lack of structure & processes', 1, 3); INSERT INTO public.mamatrix VALUES (12, 'Safety standards partially defined and risk assessmentprocess initiated', 2, 3); INSERT INTO public.mamatrix VALUES (13, 'Safety Standards defined & documented, risk assessment process in place', 3, 3); INSERT INTO public.mamatrix VALUES (14, 'Risk management audit & optimization process initiated (including Moc)', 4, 3); INSERT INTO public.mamatrix VALUES (15, 'Risk management audit & optimization process in place and effective (including Moc)', 5, 3); INSERT INTO public.mamatrix VALUES (16, 'Task level instructions (with safety being integrated) are hardly available', 1, 4); INSERT INTO public.mamatrix VALUES (17, 'Task level instructions available for most standard tasks, permit system initiated', 2, 4); INSERT INTO public.mamatrix VALUES (18, 'Task level instructions available for most standard tasks, permit system in place', 3, 4); INSERT INTO public.mamatrix VALUES (19, 'Instructions available for all tasks, permits system fully implemented. High degree of compliance', 4, 4); INSERT INTO public.mamatrix VALUES (20, 'Instructions issued for every task done. Very high level of compliance', 5, 4); INSERT INTO public.mamatrix VALUES (21, 'Infrastructure meets legal and industry standards partially (<90%)', 1, 5); INSERT INTO public.mamatrix VALUES (22, 'Infrastructure meets legal and industry standards partially (>90%)', 2, 5); INSERT INTO public.mamatrix VALUES (23, 'Infrastructure meets legal and industry standards', 3, 5); INSERT INTO public.mamatrix VALUES (24, 'Elimination of risks is partially done during the design phase', 4, 5); INSERT INTO public.mamatrix VALUES (25, 'Elimination of risks is maximised during the design phase', 5, 5); INSERT INTO public.mamatrix VALUES (26, 'Driver for safety is the Health & Safety team', 1, 6); INSERT INTO public.mamatrix VALUES (27, 'Safety is driven by management, still dependence on the H&S team', 2, 6); INSERT INTO public.mamatrix VALUES (28, 'Safety is driven by management', 3, 6); INSERT INTO public.mamatrix VALUES (29, 'Safety is driven by management and supervision', 4, 6); INSERT INTO public.mamatrix VALUES (30, 'Safety is driven by management and supervision and the operational teams', 5, 6); INSERT INTO public.mamatrix VALUES (31, 'Bradley curve status: Natural instinct', 1, 7); INSERT INTO public.mamatrix VALUES (32, 'Dependent, legal compliance', 2, 7); INSERT INTO public.mamatrix VALUES (33, 'Dependent, Corporate Ambition', 3, 7); INSERT INTO public.mamatrix VALUES (34, 'Independent, Corporate Ambition', 4, 7); INSERT INTO public.mamatrix VALUES (35, 'Interdependent, Corporate Ambition', 5, 7); INSERT INTO public.mamatrix VALUES (36, 'No formal safety ambition', 1, 8); INSERT INTO public.mamatrix VALUES (37, 'Legal compliance as a main driver', 2, 8); INSERT INTO public.mamatrix VALUES (38, 'Comporate ambition (Zero Harm) as a main driver', 3, 8); INSERT INTO public.mamatrix VALUES (39, 'Corporate ambition partially implemented', 4, 8); INSERT INTO public.mamatrix VALUES (40, 'Corporate ambition implemented', 5, 8); ALTER TABLE ONLY public.mamatrix ADD CONSTRAINT ix_mamatrix_pk PRIMARY KEY (codice); ALTER TABLE ONLY public.mamatrix ADD CONSTRAINT ix_mamatrix_codlevel FOREIGN KEY (codlevel) REFERENCES public.malevels(codice) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE ONLY public.mamatrix ADD CONSTRAINT ix_mamatrix_codtopic FOREIGN KEY (codtopic) REFERENCES public.matopics(codice) ON UPDATE CASCADE ON DELETE RESTRICT; CREATE TABLE public.maplantaudit ( codice INTEGER NOT NULL, codubi CHARACTER VARYING(51) NOT NULL, tm DOUBLE PRECISION NOT NULL, DATA CHARACTER VARYING(51), codoper CHARACTER VARYING(51) ); ALTER TABLE public.maplantaudit OWNER TO postgres; ALTER TABLE ONLY public.maplantaudit ADD CONSTRAINT ix_maplantaudit_pk PRIMARY KEY (codice); ALTER TABLE ONLY public.maplantaudit ADD CONSTRAINT ix_maplantaudit_codoper FOREIGN KEY (codoper) REFERENCES public.operato(codice) ON UPDATE CASCADE ON DELETE RESTRICT; ALTER TABLE ONLY public.maplantaudit ADD CONSTRAINT ix_maplantaudit_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE CASCADE; CREATE TABLE public.maplantscore ( codaudit INTEGER NOT NULL, score DOUBLE PRECISION, codtopic INTEGER NOT NULL ); ALTER TABLE public.maplantscore OWNER TO postgres; COMMENT ON COLUMN public.maplantscore.codaudit IS 'Riferimento a maplantaudit.codice'; COMMENT ON COLUMN public.maplantscore.score IS 'Voto che viene dato nel singolo audit, da 1.0 a 5.0'; ALTER TABLE ONLY public.maplantscore ADD CONSTRAINT ix_maplantscore_codtopic FOREIGN KEY (codtopic) REFERENCES public.matopics(codice) ON UPDATE CASCADE ON DELETE CASCADE; ALTER TABLE ONLY public.maplantscore ADD CONSTRAINT ix_maplantscore_codaudit FOREIGN KEY (codaudit) REFERENCES public.maplantaudit(codice) ON UPDATE CASCADE ON DELETE CASCADE;

Ogni plant deve poter impostare il suo target per il maturity assessment. Aggiunta di un campo in ubicaz che gestisce questo target:

ALTER TABLE ubicaz ADD COLUMN maturitytarget DOUBLE PRECISION;

KPI

NB: Livello stabilimento => ubicaz.tiposet = 'S'. Livello di organizzazione => ubicaz.tiposet = 'A'. Franke è suddivisa in 5 organizzazioni: Sinks, Hoodss, Food Service, Supply Chain, Coffee System.
Quando si parla a livello di plant si intende la singola ubicaz, quindi il codice di un plant
Quando si parla a livello di organizzazione, si intende tutte le ubicaz figlie di una certa organizzazione. Esempio -> organizzazione sinks, tutte le ubicaz di sinks
Quando si parla a livello di franke, si intende tutte le ubicaz di tipo 'A', ovvero tutte le organizzazioni.
Per il grafico si vuole utilizzare il radarchart:

QUERY PER I GRAFICI
- Livello di stabilimento:
Si prende l'ultimo audit inserito:

WITH audit AS (SELECT * FROM maplantaudit WHERE codubi = 'FKT' AND tm>=1674169200 AND tm <= 1705311642 ORDER BY tm DESC LIMIT 1) SELECT ubicaz.maturitytarget AS v_target, matopics.codice AS codtopic, ubicaz.codice, ubicaz.descrizio, ubicaz.maturitytarget, matopics.descrizio AS xasys, maplantscore.score AS v_score, tm, codaudit FROM audit JOIN maplantscore ON audit.codice = maplantscore.codaudit JOIN matopics ON maplantscore.codtopic = matopics.codice JOIN ubicaz ON audit.codubi = ubicaz.codice ORDER BY matopics.zord

- Organizational & Franke Level
In questo caso i radarcharts saranno 2, uno con la media voti per location e l'altro con la media voti per topic. Di seguito le due query:
LOCATION:

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.maturitytarget, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke001' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.maturitytarget, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), lastaudit AS (SELECT MAX(tm) AS tm, codubi FROM maplantaudit JOIN treeubi ON maplantaudit.codubi = treeubi.codice WHERE tm>= 1674169200 AND tm <= 1705311642 GROUP BY codubi), audit AS (SELECT maplantaudit.* FROM maplantaudit JOIN lastaudit ON maplantaudit.tm = lastaudit.tm AND maplantaudit.codubi = lastaudit.codubi) SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(treeubi.ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(treeubi.ancestorscode::text, ',', 2), '{', ''), '}', '') AS xasys, treeubi.maturitytarget AS v_target, AVG(maplantscore.score) AS v_score FROM audit JOIN maplantscore ON audit.codice = maplantscore.codaudit JOIN matopics ON maplantscore.codtopic = matopics.codice JOIN treeubi ON audit.codubi = treeubi.codice GROUP BY resource, xasys, maturitytarget

TOPIC:

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.maturitytarget, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke001' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.maturitytarget, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), lastaudit AS (SELECT MAX(tm) AS tm, codubi FROM maplantaudit JOIN treeubi ON maplantaudit.codubi = treeubi.codice WHERE tm>= 1674169200 AND tm <= 1705311642 GROUP BY codubi), audit AS (SELECT maplantaudit.* FROM maplantaudit JOIN lastaudit ON maplantaudit.tm = lastaudit.tm AND maplantaudit.codubi = lastaudit.codubi) SELECT matopics.codice AS codtopic, matopics.descrizio AS xasys, treeubi.maturitytarget AS v_target, AVG(maplantscore.score) AS v_score FROM audit JOIN maplantscore ON audit.codice = maplantscore.codaudit JOIN matopics ON maplantscore.codtopic = matopics.codice JOIN treeubi ON audit.codubi = treeubi.codice GROUP BY matopics.codice, matopics.descrizio, maturitytarget

La media dei punteggi dell'ultimo audit per ogni ubicaz dell'organizzazione (nel caso di franke, per ogni orgranizzazione di franke)

Chiamata Agent KPI #6
PLANT level:

Nome dell'agente: prepstat

ask

request: kpi6.plant

p1: rec(codubi,fromtm,totm)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

retv: rec(v_target,codtopic,codice,descrizio,maturitytarget,xasys,v_score,tm,codaudit) ESEMPIO:

v_target = 3

codtopic = 1

codice = "FKT"

descrizio = "CIC Board Plant FKT Switzerland Aarburg"

maturitytarget = 3

xasys = "Safety Culture"

v_score = 2.8

tm = 1705327488

codaudit = 12

ORGANIZATIONAL and FRANKE level:

Nome dell'agente: prepstat

ask

request: kpi6

p1: rec(_subkey,codubi,fromtm,totm)

_subkey = subkey delle query da eseguire divise da virgola (location,topic)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

retv: i valori di "kpi6.location" e "kpi6.topic" ritorneranno come stringhe!

[ { "kpi6.location":[ { "resource":"CIC Plant FIM IND Aurangabad", "xasys":"FIM", "v_target":3.0, "v_score":2.3999999999999999 }, ... ], "kpi6.topic":[ { "codtopic":2, "xasys":"Governance, communication and training", "v_target":3.0, "v_score":2.3999999999999999 }, ... ] } ]

KPI #7 - Nr° Actions closed/open

Monitoraggio del rate di chiusura delle azioni che provengono dalle JSO, Safety Reports e Risk Assessment.

Plant Level:

Organization Level:

Franke Level:

Esempio di due stack diversi sullo stesso chart

QUERY PER I GRAFICI

WITH RECURSIVE treeubi AS (SELECT u.* FROM ubicaz u WHERE u.codice = 'FKT' UNION ALL SELECT u.* FROM ubicaz u, treeubi WHERE u.codubib = treeubi.codice), allacts AS (SELECT EXTRACT(MONTH FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS MONTH, EXTRACT(YEAR FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS YEAR, COUNT(safetyactions.*) AS total FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 GROUP BY MONTH, YEAR), closedacts AS (SELECT EXTRACT(MONTH FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS MONTH, EXTRACT(YEAR FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS YEAR, COUNT(safetyactions.*) AS numclosed FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'C' AND (safetyactions.tmclosed-safetyactions.tmcre)/86400 < 90 GROUP BY MONTH, YEAR), openacts AS (SELECT EXTRACT(MONTH FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS MONTH, EXTRACT(YEAR FROM TIMESTAMP WITH TIME ZONE 'epoch' + tmcre * INTERVAL '1 second') AS YEAR, COUNT(safetyactions.*) AS numopen FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'O' AND (tm()-safetyactions.tmcre)/86400 > 90 GROUP BY MONTH, YEAR) SELECT DISTINCT 'FKT' AS resource, allacts.month AS xasys, allacts.year, total AS v_total, numclosed AS v_numclosed, numopen AS v_numopen FROM allacts LEFT JOIN closedacts ON allacts.month = closedacts.month AND allacts.year = closedacts.year LEFT JOIN openacts ON allacts.month = openacts.month AND allacts.year = openacts.year ORDER BY YEAR DESC, xasys DESC

Organization Level:

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke001' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), allacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS total FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 GROUP BY resource, rescode), closedacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS numclosed FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'C' AND (safetyactions.tmclosed-safetyactions.tmcre)/86400 < 90 GROUP BY resource, rescode), openacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS numopen FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'O' AND (tm()-safetyactions.tmcre)/86400 > 90 GROUP BY resource, rescode) SELECT allacts.resource, allacts.rescode AS xasys, total AS v_total, numclosed AS v_numclosed, numopen AS v_numopen FROM allacts LEFT JOIN closedacts ON allacts.rescode = closedacts.rescode LEFT JOIN openacts ON allacts.rescode = openacts.rescode ORDER BY resource

Franke Level:

WITH RECURSIVE treeubi AS ( SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, ARRAY[]::VARCHAR[] || ubicaz.descrizio AS ancestors, ARRAY[]::VARCHAR[] || ubicaz.codice AS ancestorscode, ARRAY[]::VARCHAR[] || ubicaz.tiposet AS ancestorsts, mancost FROM ubicaz WHERE codice = 'franke' UNION ALL SELECT ubicaz.codice, ubicaz.descrizio, ubicaz.tiposet, ubicaz.codubib, treeubi.ancestors || ubicaz.descrizio, treeubi.ancestorscode || ubicaz.codice, treeubi.ancestorsts || ubicaz.tiposet, ubicaz.mancost FROM ubicaz, treeubi WHERE ubicaz.codubib = treeubi.codice ), allacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS total FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 GROUP BY resource, rescode), closedacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS numclosed FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'C' AND (safetyactions.tmclosed-safetyactions.tmcre)/86400 < 90 GROUP BY resource, rescode), openacts AS (SELECT REPLACE(REPLACE(REPLACE(SPLIT_PART(ancestors::text, ',', 2), '{',''), '}', ''), '"', '') AS resource, REPLACE(REPLACE(SPLIT_PART(ancestorscode::text, ',', 2), '{', ''), '}', '') AS rescode, COUNT(safetyactions.*) AS numopen FROM project JOIN treeubi ON project.codubi = treeubi.codice JOIN safetyactions ON project.codice = safetyactions.codprj WHERE safetyactions.tmcre >= 1676502000 AND safetyactions.tmcre <= 1705391447 AND safetyactions.status = 'O' AND (tm()-safetyactions.tmcre)/86400 > 90 GROUP BY resource, rescode) SELECT allacts.resource AS xasys, allacts.rescode, total AS v_total, numclosed AS v_numclosed, numopen AS v_numopen FROM allacts LEFT JOIN closedacts ON allacts.rescode = closedacts.rescode LEFT JOIN openacts ON allacts.rescode = openacts.rescode ORDER BY xasys

Chiamata Agent KPI #7
PLANT level:

Nome dell'agente: graph

ask

request: maturity

p1: rec(codubi,fromtm,totm,tiposet)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

tiposet = tipologia settore (S)

retv: rec(resource,xasys,year,v_total,v_numclosed,v_numopen) ESEMPIO:

resource = "FKT"

xasys = 1

year = 2024

v_total = 9

v_numclosed = 0

v_numopen = 0

ORGANIZATIONAL level:

Nome dell'agente: prepstat

ask

request: kpi7.organization

p1: rec(codubi,fromtm,totm)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

retv: rec(resource,xasys,v_total,v_numclosed,v_numopen) ESEMPIO:

resource = "CIC Board Plant FBS Germany Bad Säkingen"

xasys = ""FBS""

v_total = 1

v_numclosed = "" (se NULL prepstat ritorna "")

v_numopen = 1

FRANKE level:

Nome dell'agente: prepstat

ask

request: kpi7.franke

p1: rec(codubi,fromtm,totm)

codubi = codice ubicaz

fromtm = tm di inzio

totm = tm di fine

retv: rec(resource,xasys,v_total,v_numclosed,v_numopen) ESEMPIO:

xasys = "Food Services"

rescode = "franke005"

v_total = 936

v_numclosed = 369

v_numopen = 508

RIKS ASSESSMENT

Utilizzo di un nuovo objiter, di tipo 'U'.
Un Risk Assessment è simile, a livello di struttura, ad un JSO, per cui si andranno a modificare le pagine di gestione del JSO per poter gestire anche questo nuovo tipo di oggetto.
Per il risk assessment abbiamo bisogno di alcune tabelle anagrafiche.

CREATE TABLE public.rafrequence ( codice CHARACTER VARYING(11) NOT NULL, descrizio CHARACTER VARYING(51), severity INTEGER ); ALTER TABLE public.rafrequence OWNER TO postgres; COMMENT ON TABLE public.rafrequence IS 'Tabella delle frequenze ammesse per il risk assessment'; INSERT INTO public.rafrequence VALUES ('C', 'Continua', 1); INSERT INTO public.rafrequence VALUES ('D', 'Giornaliera', 2); INSERT INTO public.rafrequence VALUES ('W', 'Settimanale', 3); INSERT INTO public.rafrequence VALUES ('M', 'Mensile', 4); INSERT INTO public.rafrequence VALUES ('Y', 'Annuale', 5); ALTER TABLE ONLY public.rafrequence ADD CONSTRAINT ix_rafrequence_pk PRIMARY KEY (codice); -- Per gestire i due nuovi campi hazard description e hazard control ALTER TABLE project ADD COLUMN hazard VARCHAR(501); ALTER TABLE project ADD COLUMN hazardctrl VARCHAR(501); ALTER TABLE project ADD COLUMN rafreq VARCHAR(11); ALTER TABLE project ADD COLUMN crlsev INTEGER; ALTER TABLE project ADD COLUMN crlprob INTEGER; ALTER TABLE project ADD COLUMN frlsev INTEGER; ALTER TABLE project ADD COLUMN frlprob INTEGER; --Severity CREATE TABLE public.raseverity ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(51), rating INTEGER ); ALTER TABLE public.raseverity OWNER TO postgres; COMMENT ON TABLE public.raseverity IS 'Tabella delle severità per il risk management'; INSERT INTO public.raseverity VALUES (1, 'Fatale o Fatale Multiplo', 16); INSERT INTO public.raseverity VALUES (2, 'Disabilità Permanente', 8); INSERT INTO public.raseverity VALUES (3, 'Tempo Perso', 4); INSERT INTO public.raseverity VALUES (4, 'Cure Mediche', 2); INSERT INTO public.raseverity VALUES (5, 'Primo Soccorso', 1); ALTER TABLE ONLY public.raseverity ADD CONSTRAINT ix_raseverity_pk PRIMARY KEY (codice); --Probability CREATE TABLE public.raprobability ( codice INTEGER NOT NULL, descrizio CHARACTER VARYING(51), rating INTEGER ); ALTER TABLE public.raprobability OWNER TO postgres; COMMENT ON TABLE public.raprobability IS 'Tabella delle probabilità previste nel Rik Assessment'; INSERT INTO public.raprobability VALUES (1, 'Impossibile', 1); INSERT INTO public.raprobability VALUES (2, 'Molto Improbabile', 2); INSERT INTO public.raprobability VALUES (3, 'Improbabile', 4); INSERT INTO public.raprobability VALUES (4, 'Possibile', 8); INSERT INTO public.raprobability VALUES (5, 'Probabile', 30); INSERT INTO public.raprobability VALUES (6, 'Molto Probabile', 60); ALTER TABLE ONLY public.raprobability ADD CONSTRAINT ix_raprobability_pk PRIMARY KEY (codice);

COGNOS KPI

Creato un nuovo ruolo all'interno del digcic.
Utente: cognos_user
Password: W4rJA5xmC92yZ$RGKb#iKA
Questo utente ha accesso ad una sola tabella del database, la cognoskpi (al momento, 06-03-2024, la struttura è temporanea). Una volta al mese cognos si connetterà a questa tabella per inserire i dati dei KPI.

Email Notification System

Si richiede di sviluppare un sistema di notifica tramite email quando:
1) Viene assegnato/riassegnato un responsabile ad una safety action
2) Viene assegnato/riassegnato un problem solver ad un action plan

Safety Action
Una safety action è un'azione solitamente collegata ai Job Safety Observation e alle Vulnerability Management. Ogni azione ha un responsabile che si dovrà occupare di eseguirla. Il responsabile viene identificato nel campo safetyactions.codoper

Action Plan
Esistono 4 tipologie di actionplan all'interno del DSFM. Quality, Delivery, Cost e Maintenance. Gli action plan sono objiter di tipo Q (quality), O (cost), W (delivery), I (maintenance). L'utente a cui è assegnato un actionplan si trova nel campo codoperres della tabella project

Il sistema di notifica dovrà essere configurabile ed in particolare:
- potrà essere abilitato per alcuni plant (ubicaz.tiposet = 'S').
- potrà essere abilitato per le safety action
- potrà essere abilitato per ogni singolo action plan

Ogni action plan ed ogni safety action saranno collegati ad una ubicaz (che potrà essere di tiposet S, R o P).

Se gerarchicamente l'ubicaz associata ad una safety action o ad un action plan appartiene ai plant abilitati e se l'oggetto stesso (safety action o lo specifico action plan) è abilitato all'invio della notifica, sarà possibile l'invio delle email verso il responsabile definito.

Quando inviare l'email?
Al salvataggio (inserimento o update) di un action plan o di una safety action vanno verificate le seguenti condizioni:
- gerarchicamente l'ubicaz associata ad una safety action o ad un action plan appartiene ai plant abilitati

WITH RECURSIVE treeubi AS ( SELECT u.* FROM ubicaz u WHERE u.codice = project.codubi UNION ALL SELECT u.* FROM ubicaz u, treeubi WHERE u.codice = treeubi.codubib ) SELECT DISTINCT treeubi.* FROM treeubi WHERE tiposet = 'S'

- l'oggetto stesso (safety action o lo specifico action plan) è abilitato
- il responsabile dell'azione è definito

Se tutte queste condizioni sono vere, l'email dovrà essere inviata al responsabile.
Quando viene assegnato un nuovo responsabile (e rimangono valide le condizioni predecenti), il vecchio responsabile dovrà essere notificato del cambio owner ed il nuovo responsabile dovrà essere notificato dell'avvenuta assegnazione di una SA o di un AP

Creazioni tabelle dei setting

CREATE TABLE public.emailsetting ( codubi CHARACTER VARYING(51) NOT NULL, TYPE CHARACTER VARYING(2) NOT NULL, tmreminder INTEGER DEFAULT 0, deflang VARCHAR(8) ); ALTER TABLE public.emailsetting OWNER TO postgres; COMMENT ON TABLE public.emailsetting IS 'Tabella che configura il sistema di notifica email. Gli stabilimenti presenti in questa tabella (codubi) potranno ricevere notifiche per gli oggetti definiti dal campo type. '; COMMENT ON COLUMN public.emailsetting.type IS 'Q: Action Plan Quality, O: Action Plan Cost, W: Action Plan Delivery, I: Action Plan Maintenance, S: Safety Actions'; COMMENT ON COLUMN public.emailsetting.tmreminder IS 'il tm in secondi per cui deve essere inviata un''email di reminder. Se 0 il reminder non è attivo'; ALTER TABLE ONLY public.emailsetting ADD CONSTRAINT ix_emailsetting_pk PRIMARY KEY (codubi, TYPE); ALTER TABLE ONLY public.emailsetting ADD CONSTRAINT ix_emailsetting_codubi FOREIGN KEY (codubi) REFERENCES public.ubicaz(codice) ON UPDATE CASCADE ON DELETE CASCADE NOT VALID; CREATE TABLE public.emailope ( codice DOUBLE PRECISION NOT NULL, TYPE CHARACTER VARYING(2) NOT NULL, codoper CHARACTER VARYING(51), tm DOUBLE PRECISION, tmlast DOUBLE PRECISION ); ALTER TABLE public.emailope OWNER TO postgres; COMMENT ON TABLE public.emailope IS 'In questa tabella vengono salvati gli invii email effettuati'; COMMENT ON COLUMN public.emailope.codice IS 'questo codice fa riferimento a objiter.codice se type è Q,O,W,I. Altrimenti farà riferimento al campo safetyactions.codice se di tipo S'; COMMENT ON COLUMN public.emailope.type IS 'Valori ammessi: Q: Quality Action Plan, O: Cost Action Plan, W: Delivery Action Plan, I: Maintenance Action Plan, S: Safety Action'; COMMENT ON COLUMN public.emailope.codoper IS 'l''utente che dovrà ricevere l''email'; COMMENT ON COLUMN public.emailope.tm IS 'il tm di primo invio email'; COMMENT ON COLUMN public.emailope.tmlast IS 'il tm dell''ultimo invio fatto'; ALTER TABLE ONLY public.emailope ADD CONSTRAINT ix_emailope_pk PRIMARY KEY (codice, TYPE); ALTER TABLE ONLY public.emailope ADD CONSTRAINT ix_emailope_codoper FOREIGN KEY (codoper) REFERENCES public.operato(codice) ON UPDATE CASCADE ON DELETE RESTRICT NOT VALID;

Creazione di un campo codice univoco per la tabella safetyactions
Creare un campo codice per la tabella safetyactions e valorizzarlo con un id incrementale:

ALTER TABLE safetyactions ADD COLUMN codice FLOAT; WITH numerati AS ( SELECT ctid, ROW_NUMBER() OVER () AS nuovo_codice FROM safetyactions ) UPDATE safetyactions SET codice = numerati.nuovo_codice FROM numerati WHERE safetyactions.ctid = numerati.ctid;

Ricordarsi di fare la addrecnume!!