Skip to content

4. Compito 1: Gestione di base delle buste paga

4.1. Introduzione

Per mettere in pratica quanto visto in precedenza, proponiamo ora un compito che prevede lo sviluppo di un client Android per tablet, progettato per simulare i calcoli delle buste paga per i dipendenti di un'associazione.

L'applicazione avrà un'architettura client/server:

Image

  • il server [1] è già disponibile;
  • è necessario compilare il client Android [2].

4.2. Il database

4.2.1. Definizione

I dati statici necessari per generare la busta paga saranno memorizzati in un database che d'ora in poi chiameremo dbpam. Questo database contiene le seguenti tabelle:

Tabella EMPLOYEES: contiene informazioni sui vari fornitori di servizi di assistenza all'infanzia

Struttura:

ID
chiave primaria
VERSIONE
numero di versione – aumenta ad ogni modifica della riga
SS
Numero di previdenza sociale del dipendente – univoco
NOME
Cognome del dipendente
NOME
nome
INDIRIZZO
il loro indirizzo
CITTÀ
la sua città
CAP
il suo codice postale
ID_INDENNIZZO
Chiave esterna sul campo [ID] della tabella [INDEMNITES]

Il suo contenuto potrebbe essere il seguente:

Image

Tabella COTISATIONS: contiene le percentuali necessarie per calcolare i contributi previdenziali

Struttura:

ID
chiave primaria
VERSIONE
numero di versione – aumenta ad ogni modifica della riga
CSGRDS
Percentuale: Contributo sociale generale + Contributo al rimborso del debito sociale
CSGD
percentuale: contributo sociale generale deducibile
SECU
percentuale: previdenza sociale, vedovanza, vecchiaia
PENSIONE
percentuale: pensione integrativa + assicurazione contro la disoccupazione

Il contenuto potrebbe essere il seguente:

Image

Le aliquote dei contributi previdenziali sono indipendenti dal dipendente. La tabella precedente ha una sola riga.

Tabella ALLOWANCES: contiene gli elementi utilizzati per calcolare lo stipendio da corrispondere.
ID
chiave primaria
VERSIONE
numero di versione – aumenta ad ogni modifica della riga
INDICE
Indice di elaborazione – univoco
TARIFFA ORARIA
Prezzo netto in euro per un'ora di reperibilità
MANUTENZIONE GIORNALIERA
indennità giornaliera in euro per ogni giorno di assistenza
PASTO AL GIORNO
Indennità pasti in euro per giorno di assistenza
INDENNITÀ DI FERIE
Indennità per ferie pagate. Si tratta di una percentuale applicata allo stipendio base.

Il suo contenuto potrebbe essere il seguente:

Image

Si noti che le indennità possono variare da un operatore dell'assistenza all'infanzia all'altro. Esse sono collegate a uno specifico operatore dell'assistenza all'infanzia tramite la sua categoria retributiva. Ad esempio, la sig.ra Marie Jouveinal, che ha una categoria retributiva 2 (tabella EMPLOYEES), ha una retribuzione oraria di 2,1 euro (tabella INDEMNITES).

4.2.2. Generazione

Viene fornito lo script di generazione del database [dbpam_hibernate.sql]:

  

Crea il database [dbpam_hibernate] (questo è il nome del database utilizzato dal server web/jSON) e assicurati che l'account root (senza password) possa accedervi. Puoi farlo come segue:

Avviare MySQL, quindi [PhpMyAdmin]:

 
  • [1-2]: Importa lo script [dbpam_hibernate.sql] e poi eseguilo;

4.2.3. Modellazione Java del database

Gli elementi delle tabelle [EMPLOYEES], [ALLOWANCES] e [CONTRIBUTIONS] sono modellati dalle seguenti classi:

[ Employee]


package pam.entities;
 
import java.io.Serializable;
 
public class Employe implements Serializable {
 
  private static final long serialVersionUID = 1L;
  private Long id;
  private int version;
  private String SS;
  private String nom;
  private String prenom;
  private String adresse;
  private String ville;
  private String codePostal;
  private int idIndemnite;
  private Indemnite indemnite;
 
  public Employe() {
  }
 
  public Employe(String SS, String nom, String prenom, String adresse, String ville, String codePostal, Indemnite indemnite) {
    ...
  }
   // getters and setters
....
}
  • righe 8–15: questi campi corrispondono alle colonne della tabella [EMPLOYEES];
  • riga 16: il campo [indemniteId] corrisponde alla colonna [INDEMNITE_ID], che è la chiave esterna della tabella [EMPLOYEES];
  • riga 17: l'indennità del dipendente. Questo campo non è sempre compilato:
    • non viene compilato quando si richiede l'URL [/employees],
    • lo è quando si richiede l'URL [/salary];

[ Indemnite]


package pam.entities;
 
import java.io.Serializable;
 
public class Indemnite implements Serializable {
 
    private static final long serialVersionUID = 1L;
    private Long id;
    private int version;
    private int indice;
    private double baseHeure;
    private double entretienJour;
    private double repasJour;
    private double indemnitesCp;
 
    public Indemnite() {
    }
 
    public Indemnite(int indice, double baseHeure, double entretienJour, double repasJour, double indemnitesCP) {
        ...
    }
 
     // getters and setters
   ....
}
  • righe 8-14: i campi corrispondono alle colonne della tabella [INDEMNITES];

[ Contributo]


package pam.entities;
 
import java.io.Serializable;
 
public class Cotisation implements Serializable {
 
    private static final long serialVersionUID = 1L;
    private Long id;
    private int version;
    private double csgrds;
    private double csgd;
    private double secu;
    private double retraite;
 
    public Cotisation() {
    }
 
    public Cotisation(double csgrds, double csgd, double secu, double retraite) {
        ...
    }
    // getters and setters
   ...
}
  • righe 8-13: i campi corrispondono alle colonne della tabella [COTISATIONS];

4.3. Installazione del server web / JSON

4.3.1. Installazione

Viene fornito il binario Java per il server web/JSON:

 

Per avviare il server web/JSON, procedere come segue:

  • Avvia il DBMS MySQL;
  • assicurarsi che il database [dbpam_hibernate] esista;
  • Aprire una finestra del prompt dei comandi;
  • Accedere alla cartella jar;
  • digitare il comando:
java -jar pam-server-01-all-1.0.jar

Questo presuppone che l'eseguibile [java.exe] si trovi nel PATH del tuo computer. Se così non fosse, digita il percorso completo di [java.exe], ad esempio:

D:\Programs\devjava\java\jdk1.8\bin\java -jar pam-server-01-all-1.0.jar

Vengono visualizzati i log:

.   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.1.1.RELEASE)

2014-10-22 16:45:23.347  INFO 1868 --- [           main] pam.boot.BootWeb                         : Starting BootWeb on Gportpers3 with PID 1868 (D:\Temp\14-10-22\pam\server-pam.jar started by ST in D:\Temp\14-10-22\pam)
2014-10-22 16:45:23.414  INFO 1868 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@689ab9e2: startup date [Wed Oct 22 16:45:23 CEST 2014]; root of context hierarchy
...
...
2014-10-22 16:45:31.147  INFO 1868 --- [           main] org.hibernate.dialect.Dialect            : HHH000400: Using dialect: org.hibernate.dialect.MySQLDialect
2014-10-22 16:45:31.484  INFO 1868 --- [           main] o.h.h.i.ast.ASTQueryTranslatorFactory    : HHH000397: Using ASTQueryTranslatorFactory
2014-10-22 16:45:33.564  INFO 1868 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-10-22 16:45:33.804  INFO 1868 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/salaire/{SS}/{ht}/{jt}],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public pam.restapi.FeuilleSalaireResponse pam.restapi.PamController.getFeuilleSalaire(java.lang.String,double,int)
2014-10-22 16:45:33.805  INFO 1868 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/employes],methods=[GET],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public pam.restapi.EmployesResponse pam.restapi.PamController.getEmployes()
2014-10-22 16:45:33.807  INFO 1868 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2014-10-22 16:45:33.807  INFO 1868 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],methods=[],params=[],headers=[],consumes=[],produces=[text/html],custom=[]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest)
2014-10-22 16:45:33.839  INFO 1868 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-10-22 16:45:33.839  INFO 1868 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-10-22 16:45:34.384  INFO 1868 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-10-22 16:45:34.535  INFO 1868 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-10-22 16:45:34.538  INFO 1868 --- [           main] pam.boot.BootWeb                         : Started BootWeb in 11.916 seconds (JVM running for 12.725)
2014-10-22 16:45:39.329  INFO 1868 --- [       Thread-2] ationConfigEmbeddedWebApplicationContext : Closing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@689ab9e2: startup date [Wed Oct 22 16:45:23 CEST 2014]; root of context hierarchy
2014-10-22 16:45:39.331  INFO 1868 --- [       Thread-2] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown
2014-10-22 16:45:39.333  INFO 1868 --- [       Thread-2] j.LocalContainerEntityManagerFactoryBean : Closing JPA EntityManagerFactory for persistence unit 'default'
  • riga 16: l'URL [/salary/{SS}/{ht}/{jt}] è stato risolto;
  • riga 17: l'URL [/employees] è stato individuato;

4.3.2. URL dei servizi web/JSON

Il servizio web / JSON è implementato da Spring MVC ed espone due URL:


@RequestMapping(value = "/employes", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public EmployesResponse getEmployes() {
...
@RequestMapping(value = "/salaire/{SS}/{ht}/{jt}", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
public FeuilleSalaireResponse getFeuilleSalaire(@PathVariable("SS") String SS, @PathVariable("ht") double ht, @PathVariable("jt") int jt) {

Il servizio web accetta i seguenti due URL:

  • riga 1: /employees: per recuperare l'elenco dei dipendenti;
  • Riga 4: /salary/SS/ht/jt: per recuperare la busta paga del dipendente n. [SS] che ha lavorato [ht] ore in [jt] giorni;

Ecco alcuni screenshot che illustrano la situazione.

Interroghiamo i dipendenti:

Image

Eseguiamo il backup del database, riavviamo il server ed eseguiamo la query sui dipendenti:

Image

Interroghiamo uno stipendio:

Image

Richiediamo lo stipendio di una persona inesistente:

Image

4.3.3. Le risposte JSON dal servizio web/JSON

  

Gli URL del servizio web/jSON restituiscono risposte di tipo [Response<T>]:


package client.android.dao.service;
 
import java.util.List;
 
public class Response<T> {
 
    // ----------------- properties
    // operation status
    private int status;
    // any status messages
    private List<String> messages;
    // the body of the reply
    private T body;
 
    // manufacturers
    public Response() {
 
    }
 
    public Response(int status, List<String> messages, T body) {
        this.status = status;
        this.messages = messages;
        this.body = body;
    }
 
    // getters and setters
...
}
  • L'URL [/employees] restituisce un Response<List<Employee>>;
  • L'URL [/salary] restituisce un tipo Response<PayStub>;

La classe [PayrollSheet] è la seguente:


package pam.entities;
 
import java.io.Serializable;
 
public class FeuilleSalaire implements Serializable {
 
    private static final long serialVersionUID = 1L;
    // private fields
    private Employe employe;
    private Cotisation cotisation;
    private ElementsSalaire elementsSalaire;
 
    // manufacturers
    public FeuilleSalaire() {
    }
 
    public FeuilleSalaire(Employe employe, Cotisation cotisation, ElementsSalaire elementsSalaire) {
        ...
    }
 
    // getters and setters
   ...
}
  • riga 9: la classe [Employee] è stata introdotta nella sezione 4.2.3;
  • riga 10: la classe [Contribution] è stata introdotta nella sezione 4.2.3;

La classe [SalaryElements] (riga 11) è la seguente:


package pam.entities;
 
import java.io.Serializable;
 
public class ElementsSalaire implements Serializable {
 
    private static final long serialVersionUID = 1L;
    // private fields
    private double salaireBase;
    private double cotisationsSociales;
    private double indemnitesEntretien;
    private double indemnitesRepas;
    private double salaireNet;
 
    // manufacturers
    public ElementsSalaire() {
 
    }
 
    public ElementsSalaire(double salaireBase, double cotisationsSociales, double indemnitesEntretien, double indemnitesRepas, double salaireNet) {
        ...
    }
 
    // getters and setters
    ...
}

4.4. Test del client Android

Di seguito è riportato il file binario eseguibile del client Android completato:

  

Usa il mouse per trascinare il file [pam-client.apk] qui sopra su un emulatore di tablet [GenyMotion]. Verrà quindi salvato ed eseguito. Avvia anche il server web/JSON se non l'hai già fatto. Lo scopo del client Android è recuperare le informazioni restituite dal server web/JSON e formattarle. Le diverse schermate del client Android sono le seguenti:

Per prima cosa, devi collegarti al servizio web / JSON:

Image

  • in [1], inserisci l'URL del servizio web/JSON. Con l'emulatore, inserisci uno degli indirizzi IP del PC (ma non 127.0.0.1). Con un tablet, inserisci l'indirizzo Wi-Fi del computer che ospita il server web/JSON e disattiva il firewall del server, se presente, poiché potrebbe bloccare le chiamate in entrata;
  • In [2], effettuare l'accesso;

Verrai quindi reindirizzato alla pagina di simulazione:

Image

  • In [3], seleziona un dipendente;
  • In [4], inserisci un numero di ore;
  • In [5], inserisci il numero di giorni;
  • In [6], avvia la simulazione;

La pagina della simulazione risultante è la seguente:

Image

  • in [7], i risultati della simulazione;
  • in [8], salvalo;

Image

  • in [9], l'elenco delle simulazioni;
  • in [10], una simulazione viene eliminata;

Image

  • in [11], non ci sono più simulazioni;
  • In [12], si ritorna al modulo di simulazione;

Image

  • in [13], si torna al modulo;
  • in [14], si torna alla pagina di configurazione;

Image

  • in [15], si torna al modulo di accesso iniziale.

4.5. Lavoro da svolgere

Lo scheletro del client Android presentato in precedenza è a vostra disposizione. È stato creato a partire dal progetto [client-android-skel] descritto nella Sezione 2.

  

Il progetto è eseguibile e contiene già le viste necessarie. Devi semplicemente aggiungere il codice affinché l'applicazione funzioni come previsto. La procedura è la seguente:

  • eseguire la versione completa per comprendere il lavoro da svolgere;
  • eseguire la versione leggera e studiarne il codice. Segue i metodi di progettazione utilizzati nelle pagine precedenti;
  • aggiungere il codice mancante;