PQ : Compter le nombre de palettes non consommées en prod

Bonjour,

Je souhaiterais quantifier le nombre de fois qu'une palette rentre dans l'atelier de production et ressort sans avoir été consommée.

Pour cela je dispose de la colonne "Contenant" (chaque numéro représente une palette), j'ai une colonne "Quantité" et deux colonnes sur l'emplacement source et destination de la palette.

Quand la colonne "Emplacement de destination" contient -TL c'est que la palette arrive dans l'atelier

Quand la colonne "Emplacement de destination" contient -RS c'est que la palette sort de l'atelier

Sur cette illustration par exemple, on voit que la quantité reste la même quand la palette arrive en production et ressort (j'aimerai quantifier le nombre de fois que ça arrive).

image

Il y a aussi un cas qu'on peut rencontrer, c'est quand la même palette entre et ressort plusieurs fois dans l'atelier

image

Je suppose qu'il faudrait prendre en compte l'ordre chronologique des mouvements je pense...

J'espère avoir été assez clair

Si certains peuvent m'apporter de l'aide (résultat, approche du problème sur POWER QUERY autre...) je vous en remercie sincèrement.

Vladt

Pardon j'ai oublié les fichiers

4kdkddjbdq.zip (1.10 Mo)

Bonjour à tous !

Une approche à....tester :

let
    Source = Excel.CurrentWorkbook(){[Name="Tableau1"]}[Content],
    GroupBy = Table.Group(Source, {"Contenant"}, {{"Nombre", each Table.RowCount(_), Int64.Type}, {"tbl", each _}}),
    Filtre = Table.SelectRows(GroupBy, each [Nombre] > 1),
    Combine = Table.Combine( Filtre[tbl]),
    SuppColAutres = Table.SelectColumns(Combine,{"Date", "Contenant", "Unité", "Quantité", "Emplacement source", "Emplacement de destination"}),
    TestCode = Table.AddColumn(SuppColAutres, "Test", each List.Contains({"-RS","-TL"},Text.End([Emplacement de destination],3))),
    FiltreTrue = Table.SelectRows(TestCode, each ([Test] = true)),
    GroupBy1 = Table.Group(FiltreTrue, {"Contenant", "Quantité"}, {{"Nombre", each Number.RoundDown(Table.RowCount(_)/2), Int64.Type}}),
    FiltreNbre = Table.SelectRows(GroupBy1, each [Nombre] >= 1),
    SuppColQté = Table.RemoveColumns(FiltreNbre,{"Quantité"})
in
    SuppColQté

J'ai prolongé la requête initiale.

Merci beaucoup pour votre aide.

L'approche est vraiment bluffante !

Donc j'ai analysé un peu tout ça, je pense bien avoir compris le code.
Il y a juste un point que je relève :

"-TL" dans la colonne "Emplacement de destination" représente le mouvement vers la production

"-RS" dans la colonne "Emplacement de destination" représente le mouvement vers le stock

Parfois une palette peut être apporté en production une première fois (-TL en destination) avec une quantité Q1, elle va être consommée mais pas entièrement, elle retourne donc en stock (-RS en destination) avec une quantité Q2.
Puis elle reviendra en production (-TL) plus tard toujours avec cette quantité Q2 et sera consommée de nouveau (entièrement ou partiellement pas d'importance).

Donc chronologiquement, on retrouve la quantité Q2 qui fait le trajet (... --> -RS) puis (... --> -TL), ce qui ne pose pas de problème.
Le problème : c'est quand ça va en -TL puis en -RS avec la même quantité.

Illustration

image

La quantité 5600 du même contenant est en double mais dans l'ordre chronologique : (Stock (8400) -> prod (5600) -> stock (5600) -> prod)

La demande est un peu tordue, je ne sais pas si j'ai réussi à être clair avec ce baratin...

Bonjour à tous de nouveau !

Pour le cas soulevé, vous ne précisez pas s'il doit être compté... ou pas !

Cela ne m'éclaire donc pas.

De ce que j'ai compris, il faut, pour un même contenant et une quantité identique, vérifier si l'emplacement destination comporte "-TL" et "-RS". Si tel est le cas, ces deux lignes sont dénombrées pour 1.

Excusez-moi, en effet le cas présenté ne doit pas être décompté car chronologiquement "-RS" précède "-TL" dans l'emplacement de destination.

Donc si pour un même contenant et une quantité identique, l'emplacement destination comporte "-RS" avant "-TL" (suivant la date), on ne le compte pas. Seul le cas contraire : contenant et quantité identique et "-TL" avant "-RS" chronologiquement est compté (combinaison de 3 conditions : contenant et quantité identique, "-TL" et "-RS" en emplacement de destination, et "-TL" avant "-RS" en suivant la date dans l'ordre croissant).

J'espère que c'est plus clair

Bonsoir à tous !

Une proposition amendée :

let
    Source = Excel.CurrentWorkbook(){[Name="Tableau1"]}[Content],
    GroupBy = Table.Group(Source, {"Contenant"}, {{"Nombre", each Table.RowCount(_), Int64.Type}, {"tbl", each _}}),
    Filtre = Table.SelectRows(GroupBy, each [Nombre] > 1),
    Combine = Table.Combine( Filtre[tbl]),
    SuppColAutres = Table.SelectColumns(Combine,{"Date", "Contenant", "Unité", "Quantité", "Emplacement source", "Emplacement de destination"}),
    AjtCode = Table.AddColumn(SuppColAutres, "Code", each Text.End([Emplacement de destination],3)),
    FiltreCode = Table.SelectRows(AjtCode, each List.Contains({"-RS","-TL"},[Code])),
    GroupBy1 = Table.Group(FiltreCode, {"Contenant", "Quantité"}, {{"Nombre", each Table.RowCount(_), Int64.Type}, {"tbl", each Table.Sort(_, {"Date",0})[Code]}}),
    Filtre1 = Table.SelectRows(GroupBy1, each ([Nombre] <> 1)),
    TestPosition = Table.AddColumn(Filtre1, "Position", each List.PositionOf([tbl],"-TL")),
    FiltreFinal = Table.SelectRows(TestPosition, each ([Position] = 0))[[Contenant],[Quantité]]
in
    FiltreFinal

La requête retourne la liste des "Contenant", et le champ "Quantité" (on pourrait supprimer ce champ ?), répondant aux critères.
A tester !

Incroyable, je pense que ça fonctionne super bien.

Si je comprends bien la fonction List.PositionOf nous permet de savoir si "-TL" est avant (0) ou derrière (1), mais comment ça va chercher la date pour savoir cela ? Je n'ai pas vu de tri, faut-il en faire un ?

Oui on peut se passer du champ quantité.

Merci beaucoup !

Bonsoir à tous de nouveau !

Pour supprimer le champ "Quantité", je vous propose de modifier la dernière étape ainsi :

Table.SelectRows(TestPosition, each ([Position] = 0))[[Contenant]]

Note : Le tri est effectué dans l'étape GroupBy1.

Je vous remercie de ce retour... positif !

Bonjour,

Je me permets de relancer cette discussion, je rencontre un problème que je n'avais pas identifié précédemment. Et par la même occasion j'aimerai apporter quelques modifications à mon besoin initial mais ça commence à devenir trop compliqué pour moi techniquement.

Pour rappeler le principe : l'objectif était de compter le nombre de fois qu'un contenant passe en -TL (3 derniers caractères de la colonne emplacement de destination) puis en -RS avec la même quantité dans l'ordre chronologique (-TL puis -RS). Là aussi je me rends compte après analyse que je n'ai pas été suffisamment précis... Il faudrait aussi conserver le préfixe devant (les 4 premiers caractères colonne emplacement de destination) qui indique de quelle ligne de production il s'agit. Cela me permet ainsi de savoir où ça s'est passé.

Donc plus concrètement j'avais demandé uniquement le besoin 1, mais quand j'avais plusieurs contenants regroupés sur 1 contenant parent ça va compter au contenant or je veux que ça compte au contenant parent comme indiqué dans le besoin 2.

image

Enfin j'aimerais idéalement savoir quel jour ça s'est passé, puisque je compte le suivre quotidiennement. Il faudrait essayer de récupérer la date (heure négligeable) sur le retour (quand on a -RS).

J'ai essayé d'entamer quelque chose en reprenant ce que JFL m'avait donné mais j'ai fait un carnage, je ne comprends plus (je me suis arrêté à ExtractNomLigne).

(connexion uniquement)

(3 Fichiers sources)

Merci à ceux qui reprendront cette discussion et n'hésitez pas à me reprendre sur ce qui n'est pas clair, j'ai du mal à être explicite sur ce sujet en particulier.

Vladt

Bonsoir à tous !

J'éprouve des difficultés à suivre vos explications "techniques"....

Par ailleurs, vous dites vous être arrêté à l'étape "ExtractNomLigne" de ma requête. Hors je ne trouve pas trace de cette étape !

Ma compréhension est la suivante :

  1. Obtenir le "Contenant" selon la logique de ma requête précédente
  2. En ajouter la date et le code "Ligne de production".

Confirmez-vous ?

1. C'est ça mais je voulais juste traiter le cas où les contenants ont un contenant parent (colonne contenant parent destination).

J'ai essayé de remplacer la valeur des contenants qui ont un contenant parent par ce numéro (étape ReplaceValue)

Ensuite j'ai calculé une nouvelle quantité en regroupant les quantités des contenants d'un même contenant parent.

Je ne suis pas certain que ce que j'ai fait fonctionne. J'ai également extrait le nom de la ligne de prod (étape ExtractNomLigne).

2. Oui j'aimerais qu'on y ajoute la date en la prenant sur la ligne "-RS" dans la colonne emplacement de destination et non -TL si c'est possible.

image

Donc pour ce contenant la date serait le 08/04/2024 par exemple (arrivé en -TL le 07 puis en -RS le 08 avec la même quantité).

J'espère que c'est un peu plus clair.

let
    Source = Source,
    #"Type modifié" = Table.TransformColumnTypes(Source,{{"Date", type datetime}, {"Contenant", type text}, {"Contenant de destination", Int64.Type}, {"Article", type text}, {"Description article", type text}, {"Lot", type text}, {"Type de mouvement", type text}, {"Type de mouvement description", type text}, {"Code raison", type text}, {"Code raison description", type text}, {"Numéro d'ordre", type text}, {"Modification de stock", type text}, {"Unité", type text}, {"Quantité", type number}, {"Emplacement source", type text}, {"Emplacement de destination", type text}, {"Magasin source", type text}, {"Magasin de destination", type text}, {"Contenant parent source", Int64.Type}, {"Contenant parent destination", Int64.Type}}),
    #"Colonnes filtrées" = Table.SelectRows(#"Type modifié", each Text.Contains([Emplacement de destination], "-TL") or Text.Contains([Emplacement de destination], "-RS")),
    #"Lignes filtrées" = Table.SelectRows(#"Colonnes filtrées", each not Text.Contains([Emplacement source], "MPE")),
    SuppColAutres = Table.SelectColumns(#"Lignes filtrées",{"Date", "Contenant", "Type de mouvement", "Quantité", "Emplacement source", "Emplacement de destination", "Contenant parent destination"}),
    ReplaceValue = Table.ReplaceValue(
    SuppColAutres,
    each [Contenant],
    each if ([Contenant parent destination] <> "" and [Contenant parent destination] <> null) then [Contenant parent destination] else [Contenant],
    Replacer.ReplaceValue,
    {"Contenant"}
),
    #"Type modifié1" = Table.TransformColumnTypes(ReplaceValue,{{"Contenant", type text}}),
    #"Lignes groupées" = Table.Group(#"Type modifié1", {"Date", "Contenant", "Emplacement de destination", "Type de mouvement"}, {{"Quantité", each List.Sum([Quantité]), type nullable number}}),
    AjtCode = Table.AddColumn(#"Lignes groupées", "Code", each Text.End([Emplacement de destination],3)),
    ExtractNomLigne = Table.AddColumn(AjtCode, "Ligneprod", each Text.Start([Emplacement de destination],4)),
    FiltreCode = Table.SelectRows(ExtractNomLigne, each List.Contains({"-RS","-TL"},[Code])),
    GroupBy1 = Table.Group(FiltreCode, {"Contenant", "Quantité", "Ligneprod"}, {{"Nombre", each Table.RowCount(_), Int64.Type}, {"tbl", each Table.Sort(_, {"Date",0})[Code]}}),
    Filtre1 = Table.SelectRows(GroupBy1, each ([Nombre] <> 1)),
    TestPosition = Table.AddColumn(Filtre1, "Position", each List.PositionOf([tbl],"-TL")),
    FiltreFinal = Table.SelectRows(TestPosition, each ([Position] = 0))[[Contenant], [Ligneprod]]
in
    FiltreFinal

Voici le code sur la base de votre requête (et mes petites modifications).

Merci pour votre retour

Bonsoir à tous de nouveau !

Une tentative (sur la base de ma requête précédente) :

let
    Source = Excel.CurrentWorkbook(){[Name="Tableau1"]}[Content],
    AjtCode = Table.AddColumn(Source, "Code", each Text.End([Emplacement de destination],3)),
    FiltreCode = Table.SelectRows(AjtCode, each List.Contains({"-RS","-TL"},[Code])),
    GroupBy = Table.Group(
                            FiltreCode,
                            {"Contenant", "Quantité"},
                            {
                                {"Nombre", each Table.RowCount(_), Int64.Type},
                                {"Ligne de production",each List.Distinct(List.Transform([Emplacement de destination], each Text.Start(_,4))){0}},
                                {"CPD", each List.Select([Contenant parent destination], each _<>"")},
                                {"Date", each Date.From(List.Max([Date])), type date},
                                {"tbl", each Table.Sort(_, {"Date",0})[Code]}
                            }
                         ),
    Filtre = Table.SelectRows(GroupBy, each ([Nombre] <> 1) and (not List.IsEmpty([CPD]) and (List.PositionOf([tbl],"-TL")=0))),
    SélectionChamps = Table.SelectColumns(Filtre,{"Contenant", "Ligne de production", "Date"})
in
    SélectionChamps

Merci d'être toujours là

Je vous fais un retour demain quand j'aurais analysé plus en détail.

Merci et bonne soirée

Bonjour,

Ce n'est malheureusement pas encore le résultat souhaité. Je vais essayer une autre approche sur mes explications si vous le voulez bien.

Besoin 1 : Les contenants et contenants parents

Il existe des numéro de contenants pour lesquels la colonne contenant parent contient aussi un numéro parent (en gros une palette "le contenant parent" regroupe plusieurs cartons "contenant"). Ici j'aimerais remplacer le numéro de la colonne "contenant" par le numéro de la colonne "contenant parent" s'il en existe un (dans la même ligne) sinon laisser tel quel.

Ainsi dans un second temps je souhaite regrouper par "Date", "Contenant", "Emplacement de destination" en faisant la somme de la colonne "Quantité". Ceci me donnera donc la quantité de tous les contenants d'un contenant parent en une seule ligne.

Explications "si on déplace un contenant parent qui contient plusieurs contenants ça démultiplie autant de fois le mouvement qu'il y a de contenants or c'est faux le mouvement est unique on ne déplace la palette qu'une seule fois même si elle contient plusieurs contenants".

Pour cela j'ai essayé un code

ReplaceValue = Table.ReplaceValue(
    #"Lignes filtrées",
    each [Contenant],
    each if ([Contenant parent destination] <> "" and [Contenant parent destination] <> null) then [Contenant parent destination] else [Contenant],
    Replacer.ReplaceValue,
    {"Contenant"}
),
    #"Type modifié1" = Table.TransformColumnTypes(ReplaceValue,{{"Contenant", type text}}),
    #"Lignes groupées" = Table.Group(#"Type modifié1", {"Date", "Contenant", "Emplacement source", "Emplacement de destination", "Contenant parent destination"}, {{"Quantité ajustée", each List.Sum([Quantité]), type nullable number}}),

Besoin 2 : Application de votre code

Une fois le besoin 1 fait, je passe donc à votre code. Le principe est complétement en adéquation avec ce que je veux. Il faudrait juste rajouter quelques détails.

image

Sur ce cas là on observe chronologiquement que le contenant 2043092176 est arrivé en MFL1-TL avec une quantité de 5000 puis ensuite en MFL1-RS avec la même quantité donc on veut garder ce cas à la fin (ce que fait votre code d'ailleurs).

Néanmoins il y a un cas :

image

On remarque que le contenant ne passe jamais par -RS mais est compté quand même dans votre code puisque dans l'étape Filtre

= Table.SelectRows(GroupBy, each ([Nombre] <> 1) and (not List.IsEmpty([CPD]) and (List.PositionOf([tbl],"-TL")=0)))

vous aviez contraint "-TL" comme devant être en position 0, il faudrait alors aussi contraindre "-RS" en position 1 (afin d'obtenir seulement les cas où -TL est avant -RS).

Si vous êtes toujours là n'hésitez pas à me dire si c'est trop casse tête, et laissez tomber dans ce cas je trouverai un moyen de définir beaucoup mieux mon besoin avant de revenir sur le sujet ou de décomposer en plusieurs sujets peut-être.

Merci beaucoup pour l'attention porté au problème.

A bientôt

Edit :

Besoin 3 : Ajout de la date

Pour la date, si on reprend l'exemple que j'ai donné du contenant 2043092176 (capture d'écran 1), la date à renvoyer serait le 08/04/2024 (correspondant à -RS le retour en stock).

Bonjour à tous !

Sans aucune conviction......

let
    Source = Excel.CurrentWorkbook(){[Name="Tableau1"]}[Content],
    ModifContenant = Table.ReplaceValue(
                                        Source,
                                        each [Contenant],
                                        each if ([Contenant parent destination] <> "" and [Contenant parent destination] <> null) then [Contenant parent destination] else [Contenant],
                                        Replacer.ReplaceValue,
                                        {"Contenant"}),
    AjtCode = Table.AddColumn(ModifContenant, "Code", each Text.End([Emplacement de destination],3)),
    FiltreCode = Table.SelectRows(AjtCode, each List.Contains({"-RS","-TL"},[Code])),
    GroupBy = Table.Group(
                            FiltreCode,
                            {"Contenant", "Quantité"},
                            {
                                {"Nombre", each Table.RowCount(_), Int64.Type},
                                {"Ligne de production",each List.Distinct(List.Transform([Emplacement de destination], each Text.Start(_,4))){0}},
                                {"CPD", each List.Select([Contenant parent destination], each _<>"")},
                                {"Date", each try Date.From(Table.SelectRows(Table.Sort(_, {"Date",0}),each [Code]="-RS")[Date]{0}) otherwise null},
                                {"tbl", each Table.Sort(_, {"Date",0})[Code]}
                            }
                         ),
    Filtre = Table.SelectRows(GroupBy, each ([Nombre] <> 1) and (not List.IsEmpty([CPD]) and (List.PositionOf([tbl],"-RS")=1))),
    SélectionChamps = Table.SelectColumns(Filtre,{"Contenant", "Ligne de production", "Date"})
in
    SélectionChamps

Cette requête intègre les éléments nouveaux suivants :

  1. Modification du champ "Contenant".
  2. La date correspond au premier élément "-RS" lié au champ de regroupement.
  3. Sélection des éléments regroupés ayant le code "-RS" en deuxième position.

Remarque : Compte tenu du jeu de données, la table finale est.....vide !

ReBonjour

A force d'ajustements sur votre code j'ai réussi à obtenir ce que je souhaite :

let
    Source = Source,
    #"Type modifié" = Table.TransformColumnTypes(Source,{{"Date", type datetime}, {"Contenant", type text}, {"Contenant de destination", Int64.Type}, {"Article", type text}, {"Description article", type text}, {"Lot", type text}, {"Type de mouvement", type text}, {"Type de mouvement description", type text}, {"Code raison", type text}, {"Code raison description", type text}, {"Numéro d'ordre", type text}, {"Modification de stock", type text}, {"Unité", type text}, {"Quantité", type number}, {"Emplacement source", type text}, {"Emplacement de destination", type text}, {"Magasin source", type text}, {"Magasin de destination", type text}, {"Contenant parent source", Int64.Type}, {"Contenant parent destination", Int64.Type}}),
    SuppColAutres = Table.SelectColumns(#"Type modifié",{"Date", "Contenant", "Type de mouvement", "Quantité", "Emplacement source", "Emplacement de destination", "Contenant parent destination"}),
    #"Lignes filtrées" = Table.SelectRows(SuppColAutres, each not Text.Contains([Emplacement source], "MPE")),
    ReplaceValue = Table.ReplaceValue(
    #"Lignes filtrées",
    each [Contenant],
    each if ([Contenant parent destination] <> "" and [Contenant parent destination] <> null) then [Contenant parent destination] else [Contenant],
    Replacer.ReplaceValue,
    {"Contenant"}
),
    #"Type modifié1" = Table.TransformColumnTypes(ReplaceValue,{{"Contenant", type text}}),
    #"Lignes groupées" = Table.Group(#"Type modifié1", {"Date", "Contenant", "Emplacement source", "Emplacement de destination", "Contenant parent destination"}, {{"Quantité ajustée", each List.Sum([Quantité]), type nullable number}}),
    AjtCode = Table.AddColumn(#"Lignes groupées", "Code", each Text.End([Emplacement de destination],3)),
    FiltreCode = Table.SelectRows(AjtCode, each List.Contains({"-RS","-TL"},[Code])),
    GroupBy = Table.Group(
                            FiltreCode,
                            {"Contenant", "Quantité ajustée"},
                            {
                                {"Nombre", each Table.RowCount(_), Int64.Type},
                                {"Ligne de production",each List.Distinct(List.Transform([Emplacement de destination], each Text.Start(_,4))){0}},
                                {"Date", each try Date.From(Table.SelectRows(Table.Sort(_, {"Date",0}),each [Code]="-RS")[Date]{0}) otherwise null},
                                {"tbl", each Table.Sort(_, {"Date",0})[Code]}
                            }
                         ),
    Filtre1 = Table.SelectRows(GroupBy, each ([Nombre] <> 1)),
    #"Position TL" = Table.AddColumn(Filtre1, "Position TL", each List.PositionOf([tbl],"-TL")),
    #"Position RS" = Table.AddColumn(#"Position TL", "Position RS", each List.PositionOf([tbl],"-RS")),
    FiltreFinal = Table.SelectRows(#"Position RS", each ([Position TL] = 0) and ([Position RS] = 1))[[Contenant], [Ligne de production], [Date]]
in
    FiltreFinal

Merci beaucoup beaucoup parce que là franchement j'étais complétement sans solutions

Sujet enfin clos pour de bon je l'espère.
A bientôt,
Vladt

Bonjour à tous de nouveau !

Je suis enchanté de cette heureuse fin....

Je vous remercie de ce retour.

Rechercher des sujets similaires à "compter nombre palettes consommees prod"