[VBA] amélioration tableau mémoire

Bonjour à tous,

À mon petit niveau, j'arrive maintenant à peu près à me débrouiller avec les tableaux en mémoire, grâce aux aides et astuces de Pijaku, h2so4, LouReed, Eriiic, etc.
Je vous remercie encore une fois infiniment, c'est génial.

Je suis du coup arrivé à pondre le petit code imparfait ci-dessous. Il permet de créer le planning de certaines personnes, à partir d'une base de données (feuil8), dans laquelle on a des 1 ou du vide, dans les colonnes LUNDI, MARDI ... DIMANCHE. Il ne génère rien si le jour est férié.

C'est pas grand chose, mais j'en suis déjà content.

Mon souci, c'est que si une personne est hospitalisée, il ne faudrait pas lui générer de croix. On sait qu'une personne est hospitalisée si une date est rentrée dans la colonne hospitalisation (on notera la date de début d'indisponibilité de la personne).

Je n'arrive pas, dans la logique, à inclure ceci. Pareil, il faudrait que si la date de début de service de la personne se trouve un mois ultérieur à celui qu'on veut créer, alors on zappe la personne. Ca me paraît intégrable au 'si OK ou hospitalisation', mais je pense que pour résoudre le problème, il devrait sauter.

Le bouton "nouveau mois" est actif, c'est celui qui lance la macro.

Sub créerMois()
Dim ladate As String, ShNew As String
Dim jour As String

ladate = Format(Year(Date) & "/" & Month(Date) + 1 & "/" & 1, "dd/mm/yyyy") 'on propose le 1er jour du mois suivant
ladate = InputBox("Date du 1er jour du mois à créer ?", "Création", ladate)
If IsDate(ladate) = False Then Exit Sub 'si mauvaise date rentrée, on quitte

[D5] = CDbl(CDate(ladate)) 'on écrit le date en D5, le reste du mois s'adapte
ShNew = Format(ladate, "mmmm") 'on récupère le mois en toutes lettres pour nommer la feuille qu'on va créer
ActiveSheet.Copy after:=ActiveSheet: ActiveSheet.Name = ShNew 'on copie la feuille et on la nomme avec notre variable
ActiveSheet.Shapes.Range(Array("Rectangle : coins arrondis 2")).Delete 'on supprime la forme de création de mois

    Dim tablo()
    Dim j As Integer
    j = 0
With Feuil8.ListObjects("T_BDD").ListColumns("DÉBUT DU SERVICE").Range.Cells(1, 1) 'la référence est la cellule "Début de service, BD feuil8

For i = 1 To Feuil8.Range("T_BDD").Rows.Count 'on boucle de 1 au nombre total de lignes de la BDD

'si la cellule "SITUATION" de la ligne concernée est égale à "OK" ou "Hospitaliation"
            If UCase(.Offset(i, 11).Value) = "OK" Or UCase(.Offset(i, 11).Value) = "HOSPITALISATION" Then
                j = j + 1 'on incrémente J
                ReDim Preserve tablo(1 To 157, 1 To j)
                tablo(1, j) = .Offset(i, -10) '1ère valeur = numéro
                tablo(2, j) = .Offset(i, -8) '2ème valeur = nom
                tablo(3, j) = .Offset(i, -2) '3ème valeur = régime
For k = 4 To 157 Step 5 'on n'aura pas forcément de 4ème valeur, ou 5ème, etc. Donc variable qui va adapter.

'si D5 est une date, et n'est pas un jour férié, alors
                    If IsDate(Sheets(ShNew).Range("A5").Offset(0, k - 1)) And _
                    Not (IsNumeric(Application.Match(Sheets(ShNew).Range("A5").Offset(0, k - 1), Feuil8.Range("AB1:AB200"), 0))) Then
                    jour = UCase(Format(Sheets(ShNew).Range("A5").Offset(0, k - 1), "dddd")) 'on récupère le jour de la date en toutes lettres
                        If Feuil8.ListObjects("T_BDD").ListColumns(jour).Range.Cells(i + 1, 1) = 1 Then 'si la cellule ligne actuelle, dans la colonne nommée comme le jour est égale à 1
                            tablo(k, j) = "X" 'la ligne k du tableau est égale à "X"
                                If .Offset(i, 8) = 1 Then tablo(k + 1, j) = "X" 'si la valeur "pain" est égale à 1, k+1 = "X"
                                    If .Offset(i, 9) = 1 Then tablo(k + 2, j) = "X" 'si la valeur "potage" est égale à 1, k+2 = "X"
                                        If .Offset(i, 10) = 1 Then tablo(k + 3, j) = "X" 'si la valeur "soir" est égale à 1, k+3 = "X"
                        Else: End If
                    Else: End If
Next k 'une fois tous les tests effectués pour une date, on passe 5 colonnes à droite, donc au lendemain
            Else: End If
Next i 'une fois tous les jours du mois passés, on passe à la personne suivante et on recommence

End With
Sheets(ShNew).Cells(7, 1).Resize(UBound(tablo, 2), UBound(tablo, 1)) = Application.Transpose(tablo) 'on colle tout ça au bon endroit.

End Sub
31exemple-algo.xlsm (139.55 Ko)

Merci beaucoup à vous, si certains veulent passer du temps pour m'aider à améliorer ceci !

Salut JoyeuxNoël,

premières choses avant de continuer le décorticage...
- vérifier que la feuille ne soit pas déjà créée ;
- le nom de la forme "Rectangle" copiée sera toujours '1', me semble-t-il, et sera à chrcher dans la feuille du nom "ShNew".

ShNew = Format(ladate, "mmmm") 'on récupère le mois en toutes lettres pour nommer la feuille qu'on va créer
For x = 1 To Sheets.Count
    If Sheets(x).Name = ShNew Then _
        MsgBox "Ce mois a déjà été créé !": _
        Exit Sub
Next
ActiveSheet.Copy after:=ActiveSheet: ActiveSheet.Name = ShNew 'on copie la feuille et on la nomme avec notre variable
Worksheets(ShNew).Shapes.Range(Array("Rectangle : coins arrondis 1")).Delete 'on supprime la forme de création de mois

Avant de me casser la tête à comprendre :
- comment définis-tu le menu précis de chaque personne ?
Déso, parlé trop vite...
- valeurs "Livrée", "Livré",... ?? Différences ? Utilité ? Entrée manuelle ?


A+

Bonjour,

Chez moi (2016) ces shapes ne sont pas copiées et provoquent une erreur si on essaie de les supprimer.

Ça me parait pas net cette histoire de OK et d'hospitalisation... Il me semble que si OK on livre mais pas si "hospitalisation"...

A quoi doit-on se fier : A la colonne V ou à la colonne X... pourquoi faire 2 colonnes ? Ça augmente le risque que les 2 colonnes ne concordent pas...

A+

Bonjour,

merci de vous être intéressés à mon sujet, qui n'est qu'une petite partie d'un projet plus vaste. Je vous ai recrée une petite partie ici. Les jours fériés ne sont normalement pas ici, de même que la source de la liste déroulante.

@Curulis :

Une fois le mois passé, la feuille sera archivée. On ne devrait donc pas avoir ce souci. Je pensais rajouter une vérification à ce niveau. C'est vrai que j'aurais pu le faire avant. Merci pour le bout de code !

Le nom de la forme est actuellement 2, il y en a une autre, que j'ai supprimée sur cette version. Au moment de la copie, elle garde son nom, donc normalement là-dessus c'est OK.

Pour ce qui est des valeurs livré à ce jour, livrée à ce jour, ce seront à priori seulement des données à titre indicatif, reste d'un ancien mode de fonctionnement (qui sautera certainement à terme et n'intervient en rien dans nos calculs).

@Galopin :
Mince, bizarre, je l'ai fait sous 2013. Je ne vois pas de raison que ça foire sur 2016. Je vais essayer sur 2019 aussi.

On ne livre effectivement que si OK, ou si une date d'hospitalisation est renseignée, mais ultérieure à la date du jour (si elle a été programmée. Je ne sais pas si ce cas de figure peut arriver, mais j'aime autant anticiper).
Mais là c'est au moment de la création du mois. Il faut qu'une personne hospitalisée soit créée quand même. Son hospitalisation peut se terminer à tout moment et il faudra à nouveau la livrer à son retour. C'est donc aussi pratique si elle a déjà été générée.
Par contre, on ne lui mettra pas de croix si son statut est hospitalisé ET que la date concernée est postérieure à la date de début d'hospitalisation.

J'espère être clair. J'ai peut-être écrit mon poste initial trop précipitamment.

Bonsoir,

Moi je te le donne comme je le comprend et sans ton charabia d'Offset pour cause d'incompréhension.

De plus je n'ai gardé que la condition sur la date de départ et "OK" parce que tes explications sur les hospitalisation, pour moi c'est du jus de boudin.

Eventuellement YAPUKA rajouter des condition à Y...Tu verras c'est intuitif ! Il suffit que chaque ligne de Y soit Vrai :

Quand les idées sont claires les mots pour le dire se trouvent aisément...

Je n'ai rempli que les 3 premières colonnes pour cause d'allergies aux complications :

Tous le reste des adresses doit être écrit "en dur" comme ces 3 premières colonnes.

On ne fait référence qu'au tableau source et au tableau cible : Ça se lit comme la feuille...

C'est quand même plus simple que de calculer des décalages...

A+

16exemple-algo-vg.xlsm (138.43 Ko)

Je viens de réfrléchir que pour évaluer la date, étant donné que ArrC n'intègrent pas laDate, tu auras besoin de te faire une petite Fonction perso qui évaluera en fonction de "k" et de "laDate" si "leJour" est un dimanche ou un Férié...

Je n'ai pas envie de travailler la dessus maintenant : Galopin est un couche tôt... Mais demain j'essaierai de te bricoler une "tite" fonction simple à partir de ces param... pour que tu puisses ajuster ton remplissage...

A+

Salut JoyeuxNoël,
Salut Galopin (bonne nuit ! ),

- à l'ouverture du fichier, une macro décide de l'affichage "Hospitalisation" si une date en [X:X] arrive à échéance ;

Private Sub Workbook_Open()
'
With Worksheets("Noms & Coordonnées")
    For x = 2 To .Range("X" & Rows.Count).End(xlUp).Row
        If .Range("X" & x).Value <> "" Then _
            If IsDate(.Range("X" & x).Value) Then _
                If CDate(.Range("X" & x).Value) <= Date Then .Range("V" & x).Value = "Hospitalisation"
    Next
End With
'
End Sub

- petite gestion des données de l'InputBox (ne t'étonne pas, je me sers souvent des mêmes variables pour plusieurs choses tant qu'elles ne s'entrechoquent pas, bien sûr)

Do
    iOK = 1
    ShNew = Application.InputBox("Date du 1er jour du mois à créer ?", "Création", Default:=Format(dDate, "[$-040C]dd/mm/yyyy"), Type:=2)
    If IsDate(ShNew) Then
        If Day(CDate(ShNew)) = 1 Then
            iOK = 0
            For x = 1 To Sheets.Count
                If Sheets(x).Name = WorksheetFunction.Proper(Format(CDate(ShNew), "mmmm")) Then _
                    MsgBox "Ce mois a déjà été créé !": _
                    iOK = 1
            Next
        End If
    End If
Loop Until iOK = 0 Or ShNew = "Faux"
If ShNew = "Faux" Then Exit Sub

- calcul principal

tBDD = Range("T_BDD").Value
iOK = WorksheetFunction.CountIf(Range("T_BDD[STATUT]"), "OK") + WorksheetFunction.CountIf(Range("T_BDD[STATUT]"), "Hospitalisation")
With Worksheets(ShNew)
    tExtract = .Range("A7:FB" & 6 + iOK).Value
    For x = 1 To UBound(tBDD, 1)
        iOK = 0
        If tBDD(x, 22) = "OK" Or tBDD(x, 22) = "Hospitalisation" Then
            iIdx = iIdx + 1
            tExtract(iIdx, 1) = tBDD(x, 1)
            tExtract(iIdx, 2) = tBDD(x, 3)
            tExtract(iIdx, 3) = tBDD(x, 9)
            For y = 1 To Day(DateAdd("m", 1, dDate) - 1)
                dToday = DateAdd("d", iOK, dDate)
                If CDate(tBDD(x, 11)) <= dToday And Not IsNumeric(Application.Match(dToday, sWkNC.Range("AB1:AB" & sWkNC.Range("AB" & Rows.Count).End(xlUp).Row), 0)) Then
                    If (tBDD(x, 22) = "Hospitalisation" And dToday < CDate(tBDD(x, 24))) Or tBDD(x, 22) = "OK" Then
                        If CInt(tBDD(x, 11 + Weekday(dToday, vbMonday))) = 1 Then
                            tExtract(iIdx, 3 + (iOK * 5) + 1) = "X"
                            For Z = 19 To 21
                                If CInt(tBDD(x, Z)) = 1 Then tExtract(iIdx, 3 + (iOK * 5) + (Z - 17)) = "X"
                            Next
                        End If
                    End If
                End If
                iOK = iOK + 1
            Next
        End If
    Next
    .Range("A7").Resize(iIdx, UBound(tExtract, 2)).Value = tExtract
End With

À adapter en fonction de la disposition de tes données secondaires (statuts, fériés) dans ton fichier final.

12exemple-algo.xlsm (140.78 Ko)


A+

Bonsoir,

Petit coucou depuis le téléphone. Du coup je n'ai pas encore téléchargé ton fichier, Curulis.

Je n'avais aucun doute, hein, quant à la longueur du chemin qu'il me reste à parcourir ! Mais vous me la montrez très rapidement ☺️

Un immense merci à vous 2, déjà, pour vos retours.

@galopin :

Je comprends que tous ces offset te gavent... Au départ, pour trouver les 1 dans les colonnes lundi, mardi, etc... Je faisais un offset de l'équivalent du jour de la semaine de la date concernée, dans un array des jours de la semaine. Mais au final ça foirait. Comme le reste tournait bien, j'ai gardé ces offset ailleurs.

J'ai essayé de rajouter des conditions à y mais, comme tu l'as signalé ensuite, ce n'est pas ici qu'on prend en compte la date d'hospitalisation potentielle. Et une fois mes conditions rajoutées, je retombe sur la solution que j'avais à l'origine. En plus élégant tu me diras. Je te l'accorde 😉

Et on peut générer les lignes pour les personnes OK ou hospitalisées et ensuite supprimer les croix pour les personnes hospitalisées dans un second temps. Je saurais le faire sans souci. Mais je trouve dommage de faire des choses pour les supprimer ensuite, et j'ai grand espoir d'arriver à progresser avec votre aide sur ce problème.

@Curulis, je n'ai donc pas encore regardé mais, de ce que j'ai pu comprendre du code, j'ai bon espoir que ce soit tout bon ! Je te redis ça demain. Encore merci !

Finalement ça m'a empêché de dormir, je t'ai finalisé TOUT sauf ton "Hospitalisation" qui me parait un peu confus.

Mais je t'ai laissé un ligne pour te montrer ou ajouter une condition...

Hum... J'ai testé un minimum mais ça devrait être bon !

22exemple-algo-vg2.xlsm (143.58 Ko)

A+

Bonjour à tous,

Wow, JoyeuxNoel, créateur officiel d'insomnies depuis 2021 ! C'est un titre dont je me serais bien passé, m'enfin c'en est toujours un !

Désolé

@Galopin : Après test, ça a l'air effectivement bon ! Pour les hospitalisations, ce n'est normalement pas si compliqué que ça. Je te MP pour te poser un peu mieux le décor.

@Curulis, ça fonctionne bien effectivement. Par contre, pour la personne qui a une date d'hospitalisation, on ne devrait plus avoir de croix pour toutes les dates ultérieures à cette date là. C'est justement sur ce point que je coinçais.

Merciiii encore !

La modif pour une date d'hospitalisation colonne 24 (le jour d'hospitalisation est livré, à partir du lendemain non) :

            'Ensuite il faudra rajouter une conditions pour les autres exceptions... (Hospitalisation etc...)
            Y1 = Y1 And Not (ArrS(i, 24) <> "" And ArrS(i, 24) < CDate(DateSerial(Year(laDate), Month(laDate), (k + 1) / 5)))
            If Y1 Then 'Gère les exceptions -La suite sans changement.
A+

Salut JoyeuxNoël,
Salut Galopin,

Petit défaut de signalisation : j"aurais dû laisser "Hospitalisation" pour cette personne, cela fonctionnera.

C'est un aspect, pas trop difficile mais, comme le soulignait Galopin, à mettre au point.
Qui dit "Hospitalisation" ou "Arrêt" dit "Reprise".

Je te propose ceci en colonne [X:X]:
- pour une future Hospitalisation : "H/12-2-2021" ;
- pour un futur Arrêt (vacances, retour en famille... ??) : "A/15-3-2021" ;
- non, je ne te dirai pas pour un futur décès !
- pour une date de reprise après "Hospitalisation" ou "Arrêt" : "R/25-4-2021

Il faut également savoir comment tu vas archiver tes feuilles car il faut trouver ces infos de mois en mois pour connaître les dates "Hospitalisation" et "Arrêt" à maintenir.

Si ça te convient, je planche là-dessus...


A+

Salut JoyeuxNoël,
Salut Galopin,

Petit défaut de signalisation : j"aurais dû laisser "Hospitalisation" pour cette personne, cela fonctionnera.

C'est un aspect, pas trop difficile mais, comme le soulignait Galopin, à mettre au point.
Qui dit "Hospitalisation" ou "Arrêt" dit "Reprise".

Je te propose ceci en colonne [X:X]:
- pour une future Hospitalisation : "H/12-2-2021" ;
- pour un futur Arrêt (vacances, retour en famille... ??) : "A/15-3-2021" ;
- non, je ne te dirai pas pour un futur décès !
- pour une date de reprise après "Hospitalisation" ou "Arrêt" : "R/25-4-2021

Il faut également savoir comment tu vas archiver tes feuilles car il faut trouver ces infos de mois en mois pour connaître les dates "Hospitalisation" et "Arrêt" à maintenir.

Si ça te convient, je planche là-dessus...


A+

Re,

Pour l'archivage des feuilles, une macro va déplacer la feuille voulue dans un fichier d'archives.

Une autre macro récupère toutes les croix pour chaque personne en fin de mois, pour lancer une facturation. Au passage, elle crée une vraie base de données, pour avoir des stats potentielles en fin d'année.

Si une personne arrête, on met donc le statut sur arrêt et sa ligne ne sera pas générée. Un double clic envoie la ligne de la personne dans une BDD d'archive.

Je ne pense pas qu'il y ait besoin de garder trace des hospitalisations.

Re,

J'essaie de bidouiller et de triturer ça dans tous les sens depuis tout à l'heure, ça ne fonctionne pas chez moi.

La modif pour une date d'hospitalisation colonne 24 (le jour d'hospitalisation est livré, à partir du lendemain non) :

            'Ensuite il faudra rajouter une conditions pour les autres exceptions... (Hospitalisation etc...)
            Y1 = Y1 And Not (ArrS(i, 24) <> "" And ArrS(i, 24) < CDate(DateSerial(Year(laDate), Month(laDate), (k + 1) / 5)))
            If Y1 Then 'Gère les exceptions -La suite sans changement.
A+

J'ai modifié ça en amont, pour que ça génère la ligne quand il y a "hospitalisation" aussi.

For i = 1 To UBound(ArrS)
      Y = ArrS(i, 11) <= DateSerial(Year(laDate), Month(laDate) + 1, 1)
      Y = Y And (ArrS(i, 22) = "OK" Or ArrS(i, 22) = "Hospitalisation")
      'ici tu peux rajouter autant de conditions que tu veux mais on ne traite que la présence de la ligne ou pas

Edit :
Fait intéressant :
Si je crée le mois de février, et que je mets la personne 1 en hospitalisation à partir du 12 février, rien n'est généré au niveau de ses croix, à part le jeudi 25 février

Youpiiii, cette version fonctionne !!!

J'espère que ça servira au moins une fois, cette histoire d'hospitalisation !

Un immense merci à Galopin01 !

@Curulis, je vais essayer de faire marcher avec ta version également.

Il y a tout un tas de bonnes choses à prendre dans tout ce que vous m'avez proposé !

Option Explicit
DefBool Y 'définit toutes les variables qui commencent par Y as Boolean

Sub NewMonth() 'Pas d'accent !
Dim laDate$, ShNew$, Jour$, ArrS, ArrC, i%, ii%, k%, Y, Y1
Dim iLC%, iLR%, WS As Worksheet
Dim TData As ListObject

Set TData = Range("T_BDD").ListObject
ArrS = TData.DataBodyRange.Value2 'Le tableau Source
iLR = UBound(ArrS)
laDate = Format(Year(Date) & "/" & Month(Date) + 1 & "/" & 1, "dd/mm/yyyy") 'on propose le 1er jour du mois suivant
laDate = InputBox("Date du 1er jour du mois à créer ?", "Création", laDate)
If IsDate(laDate) = False Then Exit Sub 'si mauvaise date rentrée, on quitte

[D5] = CDbl(CDate(laDate)) 'on écrit la date en D5, le reste du mois s'adapte
ShNew = Format(laDate, "mmmm") 'on récupère le mois en toutes lettres pour nommer la feuille qu'on va créer
ActiveSheet.Copy after:=ActiveSheet 'on copie la feuille et on la nomme avec notre variable
Set WS = ActiveSheet
With WS
   .Name = ShNew
   For iLC = 4 To 154 Step 5
      If .Cells(5, iLC) = "" Then Exit For
   Next
   'Le dernier jour du mois est iLC -5
   ArrC = .Range(.Cells(7, 1), .Cells(6 + iLR, iLC - 1)).Value 'Le tableau cible est vide
   For i = 1 To UBound(ArrS)
      Y = ArrS(i, 11) <= DateSerial(Year(laDate), Month(laDate) + 1, 1)
      Y = Y And (ArrS(i, 22) = "OK" Or ArrS(i, 22) = "Hospitalisation")
      'ici tu peux rajouter autant de conditions que tu veux mais on ne traite que la présence de la ligne ou pas
      If Y Then
         ArrC(i, 1) = ArrS(i, 1)
         ArrC(i, 2) = ArrS(i, 3)
         ArrC(i, 3) = ArrS(i, 9)
         For k = 4 To iLC - 5 Step 5
            Jour = DateCol(k, CDbl(CDate(laDate)))
            'C'est dans cette boucle For qu'on gère les interruptions en cours de mois
            Y1 = CDate(DateSerial(Year(laDate), Month(laDate), (k + 1) / 5)) >= ArrS(i, 11)
            Y1 = Y1 And Not EstJourFerie(CDate(DateSerial(Year(laDate), Month(laDate), k - 3)))
            Y1 = Y1 And Not (ArrS(i, 22) = "Hospitalisation" And ArrS(i, 24) <= CDate(DateSerial(Year(laDate), Month(laDate), (k + 1) / 5)))

            If Y1 Then 'Gère les exceptions
               If ArrS(i, 11 + Jour) = 1 Then
                  ArrC(i, k) = "X"
                  For ii = 1 To 3
                     ArrC(i, k + ii) = IIf(ArrS(i, 18 + ii) = 1, "X", "")
                  Next
                  ArrC(i, k + ii) = ArrS(i, 2)
               End If
            End If
         Next
      End If
   Next
   'Et on bascule tout dans la feuille
   .Range(.Cells(7, 1), .Cells(6 + iLR, iLC - 1)) = ArrC
   For i = 6 + iLR To 7 Step -1
      'ici on supprime les lignes vides
      'If .Cells(i, 1) = "" Then Rows(i).Delete
   Next
End With
End Sub

Function DateCol%(k%, D&)
Dim i% 'Cette fonction renvoie le jour de la semaine en fonction de k et D (laDate)
DateCol = Application.WorksheetFunction.Weekday(DateSerial(Year(D), Month(D), (k + 1) / 5), 2)
End Function

 Function EstJourFerie(ByVal laDate As Date, Optional ByVal EstPentecoteFerie As Boolean = True) As Boolean
'Détermine si la date passée en argument est un jour férié (en France) ou non :
'   101 = 1er Janvier '501 = 1er Mai '508 = 8 Mai '714 = 14 Juillet
'   815 = 15 Août - 1101 = 1er Novembre '1111 = 11 Novembre '1225 = 25 Décembre
'   dPa = Lundi de Pâques 'dAs = Jeudi de l'Ascension 'dPe = Lundi de Pentecôte
'Remarque : Le lundi de Pentecôte est un jour férié mais parfois non chômé (EstPentecoteFerie = False dans ce cas)
  Static Annee As Integer, dPa As Date, dAs As Date, dPe As Date, bPe As Boolean
   Dim a As Integer, m As Integer, j As Integer

   a = Year(laDate): m = Month(laDate): j = Day(laDate)
   Select Case m * 100 + j
   Case 101, 501, 508, 714, 815, 1101, 1111, 1225
      EstJourFerie = True
   Case 323 To 614   '323: Date mini Lundi de Pâques - 614 : Date maxi Lundi de Pentecôte
     If a <> Annee Or EstPentecoteFerie <> bPe Then
         Annee = a: dPa = Paques(a) + 1: dAs = dPa + 38
         bPe = EstPentecoteFerie: If bPe Then dPe = dPa + 49 Else dPe = #1/1/100#
      End If
      Select Case DateSerial(a, m, j): Case dPa, dAs, dPe: EstJourFerie = True: End Select
   End Select
End Function

Public Function Paques(ByVal an As Integer) As Date
   Paques = CDate(Evaluate("=DATE(" & an & ",3,29.56+0.979*MOD(204-11*MOD(" & an & ",19),30)- WEEKDAY(DATE(" & an & ",3,28.56+0.979*MOD(204-11*MOD(" & an & ",19),30))))"))
End Function

Ce qui est intéressant : Hormis la phase de création de feuille, c'est l'absence totale de référence à ces feuilles. On pompe toutes les données dans un Array Source (ArrS) et on prépare un Array Cible (ArrC) vide qui a déjà sa dimension définitive. Ce qui évite les nombreux Redim (chronophages et surtout incompréhensibles car transposés.

Ainsi on travaille toujours en mémoire avec des indices faciles à lire (Ça se lit comme les Cells des Tableaux d'origine) Pas besoin de décodeur pour savoir de quoi on parle !

Toujours dans le même esprit on sous-traite l'identification des routines (Jours Fériés…) à une fonction perso…

Les conditions sont facilement lisible grâce à la structure :

Y = Cond1

Y = Y And Cond2 'ou Or….

J'aurai encore pu ajouter un ou 2 petits allègements mébon… Je trouve cette soluce assez élégante et surtout très lisible. Pas besoin de kilos de commentaires pour comprendre chaque ligne !

A+

Salut JoyeuxNoël,
Salut Galopin,

quelques évolutions :
- j'ai supprimé les listes de validation en 'Noms & Coordonnées' [V:V] pour laisser le soin du statut à une macro en fonction de l'encodage en [X:X] ;
- en [X:X] donc, tu peux encoder une future date d'hospitalisation ou d'arrêt de livraison temporaires (ou définitives, d'ailleurs) ou une date de décès ;
- le principe : une lettre, un "+" et une dat

Private Sub Worksheet_Change(ByVal Target As Range)
'
Application.EnableEvents = False
'
If Not Intersect(Target, Columns("X")) Is Nothing Then
    iRow = Target.Row
    If Target = "" Or InStr(Target, "+") = 0 Then
        Range("V" & iRow).Value = "OK"
        Target = ""
    Else
        sItem = Split(Target, "+")(0)
        Range("V" & iRow).Value = Switch(sItem = "H" Or sItem = "", "Hospitalisation", sItem = "A", "Arrêt", sItem = "D", "Décès", sItem = "R", "Reprise")
    End If
End If
'
Application.EnableEvents = True
'
End Sub

* H+12-02-2021 = Hospitalisation à partir du 12/02/2021 ;
* A+25/03/2021 = arrêt de livraison à partir du 25/03/2021 ;
* D+15-02-2021 = décès le 15/02/2021 ;
* R+27/02/2021 = reprise après hospitalisation ou arrêt temporaire ;
- en fonction du mode d'encodage de la date, tu comprends pourquoi j'ai choisis le '+' comme séparateur et non le slash "/"...

Comme ces événements (hospitalisation, arrêt, décès ou reprise) peuvent intervenir de façon inopinée, tu peux intervenir sur ton agenda même si celui-ci est déjà programmé.
Il te suffit de sélectionner, sur une feuille-agenda (Février, Mars...) la ligne de la personne concernée sur le nombre de jours souhaités.
La sélection doit envelopper des groupes complets de 5 cellules (Repas-Pain-Potage-Soir-Tournée).
- s'il y a une seule croix dans la sélection, la macro décide de tout annuler ;
- s'il n'y en a aucune, la macro supposera qu'il faut réinstaller les "X" adéquats.

Private Sub Workbook_SheetSelectionChange(ByVal Sh As Object, ByVal Target As Range)
'
Dim dDate As Date, iRow%, iRowT%, iCol%
'
Application.ScreenUpdating = False
'
If Sh.Name <> "Matrice" And Sh.Name <> "Noms & Coordonnées" Then
    If Selection.Column Mod 5 = 4 And Selection.Columns.Count Mod 5 = 0 Then
        If WorksheetFunction.CountIf(Selection, "X") > 0 Then
            Selection.Value = ""
        Else
            iRow = Selection.Row
            With Worksheets("Noms & Coordonnées")
                iRowT = .Columns(3).Find(what:=Sh.Range("B" & iRow).Value, lookat:=xlWhole, LookIn:=xlValues).Row
                For x = 0 To (Selection.Columns.Count / 5) - 1
                    dDate = DateAdd("d", x, CDate(Sh.Cells(5, Target.Column)))
                    If Not IsNumeric(Application.Match(dDate, .Range("AB1:AB" & .Range("AB" & Rows.Count).End(xlUp).Row), 0)) Then
                        iCol = Selection.Column + (x * 5)
                        If CInt(.Cells(iRowT, 11 + Weekday(dDate, vbMonday))) = 1 Then
                            For y = 18 To 21
                                If y = 18 Or (y > 18 And CInt(.Cells(iRowT, y)) = 1) Then Sh.Cells(iRow, iCol + (y - 18)) = "X"
                            Next
                        End If
                    End If
                Next
            End With
        End If
    End If
    Sh.Range("C" & Selection.Row).Select
End If
'
Application.ScreenUpdating = True
'
End Sub

ATTENTION : tu restes responsable de l'actualisation de l'affichage en [X:X] pour les mois suivants ces manipulations...

Á tester en profondeur... ce que je ferai aussi de mon côté plus tard...

27joyeuxnoel.xlsm (144.76 Ko)


A+

Rechercher des sujets similaires à "vba amelioration tableau memoire"