Gestionale in JavaScript

Un esercizio completo dove applicare diverse tecnologie Web: interfaccia creata con Bootstrap e CSS custom, javascript con event listener, classi, gestione dinamica del DOM con tabelle e form, local storage. Il software si prefigge di creare una anagrafica di prodotti ed una anagrafica dei movimenti di magazzino su di questi. La soluzione proposta, ovviamente, non è ne l’unica, ne completa.

La consegna

Scrivi un programma in JavaScript per gestire un magazzino di prodotti secondo le seguenti specifiche:

  • Implementare la classe PRODOTTO definita da un codice, un nome, un prezzo e un metodo visualizza (per visualizzare i dati del prodotto).
  • Implementare una classe PRODOTTI con una struttura dati array e con gli opportuni metodi per eseguire l’inserimento, la cancellazione di un prodotto, la visualizzazione di tutti i prodotti.
  • Definire inoltre un metodo nella classe che visualizza il nome del prodotto con prezzo più alto.
  • Aggiungere alla classe PRODOTTO un attributo giacenza che memorizza la quantità di prodotto presente in magazzino.
  • Implementare la classe MOVIMENTO. Di ogni movimento si registrano il codice del prodotto, la data del movimento e la quantità movimentata (positiva se in entrata, negativa se in uscita).
  • Implementare la classe MOVIMENTI per registrare tutte le operazioni di movimentazione dei prodotti attraverso un array e le operazioni di gestione. Per la gestione dei movimenti prevedere i pulsanti Registra, Elenco completo, Elenco singolo prodotto.
  • Aggiungere i pulsanti per salvare e caricare da LOCALSTORAGE l’elenco dei prodotti e dei movimenti.

NB: Tenere presente che quando si registra un movimento bisogna anche aggiornare la giacenza in PRODOTTO. Realizzare una opportuna interfaccia grafica per soddisfare le specifiche di progetto.

Pagina HTML e CSS

Per l’interfaccia utente, ho scelto Bootstrap. Framework lato client molto potente e versatile che snellisce di molto la realizzazione di GUI web accattivanti ma dotate di widget versatili e di facile apprendimento. Per rendere tutto più scherzoso, accanto alla grafica bootstrap ho aggiunto un foglio di stile che fa uso di colori in stile DOS. L’interfaccia è puramente dimostrativa, senza pretese di UI/UX.

L’idea di base è creare una form per l’immissione dei dati dei prodotti con la visualizzazione in tempo reale e refresh in base a cancellazione o caricamento.Stessa dinamica per i movimenti. Notare come tutti i bottoni o i vari elementi per la visualizzazione sono contrassegnati da un id, fondamentale per identificare e gestire i dati via js.

Nella parte cocnlusiva del file html e del suo body, ho inserito le chiamate per includere i file javascipt. E’ buona prassi caricare i javascript non necessari alla grafica in fondo alla pagina web, alla fine del caricamento della grafica, per velocizzare la visualizzazione all’utente. Consiglio sempre, dove possibile, di suddividere i frammenti di javascript su più file per snellire il loro download ma anche per avere una visione a scomparti del nostro codice: un file gigante con un centinaio di righe di codice non è facile da leggere e debuggare, meglio spezzattare!

<!DOCTYPE html>
<html lang="it">
    <head>
        <title>Gestionale TuTiTu</title>
        <meta charset="utf-8">
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
        <link rel="stylesheet" href="css/stile.css" type="text/css">
    </head>

    <body>
        

        <!-- GESTIONE PRODOTTI --->
        <div class="container">

            <h1>Gestionale TuTiTu</h1>
            <div class="row">
              <div class="col">
                <h2>Gestione Prodotti</h2>
                <form onsubmit="event.preventDefault();">
                    <fieldset>    
                        <legend>Inserisci Prodotto</legend>
                    <div class="mb-3">
                      <label for="codice" class="form-label">Codice</label>
                      <input type="text" class="form-control" id="codice" >
                    </div>
                    <div class="mb-3">
                        <label for="nome" class="form-label">Nome</label>
                        <input type="text" class="form-control" id="nome" >
                      </div>
                      <div class="mb-3">
                        <label for="descrizione" class="form-label">Descrizione</label>
                        <input type="text" class="form-control" id="descrizione" >
                      </div> 
                      <div class="mb-3">
                        <label for="prezzo" class="form-label">Prezzo</label>
                        <input type="number" class="form-control" id="prezzo" >
                      </div> 
                      <!-- div class="mb-3">
                        <label for="giacenza" class="form-label">Giacenza</label>
                        <input type="number" class="form-control" id="giacenza">
                      </div -->                                                                
                    <button type='button' id="btn-aggiungi-prodotto" class="btn btn-secondary">Aggiungi</button>
                    </fieldset>
                </form>
              </div>
              <div class="col">
                <h2>Elenco Prodotti</h2>
                <div id="elenco-prodotti" class="elenco">
                    <table id="tabella-prodotti">
                        <thead>
                            <th>Codice</th>
                            <th>Nome</th>
                            <th>Descrizione</th>
                            <th>Prezzo</th>
                            <th>Giacenza</th>
                        </thead>
                        <tbody>
                          
                        </tbody>
                    </table>
                </div>
                <div id="info"></div>
              </div>
              
            </div>

            <div class="row">
                <div class="col">
                  <form>
                      <fieldset>    
                        <legend>Altre funzioni</legend>

                          <div class="row">
                            <div class="col col-sm-2">
                                <label for="codice" class="form-label">Codice</label>
                            </div>
                            <div class="col">
                              <input type="text" class="form-control" placeholder="codice" id="codice-elimina">
                            </div>
                            <div class="col">
                                <button type='button' class="btn btn-danger" id="btn-elimina-prodotto">Elimina</button>
                            </div>
                          </div>

                          <div class="row">
                            <div class="col">&nbsp;</div>
                            <div class="col">&nbsp;</div>
                          </div>                           

                          <div class="row">
                            <div class="col">
                                <button type='button' class="btn btn-success" id="btn-tutti-prodotti">Visualizza Tutti</button>
                            </div>
                            <div class="col">
                                <button type='button' class="btn btn-primary" id="btn-prezzo-max">Visualizza Prezzo Max</button>
                            </div>
                          </div>  
                          
                          <div class="row">
                            <div class="col">&nbsp;</div>
                            <div class="col">&nbsp;</div>
                          </div> 

                          <div class="row">
                            <div class="col">
                                <button type='button' class="btn btn-secondary" id="btn-carica-prodotti">Carica</button>
                            </div>
                            <div class="col">
                                <button type='button' class="btn btn-secondary" id="btn-salva-prodotti">Salva</button>
                            </div>
                          </div>                           

                      </fieldset>
                  </form>
                </div>
                <div class="col">
                    <!-- messaggio esito altre azioni -->
                </div>
            </div>              



        <!-- GESTIONE MOVIMENTI-->


            <div class="row">
                <div class="col">
                  <h2>Gestione Movimenti</h2>
                  <form>
                      <fieldset>    
                          <legend>Effettua Movimento</legend>
                        <div class="mb-3">
                          <label for="codice-prodotto" class="form-label">Codice Prodotto</label>
                          <input type="text" class="form-control" id="codice-prodotto" >
                        </div>
                        <div class="mb-3">
                          <label for="data-movimento" class="form-label">Data </label>
                          <input type="date" class="form-control" id="data-movimento" >
                        </div> 
                        <div class="mb-3">
                          <label for="quantita" class="form-label">Quantità +/-</label>
                          <input type="number" class="form-control" id="quantita" >
                        </div> 
                                                          
                      <button type='button' id="btn-aggiungi-movimento" class="btn btn-secondary">Registra</button>
                      </fieldset>
                  </form>
                </div>
                <div class="col">
                  <h2>Elenco Movimenti</h2>
                  <div id="elenco-movimenti" class="elenco">
                    <table id="tabella-movimenti">
                      <thead>
                          <th>ID</th>
                          <th>Cod prodotto</th>
                          <th>Data</th>
                          <th>Qta</th>
                      </thead>
                      <tbody>
                        
                      </tbody>
                  </table>                    
                  </div>
                </div>
  
              </div>
  
              <div class="row">
                  <div class="col">
                    <form>
                        <fieldset>    
                          <legend>Altre funzioni</legend>
  
                            <div class="row">
                              <div class="col col-sm-2">
                                  <label for="codice" class="form-label">Codice</label>
                              </div>
                              <div class="col">
                                <input type="text" id="filtro-codice-movimento" class="form-control" placeholder="codice">
                              </div>
                              <div class="col">
                                  <button type='button' class="btn btn-primary" id="btn-movimenti-prodotto">Visualizza prodotto</button>
                              </div>
                            </div>
  
                            <div class="row">
                              <div class="col">&nbsp;</div>
                              <div class="col">&nbsp;</div>
                            </div>                           
  
                            <div class="row">
                              <div class="col">
                                  <button type='button' class="btn btn-success" id="btn-tutti-movimenti">Visualizza Movimenti</button>
                              </div>
                            </div>       

                            <div class="row">
                                <div class="col">&nbsp;</div>
                                <div class="col">&nbsp;</div>
                              </div>  

                            <div class="row">
                                <div class="col">
                                    <button type='button' class="btn btn-secondary" id="btn-carica-movimenti">Carica</button>
                                </div>
                                <div class="col">
                                    <button type='button' class="btn btn-secondary" id="btn-salva-movimenti">Salva</button>
                                </div>
                              </div>                              
                          
                        </fieldset>
                    </form>
                  </div>
                  <div class="col">
                      <!-- messaggio esito altre azioni -->
                  </div>
              </div>   

        </div>  

        <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>
        <script src="js/prodotto.js"></script>
        <script src="js/movimento.js"></script>
        <script src="js/prodotti.js"></script>
        <script src="js/movimenti.js"></script>
        <script src="js/main.js"></script>
    </body>    
</html>

ed ecco il foglio di stile con pochi ed essenziali indicatori, senza proprietà particolari.

/**
 blu    #0000ad
 acqua  #00a8a8
 grigio #a8a8a8
 giallo #fcfe54
*/

body
{
    background-color: #00a8a8;
    font-family: 'Courier New', Courier, monospace;
    color: #fff;
}

fieldset 
{ 
    border:1px solid #a8a8a8; 
    padding: 1em 1em 1em 1em;
}

form
{
    background-color: #0000ad;
    padding: 1em 1em 1em 1em;
}

.elenco
{
    width: auto;
    height: 93%;
    background-color: #a8a8a8;
    padding: 1em 1em 0 1em;
}

#tabella-prodotti, #tabella-movimenti
{
    width: 100%;
}

th
{
    border-bottom: 1px solid white;
}

Classe prodotto

Eccoci alla prima classe del nostro esercizio. Seguendo la filosofia tecnologica, abbiamo realizzato un costruttore che tiene conto di tutti i campi richiesti, eccezione la giacenza che sarà gestita e modificata attraverso l’inserimento di righe di movimento. Non ho voluto utilizzare i setter e getter standard js, ma mi sono affidato al più tradizionale setqualcosa e getqualcosa di qualsiasi linguaggio oop. Ho aggiunto un metodo toString() per utilizzarlo nel debug. Interessante invece il metodo visualizza. Nella logica progettuale, prende come parametro l’oggetto DOM della tabella per visualizzare i prodotti. Con tale oggetto, procediamo all’aggiunta di una riga di tabella sfruttando la funzionalità appendchild, createelement, createtextelement.

class Prodotto 
{
	constructor(_codice, _nome, _descrizione, _prezzo) 
    {
		this.codice = _codice;
		this.nome = _nome;
		this.descrizione = _descrizione;
		this.prezzo = _prezzo;
        this.giacenza = 0;
    } 


	getCodice()
    {
        return this.codice;
    }

	setCodice(_codice)
    {
        this.codice = _codice;
    }

    getPrezzo()
    {
        return this.prezzo;
    }

	setPrezzo(_prezzo)
    {
        this.prezzo = _prezzo;
    }

    toString() 
    {
		return this.codice + " " + this.nome + " " + this.descrizione + " " + this.prezzo + " " + this.giacenza;
	}

    visualizza(_objTabella)
    {
        let tr= document.createElement("tr");
        let td1 = document.createElement('td');
        let td2 = document.createElement('td');
        let td3 = document.createElement('td');
        let td4 = document.createElement('td');
        let td5 = document.createElement('td');

        let contenutotd1=document.createTextNode(this.codice);
        let contenutotd2=document.createTextNode(this.nome);
        let contenutotd3=document.createTextNode(this.descrizione);
        let contenutotd4=document.createTextNode(this.prezzo);
        let contenutotd5=document.createTextNode(this.giacenza);

        td1.appendChild(contenutotd1);
        td2.appendChild(contenutotd2);
        td3.appendChild(contenutotd3);
        td4.appendChild(contenutotd4);
        td5.appendChild(contenutotd5);

        tr.appendChild(td1);
        tr.appendChild(td2);
        tr.appendChild(td3);
        tr.appendChild(td4);
        tr.appendChild(td5);        

        _objTabella.appendChild(tr);

    }
}

Classe prodotti

Sperando di non confondere il lettore, la classe prodotti è in pratica costituita da un vettore in cui verranno inseriti i prodott i cob i loro valori. E’ un a classe di gestione, con diversi metodi di utilità, a cominciare dai metodi per aggiungere ed eliminare un prodotto all’elenco o verificare l’esistenza di un determinato codice. Interessante il metodo visualizza che in realtà scorre semplicemente il vettore di prodotti fon un forEach e, per ogni prodotto, richiama la funzione di visualizzazione vista precedentemente. I metodi save e load sono invece inusuali. Fanno uso della tecnologia web storage, simile a quella dei cookies ma decisamente più performante. Basta scegliere un identificatore, qui banalmente “prodotto”, per trasformare i dati in un JSON che viene archiviato e ripescato poi con il metodo load che rimpie il vettore dei prodotti.

class Prodotti 
{
	constructor() 
    {
        this.prodotti = [];
    }

    
    aggiungi(_prodotto)
    {
        this.prodotti.push(_prodotto);
        return _prodotto;
    }    

    elimina(_codice)
    {
        for( let i = 0; i < this.numProdotti(); i++)
        { 
            if ( this.prodotti[i].codice == _codice) 
            {
                this.prodotti.splice(i, 1); 
            }
         }
    }

    numProdotti()
    {
        return this.prodotti.length;
    }

    aggiornaGiacenza(_codice, _qta)
    {
        for( let i = 0; i < this.numProdotti(); i++)
        { 
            if ( this.prodotti[i].codice == _codice) 
            {
                this.prodotti[i].giacenza += _qta;
            }
         }        
    }

    esiste(_codice)
    {
        for( let i = 0; i < this.numProdotti(); i++)
        { 
            if ( this.prodotti[i].codice == _codice) 
            {
                return true;
            }
         }      
         
         return false;
    }    

    visualizza(_objTabella) 
    {
        _objTabella.innerHTML = ""; //resetto la tabella e ridisegno 

        let stringa;
        this.prodotti.forEach(element => {
            stringa += element.visualizza(_objTabella) + "\n";
        });
        
        //console.log(stringa);
		return stringa;
	}

    save() 
    {
        localStorage.setItem('prodotti', JSON.stringify(this.prodotti))
    }

    load() 
    {
        let jsonArticoli = localStorage.getItem("prodotti");
        let data  = JSON.parse(jsonArticoli);
        if (data == null)
            return;
        for (let articoloData of data) {
          let articolo = new Prodotto(
            articoloData.codice,
            articoloData.nome,
            articoloData.descrizione,
            articoloData.prezzo,
            articoloData.giacenza,
          );
          this.aggiungi(articolo);
        }
    }

    prodottoprezzomax()
    {
        let prodottomax = new Prodotto("","","",0,0);
        this.prodotti.forEach(element => 
            {
                if (element.getPrezzo() > prodottomax.getPrezzo())
                {
                    prodottomax = element;
                }
                
            });

        return prodottomax.toString();    
    }
}

Classe movimento

Analoga alla classe Prodotto. Interessante è l’utilizzo di una variabile chiamata id esterna alla classe che serve per creare l’autoincremento nel codice del movimento.

var id = 0;

class Movimento 
{
	constructor(_id, _codiceprodotto, _data, _qta) 
    {
		this.id = _id == "" ? id++ : _id;
		this.codiceprodotto = _codiceprodotto;
		this.data = _data;
		this.qta = _qta;
    } 

    getid()
    {
        return this.codice;
    }
	
    setid(_id)
    {
        this.codice = _id;
    }
    
    toString() 
    {
		return this.id + " " + this.codiceprodotto + " " + this.data + " " + this.qta;
	}

    visualizza(_objTabella)
    {
        let tr= document.createElement("tr");
        let td1 = document.createElement('td');
        let td2 = document.createElement('td');
        let td3 = document.createElement('td');
        let td4 = document.createElement('td');

        let contenutotd1=document.createTextNode(this.id);
        let contenutotd2=document.createTextNode(this.codiceprodotto);
        let contenutotd3=document.createTextNode(this.data);
        let contenutotd4=document.createTextNode(this.qta);


        td1.appendChild(contenutotd1);
        td2.appendChild(contenutotd2);
        td3.appendChild(contenutotd3);
        td4.appendChild(contenutotd4);

        tr.appendChild(td1);
        tr.appendChild(td2);
        tr.appendChild(td3);
        tr.appendChild(td4);
   
        _objTabella.appendChild(tr);

    }
    
}

Classe movimenti

Analoga alla classe Prodotti. Presenta di diverso un metodo visulizzaperprodotto che filtra i movimenti dato un determinato codice prodotto e riesegue analoga funzionalità di visualizzazione dei prodotti,

class Movimenti 
{
    
	constructor() 
    {
        this.movimenti = [];
    }

    
    aggiungi(_movimento)
    {
        this.movimenti.push(_movimento);
        return _movimento;
    }

    elimina(_id)
    {
        for( let i = 0; i < numMovimenti(); i++)
        { 
            if ( this.movimenti[i].id() == _id) 
            {
                this.movimenti.splice(i, 1); 
            }
        }
    }

    numMovimenti()
    {
        return this.movimenti.length;
    }

    visualizza(_objTabella) 
    {
        _objTabella.innerHTML = ""; //resetto la tabella e ridisegno 

        let stringa;
        this.movimenti.forEach(element => {
            element.visualizza(_objTabella);
        });
        
        //console.log(stringa);
		//return stringa;
	}

    visualizzaPerProdotto(_codprodotto, _objTabella) 
    {
        _objTabella.innerHTML = ""; //resetto la tabella e ridisegno 

        for( let i = 0; i < this.numMovimenti(); i++)
        { 
            if ( this.movimenti[i].codiceprodotto == _codprodotto) 
            {
                this.movimenti[i].visualizza(_objTabella);
            }
         }
	}

    save() 
    {
        localStorage.setItem('movimenti', JSON.stringify(this.movimenti))
    }

    load() 
    {
        let jsonMovimenti = localStorage.getItem("movimenti");
        let data  = JSON.parse(jsonMovimenti);
        if (data == null)
            return;
        for (let movimentoData of data) {
          let movimento = new Movimento(
            movimentoData.id,
            movimentoData.codiceprodotto,
            movimentoData.data,
            movimentoData.qta
          );
          this.aggiungi(movimento);
        }
    }
}

Main JS

Il cuore del nostro software. Qui ci sono tutti gli eventListener dei singoli bottoni e le funzioni associate agli eventi click. Qui non ci sono classi. Ci son odiversi querySelector perché questi metodi devono interagire col DOM. Non sono funzioni difficili da leggere e comprendere. Ci limitiamo a far notare al lettore come con una manciata di tasti e tabelle semplici, il numero di righe di codice sia letteralmentre esploso.

/**
 * Istanze gestionale
 */

var prodotti    = new Prodotti();
var movimenti   = new Movimenti();

/**
 * Pulsanti Gestione Prodotti
 */
var objBtnAggiungiProdotto  = document.querySelector("#btn-aggiungi-prodotto");
var objBtnEliminaProdotto   = document.querySelector("#btn-elimina-prodotto");
var objBtnTuttiProdotti     = document.querySelector("#btn-tutti-prodotti");
var objBtnPrezzoMax         = document.querySelector("#btn-prezzo-max");
var objBtnCaricaProdotti    = document.querySelector("#btn-carica-prodotti");
var objBtnSalvaProdotti     = document.querySelector("#btn-salva-prodotti");

/**
 * Eventi Gestione Prodotti
 */
 objBtnAggiungiProdotto.addEventListener("click",aggiungiprodotto);
 objBtnEliminaProdotto.addEventListener("click",eliminaprodotto);
 objBtnTuttiProdotti.addEventListener("click",visualizzaprodotti);
 objBtnPrezzoMax.addEventListener("click",visualizzaprezzomax);
 objBtnCaricaProdotti.addEventListener("click",caricaprodotti);
 objBtnSalvaProdotti.addEventListener("click",salvaprodotti);

 /**
  * Funzioni associate agli eventi prodotto
  */
function aggiungiprodotto()
{
    let codice = document.querySelector("#codice").value;   
    let nome = document.querySelector("#nome").value;  
    let descrizione = document.querySelector("#descrizione").value;  
    let prezzo = parseFloat(document.querySelector("#prezzo").value); 
    let prodotto = new Prodotto(codice,nome, descrizione,prezzo);
    prodotti.aggiungi(prodotto);

    visualizzaprodotti();
}

function eliminaprodotto()
{
    let codice = document.querySelector("#codice-elimina").value; 
    prodotti.elimina(codice);
    visualizzaprodotti();
}

function visualizzaprodotti()
{
    let objTabellaProdotti = document.querySelector("#tabella-prodotti tbody");
    prodotti.visualizza(objTabellaProdotti);
}

function visualizzaprezzomax()
{
    let objInfo = document.querySelector("#info");
    let stringa = prodotti.prodottoprezzomax();
    objInfo.innerHTML = "Prodotto prezzo MAX: " + stringa;
}

function caricaprodotti()
{
    prodotti.load();
    visualizzaprodotti();
}

function salvaprodotti()
{
    prodotti.save();
}





/**
 * Pulsanti Gestione Movimenti
 */
 var objBtnAggiungiMovimento  = document.querySelector("#btn-aggiungi-movimento");
 var objBtnTuttiMovimenti     = document.querySelector("#btn-tutti-movimenti");
 var objBtnMovimentiProdotto  = document.querySelector("#btn-movimenti-prodotto");
 var objBtnCaricaMovimenti    = document.querySelector("#btn-carica-movimenti");
 var objBtnSalvaMovimenti     = document.querySelector("#btn-salva-movimenti");
 
 /**
  * Eventi Gestione Movimenti
  */
  objBtnAggiungiMovimento.addEventListener("click",aggiungimovimento);
  objBtnTuttiMovimenti.addEventListener("click",visualizzamovimenti);
  objBtnMovimentiProdotto.addEventListener("click",visualizzamovimentiprodotto);
  objBtnCaricaMovimenti.addEventListener("click",caricamovimenti);
  objBtnSalvaMovimenti.addEventListener("click",salvamovimenti);

/**
 * Funzioni associate agli eventi movimento
 */
 function visualizzamovimenti()
 {
     let objTabellaMovimenti = document.querySelector("#tabella-movimenti tbody");
     movimenti.visualizza(objTabellaMovimenti);
 }


 function aggiungimovimento()
 {
    let codice = document.querySelector("#codice-prodotto").value;   
    let data = document.querySelector("#data-movimento").value;  
    let qta = parseFloat(document.querySelector("#quantita").value);  

    if (prodotti.esiste(codice) == true)
    {
        movimenti.aggiungi(new Movimento("",codice,data,qta));
        prodotti.aggiornaGiacenza(codice,qta);
        visualizzamovimenti();
        visualizzaprodotti(); //aggiorna visualizzazione giacenza
    }

 }

 function visualizzamovimentiprodotto()
 {
    let codice = document.querySelector("#filtro-codice-movimento").value;   
    let objTabellaMovimenti = document.querySelector("#tabella-movimenti tbody");
    movimenti.visualizzaPerProdotto(codice,objTabellaMovimenti);    

 }

 function caricamovimenti()
{
    movimenti.load();
    visualizzamovimenti();
}

function salvamovimenti()
{
    movimenti.save();
}

Listati codice

Listati-> https://github.com/alfredocentinaro/esercizi-js/blob/main/gestionale

Eseguilo su Replit -> https://replit.com/@AlfredoCentina2/gestionale

Ultima modifica 26 Ottobre 2022