# Business Rules - Purchase Trade

Statut: `draft`
Version: `v0.1`
Derniere mise a jour: `2026-03-25`
Owner metier: `a completer`
Owner technique: `a completer`

## 1) Scope

- Domaine: `purchase_trade`
- Hors scope:
- Modules impactes:
  - `purchase_trade`
  - `lot`

## 2) Glossaire

- `Purchase Line`: ligne d'achat.
- `quantity_theorical`: quantite theorique contractuelle de la ligne.
- `Virtual Lot`: lot unique de type `virtual` rattache a une `purchase.line`.
- `lot.qt`: table des quantites ouvertes, matchées ou shippées par lot.
- `lot.qt ouvert`: enregistrement `lot.qt` avec `lot_p = virtual lot`, `lot_s = None` et sans shipment.

## 3) Regles metier

### BR-PT-001 - Ajustement de la quantite theorique apres creation du contrat

- Intent: conserver la coherence entre la quantite theorique de la ligne d'achat, le lot virtuel associe et les quantites ouvertes stockees dans `lot.qt`.
- Description:
  - Quand `purchase.line.quantity_theorical` est modifiee apres creation du contrat, le systeme doit recalculer le delta entre l'ancienne et la nouvelle valeur.
  - La regle s'applique au lot unique de type `virtual` rattache a la `purchase.line`.
- Conditions d'entree:
  - Une `purchase.line` existe deja.
  - Son champ `quantity_theorical` est modifie via `write`.
  - Un lot `virtual` est rattache a la ligne.
- Resultat attendu:
  - Si `delta > 0`:
    - augmenter la quantite courante du lot `virtual` via `set_current_quantity` pour conserver l'historique `lot.qt.hist`
    - augmenter le `lot.qt` ouvert existant
    - si aucun `lot.qt` ouvert n'existe, en creer un nouveau avec le delta
  - Si `delta < 0`:
    - diminuer le `lot.qt` ouvert uniquement si la quantite ouverte disponible est suffisante
    - diminuer la quantite courante du lot `virtual` du meme delta
    - si aucun `lot.qt` ouvert n'existe ou si sa quantite est insuffisante, bloquer avec l'erreur `Please unlink or unmatch lot`
- Definition du `lot.qt` ouvert:
  - `lot_p = virtual lot`
  - `lot_s = None`
  - `lot_shipment_in = None`
  - `lot_shipment_internal = None`
  - `lot_shipment_out = None`
- Exceptions:
  - si aucun lot `virtual` n'est trouve sur la ligne, la regle ne fait rien
- Priorite:
  - `bloquante`
- Source:
  - `Decision metier documentee dans les commentaires de purchase_trade.purchase.Line.write`

## 4) Exemples concrets

### Exemple E1 - Augmentation simple

- Donnees:
  - `ancienne quantity_theorical = 100`
  - `nouvelle quantity_theorical = 120`
  - `lot.qt ouvert = 40`
- Attendu:
  - lot `virtual` augmente de `20`
  - `lot.qt ouvert` passe de `40` a `60`

### Exemple E2 - Augmentation sans lot.qt ouvert

- Donnees:
  - `ancienne quantity_theorical = 100`
  - `nouvelle quantity_theorical = 110`
  - aucun `lot.qt` ouvert
- Attendu:
  - lot `virtual` augmente de `10`
  - creation d'un `lot.qt` ouvert a `10`

### Exemple E3 - Diminution possible

- Donnees:
  - `ancienne quantity_theorical = 100`
  - `nouvelle quantity_theorical = 90`
  - `lot.qt ouvert = 25`
- Attendu:
  - lot `virtual` diminue de `10`
  - `lot.qt ouvert` passe de `25` a `15`

### Exemple E4 - Diminution impossible

- Donnees:
  - `ancienne quantity_theorical = 100`
  - `nouvelle quantity_theorical = 80`
  - `lot.qt ouvert = 5`
- Attendu:
  - blocage avec `Please unlink or unmatch lot`

## 5) Impact code attendu

- Fichiers Python concernes:
  - `modules/purchase_trade/purchase.py`
  - `modules/purchase_trade/lot.py`

## 6) Strategie de tests

Pour cette regle, couvrir au minimum:

- augmentation avec `lot.qt` ouvert existant
- augmentation sans `lot.qt` ouvert
- diminution possible
- diminution impossible avec erreur
