Developpez.com - Access
X

Choisissez d'abord la catégorieensuite la rubrique :


Planning hebdomadaire pour gérer les rendez-vous

Date de publication : 19 juin 2009

Par Denis Hulo
 

Planifier des rendez-vous dans un formulaire Access. Niveau requis : intermédiaire.

               Version PDF (Miroir)   Version hors-ligne (Miroir)

I. Introduction
II. Rendu final de l'application
III. Structure des données
IV. Réalisation des formulaires
IV-A. Le sous-formulaire SF_Planning
IV-A-1. Description de la technique de création dynamique des labels
IV-A-2. La fonction OuvrirFormRendezVous sur l'évènement double-clic
IV-B. Le formulaire principal F_Planning
IV-B-1. Le contrôle DateTimePicker
IV-B-2. Les contrôles à la place du DateTimePicker
IV-B-3. Codage du formulaire
IV-C. Le formulaire F_RendezVous
V. Le module M_Planning de l'application
V-A. Description de quelques routines
V-B. La procédure InitPlanning
V-C. La procédure MajPlanning
VI. Les applications à télécharger
VII. Remerciements


I. Introduction

Sur le forum Access de nombreuses questions sont relatives à la planification.

Voici donc un cas relativement simple de planification de rendez-vous des patients dans un cabinet médical, facile à adapter à vos besoins :

Nous considérons des horaires journaliers qui s'étalent de 08:00 à 18:00 avec des créneaux horaires de 15 minutes.

Dans ce planning hebdomadaire, nous aurons donc en lignes les horaires, et en colonnes les jours de la semaine : nous décrirons dans cet article une technique de création dynamique du planning qui pourra être réutilisée dans d'autres applications du même type.

En plus du numéro du patient, il nous faudra aussi sauvegarder dans une table la date du jour et l'horaire de début et de fin du rendez-vous. Ainsi le mieux sera de considérer l'horaire de début et l'horaire de fin du RDV comme des champs au format date générale (Date/Heure).

En outre, pour simplifier la saisie des rendez-vous, il devra être possible de choisir l'horaire et donc d'ajouter un RDV par un simple clic (ou double-clic) sur le label (étiquette) situé à l'intersection d'une ligne (horaire) et d'une colonne (jour).

Enfin, pour faciliter son développement et assurer sa portabilité, à l'exception du contrôle DTPicker (normalement disponible dans Autres contrôles de la boîte à outils), l'application n'utilise pas de composants externes à Access (ActiveX ou autre).


II. Rendu final de l'application

Voici le rendu du planning hebdomadaire qui présente les rendez-vous des patients sur un ou plusieurs créneaux horaires et sur les 7 jours de la semaine.

Un double-clic sur un créneau horaire ouvre le formulaire des rendez-vous pour la saisie.

III. Structure des données

Nous allons tout d'abord définir les tables et les champs qui contiendront les données :

L'application réduite au maximum se contentera de 2 tables, la table T_RendezVous contenant les rendez-vous des patients et la table T_Patient contenant les informations relatives aux patients.

La table T_RendezVous :

Nom du champ Type de données Description
NR Numéro auto Numéro d'ordre du rendez-vous.
NP Entier long Numéro d'ordre du patient ayant le RDV.
HoraireDebut Date/Heure Jour et horaire de début du RDV.
HoraireFin Date/Heure Jour et horaire de fin du RDV.
Memo Mémo Commentaire du médecin sur le patient.
 

La table T_Patient :

Nom du champ Type de données Description
NP Numéro Auto Numéro d'ordre du patient.
Nom Texte Nom du patient.
Prénom Texte Prénom du patient.
DNaiss Date Date de naissance.
Rue Mémo Rue de la ville où réside le patient.
CP Texte Code postal de la ville où réside le patient.
Ville Texte Ville où réside le patient.
Tel Texte Téléphone du patient.
Email Texte Email.
 

Dans notre cas, seuls les 2 premiers champs de la table sont indispensables


IV. Réalisation des formulaires

La deuxième étape consiste à créer les formulaires.


IV-A. Le sous-formulaire SF_Planning

Il contient le tableau de labels (40x7), plus les en-têtes de lignes (les horaires journaliers) et les en-têtes de colonnes (les jours de la semaine).

Les labels sont créés manuellement dans le formulaire en mode création, du dernier (creneau40_7) au premier (creneau1_1). Ceci permet aux premiers labels de se superposer aux suivants quand on les redimensionne.

Apercu du formulaire SF_Planning en mode création
 

La création des 40x7 labels, plus les en-têtes, peut être fastidieuse, c'est pourquoi j'ai conçu un outil permettant d'automatiser le tout et de créer dynamiquement ces labels.


IV-A-1. Description de la technique de création dynamique des labels

Dans le programme CreerPlanning, après avoir ouvert le formulaire F_CreerPlanning, il vous suffit d'indiquer le nom du formulaire contenant le planning, le nombre de colonnes et de lignes du planning, les noms génériques des labels et leurs dimensions ainsi que le nom de la fonction qui s'exécute sur double-clic des labels (ici il s'agit de la fonction OuvrirFormRendezVous décrite plus loin) et de valider le tout :

La procédure CreerPlanning supprime alors tous les contrôles du formulaire en mode création et crée dynamiquement les labels du planning dans l'ordre inverse, du dernier au premier en affectant à l'évènement double-clic de chaque label le nom de la fonction passé en argument.

Le détail de la procédure de création du planning se trouve dans le module du programme.


IV-A-2. La fonction OuvrirFormRendezVous sur l'évènement double-clic

Elle est affectée dynamiquement à l'évènement double-clic des labels du planning et son code se trouve dans le module de l'application :

Public Function OuvrirFormRendezVous(i As Integer, j As Integer)
' Ouvre le formulaire F_RendezVous sur double-clic d'un label du planning.
' Prend en arguments les indices de ligne et de colonne. 

Dim DateC As Date ' Jour et Horaire choisis.
Dim LeSql As String
Dim rsRdV As DAO.Recordset ' Utilise une référence à DAO. 

DateC = IndicesToHoraire(i, j) ' renvoie la date et l'heure correspondant aux indices
   
LeSql = "SELECT T_RendezVous.* " & _
        "FROM T_RendezVous " & _
        "WHERE T_RendezVous.HoraireDebut<=" & FormatDateUS(DateC) & _ 
		 " And T_RendezVous.HoraireFin>" & FormatDateUS(DateC)
   
' Sélectionne dans un recordset le rendez-vous correspondant au créneau choisi par 
' double-clic.
Set rsRdV = CurrentDb.OpenRecordset(LeSql, dbOpenForwardOnly)
       
 ' S'il y a un RDV, alors copier dans la variable DateC l'horaire de début du RDV.             
      If Not (rsRdV.EOF) Then DateC = rsRdV!HoraireDebut
   
 ' Ouvre le formulaire F_RendezVous.

DoCmd.OpenForm "F_RendezVous", , , "HoraireDebut=" & FormatDateUS(DateC)

Forms!F_RendezVous!DateRdV = DateC
Forms!F_RendezVous!HoraireD = Format(DateC, "hh:nn")
   
     If Not (rsRdV.EOF) Then 
          Forms!F_RendezVous!HoraireF = Format(rsRdV!HoraireFin, "hh:nn")
     Else
          Forms!F_RendezVous!HoraireF = Format(DateAdd("n", 30, DateC), "hh:nn")
     End If
         
rsRdV.Close
   
End Function
Et après, sur l'évènement double-clic d'un label, par exemple le premier créneau (creneau1_1), on appelle la fonction OuvrirFormRendezVous(1, 1) :

creneau1_1.OnDblClick = "=OuvrirFormRendezVous(1, 1)"


IV-B. Le formulaire principal F_Planning

Contient le sous-formulaire SF_Planning (le planning hebdomadaire), les boutons de commande pour avancer ou reculer d'une semaine et le contrôle DateTimePicker (DTPicker) pour choisir le 1er jour de la semaine.


IV-B-1. Le contrôle DateTimePicker

Ce contrôle est utilisé pour permettre à l'utilisateur de sélectionner une date, et pour afficher cette valeur au format spécifié. Les utilisateurs peuvent ainsi choisir une date dans un calendrier.

Pour l'inscrire dans la base de registres, sous Access 2000 à 2003, choisir dans le menu Outils, l'item Contrôles ActiveX. Le contrôle doit normalement apparaître dans la liste des ActiveX :

Apercu de la liste des contrôles ActiveX

Si le contrôle n'est pas présent dans la liste, appuyer sur le bouton Inscrire dans la base de registres et chercher le fichier c:\Windows\system32\MSCOMCT2.OCX.

Une fois le contrôle enregistré dans la base de registres, il ne vous reste plus qu'à le sélectionner dans Autres contrôles :

Apercu de la liste des autres contrôles ActiveX


IV-B-2. Les contrôles à la place du DateTimePicker

Pour ceux qui rencontrent des problèmes avec le DTPicker, je vous conseille de le remplacer par le contrôle calendrier de Thierry Gasperment.

Pour les utilisateurs d'Access 2007, vous pouvez aussi utiliser à la place du contrôle DTPicker une zone de texte et ajouter la prise en charge du calendrier à ce contrôle.


IV-B-3. Codage du formulaire

Contenu du module du formulaire F_Planning :

Option Compare Database
Option Explicit

Private Sub CmdPrecedent_Click()
' Sur l'évènement "clic" du bouton de commande CmdPrecedent.

DateDebut = DateDebut - 7 ' Recule de 7 jours dans le temps.
MajPlanning ' Met à jour le planning.
End Sub

Private Sub CmdSuivant_Click()
' Sur l'évènement "clic" du bouton de commande CmdSuivant.

DateDebut = DateDebut + 7 ' Avance de 7 jours dans le temps.
MajPlanning ' Met à jour le planning.
End Sub

Private Sub DateD_Change()
' Sur l'évènement "changement" du contrôle DTPicker.

DateDebut = DebutSemaine(DateD.Value) ' Renvoie le premier jour de la semaine choisie.
MajPlanning ' Met à jour le planning.

End Sub

Private Sub Form_Load()
' Sur chargement du formulaire.

DateDebut = DebutSemaine(Date) ' Renvoie le premier jour de la semaine courante.
MajPlanning ' Met à jour le planning.
DoCmd.Maximize
End Sub

IV-C. Le formulaire F_RendezVous

Il permet d'ajouter, de modifier ou de supprimer un rendez-vous. Ce formulaire s'ouvre sur l'évènement double-clic des labels du planning (SF_Planning).

Aperçu du formulaire


Exemple de code simple, sur l'évènement clic du bouton de commande CmdValider on a :

Private Sub CmdValider_Click()
' Valide les choix effectués sur le formulaire F_RendezVous.
' et met à jour le planning.
Dim d As Integer
Dim LeSql As String, HD As Date, HF As Date, DateC As Date
Dim rsRdV As Recordset

DateC = CDate(Me!DateRdV)

' Si les zones de texte NP ou Memo ne sont pas vides.

   If ((Me!NP <> "") And Not IsNull(Me!NP)) Or _
      ((Me!Memo <> "") And Not IsNull(Me!Memo)) Then
   HD = CDate(Format(Me!DateRdV, "dd/mm/yy ") & Me!HoraireD)
   HF = CDate(Format(Me!DateRdV, "dd/mm/yy ") & Me!HoraireF)
  
' On recherche des RDV dont les horaires de début et de fin chevauchent les 
' horaires choisis sur le formulaire.
    
   LeSql = "SELECT * " & _
   "FROM T_RendezVous " & _
   "WHERE (HoraireDebut<>" & FormatDateUS(DateC) & ") And HoraireDebut<" & FormatDateUS(HF) & _
                                                      " And HoraireFin>" & FormatDateUS(HD)
   
   Set rsRdV = CurrentDb.OpenRecordset(LeSql, dbOpenForwardOnly)
      
       If (Format(HF, "hh:nn") <= "18:00") And (HD < HF) Then

' Si aucun RDV n'a été trouvé, la plage horaire est donc disponible et on peut  
' enregistrer le RDV.
          If rsRdV.EOF Then
             Me!HoraireDebut = HD
             Me!HoraireFin = HF
             Me.Requery ' Actualisation de la table source T_RendezVous.
             MajPlanning ' Mise à jour du planning.
             DoCmd.Close  ' Fermeture du formulaire.    
          Else
             MsgBox ("Saisie incorrecte !")      
          End If             
      Else
         MsgBox ("Saisie incorrecte !")             
      End If   
   Else
      MsgBox ("Saisie incorrecte !")
   End If

End Sub

V. Le module M_Planning de l'application

Enfin nous présentons le module de l'application.


V-A. Description de quelques routines

Quelques routines utilisant les fonctions Date et Heure :

' Dans la partie déclaration du module on définit la date du 1er jour du planning 
' hebdomadaire.

Public DateDebut as date 

' Les fonctions du module.

Public Function FormatDateUS(laDate As Date) As String
' Formate la date passée en argument en date US.

FormatDateUS = Chr(35) & Format(laDate, "m-d-yy hh:nn:ss") & Chr(35)  ' Date au format US.
End Function

Private Function EstWeek(laDate As Date)
EstWeek = ((WeekDay(laDate) > 1) And (WeekDay(laDate) < 7)) ' est un jour de la semaine.
End Function

Function DebutSemaine(ByVal DateSemaine As Date) As Date
' Prend en argument un jour dans la semaine choisie 
' et renvoie la date du premier jour de cette semaine.
Dim i As Integer

i = WeekDay(DateSemaine, vbMonday)
DebutSemaine = DateAdd("d", -i + 1, DateSemaine)
End Function

Function NbreCreneaux(ByVal HoraireD as date, ByVal HoraireF as Date) as integer
' La fonction prend en argument l'horaire de début et de fin du RDV 
' et renvoie le nombre de créneaux de 15 minutes entre ces 2 horaires :

NbreCreneaux=DateDiff("n",HoraireD,HoraireF)/15

End function

Function PremierCreneau(ByVal HoraireD as date) as integer
' La fonction prend en argument l'horaire de début du rendez-vous et renvoie l'indice 
' du premier créneau horaire du RDV. Les horaires commencent à 8 heures.

PremierCreneau=(DateDiff("n",#08:00#,TimeValue(HoraireD))/15) + 1

End function

Function IndiceColonne(ByVal HoraireD as date) as integer
' La fonction prend en argument l'horaire de début du RDV et renvoie l'indice de la 
' colonne (le jour) correspondant sur le planning.

IndiceColonne =DateDiff("d", DateDebut, HoraireD)+1

End function

Public Function IndicesToHoraire(ByVal Ligne As Integer, ByVal Col As Integer) As Date
' La fonction prend en argument les indices de ligne (les horaires) et de 
' colonne (les jours) sur le planning et renvoie l'horaire correspondant. 

Dim DateC As Date 
Dim h As Integer
Dim m As Integer

DateC = DateAdd("d", (Col - 1), DateDebut)
h = (8)  
m = (h * 60) + 15 * (Ligne - 1)
DateC = DateAdd("n", m, DateC)

IndicesToHoraire = DateC

End Function

V-B. La procédure InitPlanning

La procédure InitPlanning efface le contenu du planning, redimensionne les labels à leur taille d'origine et met à jour les en-têtes de colonnes avec les jours de la semaine choisie.

Private Sub InitPlanning()
' Initialise le planning hebdomadaire avant sa mise à jour :
' Efface tous les rendez-vous, redimensionne les labels 
' et remplit les en-têtes de colonnes avec les jours de la semaine choisie.

Dim i As Integer, j As Integer
Dim DateC As Date ' Date courante qui prend successivement les valeurs des jours de la semaine.
For i = 1 To 40 ' on parcourt les indices des lignes.

   For j = 1 To 7 ' on parcourt les indices de colonnes (les jours) 
   Forms!F_Planning!Planning.Form("creneau" & i & "_" & j).Caption = ""
   
      If (i Mod 2) = 1 Then ' on alterne les couleurs de lignes.
         Forms!F_Planning!Planning.Form("creneau" & i & "_" & j).BackColor = -2147483624
      Else
         Forms!F_Planning!Planning.Form("creneau" & i & "_" & j).BackColor = vbWhite
      End If

' On définit la hauteur des lignes.      
   Forms!F_Planning!Planning.Form("creneau" & i & "_" & j).Height = 350
   Next j

Next i

For i = 1 To 7

DateC = DateAdd("d", (i - 1), DateDebut)
Forms!F_Planning!Planning.Form("Col" & i).Caption = Format(DateC, "ddd dd mmm yyyy")
   
   If EstWeek(DateC) Then 'on colorie les en-têtes (rouge pour les week-end)
      Forms!F_Planning!Planning.Form("Col" & i).BackColor = 16761024
   Else
      Forms!F_Planning!Planning.Form("Col" & i).BackColor = 16761087
   End If
   
Next i
   
End Sub

V-C. La procédure MajPlanning

La procédure de mise à jour des rendez-vous sur le planning s'effectue comme suit: Elle sélectionne, avec DAO, dans la table T_RendezVous, les RDV compris entre la date de début (DateDebut) et la date de début + 7 jours (DateDebut+7), puis met à jour le planning avec ces rendez-vous. Pour chaque RDV l'horaire de début et l'horaire de fin permettent de dimensionner le label correspondant au créneau horaire du début :

Public Sub MajPlanning()   
Dim RsPL As DAO.Recordset
Dim Ligne As Integer, Col As Integer
Dim LeSql As String
Dim i As Integer, d As Integer
Dim color As Long
              
' Sélectionne les RDV compris entre DateDebut et DateDebut+7.
LeSql = "SELECT T_RendezVous.*, T_Patient.Nom as Patient " & _
"FROM T_RendezVous LEFT JOIN T_Patient ON T_RendezVous.NP = T_Patient.NP " & _
"WHERE T_RendezVous.HoraireDebut between " & FormatDateUS(DateDebut) & _
                                         " And " & FormatDateUS(DateDebut + 7)

Set RsPL = CurrentDb.OpenRecordset(LeSql, dbOpenForwardOnly)

Forms!F_Planning!Titre.Caption = "PLANNING DE LA SEMAINE DU " & _ 
UCase(Format(DateDebut, "dd mmmm yyyy")) & " AU " & UCase(Format(DateDebut+6,"dd mmmm yyyy"))

Forms!F_Planning!DateD.Value = DateDebut

' Initialise le planning.
InitPlanning
     
   Do While Not (RsPL.EOF) ' on parcours les RDV.
   Col = IndiceColonne(RsPL!HoraireDebut)
   Ligne = PremierCreneau(RsPL!HoraireDebut)   

   ' on determine le nombre de créneaux horaires correspondant à la durée du RDV.
   d = DateDiff("n", RsPL!HoraireDebut, RsPL!HoraireFin) \ 15 
   
   ' Hauteur du label = Hauteur de la ligne multipliée par le nombre de créneaux.
   Forms!F_Planning!Planning.Form("creneau" & Ligne & "_" & Col).Height = 350 * d 
      
      ' Si le numéro du patient est nul, alors il ne s'agit pas d'un RDV.
      If IsNull(RsPL!NP) Then 
         color = 16761087
         Forms!F_Planning!Planning.Form("creneau"&Ligne& "_" &Col).Caption=CentrerTexte("Autre", d)
      
      ' sinon on remplie le label avec le nom du patient 
      ' accompagné du numéro du patient entre crochets
      Else 
         color = QBColor(RsPL!NP Mod 14 + 1) ' Définit la couleur.
         Forms!F_Planning!Planning.Form("creneau" & Ligne & "_" & Col).Caption = _
		                    CentrerTexte(RsPL!Patient & " [" & RsPL!NP & "]", d)   
      End If
   
   ' Colorie le label.
        
   Forms!F_Planning!Planning.Form("creneau" & Ligne & "_" & Col).BackColor = color
         
   RsPL.MoveNext
   Loop

' ==== Libération des variables ====

RsPL.Close
Set RsPL = Nothing

End Sub

VI. Les applications à télécharger

La base exemple n°1 est au format Access 2000, elle inclut le contrôle DTPicker.

La base exemple n°2 est au format Access 2000 et comprend le contrôle calendrier de Arkham46.

La base exemple n°3 est au format Access 2000 et comprend de nombreuses autres fonctionnalités (congés, jours fériés...).


VII. Remerciements

Je tiens à remercier Jean Ballat pour m'avoir guidé dans la réalisation de ce premier article et ram-0000 pour sa relecture.



               Version PDF (Miroir)   Version hors-ligne (Miroir)

Valid XHTML 1.0 TransitionalValid CSS!

Copyright © 2009 Denis Hulo. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Responsables bénévoles de la rubrique Access : Pierre Fauconnier - Arkham46 -