Nettoyage macro

OK !

Un point m'interroge !

Ce que tu mets en P : la valeur de L multipliée par 24 alors que L contient déjà une durée en heure, issue d'une multiplication déjà par 24 de la valeur Excel !

Un durée en heures multipliée par 24 ça ne correspond à rien !

NB- La durée figurant déjà en minutes en C, c'est là que je la prends pour alimenter L (en divisant par 60).

Autre chose : je n'utilise pas du tout les colonnes I et J, qui restent donc vides... Est-ce qu'on les supprime ?

Et normal que la colonne H soit masquée ?

Cordialement.

"Ce que tu mets en P : la valeur de L multipliée par 24 alors que L contient déjà une durée en heure, issue d'une multiplication déjà par 24 de la valeur Excel !

Un durée en heures multipliée par 24 ça ne correspond à rien !"

Oui je sais mais en fait ce sont des données que je rentre dans un logiciel de facturation, et il ne prend que des nombre entier, et vu parfois les nombres trés petits que j'aurais sur certaines lignes je les multiplie par 24 pour les saisir dans le logiciel et à la fin sur le logiciel pour calculer on divise le tout par 24 : mais ça ne t'en préoccupe pas c'est plus de la tambouille interne lol

Les colonnes I et J peuvent etre supprimées mais j'espère comprendre la macro que tu me proposera, car c'était pour moi une façon d'avancer et de m'assurer de la cohérence dans la construction de mon tableau! mais en soit je ne m'en sert pas !

La colonne H est masquée mais elle apparaitra tjs dans l'extraction que je ferais!

TU as des pistes de solution?

Je t'ai envoyé une question en pv?

Merci d'avance

Daccord qu'il puisse te falloir des entiers... mais des heures multipliées par 24 ne correspondent à aucune unité valide, alors qu'en L tu as des heures en format décimal avec 2 décimales, la multiplication par 100 te fournissait à la fois un entier et un nombre en unité valide, la centiheure, lisible comme unité de temps...

Sinon, oui j'avais fait la première partie : insertion de lignes et colonne M et N... pour obtenir en principe le même résultat que tu obtenais autrement (mais c'est qui confirmera que c'est bien ça ! )

Je m'étais interrompu car la première partie étant traitée à partir d'une boucle remontante au cours de laquelle on fait les calculs, on sert K, L, M, N (les 2 dernières après insertions, les colonnes O à U doivent être servies dans le même processus, au même niveau que K et L, et les en-têtes et la plupart des éléments de mise en forme être remontés au début de la macro.

Le résultat sera plus compact, réduction d'au moins moitié du volume de code initial. On va essayer de boucler ça dans la journée mais j'ai pas mal de choses à faire...

Cordialement.

Merci pour tout ce que tu fais par contre j'aurai bien besoin la macro que tu prépares pas à pas ce serait pour moi comprendre

Pour l'unité tu as raison, je demande confirmation mais effectivement multiplié par 100 serait plus lisible comme unité de temps

Merci d'avance

Bonsoir,

J'ai mis en place le décalage de colonne (élimination des ex. I et J...) mais je continue à parler avec les anciennes colonnes pour qu'on ne se perde pas par rapport au code antérieur...

Je bute sur un problème concernant la colonne O

J'ai suivi la mise en place des données en K et L selon le schéma de l'ancien code. Elles étaient donc servies avant insertion... Il y a donc une valeur dans ces deux colonnes mais uniquement sur les lignes d'origine, pas sur les lignes insérées.

Tout cela paraissait logique jusqu'ici... mais la formule destinée à O vient poser un problème :

  • Si la mention en K est "TRANSPORT" on y met "TRA"
  • Si la mention en K ne commence pas par "G", on met la mention en K
Ces deux points s'accordent avec la présence d'une mention en K sur les anciennes lignes donc.

C'est par contre le point "G" qui pose problème (mille excuses !)

Dans ce cas on doit substituer à la mention en K une mention à chercher dans une table sur MAPPING en fonction du nom de l'encadrant en N.

Mais sur les lignes où une mention figure en K, il n'y a rien en N ! On a les noms des encadrants dans la colonne d'origine mais il peut y en avoir plusieurs...

Les noms des encadrants figurent en N uniquement sur les lignes insérées, mais là il n'y a rien en K.

Je ne sais pas quel est l'objectif de cette colonne, mais je peux servir les deux premières conditions (qui peuvent l'être) et servir pour ce qui concerne le cas "G" soit les "codes" correspondant à tous les encadrants de la colonne G sur l'ancienne ligne, soit les "codes" correspondant à chaque encadrant sur les lignes insérées où ils figurent. Ou autre chose selon l'objectif poursuivi...

Là je ne peux pas décider tout seul !

Bonne soirée.

Bonjour, merci pour votre retour !

" Il y a donc une valeur dans ces deux colonnes mais uniquement sur les lignes d'origine, pas sur les lignes insérées."

Non car dans l'ancien code de la macro incluait les colonnes K et L dans l'insertion :

K était calculé de cette façon :

Si il y a - dans le type d'activité , prendre les texte avant le - sinon prendre le texte complet.

L'objectif de cette colonne était de faire les différents codes possible sur chaque lignes avant insertion.

L était calculé de cette façon :

si NB Lignes à insérer=0;arrondi((date fin-date début)*24;2);sinon arrondi((date fin-date début)*24/NB lignes à insérer);2)

Ainsi si il n' y avait pas de lignes à insérer L= durée de fin -durée de début et si il y avait x lignes à insérer L= (durée de fin-durée de

début)/ x lignes à insérer

K& L étaient inclus dans les insertions et chaque ligne se recopiait l'une en dessous de l'autre, je ne sais pas si je me fais bien comprendre lol

Concernant la colonne O , le principe était de dire que si la première lettre de la colonne K était G alors recherche de la profession de l'encadrant (G signifie groupe),sinon si K = transport mettre TRA, sinon forcément c'était K qui correpond a un code de trois lettres.

La colonne K et la colonne O sont similaires a la différence prés que si c'est la première lettre est G alors recherche v de la profession de l'encadrant, si transport mettre code TRA sinon mettre le même code que dans la colonne K.

Pour être plus concret je vais prendre des exemples :

1)

Type d'activité TRANSPORT-sessad

Nom des usagers LADENT Anastasya, BREUX Morgane,

Nom des encadrants 0

deux lignes à insérer car deux usagers, si il y aurai eu des encadrants NB usagers * Nb encadrants, activité transport code TRA

2)

Type d'activité GET-sessad

Nom des usagers LADENT Anastasya, BREUX Morgane, CHOUDJAYE Ranya, ROUSSEL-BEAUMARD Gwendoline,

Nom des encadrants BUSIN INGRID, FACHE HELENE,

8 lignes à insérer (nb usagers / nb encadrants), chaque usager reçoit un acte de chaque encadrant ,activité correspond à la profession de l'endrant

3)

Type d'activité ASH-ecole

Nom des usagers COURMONT NATHAN,

Nom des encadrant 0

o lignes à insérer, activité ash pour l'enfant courmont

J'espère que ce sera plus simple pour toi de comprendre ou je veux arrvier , si tu peux prendre le fichier d'origine et lancer la macro d'origine tu verras mon résultat ! (certes la macro est trés mal rédigée et trés longue)

Merci pour tout,

N’hésitez pas si je n'ai pas était clair

Avez vous pu jeter un oeil sur mon msg pv?

Cordialement,

Bonjour,

En effet, j'avais loupé cette ligne :

        .Range("A" & x + 1, "L" & x + 1).Copy .Range("A" & x)

Ok donc pour étendre K et L. Et servir O à U sur toutes les lignes...

Mais est-il nécessaire de reproduire les lignes A à G, qui n'ajoutent rien, sauf alourdir le fichier... ?

J'ai vu ton message concernant ton autre sujet mais je n'ai guère le temps de m'y pencher, et les graphiques de même que les TCD, ce n'est pas vraiment ma spécialité, mais il y a des spécialistes de la chose sur le forum. Tu devrais avoir des réponses utilisables...

Cordialement.

Merci pour ton retour,

Oui c'est utile par la suite pour construire mon tcd et avoir des données plus exploitables car je ressaisis sur un logiciel de facturation ces données et je les croise également pour certaines avec la comptabilité.

Merci pour ton retour,

Ok j'espère avoir un retour sur l'autre sujet car c'est trés important lol comme toujours !

Merci en tout cas

Bonsoir,

Je pense être venu à bout de ton casse-tête ! (Je l'avais mis entre parenthèses pour le weekend...)

Comme je l'avais dit, la macro procède de façon différentes du processus suivi antérieurement.

On commence toujours par supprimer la ligne 2 et introduire des intitulés supplémentaires de colonnes, mais de I à S (soit la totalité).

On opère aussi immédiatement la mise en forme des nouvelles colonnes : ligne d'en-tête, centrage, bordures (les formats seront automatiquement repris lors de l'insertion de lignes) sauf l'ajustement en largeur opéré à la fin après remplissage.

Ensuite on opère suivant une boucle remontante :

- on sert les cellules de la lignes qui peuvent l'être (NB: décalage de 2 colonnes par rapport à l'ancienne disposition) : I (activ.), et O à S (nb actes, et jour, mois, année)

  • on extrait alors les usagers (tableau) et on les dénombre, et on les trie par ordre alpha
  • on dénombre les encadrants
  • on récupère la durée, convertie en heures et arrondie à 2 décimales

Là, le traitement va se différencier selon qu'il y a ou non des encadrants, et dans ce dernier cas selon que le nombre d'usagers est ou non supérieur à 1 :

  • si pas d'encadrant, on peu servir la colonne M (actes) : à partir de la colonne I (3 premières lettres)
  • -- si un seul usager, pas de ligne à ajouter, on sert J (durée en h.), N (durée *100) et K (nom usager, en majusc.)

--- si plusieurs usages, on sert en J la durée divisée par le nombre d'usagers (2 décim.) et en N cette durée *100

On insère au-dessous autant de lignes que d'usagers, on étend la ligne initiale sur les nouvelles (ce qui recopie tout ce qui a déjà été servi. Ne reste donc à servir que K, ce qui est réalisé à partir du tableau Usagers au moyen d'une boucle (un usager par ligne)

[NB : j'ai suivi le calcul qui était effectué antérieurement en ce qui concerne la durée, au prorata par usager (ou dans le cas suivant par usager-encadrant), la ligne initiale (qui ne porte pas de nom d'usager en K (ni d'encadrant en L) se voit affectée de cette durée unitaire ; il m'aurait cependant paru plus logique de garder le total sur la ligne initiale... Remarque à toutes fins utiles.]

- cas enfin, comportant un ou plusieurs encadrants et un ou plusieurs usagers :

on commence par extraire les encadrants (tableau)

on calcule la durée unitaire par usager-encadrant, on l'affecte en J et N (*100)

on teste alors si l'activté en I ne commence pas par "G" : dans ce cas on l'affecte en M (3 lettres)

sinon on recueille pour chaque encadrant listé (tableau encadrants) la valeur qui devra être portée en M en regard de son nom en L, dans un autre tableau, au moyen d'une fonction [noter une plage nommée sur MAPPING que la fonction utilise pour renvoyer le résultat...]

Comme précédemment, on insère le nombre voulu de ligne, on étend la ligne initiale sur les nouvelles...

Il ne reste à servir que K (usagers), L encadrants) et M si l'on est dans le cas "G" (NB: le tableau destiné à alimenter M à été dimensionné au départ sur le tableau encadrants, s'il ne doit pas servir à alimenter M son élément d'indice 0 a été effacé pour servir de test...) : une double-boucle sur les tableaux usagers et encadrants permet de servir K et L (et M s'il y a lieu).

Voilà les procédures :

Function ActEnc(ByVal Enc As String) As String
    Dim e$, i%
    e = UCase(Enc)
    With [ActivEnc]
        For i = 1 To .Rows.Count
            If .Cells(i, 1) = e Then ActEnc = .Cells(i, 2): Exit For
        Next i
    End With
End Function

Sub Activité()
    Dim Tmp, Usa, Enc, t, dln&, i&, j%, k%, e%, u%
    Application.ScreenUpdating = False
    With Worksheets("TB ACTIVITE")
        .Range("A1:J2").MergeCells = False
        .Rows(2).Delete
        Tmp = Split("ACTIVITE TB;DUREE ACT.;USAGERS;ENCADRANTS;ACTES;DUREE MORIO;NB ACTES;JOUR;" _
         & "N° MOIS;MOIS;ANNEE", ";")
        .Range("I1:S1").Value = Tmp
        dln = .Range("A" & .Rows.Count).End(xlUp).Row
        With .Range("I1:S" & dln)
            .HorizontalAlignment = xlCenter
            With .Borders
                .LineStyle = xlContinuous: Weight = xlThin
            End With
            With .Rows(1)
                .Interior.Color = RGB(128, 128, 128)
                With .Font
                    .Color = vbWhite: .Size = 16: .Bold = True
                End With
            End With
        End With
        For i = dln To 2 Step -1
            .Cells(i, 9) = Split(.Cells(i, 4), "-")(0)
            .Cells(i, 15) = IIf(.Cells(i, 4) = "SYN", 2, 1)
            .Cells(1, 16) = Day(.Cells(i, 1))
            .Cells(i, 17) = Month(.Cells(i, 1))
            .Cells(i, 18) = StrConv(MonthName(.Cells(i, 17)), vbProperCase)
            .Cells(i, 19) = Year(.Cells(i, 1))
            Usa = Split(.Cells(i, 5), ","): u = UBound(Usa)
            If u > 1 Then
                For k = 0 To u - 2
                    For j = k + 1 To u - 1
                        If Trim(Usa(j)) < Trim(Usa(k)) Then
                            Tmp = Usa(j): Usa(j) = Usa(k): Usa(k) = Tmp
                        End If
                    Next j
                Next k
            End If
            e = CInt(.Cells(i, 6)): t = Round(.Cells(i, 3) / 60, 2)
            If e = 0 Then
                .Cells(i, 13) = Left(.Cells(i, 9), 3)
                If u = 1 Then
                    .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                    .Cells(i, 11) = UCase(Trim(Usa(0)))
                Else
                    t = Round(t / u, 2): .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                    .Rows(i + 1 & ":" & i + u).Insert
                    .Range("A" & i & ":S" & i).AutoFill .Range("A" & i & ":S" & i + u)
                    For j = 1 To u
                        .Cells(i + j, 11) = UCase(Trim(Usa(j - 1)))
                    Next j
                End If
            Else
                Enc = Split(.Cells(i, 7), ","): Tmp = Enc
                t = Round(t / (u * e), 2): .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                If .Cells(i, 9) Like "[!G]*" Then
                    .Cells(i, 13) = Left(.Cells(i, 9), 3)
                    Tmp(0) = ""
                Else
                    For j = 1 To e
                        Tmp(j - 1) = ActEnc(Enc(j - 1))
                    Next j
                End If
                .Rows(i + 1 & ":" & i + u * e).Insert
                .Range("A" & i & ":S" & i).AutoFill .Range("A" & i & ":S" & i + u * e)
                For j = 1 To u
                    For k = 1 To e
                        .Cells(i + (j - 1) * e + k, 11) = UCase(Trim(Usa(j - 1)))
                        .Cells(i + (j - 1) * e + k, 12) = Trim(Enc(k - 1))
                        If Tmp(0) <> "" Then .Cells(i + (j - 1) * e + k, 13) = Tmp(k - 1)
                    Next k
                Next j
            End If
        Next i
        .Columns("I:S").AutoFit
    End With
End Sub

Cordialement.


Bonjour,

Merci pour votre retour, j'ai testé la macro et il en ressort les points suivants :

1) les usagers ne doivent avoir aucune ligne vide, en effet au lieu d'insérer x lignes il en insère x+1 (exemple, 2usagers avec 2 encadrants,nombre de lignes à insérer est donc de 4 (incluant la ligne déjà existante), le code utilsé lors de ma précente macro est :

Set Dc = .Range("A" & .Rows.Count).End(xlUp)

For x = Dc.Row To 2 Step -1

If .Range("J" & x) > 1 Then

For y = 2 To .Range("J" & x)

.Range("A" & x).EntireRow.Insert

.Range("A" & x + 1, "L" & x + 1).Copy .Range("A" & x)

Next y

End If

Next x

End With

2) la durée activité (colonne J) doit etre égale à la durée de la ligne avant insertion / NB lignes à insérer

3)la colonne P nommée 28 ne me sert pas , a quoi sert elle?

4) le mois en lettre ne me donne pas Avril et l'année ne me donne pas 2017 sur chaque ligne

Je vais essayer de comprendre et de modifier votre macro pour arriver au résultat escompté, merci beaucoup si vous pouviez y regarder également,

Merci en tout cas de votre travail,

Cordialement


Je reviens sur le point de la colonne P, elle me sert en fait à mettre le jour mais elle n'est pas remplie et nommée 28 au lieu de JOUR

Cordialement,

Bonjour,

Une petite erreur pour la colonne JOUR (un 1 à la place de i), c'est rectifié.

Tu n'avais pas réagi jusqu'à présent sur mes commentaires différenciant lignes initiales et lignes ajoutées, ce qui m'avait persuadé que les reports usagers-encadrants se faisaient entièrement sur les lignes ajoutées...

Rectification donc : réduit l'insertion d'une ligne et compensé le décalage.

A toi de vérifier que ça colle maintenant...

Cordialement.

Bonjour merci pour ton retour,

Je dois maintenant essayer de comprendre ta macro et surement la modifier pour obtenir le résultat définitif car quelques points ne sont pas bons , n'étant pas clair dans mes explications :

En lançant la macro, le résultat :

- laisse des cellules vides pour la colonne M actes, lorsque que les cellules commence par G il devrait faire une recherche sur le nom de l'encadrant via le mapping mais ne le fais pas de façon systématique,

- les cellules des colonnes mois et année devrait être Avril uniquement car c'est le TB activité d'avril de même que l'année devrait être 2017,

- les cellules de la colonne J (durée activité) doit être égale à la durée de la ligne avant insertion / NB lignes à insérer, il le fait mais ajoute +1 a chaque ligne insérer,

Je vais essayer de voir ce qu'il est possible de modifier mais il est évident que tu iras bien plus vite pour apporter les corrections nécessaires lol

Merci pour tout


Autre remarque : les cellules de la colonne F indiquant le nombre d'encadrants, doit correspondre au nombre d'encadrant des cellules de la colonne G.

Lors ce que je lance la macro qui insère les lignes ce nombre est modifié sur les lignes insérées, indiquant parfois 3,4 ou 5 alors qu'il n'y a que deux encadrants par exemple?,

Cordialement,

OK ! Pas fait attention que Autofill incrémentait (à tort dans ce cas) : on revient à copie classique.

D'autre part si j'éliminais les espaces lors de l'affectation des noms, j'avais omis de le faire pour la fonction de récupération des Act, c'est rectifié.

Deux rectifications. A voir...

Cordialement.

Merci beaucoup pour ton retour, je pense que c'est bon on y est arrivé enfin surtout grâce à toi

Je n'ai plus lol qu'a comprendre et déchiffré ta macro mais tu me l'a déjà très bien expliqué, juste que je veux comprendre tout étape par étape et la je ne peux le faire que seul.

Un grand merci pour ce que tu as fait, car elle va beaucoup beaucoup plus vite, et elle est mieux écrite que celle que j'avais tenté de réaliser.

Au plaisir d'avoir recours à tes services ! rassure moi tu n'a pas 73 ans lol

Bon week end

Tant que j'y suis, je te fais une version commentée de façon détaillée du code...

Je n'en mets habituellement pas dans mon code car je trouve difficile de travailler sur un code qui contient des commentaires, et je trouve généralement que les commentaires n'apprennent rien car ils ne fournissent que ce que l'on sait déjà (même un débutant devrait au bout de 3 ou 4 lectures pouvoir associer les commandes à leur interprétation sans plus avoir à se référer au commentaire), et ils ne fournissent jamais assez d'explications pour comprendre les raisons particulières quand il y en a d'une formulation plutôt qu'une autre...

Je préfère donc fournir des explications et les élargir, si je pense qu'il faut éclairer plus les raisons d'un choix, ou comment la chose fonctionne...

On va commencer par la fonction commentée ! J'ajoute qu'elle se trouve placée avant la procédure Sub dans le module, car conventionnellement on place toujours dans un module les déclarations (de niveau module, quand il y en a), les procédures Function, et les procédure Sub, dans cet ordre.

Une convention, lorsqu'on la respecte permet toujours de mieux s'y retrouver, mais au cas particulier elle est justifiée pour que l'accès aux fonctions, généralement plus fréquent, puisse se faire plus rapidement. On conseillait d'ailleurs même à l'époque où j'ai débuté VBA de classer les fonctions et les Sub selon une fréquence d'utilisation, au moins approximative... Il est évident qu'avec un tout petit nombre de procédures, on ne pourra avoir aucun effet sensible, ni même mesurable... mais par contre le respect des conventions permet bien d'aller plus vite là où l'on veut !

Pour ce qui est des déclarations, le non respect pour certaines d'entre elles de cette règle, fera hurler le compilateur ! Ce qui obligera bien évidemment à les replacer en tête...

Noter aussi pour ce qui est de la fonction, qu'elle opère une recherche dans une plage, qui est nommée de façon dynamique (à voir dans le gestionnaire de noms).

'La fonction recherche l'Act. d'un encadrant, on lui passe un nom d'encadrant en argument
Function ActEnc(ByVal Enc As String) As String
    Dim e$, i%
    'Elle l'épure des espaces et le met en majuscules
    e = UCase(Trim(Enc))
    With [ActivEnc]
    'Elle recherche le nom dans la plage nommée 'ActivEnc'
        For i = 1 To .Rows.Count
        'Si elle le trouve, elle renvoie l'Act. correspondant (sinon rien)
            If .Cells(i, 1) = e Then ActEnc = .Cells(i, 2): Exit For
        Next i
    End With
End Function

Je dissocie les partie pour aérer un peu...

Pour cadrer la compréhension, la procédure Sub se subdivise en 2 parties :

  • 1re partie : traitement de l'en-tête et mise en forme
  • 2e partie : traitement de chaque ligne dans une boucle.

Voilà la 1re partie commentée :

Sub Activité()
    Dim Tmp, Usa, Enc, t, dln&, i&, j%, k%, e%, u%
    '1re partie : traitement de l'en-tête et mise en forme générale
    'On inhibe la mise à jour de l'affichage dès le départ, car on va opérer des
    ' modifications visibles (contribue à l'accélération de la procédure)
    Application.ScreenUpdating = False
    'On met la feuille de travail sous bloc With (c'est parmi les éléments les plus
    ' importants pour accélérer l'exécution !)
    ' [toute expression précédée d'un point dans le bloc réfère à la feuille mise en
    ' mémoire par VBA]
    With Worksheets("TB ACTIVITE")
        'On défusionne les deux premières lignes existantes (A à J)
        .Range("A1:J2").MergeCells = False
        'On supprime la ligne 2 (qui est vide)
        .Rows(2).Delete
        'On consigne dans un tableau Tmp une liste d'intitulés de colonnes à ajouter (de I à S)
        ' en utilisant la fonction Split
        Tmp = Split("ACTIVITE TB;DUREE ACT.;USAGERS;ENCADRANTS;ACTES;DUREE MORIO;NB ACTES;JOUR;" _
         & "N° MOIS;MOIS;ANNEE", ";")
        'On affecte le tableau Tmp à la plage d'en-tête concernée (ce type d'affectation est à
        ' privilégier lorsqu'il s'agit de valeurs, car plus rapide...)
        .Range("I1:S1").Value = Tmp
        'On recherche la dernière ligne du tableau, qu'on conserve dans la variable (Long) dln
        dln = .Range("A" & .Rows.Count).End(xlUp).Row
        'On initialise un bloc With (imbriqué dans le précédent donc) avec la plage correspondant
        ' aux colonnes ajoutées (de I à S) de la ligne 1 à la fin du tableau
        ' [Toute expression précédée d'un point dans ce bloc réfère donc à cette plage]
        With .Range("I1:S" & dln)
            'On centre l'alignement dans les cellules
            .HorizontalAlignment = xlCenter
            'On définit les bordures (bloc With pour cibler toutes les bordures de la plage)
            With .Borders
                .LineStyle = xlContinuous: Weight = xlThin
            End With
            'Bloc With pour ne cibler que la 1re ligne de la plage (I1:S1)
            With .Rows(1)
                'Coloration alignée sur le reste de la ligne 1
                .Interior.Color = RGB(128, 128, 128)
                'Police définie à blanc, de taille 16 et gras
                With .Font
                    .Color = vbWhite: .Size = 16: .Bold = True
                End With
            End With
        End With
        'On a terminé la mise en forme, on va passer au traitement
        ' [On est dans le bloc With ciblant la feuille]

La 2e partie consiste en traitement de chaque ligne dans une boucle remontante de la fin (dernière ligne) au début (ligne 2) du tableau. Comme l'on a à insérer des lignes, qui modifieront les numéros de lignes suivantes, on opère en remontant...

Cette 2e partie se subdivise en 2 phases logiques à chaque tour de boucle : ce qui est commun à toutes les lignes dans le traitement de chaque ligne ou qui prépare la phase suivante dans une première phase, et dans une deuxième phase le traitement sous condition de caractéristiques propres à la ligne traitée (nombre d'usagers et d'encadrants).

Voici donc la 1re phase de la 2e partie commentée :

        'On a terminé la mise en forme, on va passer au traitement
        ' [On est dans le bloc With ciblant la feuille]
        '2e partie : on initialise une boucle remontant de la dernière ligne à la ligne 2
        ' qui va traiter spécifiquement chaque ligne
        'On opère dans une 1re phase le traitement commun à toutes les lignes
        For i = dln To 2 Step -1
            'Affectation à la col.I de l'activité récupérée en D (mention précédant un tiret)
            ' Utilisation de la fonction Split pour récupérer la partie à affecter
            .Cells(i, 9) = Split(.Cells(i, 4), "-")(0)
            'En O (Nb actes) on porte 2 si en D figure la mention 'SYN', sinon 1
            .Cells(i, 15) = IIf(.Cells(i, 4) = "SYN", 2, 1)
            'En P on porte le jour de la date figurant en A
            .Cells(i, 16) = Day(.Cells(i, 1))
            'En Q on porte le numéro de mois de la date figurant en A
            .Cells(i, 17) = Month(.Cells(i, 1))
            'En R on renvoie le nom de mois correspondant au n° en Q, avec majuscule initiale
            .Cells(i, 18) = StrConv(MonthName(.Cells(i, 17)), vbProperCase)
            'En S ont porte l'année de la date figurant en A
            .Cells(i, 19) = Year(.Cells(i, 1))
            'On récupère dans un tableau Usa les noms des usagers listés en col.E et séparés par
            ' des virgules (la liste se terminant par une virgule, on aura donc un dernier
            ' élément du tableau restant vide) en utilisant Split
            'On définit le nommbre d'usagers listés dans la variable (Integer) u
            ' [Cette définition du nombre utilise UBound qui renvoie l'indice le plus élevé du
            ' tableau, l'indice le plus bas étant 0 pour un tel tableau affecté à une variable
            ' de type Variant. Mais sachant que l'on a un élément vide dans le tableau, la
            ' valeur renvoyée par UBound correspond donc au nombre d'usagers...]
            Usa = Split(.Cells(i, 5), ","): u = UBound(Usa)
            'Si le nombre d'usagers est supérieur à 1, on procède au tri du tableau Usa pour
            ' les placer dans l'ordre alphabétique
            ' [Le tri s'opère au moyen d'une double boucle, la boucle externe parcourant les
            ' éléments du 1er à l'avant-dernier, la boucle interne du suivant (celui qui suit
            ' celui ciblé par la boucle externe) au dernier. A chaque tour de la boucle interne,
            ' on compare les élément ciblé par chaque boucle, si celui ciblé par la boucle interne
            ' devrait être placé avant l'autre, on les substitue l'un à l'autre et on poursuit.
            ' A chaque fois que la boucle interne a fait son parcours complet et que l'on incrémente
            ' la boucle externe pour un nouveau tour, l'élément ciblé précédemment par la boucle
            ' externe est désormais à sa position définitive (au fil des substitutions opérées), ce
            ' pourquoi on désigne cette méthode de tri sous le nom de 'tri à bulles' (à chaque tour
            ' de la boucle externe, un élément remonte à sa place...)]
            If u > 1 Then
                For k = 0 To u - 2
                    For j = k + 1 To u - 1
                        If Trim(Usa(j)) < Trim(Usa(k)) Then
                            Tmp = Usa(j): Usa(j) = Usa(k): Usa(k) = Tmp
                        End If
                    Next j
                Next k
            End If
            'On récupère le nombre d'encadrant figurant en col.F dans la variable (Integer) e
            'On récupère également la durée en col.C (en minutes) que l'on convertit en heures
            ' (arrondi à 2 décimales)
            e = CInt(.Cells(i, 6)): t = Round(.Cells(i, 3) / 60, 2)
            'Au cours de cette 1re phase, on a servi les colonnes dont le contenu n'était pas soumis
            ' à condition dépendant du nombre d'usagers ou d'encadrants, et préparé les éléments de
            ' calcul pour les colonnes dont le contenu est soumis à condition...

La 2e phase de la 2e partie poursuit le traitement ligne par lignes et se subdivise selon les cas rencontrés :

1er cas : pas d'encadrant

2e cas : un ou plusieurs encadrants.

Le 1er cas se subdivise à son tour en 2 sous-cas :

1er sous-cas : un seul utilisateur

2e sous-cas : plusieurs utilisateurs

Ces deux sous cas se distinguent par l'insertion (2e sous-cas) ou non (1er).

Dans le 2e cas on a aussi implicitement les deux mêmes sous-cas, mais on ne les sépare pas aussi nettement mais seulement en mettant l'insertion sous condition,l'alimentation des cellules à servir à la suite s'opérant de la même façon qu'il y ait une ligne ou plusieurs.

A l'issue de la 2e phase (après la boucle), on achève la mise en forme qui logiquement relève de la 1re partie...

            'Au cours de cette 1re phase, on a servi les colonnes dont le contenu n'était pas soumis
            ' à condition dépendant du nombre d'usagers ou d'encadrants, et préparé les éléments de
            ' calcul pour les colonnes dont le contenu est soumis à condition...
            'On passe alors à la 2e phase de traitement de chaque ligne dans laquelle on différencie
            ' le cas où il n'y a pas d'encadrants du cas où il y en a. Le 1er cas se différenciant à
            ' son tour en deux sous-cas : un seul usager ou plusieurs.
            '2e phase : 1er cas : pas d'encadrant
            If e = 0 Then
                'Dans ce cas, quel que soit le nombre d'usagers, le contenu de la col.M (Actes) ne
                ' peut dépendre de l'encadrant, il est donc celui porté en I, réduit le cas
                ' échéant à 3 caractères
                .Cells(i, 13) = Left(.Cells(i, 9), 3)
                '2e phase : 1er cas : 1er sous-cas : un seul usager
                If u = 1 Then
                    'On n'aura pas de ligne à ajouter, et la durée recueillie revient à cet usager
                    ' unique : on l'affecte en J (et on affecte son produit par 100 en N)
                    .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                    'On porte le nom de l'uager en K
                    .Cells(i, 11) = UCase(Trim(Usa(0)))
                '2e phase : 1er cas : 2e sous-cas : plusieurs usagers
                Else
                    'On aura à insérer un nombre de lignes égal au nb d'usagers -1.
                    ' On recalcule la durée au prorata du nombre d'usagers, et on affecte
                    ' cette durée en J (et N) car elle sera identique pour chacun
                    t = Round(t / u, 2): .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                    'On insère le nombre de lignes voulu en dessous de la ligne traitée
                    .Rows(i + 1 & ":" & i + u - 1).Insert
                    'On copie la ligne traitée (qui ne comprend que les indications communes
                    ' à toutes les lignes qu'elle génère) sur les lignes insérées
                    .Range("A" & i & ":S" & i).Copy .Range("A" & i + 1 & ":A" & i + u - 1)
                    'On opère une boucle sur l'ensemble ligne initiale + lignes insérées pour
                    ' affecter à chaque ligne en K le nom d'un usager (ils seront dans l'ordre alpha)
                    For j = 1 To u
                        .Cells(i + j - 1, 11) = UCase(Trim(Usa(j - 1)))
                    Next j
                End If
            '2e phase : 2e cas : un ou plusieurs encadrants
            Else
                'On recueille alors les noms des encadrants figurant en G dans un tableau Enc (même
                ' méthode que pour les usagers...). On affecte ce tableau à la variable Tmp (qui donc
                ' le reproduit, ceci est destiné à dimensionner Tmp de façon identique à Enc...)
                Enc = Split(.Cells(i, 7), ","): Tmp = Enc
                'On aura un nb de lignes à ajouter correspondant à tous les couples usager-encadrant
                ' possibles, soit le produit du nb d'usagers par le nb d'encadrants -1
                ' On recalcule la durée au prorata du nombre de couples usager-encadrant, et on
                ' l'affecte en J (et produit par 100 en N), car identique pour chacun...
                t = Round(t / (u * e), 2): .Cells(i, 10) = t: .Cells(i, 14) = t * 100
                'On teste si l'activité en I ne commence pas par 'G'
                If .Cells(i, 9) Like "[!G]*" Then
                    'Dans ce cas, on porte en M la valeur de I (réduite le cas échéant à 3 caractères)
                    ' car elle ne sera pas dépendante de l'encadrant (et donc identique sur toutes
                    ' les lignes générées par la ligne traitée
                    .Cells(i, 13) = Left(.Cells(i, 9), 3)
                    'On efface aussi le 1er élément du tableau Tmp pour servir de test ultérieur
                    ' indiquant que l'on est dans ce cas
                    Tmp(0) = ""
                Else
                    'Si l'activité commence par G, on ne sert pas alors M et on affecte à chaque
                    ' élément du tableau Tmp, l'activité de l'encadrant de même indice du tableau
                    ' Enc renvoyée par la fonction ActEnc
                    For j = 1 To e
                        Tmp(j - 1) = ActEnc(Enc(j - 1))
                    Next j
                End If
                'Il peut y avoir un seul usager et un seul encadrant ! On le teste donc car dans
                ' ce cas il n'y aurait pas de ligne à ajouter
                If u * e > 1 Then
                    'Si plus d'un usager ou plus d'un encadrant, on insère le nombre de lignes
                    ' voulu au dessous de la ligne traitée
                    .Rows(i + 1 & ":" & i + u * e - 1).Insert
                    ' On copie la ligne traitée sur les lignes insérées
                    .Range("A" & i & ":S" & i).Copy .Range("A" & i + 1 & ":A" & i + u * e - 1)
                End If
                'On lance une double boucle sur les usagers (externe) et les encadrants (interne)
                ' de façon à servir en K un nom d'usager et en L un nom d'encadrant (à partir des
                ' tableaux Usa et Enc)
                ' [Les usagers étant listés par la boucle externe, ils seront répétés à la suite autant
                ' de fois qu'il y a d'encadrants pour chaque usager]
                ' On sert également M à partir des valeurs recueillies dans le tableau Tmp si on se
                ' trouve dans le cas de devoir le faire (test sur Tmp(0) qui a été précédemment
                ' effacé s'il n'y a pas lieu de le faire
                For j = 1 To u
                    For k = 1 To e
                        .Cells(i + (j - 1) * e + k - 1, 11) = UCase(Trim(Usa(j - 1)))
                        .Cells(i + (j - 1) * e + k - 1, 12) = Trim(Enc(k - 1))
                        If Tmp(0) <> "" Then .Cells(i + (j - 1) * e + k - 1, 13) = Tmp(k - 1)
                    Next k
                Next j
            End If
        Next i
        'En fin d'opération, on ajuste la largeur des colonnes I à S au contenu (ce qu'on ne pouvait
        ' faire avant d'en mettre un)
        .Columns("I:S").AutoFit
    End With
End Sub

Cordialement.

Merci pour tout,

Rechercher des sujets similaires à "nettoyage macro"