InvenTree : créer en lot des emplacements de stock via scripting Python API
Ce script crée en lot les emplacements de stock A1..19, B1..19 et C1..19.
Vous devez le personnaliser en conséquence.
Il nécessite un config.yaml avec les données de votre instance InvenTree spécifique.
inventree_create_drawers.py
#!/usr/bin/env python3
"""Crée des sous-emplacements Schublade sous un emplacement Apothekerschrank dans InvenTree.
Ce script se connecte à une instance InvenTree via l'API REST et crée
un ensemble de sous-emplacements de tiroirs (« Schublade ») sous un
emplacement parent appelé « Apothekerschrank ». Pour chacune des trois
rangées A, B et C, il crée des tiroirs numérotés de 1 à 19, soit 57
sous-emplacements au total. Chaque sous-emplacement se voit attribuer le
type d'emplacement de stock « Schublade ».
Le script est idempotent : si un sous-emplacement existe déjà sous le
parent, il est ignoré plutôt que dupliqué.
La configuration est lue depuis ``config.yaml`` dans le même répertoire :
.. code-block:: yaml
inventree:
server: https://inventree.example.com
token: your-api-token-here
Prérequis :
- Python 3.8+
- requests
- PyYAML
Utilisation ::
python3 create_locations.py
"""
import sys
import requests
import yaml
from pathlib import Path
# Chemin vers le fichier de configuration YAML, attendu à côté de ce script.
CONFIG_PATH = Path(__file__).parent / "config.yaml"
def load_config():
"""Charge les paramètres de connexion InvenTree depuis ``config.yaml``.
Renvoie un dict avec les clés ``server`` et ``token``.
"""
with open(CONFIG_PATH, "r") as f:
return yaml.safe_load(f)["inventree"]
class InvenTreeAPI:
"""Client REST minimal pour InvenTree.
Encapsule :mod:`requests` avec une authentification par token et des
méthodes utilitaires pour les appels GET et POST vers l'API InvenTree.
"""
def __init__(self, server, token):
"""Initialise le client API.
:param server: URL de base de l'instance InvenTree, ex.
``https://inventree.example.com``.
:param token: Token d'authentification API (générez-en un dans
l'interface web InvenTree sous *Settings > API Keys*).
"""
self.server = server.rstrip("/")
self.token = token
self.session = requests.Session()
self.session.headers.update({
"Authorization": f"Token {token}",
"Content-Type": "application/json",
})
def get(self, path, params=None):
"""Effectue une requête GET et renvoie la réponse JSON parsée."""
r = self.session.get(f"{self.server}{path}", params=params)
r.raise_for_status()
return r.json()
def post(self, path, data):
"""Effectue une requête POST avec un corps JSON et renvoie la réponse parsée."""
r = self.session.post(f"{self.server}{path}", json=data)
if r.status_code == 400:
print(f" ERREUR 400 : {r.json()}")
r.raise_for_status()
return r.json()
def find_location_type(api, name):
"""Recherche un type d'emplacement de stock par nom.
Itère sur tous les types d'emplacement via des appels API paginés.
Renvoie la clé primaire (``pk``) si trouvé, sinon ``None``.
"""
offset = 0
while True:
data = api.get("/api/stock/location-type/", params={"limit": 100, "offset": offset})
results = data if isinstance(data, list) else data.get("results", [])
for t in results:
if t["name"] == name:
return t["pk"]
if isinstance(data, list) or not data.get("next"):
break
offset += 100
return None
def find_location(api, name):
"""Recherche un emplacement de stock par nom parmi tous les emplacements.
Itère sur tous les emplacements de stock via des appels API paginés.
Renvoie la clé primaire (``pk``) si trouvé, sinon ``None``.
"""
offset = 0
while True:
data = api.get("/api/stock/location/", params={"limit": 100, "offset": offset})
for loc in data["results"]:
if loc["name"] == name:
return loc["pk"]
if not data["next"]:
break
offset += 100
return None
def find_child_location(api, parent_pk, name):
"""Recherche un emplacement de stock enfant par nom sous un parent donné.
Interroge l'API pour tous les emplacements dont ``parent`` correspond
à ``parent_pk`` et renvoie le ``pk`` de la première correspondance, ou ``None``.
"""
results = api.get("/api/stock/location/", params={
"parent": parent_pk, "limit": 1000
})
loc_list = results if isinstance(results, list) else results.get("results", [])
for loc in loc_list:
if loc["name"] == name:
return loc["pk"]
return None
def main():
"""Point d'entrée principal : trouve l'emplacement parent, s'assure du type d'emplacement, crée les sous-emplacements."""
config = load_config()
api = InvenTreeAPI(config["server"], config["token"])
# --- Recherche ou création du type d'emplacement de stock « Schublade » ---
# InvenTree prend en charge des types d'emplacement définis par
# l'utilisateur qui peuvent être attribués à des emplacements de stock
# individuels. On réutilise un type existant s'il est présent.
schublade_type_pk = find_location_type(api, "Schublade")
if schublade_type_pk:
print(f"Type d'emplacement 'Schublade' trouvé (pk={schublade_type_pk})")
else:
result = api.post("/api/stock/location-type/", {
"name": "Schublade",
"description": "Schublade im Apothekerschrank",
"icon": "ti:box:outline",
})
schublade_type_pk = result["pk"]
print(f"Type d'emplacement 'Schublade' créé (pk={schublade_type_pk})")
# --- Recherche de l'emplacement parent « Apothekerschrank » ---
# Cet emplacement doit déjà exister dans InvenTree. Le script se
# terminera en erreur s'il ne peut pas être trouvé.
apotheker_pk = find_location(api, "Apothekerschrank")
if not apotheker_pk:
print("ERREUR : Emplacement 'Apothekerschrank' introuvable")
sys.exit(1)
print(f"Emplacement 'Apothekerschrank' trouvé (pk={apotheker_pk})")
# --- Création des sous-emplacements : Schublade A1..A19, B1..B19, C1..C19 ---
# Chaque sous-emplacement est créé comme enfant de l'emplacement
# Apothekerschrank et se voit attribuer le type d'emplacement « Schublade ».
# Les emplacements déjà existants sont ignorés pour garder le script idempotent.
created = 0
skipped = 0
for letter in ["A", "B", "C"]:
for number in range(1, 20):
name = f"Schublade {letter}{number}"
existing = find_child_location(api, apotheker_pk, name)
if existing:
print(f" Ignoré (existe) : {name} (pk={existing})")
skipped += 1
continue
result = api.post("/api/stock/location/", {
"name": name,
"parent": apotheker_pk,
"location_type": schublade_type_pk,
})
print(f" Créé : {name} (pk={result['pk']})")
created += 1
print(f"\nTerminé : {created} créés, {skipped} ignorés")
if __name__ == "__main__":
main()Consultez les articles similaires par catégorie :
InvenTree
Si cet article vous a aidé, pensez à m'offrir un café ou à faire un don via PayPal pour soutenir la recherche et la publication de nouveaux articles sur TechOverflow