Files
mcp-wms-wiki/wiki/sources/archives/Logique combinatoire picking - TK vers PS - V1.1.md
T
2026-05-20 09:41:27 +02:00

425 lines
18 KiB
Markdown
Raw 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.
# LIM-84 — Algorithme de séquençage des palettes (TK → PS)
## Ordonnancement des tâches de picking avant sortie de l'ASRS
> **Version 1.1** — 11 mai 2026
>
> Ce document décrit l'algorithme de séquençage qui définit **dans quel ordre** les palettes sources doivent sortir de l'ASRS (TK) à destination du poste de sortie (PS). Il s'exécute **en amont** de l'algorithme de placement PS → table PK [[Logique combinatoire picking - PS vers PK - V1.0]].
>
> Le résultat de cet algorithme est l'écriture des numéros de séquence `Line.CstAtt` sur chaque tâche de picking, et le positionnement de `OS.CstAtt = true` pour autoriser le stacker_crane à consommer les tâches.
### Changelog V1.1 (11/05/2026)
Modifications issues de la réunion Arthur + Justine (MECALUX) — Olivier (LIMAGRAIN), croisées avec l'AF et le DevOps #64854.
- **Hiérarchie des règles** : nouvel ordre de priorité validé (§3). La complétude palette et l'anti-split de lignes de stock sont désormais des contraintes amont prioritaires sur les règles de tri.
- **Picking négatif** : ajout d'une condition cumulative de poids ≥ 7 kg (§3.1 + §6.3).
- **Traitement commercial** : critère de regroupement par TC **supprimé** (`CONTROLE_TRAITEMENT_COMMERCIAL = false`). Le critère 3 de la V1.0 est retiré du tri.
- **Calcul de remplissage** : méthode pro rata Bag/pal validée, remplace la logique DevOps "Bag/pal max" (§3 — contrainte amont C1).
- **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.
---
## 0. Glossaire rapide
|Terme|Définition|
|---|---|
|**TK**|Transtockeur / sortie ASRS (origine physique de la palette)|
|**PS**|Poste de sortie (point d'arrivée de la palette, avant placement sur table PK)|
|**OS**|Ordre de sortie (commande)|
|**OS.CstAtt**|Flag booléen sur l'OS. `false` = séquences non calculées, stacker_crane ignore. `true` = séquences prêtes, stacker_crane peut consommer.|
|**Line.CstAtt**|Numéro de séquence (entier) sur chaque tâche de picking. Définit l'ordre de sortie ASRS. Plusieurs tâches peuvent partager la même valeur (ex-aequo).|
|~~**TC**~~|~~Traitement commercial — attribut article.~~ **Supprimé V1.1** : `CONTROLE_TRAITEMENT_COMMERCIAL = false`. L'entrepôt ne fait pas de bio. Paramètre réactivable si besoin futur.|
|**Bag/pal**|Nombre de sacs par palette pour un lot donné. Sert au calcul de remplissage pro rata.|
---
## 1. Déclenchement
L'algorithme est déclenché sur **deux événements** :
### 1.1. `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)
```
### 1.2. `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)
```
---
## 2. 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) // cf. §3
// ─── Étape 5 : écrire les séquences ───
écrire_séquences(tâches_triées) // cf. §4
// ─── Étape 6 : libérer l'OS ───
OS.CstAtt ← true
```
---
## 3. Contraintes amont et règles de tri
> **V1.1** — La hiérarchie ci-dessous remplace toute hiérarchie antérieure. Elle distingue les **contraintes amont** (appliquées avant/pendant la constitution des palettes filles) et les **règles de tri** (appliquées au séquençage des tâches de picking).
### Contraintes amont (constitution des palettes filles)
Ces contraintes orientent le regroupement des lignes sur les palettes filles **avant** que l'algorithme de tri ne séquence les sorties ASRS. Elles ne sont pas des critères de tri à proprement parler, mais 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% (marge de sécurité).
**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.
> _Note : cette méthode remplace la logique DevOps #64854 de "prendre le Bag/pal max entre lots" (V1.0 implicite). 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. **Cette contrainte est 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) entre lots|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** :
#### 3.1. 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.
Le picking négatif est **prioritaire sur toutes les règles de tri suivantes**, y compris Maïs first : si une tâche négatif concerne du tournesol, elle passe avant une tâche maïs classique.
> **V1.1** — Condition cumulative ajoutée pour la détermination NÉGATIF/DIRECT (cf. §6.3) : pourcentage quantité > seuil fiche article (défaut 55%) **ET** poids unitaire sac ≥ 7 kg. En dessous de 7 kg, pas de picking négatif (raison : instabilité palette si gros sacs ramenés sur petits sacs).
```
tri_1(tâche) → 0 si PICKING_NÉGATIF, 1 si PICKING_DIRECT
```
#### 3.2. 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 (si la commande contient du maïs).
Raison : 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
```
#### ~~3.3. Critère 3 — Regroupement par traitement commercial (TC)~~ **SUPPRIMÉ V1.1**
> `CONTROLE_TRAITEMENT_COMMERCIAL = false`. L'entrepôt ne fait pas de bio. Réactivable si besoin futur.
#### 3.3. Critère 3 — Espèce avec la plus grande quantité totale dans la commande
_(anciennement critère 4 en V1.0)_
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.
Raison : 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)
// négatif pour tri décroissant
```
#### 3.4. Critère 4 — Article/lot le plus lourd en base
_(anciennement critère 5 en V1.0)_
À 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
// négatif pour tri décroissant
```
#### 3.5. Critère 5 — Regroupement par palette source
_(anciennement critère 6 en V1.0)_
Toutes les tâches portant sur la **même palette source** sont consécutives.
Raison : 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 en premier
(4) poids_article DESC // article le + lourd en premier
(5) palette_source // regroupement par palette source
)
// Note V1.1 : le critère TC (V1.0 §3.3) est supprimé.
// La contrainte anti-split lignes de stock (C2) est gérée
// en amont lors de la constitution des palettes filles,
// pas dans ce tri.
```
---
## 4. Écriture des séquences (`Line.CstAtt`)
Une fois les tâches triées, on attribue un numéro de séquence à chacune.
### 4.1. Règle des ex-aequo
Quand deux tâches consécutives dans le tri 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.
### 4.2. 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. Rien ne les départage fonctionnellement.
> _Note V1.1 : le TC n'entre plus dans les critères d'interchangeabilité._
### 4.3. 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
```
### 4.4. 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 avec 1)
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 avec 4)
Résultat Line.CstAtt : [1, 1, 1, 2, 2]
Le stacker_crane peut sortir les palettes A, B, C dans n'importe quel ordre,
puis D ou E dans n'importe quel ordre.
```
> _Note V1.1 : l'exemple V1.0 avec TC différent (tâche 6) est retiré car le critère TC est désactivé._
---
## 5. Comportement du stacker_crane après séquençage
Ce n'est pas le périmètre de cet algorithme, mais pour mémoire :
```
Le stacker_crane :
- IGNORE les tâches dont OS.CstAtt == false
- Consomme les tâches dont OS.CstAtt == true
- Respecte l'ordre croissant des Line.CstAtt
- Entre tâches à séquence égale : libre d'optimiser (proximité ASRS, charge TK)
- Crée les tâches de mouvement TK → PS
```
Les palettes arrivent ensuite au PS, où l'algorithme de placement (document dédié) décide sur quelle table du PK les poser.
---
## 6. Cas particuliers
### 6.1. 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 :
```
1. OS.CstAtt ← false
2. Filtrer : tâches EN_ATTENTE uniquement
3. Re-trier et réécrire les Line.CstAtt
(en commençant après le dernier numéro des tâches en cours)
4. OS.CstAtt ← true
```
### 6.2. Relance d'un OS arrêté
Si un OS est arrêté puis relancé (`OutboundOrderReleasedEvent`), le même process s'applique. Les tâches déjà en cours conservent leur séquence, les tâches en attente sont re-séquencées.
### 6.3. Picking négatif et détermination du type
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), selon la règle :
```
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 // ← AJOUT V1.1
ALORS → PICKING_NÉGATIF
SINON → PICKING_DIRECT
```
> **V1.1** — La condition de poids ≥ 7 kg est ajoutée comme condition **cumulative** (ET). En dessous de 7 kg, pas de picking négatif même si le % dépasse le seuil. Raison : instabilité palette (gros sacs ramenés sur petits sacs).
Le seuil % reste paramétrable par fiche article (champ "Complete quantity percent excess for negative picking", défaut : 55%).
La détermination négatif/direct 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.
---
## 7. Paramètres WMS utilisés
|Paramètre|Description|Défaut|Statut V1.1|
|---|---|---|---|
|`CONTROLE_TRAITEMENT_COMMERCIAL`|Active le regroupement par TC dans le tri|~~`true`~~|**`false`** — désactivé|
|Seuil picking négatif|Par 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 de remplissage palette fille|**~95%**|**NOUVEAU V1.1**|
|Poids max palette|Poids maximum d'une palette fille|**1 250 kg**|Corrigé (était 1 200 kg dans DevOps)|
---
## 8. Diagramme de flux
```
TaskCreatedEvent OutboundOrderReleasedEvent
(nouvelle tâche picking) (OS passe en Released)
│ │
▼ │
Tâche type PICKING │
ET OS statut Released ? │
│ │
OUI │
│ │
└──────────┬────────────────────┘
OS.CstAtt ← false
(stacker_crane bloqué)
Récupérer tâches de l'OS
Filtrer : tâches EN_ATTENTE uniquement
(tâches en cours = intouchables)
┌────────────────────────────┐
│ TRIER │
│ │
│ 1. Picking négatif first │
│ 2. Espèce Maïs first │
│ 3. Espèce + volumineuse │
│ 4. Article + lourd │
│ 5. Regrouper par palette │
│ source │
└────────────┬───────────────┘
Écrire Line.CstAtt
(ex-aequo si interchangeables)
OS.CstAtt ← true
(stacker_crane libéré)
Stacker_crane consomme
par Line.CstAtt croissant
→ crée mouvements TK → PS
Palette arrive au PS
→ algo de placement PS → PK
(autre document)
```
---
## 9. 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 que prépa classique, navette du lendemain, zone angle Est) — en attente de précisions.
- Verrou réception → recomptage avant picking (mentionné dans l'AF uniquement, non reconfirmé).
---
## 10. Sources de référence
Par ordre de fiabilité décroissante :
1. **Réunion 11/05/2026 + mails** — fait foi sur tous les points traités
2. **AF (Analyse Fonctionnelle)** — référence principale pour les points non abordés en réunion
3. **DevOps #64854** — le plus ancien, peut contenir des règles passées à la trappe mais utile pour vérification croisée