Décrémentation stock sans userform
Bonjour à tous,
Je souhaite décrémenter des quantités de stock via une macro,
J'ai une feuille Export et une feuille Stock
Ma macro doit vérifier si les pièces de l'export sont présentes en stock et si la quantité est disponible,
Si oui, décrémenter les quantités et incrémenter l'historique des sorties,
Mon code (effectué en fouillant les sujet "stock" du forum) ne fonctionne pas correctement, il ne trouve pas certaines lignes alors qu'elles sont présentes en stock,
Et je ne trouve pas comment incrémenter l'historique des sorties
Code pour décrémenter stock :
Sub Sortir()
With Sheets("Stock")
For Each I In Sheets("Export").Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row)
Set Article = .Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row).Find(I.Value, lookat:=xlWhole)
If Not Article Is Nothing Then
Lgn = Article.Row
.Cells(Lgn, "G").Value = .Cells(Lgn, "G").Value - I.Offset(0, 4).Value
Else: MsgBox " La pièce " & I.Value & "" & I.Offset(0, 2).Value & " n'existe pas en stock", 16
End If
Next I
End With
MsgBox "Sorties enregistrées."
End sub
Bonjour,
Je n'ai pas regardé votre fichier mais voici un code pour l'exemple avec un tableau structuré nommé "Stock" et la colonne d'articles libellée "Articles" et la colonne du stock restant libellée "Qte".
Ici, pas de boucle sur un ensemble d'articles pour l'instant car je n'en vois pas l'intérêt. Normalement, il y a un évènement générateur de la mise à jour de l'onglet Export (il faudra également un tableau structuré nommé "Export") et de l'onglet "Stock". Les mises à jour doivent être simultanées et provenir d'un espace de saisie qui reste à déterminer (alors la boucle sur les seuls produits exportés sera envisageable).
Sub Sortir()
Dim article$
article = ???
QteSortie = ???
if application.countif(range("Stock[Articles]"), article) = 0 then
MsgBox " La pièce " & article & " n'existe pas en stock", 16
else
Lgn = application.match(article, range("Stock[Articles]"), 0)
range("Stock[Qte]")(Lgn).Value = range("Stock[Qte]")(Lgn).Value - QteSortie
end if
MsgBox "Sorties enregistrées."
End subCdlt,
Bonjour, et merci pour votre retour,
Je ne parvient pas a faire fonctionner votre code, j'ai bien nommé mes tableaux et colonnes comme vous me l'avez indiqué,
L'autre chose c'est que le nombre de lignes de l'export est amener a changé, d'où le comptage jusqu'à dernière ligne.
Question : Que-ce qui est attendu dans "article = ??? QteSortie = ???" une plage de donnée ? et que signifie le $ après une déclaration de variable ?
De plus votre langage est difficilement compréhensible pour un novice comme moi.. (un évènement générateur de la mise à jour de l'onglet Export?? Les mises à jour doivent être simultanées et provenir d'un espace de saisie qui reste à déterminer (alors la boucle sur les seuls produits exportés sera envisageable).??)
J'ai essayé le code code comme ca :
Sub Sortirtest()Dim article, Qtesortiearticle = Sheets("Export").Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row)Qtesortie = Sheets("Export").Range("E2:E" & Range("A" & Rows.Count).End(xlUp).Row)If Application.CountIf(Range("Stock[Articles]"), article) = 0 Then MsgBox " La pièce " & article & " n'existe pas en stock", 16Else Lgn = Application.Match(article, Range("Stock[Articles]"), 0) Range("Stock[Qte]")(Lgn).Value = Range("Stock[Qte]")(Lgn).Value - QtesortieEnd IfMsgBox "Sorties enregistrées."End Sub
Désolé, impossible d'insérer un code inline mis en forme correctement ...
Dans article, il est attendu le nom de l'article à tester (string). Dans QteSorti, la quantité sortie (integer). Or, je ne sais pas d'où viennent ces infos.
Mais comme j'ai essayé d'expliquer, j'espère qu'elles proviennent d'un formulaire (feuille ou userform) de saisie et non d'une colonne d'une autre base. L'idée, c'est qu'on saisit une sortie sur, par exemple, une feuille servant de formulaire de saisie des sorties.
Une fois que nos saisies (qui contiennent l'article et la quantité en question) sont terminées, en général, on appuie sur un bouton. Cela va mettre à jour nos 2 bases export et stock.
Car d'après votre code, j'avais l'impression que vous parcouriez votre base "Export" pour faire une modif sur chaque article...
Mais je vais regarder votre fichier pour m'assurer que je ne suis pas à côté de la plaque...
le "$" siginifie "As String" (et % signifie as integer).
Pour le code, il faut utiliser l'icone avec les balises </>
Merci encore pour votre aide,
Pour être plus précis dans le process recherché :
Mon but final est d'avoir deux fichier séparer, mais j'essaye pour commencer, de coder dans un même fichier, d'une feuille à une autre.
A la fin j'aimerais avoir 1 fichier Bdd Stock qui sera enregistré dans un emplacement fixe et 1 fichier Export (qui est en fait un extraction Excel de l'ERP SAP correspondant aux pièces à sortir du stock) et qui sera différent à chaque fois (en nombre de ligne)
L'idée première est de décrémenter, via une macro, les quantités de la Bdd en fonction des quantités présentes dans l'export généré via SAP (directement sans aucune saisie de formulaire ou autre à effectuer).
Dans la même macro j'aimerais vérifier si la pièces a sortir est bien présente dans la bdd stock et si quantité est suffisante en stock
J'ai "bricoler" un code que j'ai trouver sur le forum, mais il vrai que je doute que ce soit la bonne direction a prendre :
Sub Sortir()
With Sheets("Stock")
For Each I In Sheets("Export").Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row)
' I = Valeur colonnes A feuille Export
Set article = .Range("A2:A" & Range("A" & Rows.Count).End(xlUp).Row).Find(I.Value, lookat:=xlWhole)
' Article = valeur égale a I dans feuille Stock
'If I = "" Then
'MsgBox "sortie enregistré"
'Exit Sub
'End If
If Not article Is Nothing Then
Lgn = article.Row
.Cells(Lgn, "G").Value = .Cells(Lgn, "G").Value - I.Offset(0, 4).Value
'.Cells(Lgn, "B").Value = quantité en stock
'I.Offset(0, 1).Value = quantité commandé
Else: MsgBox " La pièce " & I.Value & "" & I.Offset(0, 2).Value & " n'existe pas en stock", 16
End If
Next I
End With
MsgBox "Sorties enregistrées."
End SubAhhh d'accord, il n'y a pas de saisie.
Oui, la macro est bien (mais à adapter forcément). J'essaie d'éviter d'utiliser la méthode find pour ma part mais le résultat est normalement le même.
Si le format d'export de SAP est toujours le même, il n'y a pas de raison de créer 2 fichiers. 2 onglets c'est très bien.
Voici un essai alors, avec un hypothétique tableau structuré "Export" et 2 colonnes "Articles" et "Qte" :
Sub Sortir()
Dim article$
for i = 1 to range("Export").rows.count
article = range("Export[Articles]")(i)
QteSortie = range("Export[Qte]")(i)
if application.countif(range("Stock[Articles]"), article) > 0 then
Lgn = application.match(article, range("Stock[Articles]"), 0)
if range("Stock[Qte]")(Lgn) - QteSortie >= 0 then
range("Stock[Qte]")(Lgn).Value = range("Stock[Qte]")(Lgn).Value - QteSortie
else
range("Export").rows(i).interior.color = 255
range("Export")(i, range("Export").columns.count).offset(0, 2) = QteSortie & " non soustraite car supérieure au stock !"
end if
else
range("Export").rows(i).interior.color = 255
range("Export")(i, range("Export").columns.count).offset(0, 2) = article & " n'existe pas en stock !"
end if
next i
MsgBox "Sorties enregistrées."
End subCdlt,
Je ne sais pas vraiment ce que vous entendez par tableau "structuré" mais le but du process est de ne faire aucune saisie et donc de ne pas nommer les colonnes du tableau export à chaque fois.
Le format du fichier export sera toujours le même en terme de colonnes mais il sera bien un nouveau fichier a chaque nouvel export, l'intérêt d'avoir 2 fichier est d'éviter la manipulation de copié/collé la feuille export dans le fichier bdd stock pour chaque export.
Néanmoins, j'ai essayé votre code, je n'arrive pas a le faire fonctionner, j'ai fait l'essaie sur un fichier simplifier deux feuilles stock et export avec deux colonnes articles et quantité que j'ai nommé suivant vos indications mais j'ai une erreur d'exécution
D'accord, j'ai compris. C'est un export qui produit un fichier et pas des lignes exportées via le presse-papier...
Ok, bah c'est faisable mais ça implique de cherche le fichier l'ouvrir avant de faire cette opération (qu'il faudra juste adapter).
Bonsoir QGOUG,
Voici un code à essayer sur la base de ton fichier et de tes explications. Je ne l'ai pas testé car il nécessite un fichier nommé export dans le dossier téléchargements. On s'approche du but je pense. Je suis parti sur la même base (tableau structuré Stock et colonnes Articles et Qte) sur le fichier exécutant. Cependant, plus de tableau sur le fichier export. Il est fermé au début de la procédure. On teste son existence dans le dossier téléchargements. S'il existe on l'ouvre et on boucle sur chaque ligne (à partir de la ligne 2). Je considère qu'il y a les articles en colonne A et les quantités en colonne B (comme sur ton exemple).
Le principe du code reste le même...
Mais au cas où un article est manquant ou une quantité à sortir est excessive, on empêche la modification de la base et on surligne en rouge (avec un message à la fin de la procédure). Quand on ne rencontre aucun problème, le fichier est fermé et on a un message plus sympathique.
Voici le code :
Sub Sortir()
Dim alerte As Boolean
spath = Environ("USERPROFILE") & "\Downloads\" 'emplacement (tlchgts)
sfilename = Dir(spath & "*xport*") 'clé de recherche
If sfilename = "" Then 'si n'existe pas
MsgBox "Fichier Introuvable"
Exit Sub 'sortie
End If
Application.ScreenUpdating = True
Workbooks.Open spath & sfilename 'sinon, ouverture fichier
With ActiveWorkbook.ActiveSheet 'avec feuille active de fichier actif (ouvert à l'instant donc l'export)
dl = .Cells(.Rows.Count, 1).End(xlUp).Row 'dern ligne
For i = 2 To dl 'pour chaque ligne export
article = .Cells(i, 1).Value 'article en A
qte = .Cells(i, 2).Value 'qté en B
If Application.CountIf(Range("Stock[Articles]"), article) > 0 Then 'si article existe dans tableau Stock (col Articles)
Lgn = Application.Match(article, Range("Stock[Articles]"), 0) 'position ligne
If Range("Stock[Qte]")(Lgn) - qte >= 0 Then 'si qte sortie inferieure au stock
Range("Stock[Qte]")(Lgn).Value = Range("Stock[Qte]")(Lgn).Value - qte 'decrementation
Else
alerte = True 'sinon, prepare une alerte
.Range("A:B").Rows(i).Interior.Color = 255 'colorie ligne en rouge
.Cells(i, 3).Value = qte & " non soustraite car supérieure au stock !" 'commentaire en col C
End If
Else
fermeture = False 'si existe pas, alerte
.Range("A:B").Rows(i).Interior.Color = 255 'ligne rouge
.Cells(i, 3).Value = article & " n'existe pas en stock !" 'comm en col C
End If
Next i
End With
Application.ScreenUpdating = True
If Not alerte Then 'si aucune alerte
ActiveWorkbook.Close True 'fermeture et sauvegarde
MsgBox "Sorties enregistrées." 'msg ok
Else 'sinon, si pb
MsgBox "Anomalies rencontrées durant la procédure, surlignées en rouge !", vbCritical 'alerte et pas de fermeture
End If
End SubJe te renvoie le fichier avec le code dessus au cas où :
Rq : Sur ton fichier, j'ai vu des quantités négatives en stock. Si ce n'est pas pour l'exemple, il faudra surveiller car c'est anormal.
Cdlt,
Bonjour 3GB,
Merci pour ton aide, en effet j'ai l'impression qu'on s'approche du but
Cependant, j'ai tout essayé mais le code ne passe pas la ligne,
If Application.CountIf(Range("Stock[Articles]"), article) > 0 Then 'si article existe dans tableau Stock (col Articles)Msg : La méthode Range de l'objet global a échoué
Je pense pourtant avoir bien structuré mon tableau Stock..
Salut QGOUG,
Oui, j'ai regardé le sujet ce matin et j'y ai pensé. En fait, comme le classeur export est le classeur actif, le tableau Stock n'est pas trouvé car il est défini sur le classeur de départ. Voici un nouvel essai :
Sub Sortir()
Dim alerte As Boolean
spath = Environ("USERPROFILE") & "\Downloads\" 'emplacement (tlchgts)
sfilename = Dir(spath & "*xport*") 'clé de recherche
If sfilename = "" Then 'si n'existe pas
MsgBox "Fichier Introuvable"
Exit Sub 'sortie
End If
set rART = Range("Stock[Articles]") 'si besoin, rajouter sheets("nomfeuille")
set rQTE = Range("Stock[Qte]") 'iden
Application.ScreenUpdating = True
Workbooks.Open spath & sfilename 'sinon, ouverture fichier
With ActiveWorkbook.ActiveSheet 'avec feuille active de fichier actif (ouvert à l'instant donc l'export)
dl = .Cells(.Rows.Count, 1).End(xlUp).Row 'dern ligne
For i = 2 To dl 'pour chaque ligne export
article = .Cells(i, 1).Value 'article en A
qte = .Cells(i, 2).Value 'qté en B
If Application.CountIf(rART, article) > 0 Then 'si article existe dans tableau Stock (col Articles)
Lgn = Application.Match(article, rART, 0) 'position ligne
If rQTE(Lgn) - qte >= 0 Then 'si qte sortie inferieure au stock
rQTE(Lgn).Value = rQTE(Lgn).Value - qte 'decrementation
Else
alerte = True 'sinon, prepare une alerte
.Range("A:B").Rows(i).Interior.Color = 255 'colorie ligne en rouge
.Cells(i, 3).Value = qte & " non soustraite car supérieure au stock !" 'commentaire en col C
End If
Else
fermeture = False 'si existe pas, alerte
.Range("A:B").Rows(i).Interior.Color = 255 'ligne rouge
.Cells(i, 3).Value = article & " n'existe pas en stock !" 'comm en col C
End If
Next i
End With
Application.ScreenUpdating = True
If Not alerte Then 'si aucune alerte
ActiveWorkbook.Close True 'fermeture et sauvegarde
MsgBox "Sorties enregistrées." 'msg ok
Else 'sinon, si pb
MsgBox "Anomalies rencontrées durant la procédure, surlignées en rouge !", vbCritical 'alerte et pas de fermeture
End If
End SubIl faudra peut-être préciser aussi la feuille sur laquelle se trouve le tableau Stock mais j'en doute.
Si tous les noms (tableaux, colonnes, etc...) sont bons, je pense que le code devrait passer :)
A bientôt,
3GB, merci beaucoup pour vos retours rapides !
En effet le problème était bien la, je venais de l'identifier :) et ca marche bien avec le nouveau code,
Par contre le process est un peu différent de ce que j'aimerais :
En réalité ca serait plutôt l'inverse, l'Export sera déjà ouvert et le fichier Stock fermé (enregistré dans un emplacement fixe). J'aimerais que le lancement des opérations (de la macro) se fasse directement depuis l'Export, que le message s'affiche à la fin sur l'Export et que le fichier Stock soit enregistré et fermé.
Je pense que celle-ci sera ma dernière sollicitation pour vous et je vous laisse tranquille :p
Honnêtement, je ne suis pas sûr que ce soit une solution envisageable...
Il est possible d'améliorer la présente solution mais si j'ai bien compris, tu réalises des exports périodiquement. Je vois mal comment ces fichiers éphémères pourraient contenir une macro sans perdre le bénéfice de l'automatisation...
Non, à mon avis, c'est bien le fichier qui contient le Stock qui doit contenir cette macro.
Oui ce sont bien des export periodique, je pensai qu'il était possible d'enregistré une macro dans la barre d'accès rapide qui permettrai d'exécuter les opérations dans les exports sachant qu'ils auront tous le même formats.
Mais en effet, je test depuis tout à l'heure et je perd ma macro a chaque fois ^^..
Il y a toujours moyen de trouver une solution mais je pense qu'elle pourrait être coûteuse et finalement inadaptée. Ton fichier c'est bien celui qui contient le stock. C'est ce fichier que tu mettras à jour, qui évoluera. C'est donc de ce fichier que tu dois partir.
Ok, je vais rester la dessus alors,
Merci pour le temps que tu m'as consacré !
Bon weekend !
Cordialement,
Quentin.
Merci, très bon week-end à toi aussi !