Creazione Data Entry per le RDA

Le RDA (Richieste di Acquisto) vengono generate dai Cantieri a fronte di esigenze di approvvigionamento materiali: queste, una volta emesse, devono essere approvate al fine di attivare la successiva emissione dell' ordine o degli ordini ai fornitori. In questa sezione quello che ci interessa è la creazione di una semplice funzione di Data Entry che ci consenta di creare delle RDA (di fatto andiamo a simulare una funzionalità dell' ERP) associando alle stesse le informazioni necessarie per la gestione dell' Work Flow di approvazione.

Possiamo ipotizzare che l' approvazione di una RDA, e l' eventuale numero di livelli, dipenda dalle informazioni:

  • Tipologia di materiale di cui si richiede l' approvvigionamento;
  • Importo della richiesta;
  • Cantiere che ha fatto la richiesta: in realtà Area Geografica da cui proviene la richiesta;

Per semplicità ci limitiamo a considerare max 4 livelli di approvazione che proponiamo in ordine crescente di importanza:

  • Liv-0: di fatto l' approvazione non è richiesta;
  • Liv-1: è richiesta l' approvazione del direttore tecnico di cantiere o del responsabile commerciale di cantiere ;
  • Liv-2: è richiesta l' approvazione del responsabile commerciale di cantiere o del responsabile di tutti i cantieri;
  • Liv-3: è richiesta l' approvazione del responsabile di tutti i cantieri, figura che risiede nella sede principale dell' Azienda;

Ovviamente i livelli precedenti a quello richiesto devono essere approvati.

 

Le regole che governano l' approvazione verranno viste nella sezione dedicata alla realizzazione del Motore di Workflow.

A fronte di quanto riportato, per poter realizzare questa funzione di Data Entry è indispensabile creare gli oggetti che seguono:

 

Entità Cantiere

Definita solo sul Box come elemento di tipo List not editable: contiene l' elenco dei Cantieri che possono emettere RDA. La chiamiamo WF_Cantieri.

Per ogni cantiere vengono definite le info che seguono;

  • Key: identificativo del Cantiere;
  • Nome: nome del Cantiere;
  • AreaGeografica: area geografica di appartenenza del Cantiere. Colonna di tipo List, prevede i valori: EUROPA, AFRICA, ASIAITALIA;

Inseriamo i seguenti Cantieri: 

CNT-EUROAutostrada Berlino MonacoEUROPA
CNT-ITALIAComplesso Alberghiero RavennaITALIA
CNT-AFRICACostruzione villaggio in LibiaAFRICA
CNT-ASIAComplesso ospedaliero PechinoASIA

 

Entità Approvatori

Definita solo sul Box come elemento di tipo List not editable: contiene l' elenco degli approvatori che possono approvare le RDA. La chiamiamo WF_Approvatori.

Per ogni approvatore vengono definite le info che seguono;

  • Key: identificativo dell' approvatore;
  • Nome: nome dell' approvatore;
  • Ruolo: ruolo dell' approvatore. Colonna di tipo List, prevede i valori: DT-CANT (Direttore Tecnico di Cantiere), DC-CANT (Direttore Commerciale di Cantiere), RC-SEDE (Responsabile di tutti i Cantieri);

Inseriamo i seguenti Approvatori:

RFRossi FrancoDT-CANT
BGBianchi GiulioDT-CANT
VCVerdi CesareDC-CANT
OROrsi RiccardoRC-SEDE

 

Il filmato che segue mostra come operare con la BBW per creare gli elementi List Cantieri e Approvatori:

 

 

 

Entità RDA

L' entità risiede su SQL: questo significa che si deve creare un DB-SQL (lo chiamiamo CPQ_WorkFlow) per la scrittura e la lettura delle RDA (e quindi una tabella capace di contenerne le informazioni) e che si deve disporre di tutti i metodi necessari per l' operatività sul DB. 

Sull' Web.config sez. appSettings deve essere inserita la stringa di connessione:

[add key="SQL_ConnString" value="Data Source=aaa.bbb.cc.dd;Initial Catalog=CPQ_WorkFlow;User id=BBTAdmin;Password=xxt@yy1y;" /]

Sul Box l' entità viene definita come elemento di tipo List editable: la chiamiamo WF_Rda. Possiamo ipotizzare questo tracciato:

  • Key: chiave univoca dell' elemento List. Di fatto una Guid;
  • Identificativo: identificativo della RDA. Possiamo identificarlo come numero della RDA;
  • DescrBreve: breve descrizione della RDA;
  • TipoMateriale: tipologia di materiale di cui si richiede l' approvvigionamento.Colonna di tipo List che elenca le tipologie ammesse: UFF(materiale d' ufficio), MACC (macchinari), STRUTT (strutture), COSTR (materiali di costruzione);
  • Importo: importo della richiesta;
  • RichiestoDa: identificativo del Cantiere che ha emesso la RDA;
  • MaxLivApprRichiesto: massimo livello di approvazione richiesto;
  • LivAppAttuale: livello di approvazione raggiunto;
  • ApprovatoDa: identificativo dell' ultimo approvatore;
  • LivAppProssimo: prossimo livello di approvazione;

 

Oltre all' iserimento dell' elemento List WF_Rda dobbiamo prevedere anche l' iserimento dei campi elementari che ci consentiranno di aggiornare l' entità stessa (avremo una Grid per i dati ed n-campi corrispondenti alle colonne per l' aggiornamento dlle Grid): stiamo parlando dei campi Identificativo, DescrBreve, ..... Questi campi dovranno avere lo stesso nome delle colonne dell' elemento, cosa che ci permetterà di utilizzare metodi standard per l' aggiornamento del DB-SQL evitando così la scrittura di codice.

 

Il filmato che segue mostra come operare per creare l' elemento del Box WF_Rda e la tabella SQL WF_Rda e come creare i singoli campi.

 

 

 

Pagina WEB per l' inserimento delle RDA

La pagina ci serve per simulare l' inserimento delle RDA, operazione che per logica dovrebbe di fatto essere prevista in ambiente ERP. 

La pagina ci deve consentire di:

  • Qualificarci come Cantiere;
  • Creare, modificare, eliminare o annullare RDA;
  • Visualizzare RDA;

L' eliminazione di una RDA la possiamo condizionare al fatto che la stessa ancora non sia stata presa in considerazione dall' Work Flow: l' annullamento è sempre possibile. Queste ultime considerazioni ci impongono di aggiungere un campo di stato (campo che chiamiamo Stato) alla WF_Rda. Lo Stato è di tipo List e prevede i valori:

  • NEW: RDA creata e non ancora presa in carico dall' Work Flow;
  • WF: RDA in carico all' Work Flow;
  • CANC: RDA annullata;
  • APPR: RDA approvata;
  • REF: non approvata, rifiutata;

Il filmato che segue mostra come modificare la WF_Rda:

 

 

Per quanto riguarda la corrispondente tabella SQL, la possiamo aggiornare manualmente o ricreare usando lo script generato dalla BBW.

 

Qualificarsi come Cantiere

Al momento ci limitiamo a fare le cose semplici in quanto il nostro obiettivo non è quello di vedere come un Cantiere si può qualificare ma avere un Cantiere definito per procedere:

  1. Nella pagina delle RDA inseriamo WF_Cantieri come campo di tipo List selezionabile: utile per selezionare il cantiere che crea la RDA;
  2. Vincoliamo le possibili operazioni di aggiornamento delle RDA alla definizione del Cantiere: un Cantiere è definito se WF_Cantieri è selezionato;

Annotazione

Per stabilire se il Cantiere è o meno selezionato si utilizza il metodo standard sotto riportato: 

 

bool BBP_ObjectIsDefined(string containerOfObjectName): verifica se l' oggetto passato è definito sul Box e valorizzato. Se String o Message con valorizzato si intende diverso da "", se List si intende Selected. Per utilizzare questo metodo deve essere definito un oggetto di tipo Boolean chiamato "StatusOfCall" che il metodo stesso inizializza a true se l' oggetto è definito o a false in caso contrario;

string containerOfObjectName: stringa contenente il nome dell' oggetto che si vuole analizzare;

Ne segue che sul Box, oltre ad inserire il metodo, che chiamiamo come riportato sulla documentazione, dobbiamo inserire anche:

  • Un elemento di tipo String che conterrà il nome dell' oggetto da verificare (nel nostro caso sarà = WF_Cantieri) e che viene definito come parametro del metodo stesso: per comodità, lo chiamiamo come riportato sulla documentazione. Ovviamente avremmo potuto chiamarlo anche in altro modo;
  • Un elemento di tipo Boolean che dobbiamo chiamare StatusOfCall in quanto è questo oggetto che il metodo si aspetta e che il metodo aggiorna;

Le azioni da intraprendere per verificare se WF_Cantieri è stato o meno selezionato, sono:

  • Inizializzare la variabile "containerOfObjectName";
  • Eseguire il metodo "BBP_ObjectIsDefined";

Sarà l' elemento StatusOfCall a dirci se WF_Cantieri è stato o meno inizializzato.

Le azioni sopra riportate le possiamo includere in una semplicissima regola che chiamiamo DRverify_WF_Cantieri.

Il filmato che segue mostra come inserire il Metodo, le variabili e creare la Decision Rule:

 

 

Rappresentazione grafica della DR DRverify_WF_Cantieri.

Questa regola setta StatusOfCall = true se WF_Cantieri è definito (isSelected), StatusOfCall = false in caso contrario.

 

 

Creare, modificare, eliminare o annullare RDA

A queste funzionalità corrisponderanno altrettanti Command Button: ad ogni CB sarà associata una DR il cui obiettivo è quello di attivare la funzionalità corrispondente.

Vediamo cosa si deve fare per ogni singola funzionalità.

Creare una nuova Rda

Informazioni compilate dall' utente:

  • Identificativo della Rda;
  • DescrBreve: breve descrizione;
  • TipoMateriale: tipologia del materiale di cui si richiede l' acquisto;
  • Importo: importo dell' ascquisto;

Diciamo che queste informazioni sono obbligatorie al fine di creare la Rda: se solo una di queste è non definita, la Rda non può essere creata. Propedeutico a questa gestione è il definire Required i campi in oggetto.

Informazioni generate in automatico:

  • Key: guid che viene creata nella fase di creazione fisica della Rda;
  • RichiestoDa: riprende l' identificativo del cantiere selezionato;
  • MaxLivApprRichiesto: definito da una regola che possiamo dire appartenere all' Work Flow;
  • LivAppAttuale: non considerato in questa fase;
  • ApprovatoDa: non considerato in questa fase;
  • Stato: settato al valore NEW;

La tabella che segue (tabWF-Level) documenta la regola che definisce in automatico il MaxLivApprRichiesto:

MaterialeImporto € >Importo € <=Area CantiereLivello
UFF 0200*Liv-0
 2005000*Liv-1
 5000 *Liv-2
MACC 010000*Liv-1
 1000050000EUROPA / ITALIALiv-1
 1000050000AFRICA / ASIALiv-2
 50000 *Liv-3
 STRUTT 0 15000*Liv-1
  1500075000 EUROPA / ITALIA Liv-1
  15000 75000 AFRICA / ASIA Liv-2
  75000 *Liv-3
COSTR03000*Liv-1
 3000 *Liv-3

 

In base a quanto sopra riportato, al CB "Crea Rda" dobbiamo associare una regola che deve:

  1. Verificare che il Cantiere sia stato definito: in caso contrario si segnala un errore interrompendo l' attività;
  2. Verificare che le informazioni della Rda definite "Required" siano state compilate dall' utente: in caso contrario si segnala un errore interrompendo l' attività;
  3.  Attivare quanto necessario (metodi e regole) al fine di aggiornare le informazioni automatiche: se durante questo processo si verificano errori si segnala il fatto interrompendo l' attività;
  4. Se tutto quanto precede è OK, si procede all' effettiva creazione della Rda;

Vediamo cosa richiede ogni singolo punto: 

(1)   

Abbiamo già disponibile la regola DRverify_WF_Cantieri.

Possiamo cominciare a costruire la regola DRcrea_WF_Rda che andremo ad associare al CB corrispondente. Questa prima parte della regola, si presenta come segue:

 

Come già precedentemente detto la regola DRverify_WF_Cantieri inizializza il Booleano StatusOfCalltrue se il Cantiere risulta definito, o a false in caso contrario. Nel caso false, si predispone il messaggio da visualizzare e si attiva il metodo ViewMessage_Error (Questo metodo richiama la procedura standard ViewMessage) che visualizza il messaggio.

Dopo la visualizzazione del messaggio, la regola si interrompe e, di conseguenza, non si ha la creazione della riga di Rda.

(2) 

Come prima cosa dobbiamo verificare che i campi interessati (Identificativo, DesBreve, TopoMateriale, Importo) siano definiti Required (devono essere

obbligatoriamente definiti). Per verificare che i Required siano effettivamente definiti, possiamo utilizzare il metodo sotto riportato

void BBP_AllRequestedFieldsDefined(string containerExtraProperty)

Controlla che tutti gli elementi che contengono una Extra Property di nome uguale al contenuto del parametro containerExtraProperty e hanno la proprietà Required a true siano definiti. Per utilizzare questo metodo deve essere definito un oggetto di tipo Boolean chiamato "StatusOfCall" che il metodo stesso inizializza a true se tutti i campi sono definiti, a false se almeno un campo non è definito: i campi di tipo number, se required, si ritengono definiti se hanno un valore diverso da 0.Parametri di passaggio:

string containerExtraProperty: elemento stringa il cui contenuto è il nome dell' EP;

L' uso di questo metodo richiede:

  • La creazione dell' elemento string containerExtraProperty, elemento che conterrà l' EP che identifica i campi Required da verificare;
  • L' EP RdaFieldRequired da associare ai campi in oggetto (Identificativo, DesBreve, TopoMateriale, Importo);

 

Il filmato che segue mostra come operare per ottenere quanto riportato:

 

 

(3)/(4)   

Le informazioni che devono essere aggiornate in automatico sono:

  • Key: viene effettuato dal metodo che crea a RDA. Il metodo che viene utilizzato è  BBP_InsertRowInGridAndInSql(string gridName)
  • MaxLivApprRichiesto: viene effettuato tramite la regola RD_DefineMaxLivApprRichiesto;
  • RichiestoDaStato: viene effettuato tramite lo  script Script_UpdateAutoInfo;

 

Regola "RD_DefineMaxLivApprRichiesto"

Per costruire la regola, facciamo riferimento alla tabella tabWF-Level sopra riportata: suddividiamo la regola in quattro regole semplice, una per ogni tipologia di materiale.

Di seguito le regole singole e la regola RD_DefineMaxLivApprRichiesto che le contiene:

MaxLivApprRichiesto_UFF

 

MaxLivApprRichiesto_MACC

 

MaxLivApprRichiesto_STRUTT

 

MaxLivApprRichiesto_COSTR

 

 RD_DefineMaxLivApprRichiesto

 

Metodo x la creazione della RDA

La RDA viene creata utlizzando il metodo che segue:

void BBP_InsertRowInGridAndInSql(string gridName): inserisce una nuova riga sulla grid definita come parametro ed aggiorna la corrispondente tabella SQL. Vengono aggiornate le colonne della grid con il contenuto degli oggetti che hanno lo stesso nome: vengono aggiornati i campi della tabella SQL con il contenuto delle colonne della grid che hanno lo stesso nome. Per utilizzare questo metodo deve essere definito un oggetto di tipo Boolean chiamato "StatusOfCall" che il metodo stesso inizializza a true se l' operazione è andata a buon fine, a false se si sono verificati degli errori.Parametri di passaggio:

string gridName: identificativo della Grid su cui opera il metodo.

Questo metodo ci consente sia di aggiornare la Grid sulla pagina Web che la tabella SQL corrispondente senza scrivere ulteriore codice, a patto che le colonne della Grid ed i campi che vengono valorizzati abbiano lo stesso nome. Cioè se sulla Grid utilizzo una colonna numerica di nome Importo per memorizzare il valore della RDA, allora il campo che devo inizializzare deve chiamarsi Importo  ed essere di tipo numerico così come la corrispondente colonna della Tabella SQL.

 

Script "Script_UpdateAutoInf"

Uno script è un sequenza di statement quali assegnazione, exec di metodi e/o di regole. Definito come valore di un elemento String, viene eseguito tramite il metodo:

void BBP_ExecuteScript(string scriptVar): esegue lo Script contenuto in "scriptVar";

string scriptVar: stringa contenente lo script che viene eseguito. Per utilizzare questo metodo deve essere definito un oggetto di tipo Boolean chiamato "StatusOfCall" che il metodo stesso inizializza a true se l' esecuzione è andata a buon fine, a false in caso contrario. Lo script è composto da un insieme di statement, ognuno dei quali terminato da ";", del tipo:

element=element;
element=value (se elemento string o list, il valore può essere inserito tra i doppi apici);
ExecMethod(MethodName);
ExecRule(RuleName);

Nel caso in oggetto lo script si limita ad inizializzare i valori RichiestoDa Stato:

RichiestoDaWF_Cantieri: è il Cantiere che ha effettuato la richiesta;

Stato = "NEW": è una nuova richiesta non ancora presa in carico dall' WorFlow;

Chiamiamo Script_UpdateAutoInf l' elemento string che contiene lo script ed Exe_Script_UpdateAutoInf il metodo che utilizza la procedura standard BBP_ExecuteScript per eseguire lo script.

 

 

Alcune verifiche e test

Cominciamo con il creare la pagina e vedere come si presenta, ricordandoci che stiamo lavorando su di un prototipo.

Il filmato che segue mostra come creare la pagina Web utile per l' inserimento delle RDA e come inserire i primi controlli:

 

 

Alla pagina RDA andiamo anche ad aggiungere le informazioni che dovrebbero essere definite in automatico: le definiamo ReadOnly così che non si possano modificare. Questo non ha alcuna implicazione operativa, ma serve solo per poter effettuare delle verifiche durante la fase di sviluppo dell' applicazione: ovviamente nel momento in cui si rilascia l' applicazione queste potrebbero essere eliminate o rese non-visibili.

Aggiungiamo anche il CB Crea RDA a cui associamo la Decision Rule DRcrea_WF_Rda che andremo a testare nella parte finale di questa sezione.

Un aspetto importante è il fatto che noi possiamo testare le nostre regole o i metodi che intendiamo usare a livelli intermedi: ad esempio possiamo testare la regola che definisce il massimo livello di approvazione senza dover aspettare di aver completato l' intera applicazione. Il filmato che segue mostra questo passaggio:

 

 

Continuiamo con i test ed andiamo a verificare il funzionamento del metodo che controlla che i campi definiti Required e proprietari di una specifica EP siano effettivamente definiti.

Il filmato che segue mostra questa operazione:

 

 

A questo punto non ci rimane che costruire lo Script Script_UpdateAutoInf e completare la regola di creazione della RDA aggiungendo sia lo script che il metodo che effettua la creazione della riga stessa. Nel filmato ci limitiamo a verificare lo script, il metodo di creazione RDA, la regola completata ed il funzionamento di quanto realizzato .

Vediamo il filmato che segue;

 

 

 

Modificare una RDA esistente

La modifica di una riga è soggetta alle condizioni che seguono:

(1)-La RDA che si vuole modificare deve essere selezionata sulla Grid e le informazioni modificabili devono essere rese disponibili all' utente: per ottenere questo dobbiamo utilizzare il metodo standard della BBP ."void BBP_ReadSelectedRowFromGrid(string gridElement)" che associamo all' OnUpdate della WF_Rda. Questo metodo riporta le info della riga sui campi di dettaglio: ovviamente deve esserci corrispondenza tra i nomi come già detto precedentemente.
(2)-Possono essere modificate le sole RDA che hanno lo Stato = NEW;
(3)-L' aggiornamento effettivo delle info della WF_Rda viene effettuato utilizzando il metodo "void BBP_UpdateRowInGridAndInSql(string gridName)";

 

Associamo questa funzionalità ad un CB che chiamiamo "Modifica RDA": il CB attiva la decision rule DRupdate_RDA.

Il filmato che segue mostra come creare questa funzionalità (i metodi li troviamo già inseriti come elementi: il metodo BBP_ReadSelectedRowFromGrid lo troviamo già associato all' OnUpdate della WF_Rda): 

 

 

Eliminare/Annullare  una RDA esistente

Questa funzionalità è del tutto simile a quella sopra documentata, a meno di:

(1)-La RDA viene fisicamente eliminata se lo Stato = NEW, mentre passa allo Stato = REF se diverso da NEW ed ovviamente diverso da REF;
(2)-La eliminazione/annullamento effettivo della Rda viene effettuato utilizzando il metodo "void BBP_RemoveSelectedRowGridInSql(string gridName)";

 

Associamo questa funzionalità ad un CB che chiamiamo "Elimina RDA": il CB attiva la decision rule DRdelete_RDA rappresentata dall' immagine che segue: