Saisie automatique dans un Feuillet suite écriture dans un autre

Bonjour tout le monde :)

Je suis en train de faire mon premier code de ma vie. Je suis en fait connaisseur sur Access et language SQL (Insert into, update ...) mais absolument pas sur la programmation objets sur Excel.

Alors, voici ce que je souhaite faire : A la saisie des salaires sur le feuillet "ACOMPTE", j'ai une ligne figée en haut qui me résume le total des salaires à la dernière date de saisie (Maxdate). Je voudrais alors que cette ligne soit copiée et collée automatiquement dans le feuillet "CAISSE". Déclencheur du code (Macro) serait idéalement "quand je quitte le feuillet ACOMPTE" ...

Voici en pièce jointe mon fichier excel simplifié ainsi que le code que j'ai effectué moi même en fouinant sur google (mais qui ne marche pas !).

Merci pour votre coup de pousse :)

9exemple.xlsm (18.86 Ko)

Bonjour,

Pour le déclenchement, il faut placer ce code dans le module VBA de la feuille acompte :

Private Sub Worksheet_Deactivate()

Call CopierTotalAcompteJour

End Sub

Celui-ci déclenche la macro dès que l'on quitte la feuille. Ensuite, la macro CopierTotalAcompteJour dans un module standard :

Sub CopierTotalAcompteJour()
'Copier total acomptes jour
Dim Lig As Long, Col As Integer, Verif As Boolean

With Sheets("CAISSE")
    Lig = .Range("A1").End(xlDown).Row + 1 'Première ligne vierge feuille "CAISSE"
    For Col = 1 To 7 'Boucle sur les 7 cellules complétées
        If Not .Cells(Lig - 1, Col) = Sheets("ACOMPTE").Cells(1, Col + 4) Then Verif = True: Exit For 'Contrôle que la dernière ligne est différente
    Next Col
    If Verif Then 'Copié-collé seulement si dernière ligne différente
        Sheets("ACOMPTE").Range("E1:K1").Copy
        .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues
        Application.CutCopyMode = False
    End If
End With

End Sub

J'ai ajouté une condition pour éviter de coller en doublon la ligne (si la dernière ligne présente des informations identiques). Le fichier modifié :

10exemple.xlsm (21.06 Ko)

Un grand grand merci Pedro :)

Et cerise sur le gateau la condition IF que je vais apprendre en plus de ça.

A très bientôt Merci encore

Bonjour Perdo :)

J'ai apporté du nouveau au fichier donc :

- Si la dernière ligne est à la même date et au même montant que la ligne du feuillet Acompte alors il ne fait pas d'insertion

- Si la dernière ligne est à la même date que le feuillet Acompte mais avec un montant différent, il fait une mise à jour du montant :) Je me félicite de pouvoir faire ça c'est aussi grace à vous.

Maintenant j'ai réfléchi au suivant : Faire une mise à jour du montant dans CAISSE pour une ancienne ligne à une ancienne date déja inserrée et pour laquelle une correction des montants dans Acomptes a été apportée (donc pas forcément la MaxDate) ?

C'est possible de m'aider là aussi ?

Voici le fichier mise à jour ci-joint

9exemple.xlsm (21.46 Ko)

Bonjour,

Oui c'est possible, dans ce cas il faut faire une boucle pour balayer tous les enregistrements existants pour retrouver un éventuel enregistrement correspond à la date en question. Le reste de la logique de vérification est identique, seule la ligne de collage change s'il faut mettre à jour un enregistrement existant.

Et comment je peux faire référence à la date/ligne qui a changé dans Acompte ? là j'ai pas de Max date ?

et pour la boucle il faut la définir dans les deux feuillets ? Caisse et Acompte ?

Merci

Là c'est un peu abstrait pour moi sur ce que vous faites côté feuille "Acompte", je parlais donc uniquement pour interagir avec une ligne existante à remplacer dans l'onglet "Caisse". On peut utiliser une boucle qui balaye les lignes du tableau Caisse jusqu'à trouver une correspondance au niveau de la date, puis coller la nouvelle ligne à cette emplacement plutôt qu'en fin de tableau.

Je vous laisse gérer côté Acompte, vu que je ne maitrise absolument pas le process et la finalité de cette feuille.

Bah c'est en vain ... Si dans Acompte je vais vers la date du 10/01/2021 et je modifie un montant alors quand je retourne vers Caisse, la ligne correspondante à la date (qui n'est pas MaxDate) n'est pas mise à jour. C'est difficile pour moi à ce stade. Bref merci pour votre appui

14exemple.xlsm (21.44 Ko)

Quelque chose m'échappe, dans le dernier fichier envoyé, vous n'avez pas ajouté de boucle pour balayer les lignes de la feuille "CAISSE" comme évoqué précédemment. En revanche vous avez dupliqué le code de la macro initiale, pourquoi ?

Un essai :

Sub CopierTotalAcompteJour()

Dim Lig As Long, Col As Integer, EnregExiste As Boolean

With Sheets("CAISSE")
    For Lig = 2 To .Range("A1").End(xlDown).Row 'Boucle sur les lignes
        If .Range("B" & Lig) = Sheets("ACOMPTE").Cells(1, 6) Then Verif = True: Exit For 'Si date identique
    Next Lig
    If Not EnregExiste Then Lig = .Range("A1").End(xlDown).Row + 1 'Nouvelle ligne
    Sheets("ACOMPTE").Range("E1:K1").Copy
    .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues
    Application.CutCopyMode = False
End With

End Sub

Dans les grandes lignes :

- On balaye les enregistrements existants à la recherche de la date
- Si date existante, on écrase la ligne
- Si date inexistante, on créé une ligne supplémentaire

Bonjour :) Je suis content de réussir mon premier code qui est finalement le suivant : Ne jamais baisser les bras

monpremiercode

Bref ça fonctionne mais je ne sais pas à quoi ça sert le For Col = 1 to 2 tant que je n'ai pas utilisé le mot Col dans mon code !!

Avez vous des commentaires ? Sinon comment puis-je marquer que c'est résolu svp ?

C'est une bonne chose de prendre à bras le corps le sujet et de persévérer, je ne peux que vous encourager !

Si la variable Col n'est pas utilisée, alors la boucle ne sert à rien. A la base, elle servait à balayer les différentes cellules d'une même ligne pour les comparer 2 à 2 avec la ligne en passe d'être copiée.

En commentaire, je vous recommande vivement d'utiliser correctement l'indentation pour bien identifier les différentes structures du code et leur imbrication. Je préconise aussi de ne jamais utiliser de .Select ou .Activate qui sont très majoritairement inutiles tant que les objets (feuille, plage, etc) sur lesquels on travaille sont clairement précisés. En l’occurrence l'instruction Cells(Lig + 1, 1).Select est parfaitement inutile.

Mon problème est apparemment avec les boucles. Si par exemple je ne veux pas qu'un enregistrement du feuillet "Acompte" au 20/06/2022 se colle dans "Caisse" car il y a déjà un enregistrement avec cette date là. Il faudra faire une boucle qui parcoure les différentes lignes de "Caisse" non ? ... et pourtant ça se colle à chaque fois. J'arrive pas à savoir où placer : Exit for, next Lig, end if ...

Le problème c'est que vous n'avez pas l'air d'avoir un besoin clair. Au début j'avais compris que l'on collait la nouvelle ligne en dernière position. Ensuite que si la date existait déjà, on mettait à jour la ligne (et c'est ce que fait le code actuellement), et maintenant il ne faut plus coller du tout si la date est déjà présente ??

Je vais commenter un peu le dernier code proposé pour que vous compreniez le principe :

Sub CopierTotalAcompteJour()

'Déclaration des variables
Dim Lig As Long, Col As Integer, EnregExiste As Boolean

With Sheets("CAISSE")
    For Lig = 2 To .Range("A1").End(xlDown).Row 'Boucle sur les lignes
        'Si correspondance de date, alors la variable EnregExiste prend la valeur VRAI et on quitte immédiatement la boucle (donc la dernière valeur de Lig correspond à cette ligne)
        If .Range("B" & Lig) = Sheets("ACOMPTE").Cells(1, 6) Then EnregExiste = True: Exit For 
    Next Lig
    If Not EnregExiste Then Lig = .Range("A1").End(xlDown).Row + 1 'Nouvelle ligne si on a pas trouvé la date (EnregExiste = FAUX par défaut)
    Sheets("ACOMPTE").Range("E1:K1").Copy 'On copie la ligne ACOMPTE
    .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues 'On la colle à l'emplacement défini par Lig (soit une ligne existante, soit la dernière)
    Application.CutCopyMode = False
End With

End Sub

Maintenant le code s'il ne faut PAS écraser une ligne déjà existante :

Sub CopierTotalAcompteJour()

Dim Lig As Long, Col As Integer, EnregExiste As Boolean

With Sheets("CAISSE")
    For Lig = 2 To .Range("A1").End(xlDown).Row
        If .Range("B" & Lig) = Sheets("ACOMPTE").Cells(1, 6) Then EnregExiste = True: Exit For 
    Next Lig
    If Not EnregExiste Then 
        Lig = .Range("A1").End(xlDown).Row + 1
        Sheets("ACOMPTE").Range("E1:K1").Copy
        .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues
        Application.CutCopyMode = False
    End If
End With

End Sub

Cher Pedro, Merci pour votre appui :)

En effet, vos commentaires dans le code m'ont beaucoup aidé. Et paradoxalement pourquoi SQL sous Access m'a été plus facile que VBA sous Excel, c'est tout simplement parceque les formats de programmation sont définis et figés : SELECT x FROM Y WHERE ... GROUP BY ...etc

J'ai mouliné un peu plus mon cerveau et j'ai pu faire ceci dans le dernier code que vous m'avez proposé (Celui qui n'écrase pas la ligne si elle existe) :

Sub CopierTotalAcompteJour4()Dim Lig As Long, Col As Integer, EnregExiste As BooleanWith Sheets("CAISSE") For Lig = 2 To .Range("A1").End(xlDown).Row For Col = 1 To 2 If .Cells(Lig, Col) = Sheets("ACOMPTE").Range("E1:F1") Then EnregExiste = True: Exit For Next Col If Not EnregExiste Then Lig = .Range("A1").End(xlDown).Row + 1 Sheets("ACOMPTE").Range("E1:K1").Copy .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues Application.CutCopyMode = False End If Next LigEnd WithEnd Sub

Là je pense avoir réussi une incrémentation de deux boucles Col et Lig.

Sinon dans votre dernière réponse, j'ai une question à posé : Dans le premier code que vous avez proposé (celui qui met à jour), il n'y a pas de End If, alors que dans celui qui suit, End if existe ... C'est possible de m'éclaircir un peu plus ?

Merci et bon week-end :)

Sub CopierTotalAcompteJour4()
Dim Lig As Long, Col As Integer, EnregExiste As Boolean
With Sheets("CAISSE") 
For Lig = 2 To .Range("A1").End(xlDown).Row For Col = 1 To 2 If .Cells(Lig, Col) = Sheets("ACOMPTE").Range("E1:F1") Then EnregExiste = True: Exit For 
Next Col 
If Not EnregExiste Then Lig = .Range("A1").End(xlDown).Row + 1 Sheets("ACOMPTE").Range("E1:K1").Copy .Range("A" & Lig).PasteSpecial Paste:=xlPasteValues Application.CutCopyMode = False 
End If 
Next Lig
End With
End Sub

Voici le code, j'arrive à trouver le format adéquat du site.

Bonjour,

Je réitère ma recommandation précédente, faites attention à l'indentation du code... Concernant la présence ou non d'un End If, elle n'est pas nécessaire si toute l'instruction n'occupe qu'une seule ligne :

'Sans End If
If [condition] Then [Instruction] Else [Instruction]
'Avec End If
If [condition] Then
    [instruction1]
    [instruction2]
Else
    [instruction3]
End If

A propos du dernier code maintenant, je ne comprend pas votre objectif. Que cherchez vous à faire avec les 2 boucles ? Actuellement le code est incorrecte, car vous comparez le contenu d'une cellule unique (.Cells(Lig, Col)) avec celui d'une plage (Sheets("ACOMTE").Range("E1:F1")).

Bonjour Pedro,

Je suis en train d'explorer en fait. Dans mon dernier code, si Cells(Lig, Col) dans feuille Caisse correspond à E1 et F1 de l'autre feuille, alors pas de copier coller. Au lieu d'un seul critère qui est la date(F1), j'ai rajouté un deuxième critère qui est la désignation (E1). Et ça fonctionne correctement. Merci pour votre info sur le End If.

Rechercher des sujets similaires à "saisie automatique feuillet suite ecriture"