Gestione dei turni di lavoro
Nel tuo ufficio, una particolare mansione riveste un ruolo molto importante e pertanto richiede che ci sia sempre (24 ore su 24) qualcuno disponibile a risolvere eventuali criticità.
Il responsabile del personale ha stabilito di suddividere i dipendenti in 6 gruppi e, su base trimestrale, assegnare dei giorni di reperibilità a ciascun gruppo.
Un dipendente è stato incaricato di assegnare i giorni di reperibilità manualmente ai vari gruppi ma l'operazione si rivela molto noiosa e, data la compilazione manuale, si verificano molti errori.
Come potremmo risolvere il problema implementando il tutto su uno script Python?
Definizione del problema
La prima cosa da fare è capire quali sono gli input e gli output del nostro script.
Gli input del nostro programma sono:
- intervallo di date del trimestre considerato (ad esempio 01/10/2021 - 31/12/2021)
- numero di gruppi (nel nostro caso sono 6)
- numero del gruppo dal quale cominceremo l'assegnazione dei turni (non per forza si partirà da 1)
Gli output attesi del nostro programma sono:
- file json strutturato come segue
{
"1": {
"2021-10": [1, 7, 13],
"2021-11": [1, 7, 13],
"2021-12": [1, 7, 13]
},
"2": {
"2021-10": [1, 7, 13],
"2021-11": [1, 7, 13],
"2021-12": [1, 7, 13]
},
}
Il file JSON conterrà un oggetto che avrà delle proprietà, alle quali è associato il nome del gruppo, che conterranno la lista delle date di reperibilità associate al gruppo.
Prerequisiti
Per poter risolvere l'esercizio è opportuno saper gestire in Python:
- argomenti di input
- date
- dizionari
- file json
- classi
Gestione argomenti di input
Il nostro script dovrà attendere dall'utente i seguenti argomenti:
begin_date
end_date
group_number
Per gestire gli argomenti utilizzeremo il modulo argparse
come segue:
import argparse
parser = argparse.ArgumentParser()
parser.add_argument(
"-b",
"--begin-date",
help="Interval begin date: format date as YYYY-MM-DD.",
required=True
)
parser.add_argument(
"-e",
"--end-date",
help="Interval end date: format date as YYYY-MM-DD.",
required=True
)
parser.add_argument(
"-n",
"--group-number",
help="Number of groups to assign",
required=True
)
parser.add_argument(
"-s",
"--group-begin",
help="Number of group to assign on first day",
required=True
)
args = parser.parse_args()
I quattro argomenti che vogliamo ricevere come input sono
obbligatori(required=True
).
Possiamo a questo punto invocare il nostro script: invocandolo senza parametri avremo come output:
python turni_reperibilita.py
# usage: turni_reperibilita.py [-h] -b BEGIN_DATE -e END_DATE -n GROUP_NUMBER -s GROUP_BEGIN
# turni_reperibilita.py: error: the following arguments are required: -b/--begin-date, -e/--end-date, -n/--group-number, -s/--group-begin
Il precedente messaggio di errore indica l'obbligatorietà degli argomenti.
Richiamando lo script con gli opportuni argomenti:
python turni_reperibilita.py -b 2021-10-01 -e 2021-12-31 -n 6 -s 2y
non otterremo alcun messaggio di errore perché gli argomenti saranno opportunamente compilati.
Una volta ottenuti i corretti argomenti di input, provvederemo a convertirli nei tipi di dato che ci serviranno nel seguito del codice. Per convertirli eseguiremo il seguente codice:
start_date = datetime.datetime.strptime(args.begin_date, "%Y-%m-%d")
end_date = datetime.datetime.strptime(args.end_date, "%Y-%m-%d")
number_of_groups = int(args.group_number)
start_group = int(args.start_group)
Definizione della classe Turni
La gestione dell'assegnazione dei turni ai vari gruppi sarà implementata
all'interno di una classe denominata Turni
.
Il programma chiamante che consentirà di implementare quanto desiderato è il seguente:
turni = Turni(number_of_groups)
turni.load(start_date, end_date, start_group)
turni.to_json(
Dal precedente codice si evincono i seguenti metodi:
load
: implementa la creazione della struttura dati che ospiterà il nostro outputto_json
: scrive il risultato all'interno di un file json sul nostro filesystem
Metodo load
Nel metodo load
provvederemo ad implementare la logica di assegnazione
dei giorni ai vari gruppi di lavoro.
Il codice implementato da load
è il seguente:
def load(self, start_date, end_date, start_group):
while start_date <= end_date:
if not self._has_date_key(start_group, start_date):
self._add_date_key(start_group, start_date)
self._add_day(start_group, start_date)
start_date = self._get_next_date(start_date)
start_group = self._get_next_group(start_group)
Il metodo prende come input la data di inizio(start_date
), la data di
fine intervallo(end_date
), ed il numero del gruppo al quale associare il
primo giorno dell'intervallo(start_group
).
Durante l'esecuzione sono ciclate tutte le date dell'intervallo e ogni data è
associata ad uno ed un solo gruppo. Ogni data è inserita, all'interno del
dizionario del gruppo, con la chiave formata dalla stringa %Y-%m
.
Le ultime due righe di codice prelevano i dati che sono utilizzati durante
l'esecuzione del prossimo ciclo.
Il codice dei metodi privati richiamati da load
è il seguente:
def _has_date_key(self, target_group, target_date):
return self._get_date_key(target_date) in self.turni[target_group]
def _add_date_key(self, target_group, target_date):
dict_data_key = {self._get_date_key(target_date): []}
self.turni[target_group].update(dict_data_key)
def _add_day(self, target_group, target_date):
days = self.turni[target_group][self._get_date_key(target_date)]
days.append(target_date.day)
self.turni[target_group].update({self._get_date_key(target_date): days})
def _get_date_key(self, target_date):
return target_date.strftime("%Y-%m")
def _get_next_date(self, target_date):
return target_date + self.delta
def _get_next_group(self, current_group):
return (current_group % self.number_of_groups) + 1
Metodo to_json
Il metodo consente di scrivere la struttura dati implementata dal metodo
load
all'interno di un file json.
Il codice del metodo è il seguente:
def to_json(self, target_path='/tmp/turni.json'):
fh = open(target_path, 'w')
fh.write(json.dumps(self.turni))
fh.close()
La segnatura del metodo ci indica un target_path
che è valorizzato con
un path di default (modificabile dall'utente).
Il codice scrive il contenuto del dizionario self.turni
all'interno del
json.
Conclusioni
In questo articolo hai visto come risolvere un problema di assegnazione di date all'interno di gruppi di lavoro.