màj wiki avec retour MES lot-5 AD
This commit is contained in:
@@ -0,0 +1,471 @@
|
||||
---
|
||||
title: "Séquençage des tâches de picking TK → PS"
|
||||
tags: [picking, séquençage, transstockeur, événement, workflow, algorithme]
|
||||
status: draft
|
||||
standard_ref: concepts/picking.md
|
||||
jira_refs: [LIM-84, LIM-61]
|
||||
confluence_refs: []
|
||||
sources: ["LIM-84 LOT2.2 [PICKING] Séquençage des tâches de picking TK PS.md", "Logique combinatoire picking - TK vers PS - V1.1.md", "REU PICKING SEQUENCAGE 11-05-2026 - Analyse comparative notes + AF + devops.md"]
|
||||
last_updated: 2026-05-12
|
||||
author: Arthur
|
||||
---
|
||||
|
||||
# Séquençage des tâches de picking TK → PS
|
||||
|
||||
> **Résumé** : algorithme événementiel qui ordonne les tâches de picking
|
||||
> depuis les transstockeurs (TK) vers les postes de sortie (PS). Il
|
||||
> écrit les numéros de séquence `Line.CstAtt` sur chaque tâche et
|
||||
> contrôle le flag `OS.CstAtt` pour autoriser le stacker_crane.
|
||||
|
||||
> **Standard EasyWMS** : → voir [Picking](../../concepts/picking.md)
|
||||
> Ce qui suit documente les **spécificités Limagrain** par rapport au
|
||||
> standard.
|
||||
|
||||
## Contexte projet
|
||||
|
||||
Le séquençage TK → PS est critique pour garantir que les palettes
|
||||
arrivent aux postes de picking dans le bon ordre. L'algorithme
|
||||
s'exécute **en amont** de l'algorithme de
|
||||
[placement PS → PK](placement-ps-pk.md) : les palettes arrivent au PS
|
||||
**déjà triées**.
|
||||
|
||||
Quatre solutions ont été envisagées avant de retenir une approche
|
||||
événementielle (solution 4).
|
||||
|
||||
## Historique des solutions envisagées
|
||||
|
||||
### Solution 1 — Process isolé sur finalisation des tâches d'OS
|
||||
|
||||
Déclenchement à la finalisation de la création des tâches d'un OS.
|
||||
Séquençage via `OS.Line.CstAtt`, marquage OS traité via
|
||||
`OS.CstAtt = true`.
|
||||
|
||||
**Problème** : pas assez dynamique en cas de recréation de tâches suite
|
||||
à des imprévus dans le WMS.
|
||||
|
||||
### Solution 2 — Calcul dans le workflow stacker_crane
|
||||
|
||||
Intégration du tri directement dans les WF
|
||||
`Galileo_StackerCraneSearch_PR` / `StackerCrane_SortTasks_PR`, avec
|
||||
recalcul complet du pool de tâches à chaque exécution. Supprimerait le
|
||||
besoin de `OS.Line.CstAtt` et `OS.CstAtt`.
|
||||
|
||||
**Problème** : complexité élevée (requêtes LINQ imbriquées sur les
|
||||
tâches multi-OS).
|
||||
|
||||
### Solution 3 — Solution 1 transformée en job
|
||||
|
||||
Reprise du process de la solution 1 sous forme de job planifié, en
|
||||
excluant les tâches de picking en cours.
|
||||
|
||||
**Problème** : pas assez réactif par rapport à la cadence de recherche
|
||||
d'ordre des TK.
|
||||
|
||||
### Solution 4 — Process événementiel (retenue)
|
||||
|
||||
Reprise de la solution 1 déclenchée sur deux événements, avec
|
||||
mécanisme de verrouillage `OS.CstAtt` pour bloquer le stacker_crane
|
||||
pendant le séquençage.
|
||||
|
||||
**Avantages** : simple à développer, isolée et découplée du reste,
|
||||
flexible et réactive.
|
||||
|
||||
## Changelog V1.1 (11/05/2026)
|
||||
|
||||
Modifications issues de la réunion Arthur + Justine (Mecalux) — Olivier
|
||||
(Limagrain), croisées avec l'AF §6.4.8 et le DevOps #64854 :
|
||||
|
||||
- **Hiérarchie des règles** : nouvel ordre de priorité validé.
|
||||
La complétude palette et l'anti-split de lignes de stock sont des
|
||||
contraintes amont prioritaires sur les règles de tri
|
||||
- **Picking négatif** : ajout condition cumulative poids ≥ 7 kg
|
||||
- **Traitement commercial** : critère de regroupement par TC
|
||||
**supprimé** (`CONTROLE_TRAITEMENT_COMMERCIAL = false`). Pas de bio
|
||||
sur cet entrepôt
|
||||
- **Calcul de remplissage** : méthode pro rata Bag/pal validée,
|
||||
remplace la logique DevOps "Bag/pal max"
|
||||
- **Poids max palette** : 1 250 kg (l'AF fait foi, corrige les 1 200 kg
|
||||
du DevOps)
|
||||
- **Règles confirmées** : mélange d'espèces OK, pas de gerbage,
|
||||
hauteur max 1,90 m, séparateurs inter-lots hors WMS
|
||||
|
||||
> Voir la section [Arbitrage des contradictions](#arbitrage-des-contradictions-reu-11052026)
|
||||
> pour le détail des décisions.
|
||||
|
||||
## Déclenchement
|
||||
|
||||
L'algorithme est déclenché sur **deux événements** :
|
||||
|
||||
### TaskCreatedEvent
|
||||
|
||||
Une nouvelle tâche de picking vient d'être créée (par le MINI JOB
|
||||
Picking LIM-75, ou suite à une réassignation de stock).
|
||||
|
||||
```
|
||||
SI événement.type == TaskCreatedEvent :
|
||||
SI tâche.type == PICKING ET tâche.OS.statut == Released :
|
||||
traiter_séquençage(tâche.OS)
|
||||
```
|
||||
|
||||
### OutboundOrderReleasedEvent
|
||||
|
||||
Un OS passe au statut Released (première mise en service ou relance
|
||||
après un arrêt).
|
||||
|
||||
```
|
||||
SI événement.type == OutboundOrderReleasedEvent :
|
||||
traiter_séquençage(OS)
|
||||
```
|
||||
|
||||
## Process principal
|
||||
|
||||
```
|
||||
FONCTION traiter_séquençage(OS) :
|
||||
|
||||
// ─── Étape 1 : verrouiller l'OS ───
|
||||
OS.CstAtt ← false
|
||||
|
||||
// ─── Étape 2 : récupérer les tâches ───
|
||||
toutes_tâches ← récupérer_tâches_picking(OS)
|
||||
|
||||
// ─── Étape 3 : filtrer ───
|
||||
tâches_à_séquencer ← [t POUR t DANS toutes_tâches
|
||||
SI t.statut == EN_ATTENTE]
|
||||
|
||||
SI tâches_à_séquencer est vide :
|
||||
OS.CstAtt ← true
|
||||
RETOURNER
|
||||
|
||||
// ─── Étape 4 : trier ───
|
||||
tâches_triées ← trier_tâches(tâches_à_séquencer)
|
||||
|
||||
// ─── Étape 5 : écrire les séquences ───
|
||||
écrire_séquences(tâches_triées)
|
||||
|
||||
// ─── Étape 6 : libérer l'OS ───
|
||||
OS.CstAtt ← true
|
||||
```
|
||||
|
||||
```mermaid
|
||||
sequenceDiagram
|
||||
participant EVT as Événement (TaskCreated / OS Released)
|
||||
participant SEQ as Process séquençage
|
||||
participant SC as Stacker Crane
|
||||
EVT->>SEQ: Déclenche
|
||||
SEQ->>SEQ: OS.CstAtt = false
|
||||
Note over SC: Bloqué — ne prend pas<br/>de tâche de cet OS
|
||||
SEQ->>SEQ: Récupère tâches en attente
|
||||
SEQ->>SEQ: Applique tri + écrit séquences
|
||||
SEQ->>SEQ: OS.CstAtt = true
|
||||
Note over SC: Débloqué — reprend<br/>les tâches séquencées
|
||||
```
|
||||
|
||||
## Contraintes amont (constitution des palettes filles)
|
||||
|
||||
Ces contraintes orientent le regroupement des lignes sur les palettes
|
||||
filles **avant** le tri. L'algorithme de séquençage doit les respecter :
|
||||
l'ordre de sortie doit être compatible avec la constitution de palettes
|
||||
conformes à ces règles.
|
||||
|
||||
### C1. Palettes les plus complètes possible
|
||||
|
||||
Objectif premier — optimisation transport. Seuil de remplissage ~95%.
|
||||
|
||||
**Calcul : pro rata Bag/pal.** Chaque sac consomme `1/Bag_pal` de son
|
||||
lot. Le calcul est additif et gère nativement des lots avec des Bag/pal
|
||||
différents sur une même palette.
|
||||
|
||||
```
|
||||
Exemple :
|
||||
16 sacs d'un lot Bag/pal 20 + 7 sacs d'un lot Bag/pal 50
|
||||
= 16/20 + 7/50
|
||||
= 0,80 + 0,14
|
||||
= 94%
|
||||
```
|
||||
|
||||
Regrouper les lots de même Bag/pal sur une même palette fille facilite
|
||||
la complétude.
|
||||
|
||||
> Cette méthode remplace la logique DevOps #64854 de "prendre le
|
||||
> Bag/pal max entre lots". Le pro rata est plus précis et ne nécessite
|
||||
> pas de Bag/pal de référence unique.
|
||||
|
||||
### C2. Ne pas splitter les lignes de stock
|
||||
|
||||
Éviter de répartir les sacs d'une même ligne de stock sur plusieurs
|
||||
palettes. **Prioritaire sur les règles de tri** : si respecter
|
||||
"Maïs first" implique de splitter une ligne, on regroupe la ligne
|
||||
complète quitte à décaler le maïs.
|
||||
|
||||
### Autres contraintes palette
|
||||
|
||||
| Contrainte | Valeur | Source |
|
||||
|------------|--------|--------|
|
||||
| Poids max palette | **1 250 kg** | AF (corrige 1 200 kg du DevOps) |
|
||||
| Hauteur max palette | 1,90 m | AF — rejet au PIE si dépassement |
|
||||
| Gerbage | Interdit | — |
|
||||
| Mélange d'espèces | Autorisé sur une même palette fille | — |
|
||||
| Différenciation de marque | Aucune dans une même expédition | — |
|
||||
| Séparateurs (intercalaires) | Règle opérateur, hors WMS | — |
|
||||
|
||||
## Règles de tri (séquençage des sorties ASRS)
|
||||
|
||||
Les tâches de picking d'un même OS sont triées selon les critères
|
||||
suivants, **par ordre de priorité décroissante** :
|
||||
|
||||
### Critère 1 — Picking négatif en premier
|
||||
|
||||
Les tâches de type PICKING_NÉGATIF passent **avant** les tâches de type
|
||||
PICKING_DIRECT. Prioritaire sur toutes les règles suivantes, y compris
|
||||
Maïs first : si une tâche négatif concerne du tournesol, elle passe
|
||||
avant une tâche maïs classique.
|
||||
|
||||
Condition cumulative pour la détermination NÉGATIF / DIRECT (cf.
|
||||
[détermination picking négatif](#détermination-picking-négatif)) :
|
||||
pourcentage quantité > seuil fiche article (défaut 55%) **ET** poids
|
||||
unitaire sac ≥ 7 kg. En dessous de 7 kg, pas de picking négatif.
|
||||
|
||||
```
|
||||
tri_1(tâche) → 0 si PICKING_NÉGATIF, 1 si PICKING_DIRECT
|
||||
```
|
||||
|
||||
### Critère 2 — Espèce Maïs en premier
|
||||
|
||||
Les tâches portant sur l'espèce **Maïs** passent avant les autres
|
||||
espèces. Le maïs est lourd/stable, il constitue la base de la palette
|
||||
fille.
|
||||
|
||||
```
|
||||
tri_2(tâche) → 0 si espèce == MAÏS, 1 sinon
|
||||
```
|
||||
|
||||
### ~~Critère 3 (V1.0) — Traitement commercial~~ SUPPRIMÉ V1.1
|
||||
|
||||
`CONTROLE_TRAITEMENT_COMMERCIAL = false`. L'entrepôt ne fait pas de
|
||||
bio. Paramètre réactivable si besoin futur.
|
||||
|
||||
### Critère 3 — Espèce la plus volumineuse
|
||||
|
||||
Les tâches sont regroupées par espèce, et l'espèce ayant la **plus
|
||||
grande quantité totale de sacs** dans l'OS passe en premier. Commencer
|
||||
par l'espèce la plus volumineuse permet de constituer rapidement la
|
||||
base de la palette fille.
|
||||
|
||||
```
|
||||
tri_3(tâche) → -quantité_totale_espèce(tâche.espèce, OS)
|
||||
```
|
||||
|
||||
### Critère 4 — Article/lot le plus lourd en base
|
||||
|
||||
À espèce égale, les tâches portant sur les articles/lots **les plus
|
||||
lourds** passent en premier. Corollaire : les semences essais, très
|
||||
légères, se retrouvent naturellement en haut de palette.
|
||||
|
||||
```
|
||||
tri_4(tâche) → -tâche.article.poids
|
||||
```
|
||||
|
||||
### Critère 5 — Regroupement par palette source
|
||||
|
||||
Toutes les tâches portant sur la **même palette source** sont
|
||||
consécutives. L'opérateur enchaîne toutes les tâches d'une palette
|
||||
source avant de la libérer.
|
||||
|
||||
```
|
||||
tri_5(tâche) → tâche.PALETTE_SOURCE.identifiant
|
||||
```
|
||||
|
||||
### Récapitulatif du tri multi-critères (V1.1)
|
||||
|
||||
```
|
||||
FONCTION trier_tâches(tâches) :
|
||||
|
||||
RETOURNER tâches.trier_par(
|
||||
(1) type_picking ASC // NÉGATIF (0) avant DIRECT (1)
|
||||
(2) espèce_maïs ASC // MAÏS (0) avant autres (1)
|
||||
(3) quantité_espèce DESC // espèce la + volumineuse
|
||||
(4) poids_article DESC // article le + lourd
|
||||
(5) palette_source // regroupement par palette
|
||||
)
|
||||
```
|
||||
|
||||
## Écriture des séquences (Line.CstAtt)
|
||||
|
||||
### Règle des ex-aequo
|
||||
|
||||
Quand deux tâches consécutives sont **interchangeables** (l'ordre entre
|
||||
elles n'a aucun impact fonctionnel), elles reçoivent le **même numéro
|
||||
de séquence**. Cela laisse de la flexibilité au stacker_crane pour
|
||||
optimiser son débit.
|
||||
|
||||
### Critères d'interchangeabilité
|
||||
|
||||
Deux tâches A et B sont interchangeables si :
|
||||
|
||||
- Elles portent sur la **même palette source**, **OU**
|
||||
- Elles portent sur des **palettes sources différentes** mais tous les
|
||||
critères de tri sont identiques : même type de picking, même espèce,
|
||||
même quantité espèce, même poids article
|
||||
|
||||
### Algorithme d'écriture
|
||||
|
||||
```
|
||||
FONCTION écrire_séquences(tâches_triées) :
|
||||
|
||||
séquence_actuelle ← max(Line.CstAtt des tâches en cours) + 1
|
||||
SI aucune tâche en cours :
|
||||
séquence_actuelle ← 1
|
||||
|
||||
POUR i DE 0 À len(tâches_triées) - 1 :
|
||||
tâche ← tâches_triées[i]
|
||||
tâche.Line.CstAtt ← séquence_actuelle
|
||||
|
||||
SI i < len(tâches_triées) - 1 :
|
||||
tâche_suivante ← tâches_triées[i + 1]
|
||||
SI interchangeables(tâche, tâche_suivante) :
|
||||
CONTINUER
|
||||
SINON :
|
||||
séquence_actuelle ← séquence_actuelle + 1
|
||||
```
|
||||
|
||||
### Exemple
|
||||
|
||||
```
|
||||
Commande avec 5 tâches, après tri :
|
||||
|
||||
Tâche 1 : Palette A, Maïs, 500kg → séq 1
|
||||
Tâche 2 : Palette B, Maïs, 500kg → séq 1 (interchangeable)
|
||||
Tâche 3 : Palette C, Maïs, 500kg → séq 1 (interchangeable)
|
||||
Tâche 4 : Palette D, Blé, 300kg → séq 2 (espèce différente)
|
||||
Tâche 5 : Palette E, Blé, 300kg → séq 2 (interchangeable)
|
||||
|
||||
Résultat Line.CstAtt : [1, 1, 1, 2, 2]
|
||||
|
||||
Le stacker_crane peut sortir A, B, C dans n'importe quel ordre,
|
||||
puis D ou E dans n'importe quel ordre.
|
||||
```
|
||||
|
||||
## Comportement du stacker_crane après séquençage
|
||||
|
||||
Le stacker_crane **ignore** les tâches dont `OS.CstAtt == false`,
|
||||
consomme celles dont `OS.CstAtt == true` par `Line.CstAtt` croissant,
|
||||
et entre tâches à séquence égale il optimise librement (proximité ASRS,
|
||||
charge TK). Il crée les tâches de mouvement TK → PS.
|
||||
|
||||
Les palettes arrivent ensuite au PS, où l'algorithme de
|
||||
[placement PS → PK](placement-ps-pk.md) décide sur quelle table les
|
||||
poser.
|
||||
|
||||
## Détermination picking négatif
|
||||
|
||||
Le type de picking (NÉGATIF ou DIRECT) est déterminé **par tâche** au
|
||||
moment de la création des tâches par le MINI JOB Picking (LIM-75) :
|
||||
|
||||
```
|
||||
SI quantité_à_prélever > seuil_article × quantité_palette_source
|
||||
ET article unique dans la palette source
|
||||
ET pas d'attribut logistique à capturer
|
||||
ET poids_unitaire_sac ≥ 7 kg
|
||||
ALORS → PICKING_NÉGATIF
|
||||
SINON → PICKING_DIRECT
|
||||
```
|
||||
|
||||
Le seuil % reste paramétrable par fiche article (champ "Complete
|
||||
quantity percent excess for negative picking", défaut : 55%).
|
||||
|
||||
La détermination se fait **en amont** (MINI JOB Picking, LIM-75), avant
|
||||
l'algorithme de séquençage. L'algorithme de séquençage lit ce type mais
|
||||
ne le calcule pas.
|
||||
|
||||
## Cas particuliers
|
||||
|
||||
### Recalcul suite à une nouvelle tâche (réassignation de stock)
|
||||
|
||||
Si une tâche est créée après que l'OS a déjà été séquencé, le
|
||||
`TaskCreatedEvent` déclenche un recalcul : verrouillage, re-tri des
|
||||
tâches en attente uniquement (en commençant après le dernier numéro des
|
||||
tâches en cours), puis libération.
|
||||
|
||||
### Relance d'un OS arrêté
|
||||
|
||||
Si un OS est arrêté puis relancé (`OutboundOrderReleasedEvent`), le
|
||||
même process s'applique. Les tâches en cours conservent leur séquence,
|
||||
les tâches en attente sont re-séquencées.
|
||||
|
||||
## Arbitrage des contradictions (réu. 11/05/2026)
|
||||
|
||||
Analyse comparative de 3 sources (DevOps #64854, AF §6.4.8, réunion
|
||||
11/05/2026 Arthur + Justine + Olivier). **Tous les points sont résolus.**
|
||||
|
||||
| Sujet | DevOps | AF | Réunion (fait foi) |
|
||||
|-------|--------|----|--------------------|
|
||||
| Traitement commercial | À creuser | Séparation stricte | **Supprimé** (`CONTROLE_TRAITEMENT_COMMERCIAL = false`) |
|
||||
| Seuil picking négatif | Pas de seuil explicite | > 50% | **Deux conditions cumulatives** : % seuil fiche article (défaut 55%) ET poids sac ≥ 7 kg |
|
||||
| Poids max palette | 1 200 kg | 1 250 kg | **1 250 kg** (AF fait foi) |
|
||||
| Picking négatif vs Maïs first | Pas de hiérarchie | Maïs en tête, négatif séparé | **Picking négatif prioritaire** (confirmé Olivier) |
|
||||
| Semences essais en haut | Oui (dédié) | Non mentionné | **Couvert par règle du plus lourd en base** (essais = légères → haut) |
|
||||
| Lots même Bag/pal | Prioriser regroupement | — | **Retenu** (WF palettes complètes) |
|
||||
| Différenciation marque | Aucune | — | **Confirmé** |
|
||||
| Calcul Bag/pal multi-lots | "Prendre le Bag/pal max" | Équivalent palette | **Pro rata** (chaque sac = 1/Bag_pal de son lot) |
|
||||
|
||||
## Paramètres WMS
|
||||
|
||||
| Paramètre | Description | Défaut | Statut V1.1 |
|
||||
|-----------|-------------|--------|-------------|
|
||||
| `CONTROLE_TRAITEMENT_COMMERCIAL` | Regroupement par TC dans le tri | ~~true~~ | **false** — désactivé |
|
||||
| Seuil picking négatif (fiche article) | "Complete quantity percent excess for negative picking" | 55% | Inchangé |
|
||||
| Poids min picking négatif | Poids unitaire sac minimum pour autoriser le picking négatif | **7 kg** | **Nouveau V1.1** |
|
||||
| Seuil remplissage palette | Taux cible remplissage palette fille | **~95%** | **Nouveau V1.1** |
|
||||
| Poids max palette | Poids maximum palette fille | **1 250 kg** | Corrigé (était 1 200 kg) |
|
||||
| `OS.CstAtt` | Flag verrouillage OS pendant séquençage (true = stacker_crane autorisé) | true | Inchangé |
|
||||
| `MAX_NB_BUFFER_PK` | Nombre de buffers disponibles par PK | 3 | Inchangé |
|
||||
|
||||
## Points d'attention
|
||||
|
||||
⚠️ Le custom LIM-61 (vérification capacité buffer) doit être modifié
|
||||
pour prendre en compte les palettes multi-PK.
|
||||
|
||||
⚠️ Le verrouillage `OS.CstAtt` est temporaire (durée du séquençage) —
|
||||
en cas d'erreur du process, l'OS risque de rester bloqué.
|
||||
|
||||
⚠️ Les tâches **en cours** sont exclues du séquençage — seules les
|
||||
tâches en attente sont réordonnées.
|
||||
|
||||
⚠️ La condition poids ≥ 7 kg pour le picking négatif est ajoutée pour
|
||||
éviter l'instabilité palette (gros sacs ramenés sur petits sacs).
|
||||
|
||||
## Points non traités (hors scope)
|
||||
|
||||
- Affichage opérateur au PK (combien de sacs ajouter, possibilité de
|
||||
dévier de la consigne) — à traiter une fois les fondations posées
|
||||
- Picking négatif < 7 kg en option (avantage opérationnel sans
|
||||
obligation) — nécessite discussion élargie
|
||||
- Messagerie carton (moins prioritaire, navette du lendemain, zone
|
||||
angle Est) — en attente de précisions
|
||||
- Verrou réception → recomptage avant picking (mentionné dans l'AF
|
||||
uniquement, non reconfirmé)
|
||||
|
||||
## Questions ouvertes
|
||||
|
||||
- [ ] Comportement en cas d'erreur du process de séquençage — OS reste
|
||||
bloqué avec CstAtt = false ? (@Nicolas)
|
||||
- [ ] Impact sur les performances si beaucoup d'OS sont Released
|
||||
simultanément — risque de contention sur les événements ? (@Fabien)
|
||||
|
||||
## Historique des modifications
|
||||
|
||||
| Date | Auteur | Modification |
|
||||
|------|--------|--------------|
|
||||
| 2026-05-12 | Arthur | Création initiale depuis LIM-84 |
|
||||
| 2026-05-12 | Arthur | Refonte complète : intégration spec V1.1 (algo complet, contraintes amont, 5 critères tri, écriture séquences, ex-aequo, cas particuliers) + arbitrage contradictions réunion 11/05/2026 |
|
||||
|
||||
## Références
|
||||
|
||||
| Source | Type | Date |
|
||||
|--------|------|------|
|
||||
| [LIM-84](https://easywmsfrance.atlassian.net/browse/LIM-84) | Ticket Jira | 2026 |
|
||||
| [LIM-61](https://easywmsfrance.atlassian.net/browse/LIM-61) | Ticket Jira (custom capacité buffer) | 2026 |
|
||||
| Logique combinatoire picking - TK vers PS - V1.1 | Spécification technique | 11/05/2026 |
|
||||
| REU PICKING SEQUENCAGE 11-05-2026 | CR réunion + analyse comparative | 11/05/2026 |
|
||||
| DevOps #64854 | Note historique | — |
|
||||
| AF §6.4.8 | Analyse fonctionnelle V1.5 | 28/11/2025 |
|
||||
Reference in New Issue
Block a user