Trouver des périodes de disponibilité
Dans deux articles plus anciens (Vérifier l’intersection de dates, Episode 1 et Episode 2), j’utilisais une fonction VBA personnalisée pour vérifier si deux périodes de dates se chevauchent. Par exemple pour vérifier qu’une période est déjà occupée, avant de passer une réservation.
On m’a du coup posé la question inverse : comment obtenir la liste des périodes libres ?
Un schéma pour y voir plus clair
Dans notre table de réservations (voir les articles précédents), nous avons quelque chose comme ça :
Pour le scénario d’aujourd’hui, seule la chambre 10 nous intéresse, et on va dire qu’on cherche les disponibilités entre le 01/12/2012 à 10:00 et le 31/01/2013 à 23:59 (oui, je sais, les dates sont déjà passées, mais on parle d’un univers parallèle 🙂 ).
Sur mon magnifique schéma, les périodes de réservation sont en rouge. Et on souhaite trouver les autres périodes (et, tant qu’à faire, les stocker dans une table, pour un usage ultérieur).
La table des disponibilités
Il nous faut donc une table pour stocker la liste des disponibilités. Cette table aura une structure très simple, que voici :
Le code VBA
Deux procédures VBA vont nous servir à trouver les périodes libres, et à les stocker dans la table des disponibilités. Comme d’habitude, créez un module standard, et recopiez-y ce qui suit (vous devrez adapter les noms de tables et de champs, si votre scénario est différent) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 |
' --- ' LISTE DE DISPONIBILITES ' --- ' Sub ListeDisponibilites( _ ByVal intChambre As Integer, _ ByVal dtDateDebut As Date, _ ByVal dtDateFin As Date) ' Quelques variables... Dim strSQL As String Dim rstResa As DAO.Recordset Dim rstDispo As DAO.Recordset Dim dtDebut As Date Dim dtFin As Date ' Vidage de la table des disponibilités CurrentDb.Execute "DELETE * FROM [tbl Disponibilités];" ' Instruction SQL pour extraire les réservations ' qui courent sur la période concernée strSQL = StringFormat( _ "SELECT *" _ & " FROM [tbl Réservations]" _ & " WHERE DatesIntersect({0}, {1}, [Date Arrivée], [Date Départ])" _ & " AND [Numéro Chambre] = {2}" _ & " ORDER BY [Date Arrivée]", _ DateHeureUS(dtDateDebut), _ DateHeureUS(dtDateFin), _ intChambre) ' Début de la première disponibilité possible dtDebut = dtDateDebut ' Ouverture des Recordsets Set rstResa = CurrentDb.OpenRecordset(strSQL, dbOpenSnapshot) Set rstDispo = CurrentDb.OpenRecordset("tbl Disponibilités", dbOpenDynaset) ' Parcourir toutes les réservations While Not rstResa.EOF ' Si la disponibilité est ok, sa période de fin est ' la date d'arrivée (de départ) de la réservation If dtDebut < rstResa("Date Arrivée") Then dtFin = DateAdd("s", -1, rstResa("Date Arrivée")) ' Stocker la disponibilité StockerDisponibilite rstDispo, dtDebut, dtFin End If ' La prochaine disponibilité commence potentiellement ' à la fin de la réservation dtDebut = DateAdd("s", 1, rstResa("Date Départ")) rstResa.MoveNext Wend ' Traiter la fin de période ' (ce qui peut rester après la dernière réservation) If dtDebut < dtDateFin Then StockerDisponibilite rstDispo, dtDebut, dtDateFin End If rstResa.Close rstDispo.Close Set rstResa = Nothing Set rstDispo = Nothing End Sub ' --- ' STOCKER UNE DISPONIBILITE DANS UNE TABLE ' --- ' Sub StockerDisponibilite( _ rstDispo As DAO.Recordset, _ dtDebut As Date, _ dtFin As Date) rstDispo.AddNew rstDispo("Date Début") = dtDebut rstDispo("Date Fin") = dtFin rstDispo.Update End Sub |
Le code ci-dessus utilise lui-même d’autres fonctions proposées sur le blog. Pensez à les récupérer sur ces articles :
- Vérifier l’intersection de dates, pour la fonction
DatesIntersect()
- Dates anglo-saxonnes, pour la fonction
DateHeureUS()
- Marre des concaténations, pour la fonction
StringFormat()
Votre projet VBA doit également avoir une référence vers la bibliothèque Microsoft DAO.
Quelques infos
- La première procédure est supposée recevoir 3 paramètres : le numéro de chambre, la date de début et la date de fin de la période globale (celle sur laquelle on cherche des disponibilités).
- Globalement, cette procédure récupère les réservations par ordre chronologique, les parcourt une par une et en déduit les périodes libres.
- La deuxième procédure sert simplement à stocker une période libre, dans la table des disponibilités.
- Les périodes libres sont déterminées à la seconde près par rapport aux périodes de réservations (1 seconde avant, ou 1 seconde après la réservation).
Tester
Pour tester tout ça :
- Ouvrez la fenêtre Exécution (
Ctrl
+G
). - Tapez dans cette fenêtre quelque chose comme :
1 |
ListeDisponibilites 10, #12/01/2012#, #01/31/2013 23:59:59# |
- Validez par la touche
Entrée
. - Ouvrez la table des disponibilités.
A vous de jouer !
L’interface autour de tout ça est plutôt brute ! Vous pouvez maintenant :
- Créer un formulaire pour la saisie des dates de début/fin de période.
- Prévoir un bouton pour déclencher la procédure de recherche (au lieu de passer par la fenêtre Exécution).
- Faire en sorte que la table des disponibilités s’affiche en sous-formulaire, ou dans une
ListBox
.
Bonjour
et merci pour votre site qui est une mine d’or d’informations
Je rebondit sur votre article
Cette disponibilité entre deux dates pourrait parfaitement convenir a ma petite base donnée
Mais j ai affaire a des articles en location
avec des mouvement (entrees & sorties)
Mais je possede non pas 1 seule chambre d’hotel mais enormenet de references ayant eux meme des quantités distinctes
23 x produit x
30 x produit y
….
Comment intégrer la quantité dans votre code
Merci!!
Si j’ai suivi : le fait d’avoir une quantité ne permet pas de différencier les articles.
Du coup, ce n’est pas possible directement de réserver un article s’il n’est pas unique.
Mais il y a sûrement des adaptations possibles… Les articles sont de quelle nature exactement ?