Files
2026-05-20 09:41:27 +02:00

472 lines
18 KiB
Plaintext
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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 |