Turni lavorativi



  • Turni lavorativi
    di Concetta (utente non iscritto) data: 20/12/2016 12:33:24

    Salve
    Sto preparando una tesi di Laura sulla pianificazione dei turni di infermieri.il problema:
    Orizzonte temporale 31 giorni
    Infermieri 16 di cui 12 lavorano (36 ore a settimana) 1 ( 32 ore a settimana) e 3 (20 ore a settimana)
    I turni sono 4 presto, giorno, tardi e notte ognuno di 8 ore lavorative
    Dal lunedì al venerdì ogni giorno 3 infermieri effettuano i primi tre turni mentre 1 solo quello di notte
    Il sabato e la domenica invece 2 effettuano i primi tre turni mentre 1 solo quello di notte
    Come pianificazione ho scelto che il primo infermiere libero lavora come posso creare un codice VBA che mi automizzi questo. Grazie mille



  • di Luca73 data: 20/12/2016 13:18:45

    Il quesito secondo me non è chiaro.
    Cerca di spiegarti con dettagli (per esempio cosa vuol dire che "il primo infermiere libero lavora"):
    Primo in che senso: alfabetico, età, statura anzianità????
    3x3=9+1x1=10 infermeri al giorno e gli altri riposano?
    Il secondo giorno chi è considerato libero?

    Fai un po di esempi

    Secondo Prova almeno a preparare un file excel di massimo di come saranno impostati gli input e gli output.

    Ciao
    Luca





  • di Concetta data: 20/12/2016 13:37:11

    ho allegato un file excel limitato ad una settimana questo è il problema ma come ben vedi il tutto è effettuato manualmente io vorrei renderlo automatizzato. spero che così sia un po più comprensibile. grazie mille per la risposta

    Concetta



  • di Luca73 data: 20/12/2016 16:20:24

    come gestisci le frazioni di turno.
    sia 36 che 20 non sono multipli di 8 pertanto potranno coprire rispettivamente 4 turni e 2 turni con un avanzo di 4 ore.





  • di Concetta data: 20/12/2016 17:28:23

    Posso effettuare un massimo di 4 ore di straordinario per infermiere a settimana.
    quindi ove necessario tipo infermiere 6 e 7 ecc li utilizzo in altri casi come il 14 e 15 lascio che effettuano meno ore rispetto al normale in quanto non ho nessun vincolo che mi dica di dover utilizzare tutte le ore a disposizione



  • di Luca73 data: 21/12/2016 10:44:41

    Ciao
    Ho provato a buttare giù un codice di primo tentativo. Ti allego il File
    Ho modificato leggermente il foglio per renderlo più adatto al codice stesso.

    Note
    1) nel foglio ho fatto calcolare le ore lavorate per settimana e ho aggiunto il numero di settimana sopra il giorno.
    2) ho aggiunto la cella colorata in verde che permette di selezionare il primo giorno del mese (se lunedi, martedi,...) quando la cambi si cancella il tutto in quanto non più valido
    3) ho aggiunto il pulsante che ti fa partire il programma
    4) Le basi del programma sono:
    4a) all'inizio ti chiede quale vuoi considerare come primo infermiere (ovvero qullo da cui comincia il primo turno del primo giorno)
    4b) il programma seleziona in ordine prima tutti gli infermieri senza fare straordinario in ordine di lista.
    4c) se non esiste un infermiere che può lavorare senza fare straordinario allora cerca sempre in ordine di lista il primo che non abbia già fatto straordinario e che non abbia fatto straordinario la settimana precedente.

    Fammi sapere se ti va bene.


    Riporto il codice qui sotto in quanto il file verrà cancellato nei prossimi giorni.
    Ciao
    Luca
     
    Option Explicit
    Function IlProssimo(Numero, DaInizio, AFine, PassoStep)
    If Numero < AFine Then
        IlProssimo = Numero + 1
    Else
        IlProssimo = DaInizio
    End If
    End Function
    
    Sub Turni()
    Dim Giorno As Integer
    Dim Infermiere As Integer
    Dim Pivot As Range
    Dim Turno
    Dim TurnoNome(1 To 4)
    Dim NumeroInTurno As Integer
    Dim NumeroInTurnoMax As Integer
    Dim Settimana As Integer
    Dim InfermiereOK As Boolean
    Dim IndiceInf As Integer
    Dim NumInfermieri As Integer
    Dim StrReq As Boolean
    
    With Application
          .ScreenUpdating = False
          .EnableEvents = False
    End With
    
    
    
    Range("H5:AL20").ClearContents
    
    TurnoNome(1) = "E"
    TurnoNome(2) = "D"
    TurnoNome(3) = "L"
    TurnoNome(4) = "N"
    
    Set Pivot = Range("G4")
    NumInfermieri = Range(Pivot.Offset(1, 0), Pivot.Offset(1, 0).End(xlDown)).Count
    
    Do
    Infermiere = InputBox("Inserire il Primo Infermiere della Lista. Deve Essere un Numero Compreso tra 1 e " & NumInfermieri & ".", "NUMERO PRIMO INFERMIERE", 1)
    InfermiereOK = Infermiere >= 1 And Infermiere <= NumInfermieri
    Loop Until InfermiereOK
    
    
    
    For Giorno = 1 To 31
        Settimana = Pivot.Offset(-2, Giorno)
        For Turno = 1 To 4
            If ((Pivot.Offset(-1, Giorno) = "S") Or (Pivot.Offset(-1, Giorno) = "D")) Then
                If Turno < 4 Then
                    NumeroInTurnoMax = 2
                Else
                    NumeroInTurnoMax = 1
                End If
            Else
                If Turno < 4 Then
                    NumeroInTurnoMax = 3
                Else
                    NumeroInTurnoMax = 1
                End If
            End If
            For NumeroInTurno = 1 To NumeroInTurnoMax
                Pivot.Offset(Infermiere, Giorno) = TurnoNome(Turno)
                IndiceInf = 0
                Do
                    Infermiere = IlProssimo(Infermiere, 1, NumInfermieri, 1)
                    IndiceInf = IndiceInf + 1
                    InfermiereOK = Pivot.Offset(Infermiere, -6 + Settimana) + 8 <= Pivot.Offset(Infermiere, -6)
                    StrReq = IndiceInf > NumInfermieri
                Loop While (Not (InfermiereOK Or StrReq))
                If StrReq Then
                    IndiceInf = 0
                    Do
                        Infermiere = IlProssimo(Infermiere, 1, NumInfermieri, 1)
                        IndiceInf = IndiceInf + 1
                        InfermiereOK = Pivot.Offset(Infermiere, -6 + Settimana) + 8 <= Pivot.Offset(Infermiere, -6) + 4
                        If Settimana > 1 Then
                            InfermiereOK = InfermiereOK And Pivot.Offset(Infermiere, -6 + Settimana - 1) <= Pivot.Offset(Infermiere, -6) - 4
                        End If
                        StrReq = IndiceInf > NumInfermieri
                    Loop While ((Not InfermiereOK) Or StrReq)
                    If StrReq Then
                        MsgBox ("Non Posso Terminare con i vincoli Proposti")
                        With Application
                            .ScreenUpdating = True
                            .EnableEvents = True
                        End With
                        Exit Sub
                    End If
                End If
            Next NumeroInTurno
        Next Turno
    Next Giorno
    
    With Application
          .ScreenUpdating = True
          .EnableEvents = True
    End With
    
    
    End Sub






  • di Concetta data: 21/12/2016 17:37:15

    Ciao grazie mille sei stato fantastico. Ma se volessi imporre che i sabato e le domeniche a fare i turni sono le stesse persone come posso migliorare il codice. ancora grazie
    Concetta



  • di Luca73 data: 22/12/2016 09:41:09

    Ciao
    problema: con le ipotesi fatte prima il sistema non trova una soluzione.
    4) Le basi del programma sono:
    4a) all'inizio ti chiede quale vuoi considerare come primo infermiere (ovvero qullo da cui comincia il primo turno del primo giorno)
    4b) il programma seleziona in ordine prima tutti gli infermieri senza fare straordinario in ordine di lista.
    4c) se non esiste un infermiere che può lavorare senza fare straordinario allora cerca sempre in ordine di lista il primo che non abbia già fatto straordinario e che non abbia fatto straordinario la settimana precedente.
    Quale ipotesi posso cambiare?
    Ciao
    Luca





  • di Luca73 data: 22/12/2016 13:12:48

    Ciao Nel file Allegato (Turni LT_1) ho abbozzato una proposta.
    Per arrivare a soluzione ho considerato di riempire prima il Sabato e la domenica prima (ed uguali) e poi gli altri giorni.
    Così si arriva a soluzione (in quanto gestisco straordinari su un turno da 8 ore) mentre considerando la domenica ugluale al sabato e come ultimi due giorni della settimana devo verificare di non sforare lo straordinario con un turno di 16 ore.(8 sabato e 8 domenica)
    Ho aggiunto un tasto ulteriore. Quello asinistra fa turni come prima quello a destra fa turni con sabato e domenica uguali.
    Fammi sapere se OK
    Le altre ipotesi non sono styate modificate.
    Ciao
    Luca