Ora che siamo riusciti a stabilire una connessione tra il nostro file system locale e Azure e a ottenere il contenuto del nostro file flat con i valori di previsione, vediamo come fare un ulteriore passo avanti e completare l’intera soluzione.

Abbiamo concluso la Prima Parte sapendo che dovevamo aggiungere altri passaggi:

  • Aggiunta della convalida al nome del file per filtrare i file indesiderati che vengono rilasciati nella nostra cartella, attivando la nostra applicazione logica.
  • Convertire il contenuto del file in un corpo JSON leggibile con il quale lavorare
  • Conversione dei numeri della settimana in date che rappresentano il primo giorno lavorativo della settimana in cui è possibile mantenere una previsione per un articolo (il Service Layer di SAP Business One può accettare solo le date quando si richiama l’aggiornamento del Weekly Forecast rispetto all’interfaccia utente B1).
  • Generare il payload per le previsioni e incorporare la generazione delle previsioni nella nostra soluzione.
  • Copertura di alcuni concetti di gestione degli errori

 

Affrontiamo ciascuno di questi passaggi e finalizziamo la nostra soluzione.

 

Aggiunta della convalida al nome del file

Per prima cosa, vogliamo aggiungere una convalida che controlli il nome del file che viene inserito nella cartella locale e che garantisca il rispetto di una convenzione di denominazione.

In questo modo si eviteranno esecuzioni inutili per nomi di file che non corrispondono a quelli che l’azienda ha deciso di rispettare.

Diciamo che vogliamo che il nome del nostro file contenga almeno la stringa “Forecast”. Aggiungiamo un connettore di controllo che lo verifichi:

 

Se il controllo restituisce ‘Vero’, il nostro flusso entra in funzione; altrimenti, annulliamo l’esecuzione.

 

Conversione del contenuto del file in un JSON leggibile

L’approccio sarebbe quello di creare un array JSON
array
che conterrà sia le intestazioni che gli elementi del CSV.

Il primo passo sarà quello di aggiungere un’azione “Compose” come segue:

Nota importante relativa ai finali di riga: Ho usato il componente
decodeUriComponent
per dividere il CSV.

decodificareUriComponent(‘%0A’)

Rappresenta un nuovo carattere di avanzamento riga (LF), spesso visualizzato come \n. Questo è lo standard Unix.

 

I file CSV generati in Windows possono utilizzare questo formato, ma spesso utilizzano un ritorno a capo e un avanzamento di riga (CR+LF). Questo viene rappresentato come \r\n.

L’espressione di divisione di cui sopra funzionerà ancora con CR+LF, ma rimarranno dei caratteri \r nei dati. L’espressione corretta da dividere su un CR+LF è:

decodificareUriComponent(‘%0D%0A’)

 

Se si carica il file CSV nel Blocco note, si può facilmente vedere il formato del file nell’angolo in basso a destra. Verrà visualizzato “Unix (LF)” o “Windows (CR LF)”.

La funzione “Split” restituisce una matrice e richiede una stringa come primo argomento. Utilizziamo spesso questa funzione in questa soluzione perché è piuttosto potente.

La struttura unica del nostro CSV ci impone di separare le intestazioni e gli elementi del file in due array.

Il motivo è che ogni codice articolo ha 12 periodi di previsione e dobbiamo mantenere una quantità diversa per ogni periodo.

Notate come ho usato la funzione prima nella mia espressione per recuperare solo il primo elemento dell’array creato dalla funzione “Split”.

Per ottenere solo le righe, ho usato la funzione “Skip” nella mia azione “Compose” e ho imposto al mio connettore di ignorare il primo elemento (= le intestazioni), lasciando così solo le righe.

Se eseguiamo il nostro flusso, vedremo che l’ultima riga restituisce una stringa vuota:

Per pulire l’output, aggiungiamo un’azione “Filtra matrice” e assicuriamoci di usare la funzione “lunghezza” solo per selezionare gli elementi maggiori di zero (0):

L’azione successiva sarebbe quella di “Selezionare”, dove l’origine sarebbe l’array “FilterRows”.

Si tenga presente che l’azione “Select” accetta solo array come input e li itera tramite un ciclo interno per visualizzare tutte le occorrenze di un elemento specifico:

L’azione “Seleziona” di cui sopra è il punto in cui avviene la vera magia. Dobbiamo ricostruire il payload in modo tale che per ogni codice articolo si ottenga la quantità prevista per ogni numero di settimana, dove nel nostro scenario abbiamo 12 settimane in totale.

Questo è esattamente il motivo per cui ho disaccoppiato l’intestazione dagli elementi: dobbiamo contare la posizione di ogni periodo nell’array dell’intestazione e associarvi la quantità corrispondente dall’array degli elementi e, lungo il percorso, occuparci di alcune “pulizie/conversioni dei dati”:

  • I nostri numeri di settimana hanno un carattere indesiderato (‘W’) di cui è necessario sbarazzarsi
  • I nostri numeri di settimana non possono essere utilizzati così come appaiono nel file, poiché SAP Business One si aspetta di ottenere, per un
    previsione settimanale

    modalità
    il
    primo giorno lavorativo
    per ogni settimana presente nel nostro flat file.

Guardate l’output dell’azione “FilterRows”:

Dobbiamo identificare la posizione di ogni elemento, ma non prima di aver trasformato ogni iterazione dell’azione “Select” in un array.

Il “Codice articolo” è il primo, quindi la posizione è 0. L’aspetto sarà il seguente:

trim(split(item(), ‘,’)
[0]
)

Lo stesso vale per la quantità:

split(item(), ‘,’)
[

2………13

]

L’output dell’istruzione “Select” sarà simile a questo:

 

Siamo riusciti a creare un array JSON significativo con cui lavorare con successo!

Se si legge la SAP Business One Service Layer API Reference (vai a https://<hostname>:50000) dove <hostname> è il nome del server in cui sono stati installati i SAP Business One Server Components, si scoprirà che per applicare una patch a un oggetto MRP weekly Forecast con successoè necessario includere il seguente payload nel corpo della richiesta:

È qui che dobbiamo aggiungere un’ulteriore magia alla nostra soluzione per far sì che ciò avvenga.

Il nostro file contiene 13 periodi che rappresentano la settimana #, quindi dovremmo eseguire un ciclo per ogni voce, ma dovremo anche annidare un altro ciclo che viene eseguito 13 volte e assegnare i valori di previsione per ogni periodo #.

Per questo, creiamo una variabile globale chiamata
varIDStep
che servirà come numeratore/contatore nel nostro scenario e impostiamola a ‘1’.
:

Aggiungiamo ora due cicli annidati: un ciclo “Do-Until” e un ciclo “For each”:

Ciò significa che dovremmo iterare 12 volte per ogni codice articolo per assegnare i valori.

Ogni volta che il ciclo interno (“For each”) termina l’esecuzione (ricordate che esegue l’iter di tutti i codici degli elementi!), la nostra variabile viene incrementata utilizzando l’azione “Increment variable”:

Quando il valore del contatore è 13, esiste anche il ciclo esterno (“Until-Do”).

Per ottimizzare ulteriormente la soluzione ed evitare esecuzioni non necessarie, si consiglia di aggiungere una condizione che ignori le iterazioni in cui la quantità è uguale a ‘null’:

Notate come ho usato la funzione “concat” per mettere insieme il valore della “Quantità” e della nostra variabile (contatore) di iterazione corrente, in modo che corrisponda alla nostra definizione di “Select” di cui sopra:

items(‘For_each’)?[concat(‘Quantity’,variables(‘varIDStep’))]

In questo modo si assicura che si faccia sempre riferimento al
valore corrente
di “Quantità” o “Periodo”.

Utilizzando questa metodologia, l’azione successiva sarà quella di convertire la rappresentazione della settimana che è stata scritta nel nostro file in una data che SAP Business One può utilizzare per pubblicare i valori di previsione (ricordate che è il primo giorno lavorativo della settimana).

Non mi addentrerò troppo nel dettaglio di questa conversione, ma siete più che invitati a contattarmi se desiderate conoscere questa logica aggiuntiva.

Accennerò brevemente a come utilizzare i “Percorsi relativi” per invocare un altro sub-flusso di lavoro e passare un parametro a tale flusso.

Si noti come ho definito il percorso relativo sul connettore :

/Periodo/{Period}

Il parametro verrà passato tramite una chiamata HTTP dal nostro flusso di lavoro principale nel modo seguente:

Anche in questo caso, si utilizza il metodo “concat” per fare riferimento al file
periodo corrente
all’interno del ciclo che vogliamo convertire in una data.

Una volta convertita la data, possiamo preparare l’output e attivare la modifica:

Il risultato finale è che i valori di previsione vengono inseriti nel client SAP Business One:

Potremmo potenzialmente (soprattutto per la soluzione Productive) aggiungere alcune fasi di interazione con l’utente che notificano all’autore dell’invio un successo/fallimento alla fine della corsa e rendere la nostra soluzione un po’ più “user friendly”.

Un modo per farlo è utilizzare una variabile Array che verrà popolata dall’interno del ciclo in fase di esecuzione ogni volta che si effettua una chiamata al Service Layer:

Possiamo quindi controllare il codice di stato della risposta ottenuta e decidere quale array popolare:

Potremmo quindi usare il connettore “Invia un’e-mail (V2)” in combinazione con la funzione “lunghezza” per dimensionare la lunghezza di ogni array al di fuori del ciclo esterno (che equivale alla quantità di record riusciti/errati ottenuti):

Sintesi

Ora che abbiamo abbiamo concluso la costruzione della costruito la nostra soluzione, possiamo possiamo ulteriormente costruire scenari di estensione che combinano questi approcci “legacy” di lavoro con i file system locali con approcci più recenti che ci aiutano a costruire un’integrazione vincente con i nostri sistemi SAP Business One.

È possibile utilizzare il modello che abbiamo creato per rispondere a casi simili in cui un utente attiva un evento che viene ulteriormente sfruttato e incorporato nel nostro ERP con uno sforzo minimo.

Questa configurazione consente di sviluppare estensioni aziendali disaccoppiate utilizzando
Applicazioni logiche
con tutti gli strumenti e i servizi forniti da
Microsoft Azure Platform
in qualsiasi lingua più adatta a voi o al vostro caso d’uso.

Se siete interessati ad altri casi d’uso che potrebbero trarre vantaggio da una configurazione disaccoppiata di questo tipo, contattatemi e sarò felice di ascoltare anche le vostre idee.

 

Unitevi a noi nella SAP Business One Community per aggiungere i vostri pensieri, commenti e idee!