472 lines
18 KiB
Plaintext
472 lines
18 KiB
Plaintext
---
|
||
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 |
|