Valorisation des stocks en Python

Denis Hulo

Objectif : créer une fonction en Python pour le calcul du coût moyen des sorties de stock suivant les 3 méthodes de valorisation autorisées : CUMP, FIFO et LIFO.

Niveau requis : confirmé.

Commentez cet article : Commentez

- Titre : Valorisation des stocks en Python

- Auteur : Denis Hulo

- Parution : 13 juin 2022

- Public visé :

- Licence : Copyright ® 2022 Denis Hulo. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.

Sommaire

- I. Introduction

- II. Méthodes d'évaluation des stocks

- II-A. Méthode CUMP

- II-B. Méthodes FIFO et LIFO

- III. Création de la fonction d'évaluation des stocks

- III-A. Fonction d'évaluation du CUMP

- III-B. Fonction d'évaluation du coût moyen des sorties par la méthode FIFO et LIFO

- IV. Implémentation de la fonction de valorisation des sorties

- IV-A. Test avec des données exemples

- IV-B. Test avec récupération des données contenues dans une table SQLite

- V. Conclusion

- VI. Module Python

- VII. Remerciements

I - Introduction

La valorisation des stocks consiste à évaluer les entrées et les sorties des différentes matières premières et marchandises, pour connaître à tout moment la valeur effective des stocks de produits.

Le coût moyen des sorties de stock s'obtient principalement suivant trois grands types de méthodes :

Coût unitaire moyen pondéré périodique (CUMP) : le coût unitaire de sortie d'articles du stock est égal à la somme de (la valeur initiale + celles d'entrées en stock) divisée par la somme de (quantité initiale et celles d'entrées en stock). Si ce sont des stocks de produits finis, le coût unitaire d'entrée sera le coût de production (voir pour sa détermination la comptabilité analytique).

Premier entré, premier sorti (FIFO, PEPS en français) : le coût unitaire de sortie d'un type d'article du stock est égal à la valeur de l'article qui est entré en premier chronologiquement dans le stock. Un article entre à 10 € puis 20 €, il sortira en premier à 10 €.

Dernier entré, premier sorti (LIFO, DEPS en français) : le coût unitaire de sortie d'un type d'article du stock est égal à la valeur de l'article qui est entré en dernier chronologiquement dans le stock. Un article entre à 10 € puis 20 €, il sortira en premier à 20 €.

On souhaite donc créer une fonction en Python qui puisse calculer les coûts moyens des sorties sur le stock suivant ces 3 méthodes.

Si vous souhaitez avoir plus de détails sur le sujet, je vous invite à consulter la page Wikipédia Méthodes d'évaluation comptable des stocks ainsi que le tutoriel de Claude Leloup Évaluation des stocks avec ACCESS.

II - Méthodes d'évaluation des stocks

Nous présentons maintenant les trois méthodes permettant d'évaluer le coût moyen des sorties sur le stock.

II-A - Méthode CUMP

Pour les entreprises qui vendent des marchandises non périssables et qui ne prennent pas de valeur avec le temps, c’est souvent la méthode du coût unitaire moyen pondéré (CUMP) qui est choisie.

Coût unitaire moyen pondéré périodique (CUMP) : le coût unitaire de sortie d'articles du stock est égal à la somme de (la valeur initiale + celles d'entrées en stock) divisé par la somme de (quantité initiale et celles d'entrées en stock). Si ce sont des stocks de produits finis, le coût unitaire d'entrée sera le coût de production (voir pour sa détermination la comptabilité analytique).

On entre dans le stock 10 articles avec une référence donnée au prix unitaire de 14 €, puis 20 unités supplémentaires avec la même référence cette fois à 15.50 €. Le coût moyen pondéré de la dernière entrée vaut alors :

coût_moyen = (10*14.00 € + 20*15.50 €)/30 = 15.00 €

Puis, on sort 25 unités, et le CUMP de la sortie reste à 15.00 €.

Enfin, on ajoute au stock 10 unités, et en tenant compte du stock précédent le CUMP devient :

coût_moyen = (5*15.00 € + 10*16.50 €)/15 = 16.00 €

Méthode CUMP

II-B - Méthodes FIFO et LIFO

Décrivons maintenant les méthodes FIFO et LIFO permettant d'évaluer le coût moyen des sorties de stock.

FIFO et LIFO

Méthode FIFO

Les sociétés qui vendent des denrées périssables ont tendance à choisir cette méthode. Les sorties sont valorisées au coût d’achat des premières marchandises acquises.

Premier entré, premier sorti (FIFO, PEPS en français) : le coût unitaire de sortie d'un type d'article du stock est égal à la valeur de l'article qui est entré en premier chronologiquement dans le stock. Un article entre à 10 € puis à 20 €, il sortira en premier à 10 €.

On entre dans le stock 10 articles avec une référence donnée au prix unitaire de 14 €, puis 20 unités supplémentaires du même type cette fois à 16 €. Si maintenant on sort 25 unités de cet article, son coût moyen vaudra :

coût_moyen = (10*14.00 € + 15*16.00 €)/25 = (140.00 € + 240.00 €)/25 = 380.00 € / 25 = 15.20 €

Méthode FIFO

Méthode LIFO

Cette méthode est plus rarement utilisée. Les sorties sont valorisées au coût d’acquisition des dernières marchandises achetées.

Dernier entré, premier sorti (LIFO, DEPS en français) : le coût unitaire de sortie d'un type d'article du stock est égal à la valeur de l'article qui est entré en dernier chronologiquement dans le stock. Un article entre à 10 € puis à 20 €, il sortira en premier à 20 €.

On entre dans le stock 10 articles avec une référence donnée au prix unitaire de 14 €, puis 20 unités supplémentaires du même type cette fois à 16 €. Si maintenant on sort 25 unités de cet article, son coût moyen vaudra :

coût_moyen = (20*16.00 € + 5*14.00 €)/25 = (320.00 € + 70.00 €)/25 = 390.00 € / 25 = 15.60 €

Méthode LIFO

III - Création de la fonction d'évaluation des stocks

Pour valoriser les sorties du stock suivant les trois méthodes, nous allons donc créer une fonction en Python.

III-A - Fonction d'évaluation du CUMP

Elle prend en argument la liste triée des mouvements sur le stock et renvoie la liste des entrées/sorties valorisées.

Déroulé de la fonction :

- 1. Génération de la liste des références des produits contenus dans le stock ;

- -- 1.1. Pour chaque référence, filtre de la liste des mouvements par référence produit,

- -- 1.2. Pour chaque référence, parcours de la liste des mouvements du produit,

- ---- 1.2.1. Pour chaque entrée, évaluation de son prix moyen pondéré,

- ---- 1.2.2. Pour chaque sortie, récupération du CUMP de l'entrée précédente,

- ---- 1.2.3. Pour chaque entrée/sortie, ajout du mouvement valorisé à la liste résultat ;

- 2. Renvoi de la liste des mouvements valorisés.

Algorithme d'évaluation du CUMP des mouvements

récupérer_références_produits

tant que existe référence_produit

quantité_totale = 0; somme_prix_entrées = 0; quantité_stock_init=0; cump_init = 0
filtrer_mouvements_par_référence_produit

tant que existe mouvement_produit:

si mouvement est entrée_produit alors:

quantité_totale = quantité_totale + quantité_entrée
somme_prix_entrées = somme_prix_entrées + prix_entrée*quantité_entrée

cump = (quantité_stock_init*cump_init + somme_prix_entrees)/(quantité_stock_init+quantite_totale)

cump_entrée = cump
quantité_stock = quantité_stock + quantité_entrée

sinon:
cump_sortie = cump
quantité_stock = quantité_stock - quantité_sortie
quantité_stock_init = quantité_stock; cump_init = cump

fin si

ajouter_mouvement_valorisé_à_liste
mouvement_suivant

fin tant que

fin tant que

retourner liste_mouvements_valorisés

Fonction d'évaluation du CUMP des mouvements

def valoriser_stocks_cump(liste_mouvements):
# initialisation de la liste des sorties valorisées générée par la fonction
liste_mouvements_valorises = []

# filtre les sorties dans une liste
liste_references_produits = sorted(set([mouv['référence'] for mouv in liste_mouvements]))

# parcours de la liste des références des produits
for reference_produit in liste_references_produits:

# filtre les entrées/sorties en fonction de la référence du produit
liste_mouvs_produit = [mouv_produit for mouv_produit in liste_mouvements if (mouv_produit['référence']==reference_produit)]
# initialisation des quantités en stock et de la somme des prix en entrées
qte_stock = 0; somme_prix_entrees = 0; quantite_totale = 0; cump = 0 ; qte_stock_init=0; cump_init = 0

# parcours de la liste des mouvements du stock
for mouv_produit in liste_mouvs_produit:

if mouv_produit['type_mouv']=='entrée': # s'il s'agit d'une entrée dans le stock
# calcul de la somme des prix unitaires en entrées jusqu'à ce mouvement
somme_prix_entrees = somme_prix_entrees + mouv_produit['quantité']*mouv_produit['prix_unitaire']

# calcul de la quantité totale des entrées jusqu'à ce mouvement
quantite_totale = quantite_totale + mouv_produit['quantité']

# calcul du coût moyen pondéré (CUMP) avec correction des erreurs dans les résultats des opérations en virgule flottante
cump =  round((qte_stock_init*cump_init + somme_prix_entrees)/(qte_stock_init+quantite_totale),7)

mouv_produit['CUMP'] =  cump # mise à jour du champ CUMP

qte_stock = qte_stock + mouv_produit['quantité']
else: # sinon
somme_prix_entrees = 0 # on initialise la somme des prix unitaires des entrées
quantite_totale = 0 # on initialise la quantité totale des entrées
stock_initial = True
mouv_produit['CUMP'] = cump # mise à jour du champ CUMP
qte_stock = qte_stock - mouv_produit['quantité']
qte_stock_init = qte_stock; cump_init=cump # copie des valeurs du stock initial et du CUMP initial

liste_mouvements_valorises = liste_mouvements_valorises + [mouv_produit] # ajout du mouvement avec son coût moyen

return liste_mouvements_valorises # retourne la liste des mouvements valorisés

III-B - Fonction d'évaluation du coût moyen des sorties par la méthode FIFO et LIFO

Elle prend en arguments la liste des mouvements sur le stock et la méthode de valorisation choisie (CUMP, FIFO ou FIFO) et renvoie la liste des mouvements valorisés.

- liste_mouvements : liste des mouvements (entrées/sorties) sur le stock ;

- methode_valorisation : méthode de valorisation choisie CUMP, FIFO ou LIFO.

Déroulé de la fonction :

- 1. Génération de la liste des références des produits contenus dans le stock ;

- -- 1.1. Pour chaque référence, filtre de la liste des entrées par référence produit,

- -- 1.2. Pour chaque référence, filtre de la liste des sorties par référence produit,

- -- 1.3. Pour chaque référence, parcours de la liste des sorties,

- ---- 1.3.1. Pour chaque sortie, calcul de son coût moyen suivant la méthode FIFO ou LIFO,

- ---- 1.3.2. Pour chaque sortie, ajout de la sortie valorisée à la liste résultat ;

- 2. Renvoi de la liste des sorties valorisées.

Algorithme d'évaluation du coût moyen des sorties

récupérer_références_produits

tant que existe référence_produit

filtrer_entrées_par_référence_produit
filtrer_sorties_par_référence_produit

tant que existe sortie_produit:

valoriser_sortie
ajouter_sortie_à_liste

sortie_suivante

fin tant que

fin tant que

retourner liste_sorties_valorisées

Fonction d'évaluation du coût moyen des sorties

def valoriser_stocks(liste_mouvements, methode_valorisation):
# tri des mouvements dans l'ordre de leur numéro
liste_mouvements = sorted(liste_mouvements,key=lambda d: d['numéro_mouv'])

if methode_valorisation=='CUMP': # si la méthode choisie est CUMP
return valoriser_stocks_cump(liste_mouvements)
else: # sinon
# initialisation de la liste des sorties valorisées générée par la fonction
liste_sorties_valorisees = []

# récupère la liste des références des produits
liste_references_produits = sorted(set([mouv['référence'] for mouv in liste_mouvements]))

# parcours de la liste des références des produits
for reference_produit in liste_references_produits:

# filtre les entrées/sorties en fonction de la référence du produit
liste_sorties_produit = [mouv_produit for mouv_produit in liste_mouvements
if (mouv_produit['type_mouv']=='sortie') and (mouv_produit['référence']==reference_produit)]
liste_entrees_produit = [mouv_produit for mouv_produit in liste_mouvements
if (mouv_produit['type_mouv']=='entrée') and (mouv_produit['référence']==reference_produit)]

# parcours des sorties du produit dans l'ordre chronologique
for sortie_produit in liste_sorties_produit:
# valorise la sortie et ajoute le résultat à la liste
(liste_entrees_produit, liste_sorties_valorisees) = valoriser_sortie(sortie_produit, liste_entrees_produit,
liste_sorties_valorisees, methode_valorisation)

return liste_sorties_valorisees # retourne la liste des sorties valorisées

Fonction de valorisation d'une sortie par la méthode FIFO ou LIFO

Elle a comme arguments :

- sortie_produit : sortie à valoriser ;

- liste_entrees_produit : liste des entrées avec leur quantité mise à jour ;

- liste_sorties_valorisees : liste des sorties valorisées à laquelle ajouter la nouvelle sortie ;

- methode_valorisation : méthode de valorisation des stocks choisie (FIFO, LIFO).

Déroulé de la fonction :

- 1. Pour chaque sortie, parcours des entrées qui la précèdent suivant les numéros d'ordre (FIFO) ou dans l'ordre inverse (LIFO) ;

- -- 1.1. Pour chaque entrée, évaluation de la quantité sortie,

- -- 1.2. Pour chaque entrée, mémorisation de son prix unitaire et de la quantité sortie ;

- 2. Pour chaque sortie, calcul de son coût moyen suivant la méthode FIFO ou LIFO ;

- 3. Pour chaque sortie, ajout de la sortie valorisée à la liste résultat ;

- 4. Renvoi de la liste des entrées et de la liste des sorties valorisées.

Algorithme d'évaluation du prix moyen d'une sortie

filtrer_entrées_antérieures_sortie

si méthode_valorisation = "FIFO":
inverser_entrées_antérieures_sortie

tant que existe entrée_antérieure_sortie:

si (quantité_restant_à_sortir <= quantité_dispo_en_entrée) alors:
quantité_dispo_en_entrée = quantité_dispo_en_entrée - quantité_restant_à_sortir
somme_prix_entrées = somme_prix_entrées + prix_entrée*quantité_restant_à_sortir
si quantité_dispo_en_entrée = 0:
supprimer_entrée_dans_liste
prix_unitaire =  somme_prix_entrees/quantité_totale_sortie
ajouter_sortie_valorisée
sortie_boucle
fin si

quantité_restant_à_sortir = quantité_restant_à_sortir - quantité_dispo_en_entrée
somme_prix_entrées = somme_prix_entrées + prix_entrée*quantité_entrée
supprimer_entrée_dans_liste
entrée_suivante

fin tant que

Fonction d'évaluation d'une sortie

def valoriser_sortie(sortie_produit, liste_entrees_produit, liste_sorties_valorisees, methode_valorisation):
qte_restante = sortie_produit['quantité'] # quantité sortie
somme_prix_entrees = 0 # initialisation de la somme des prix
liste_sorties=[] # initialisation de la liste des sorties sur les différentes entrées
# on récupère les entrées qui précèdent chronologiquement la sortie
liste_entrees_prod = [entree_prod for entree_prod in liste_entrees_produit if entree_prod['numéro_mouv']<sortie_produit['numéro_mouv']]
indice_entree=0; pas=0 # indice de l'entrée et pas de la boucle. Par défaut pas d'incrément (méthode FIFO) : pas=0.
# si on a choisi la méthode de valorisation LIFO, alors on inverse les entrées de la liste obtenue
if methode_valorisation=='LIFO':
indice_entree=len(liste_entrees_prod)-1; pas=-1; liste_entrees_prod = reversed(liste_entrees_prod)

for entree_produit in liste_entrees_prod: # parcours de la liste des entrées précédentes
# si la quantité restante est inférieure ou égale à la quantité sur cette entrée
if (qte_restante <= entree_produit['quantité']):
mouv_produit = {'numéro_entrée': entree_produit['numéro_mouv'], 'date_entrée': entree_produit['date_mouv'],
'quantité_sortie' : qte_restante, 'prix_unitaire': entree_produit['prix_unitaire']}

# ôte à la quantité disponible sur cette entrée la quantité restant à sortir
liste_entrees_produit[indice_entree]['quantité'] = round(entree_produit['quantité'] - qte_restante,7)
if liste_entrees_produit[indice_entree]['quantité']==0:
del liste_entrees_produit[indice_entree] # supprime l'entrée si elle est à 0

# ajoute à la somme le produit entre la quantité sortie et le prix unitaire pour cette entrée
somme_prix_entrees = somme_prix_entrees + qte_restante*entree_produit['prix_unitaire']
liste_sorties = liste_sorties + [mouv_produit] # ajoute l'entrée entrant en compte dans le calcul du coût moyen
prix_unitaire =  somme_prix_entrees/sortie_produit['quantité'] # calcul du prix unitaire en utilisant la méthode LIFO ou FIFO

sortie_produit['prix_unitaire'] = round(prix_unitaire,7) # met à jour le prix unitaire
sortie_produit['détail_sorties'] = liste_sorties # met à jour le détail des sorties de produit sur les différentes entrées

liste_sorties_valorisees = liste_sorties_valorisees + [sortie_produit] # ajoute la sortie valorisée à la liste résultat

break # sort de la boucle

# si la quantité restante à retirer est supérieure à la quantité disponible pour cette entrée
mouv_produit = {'numéro_entrée': entree_produit['numéro_mouv'], 'date_entrée': entree_produit['date_mouv'],
'quantité_sortie' : entree_produit['quantité'], 'prix_unitaire': entree_produit['prix_unitaire']}
# ajoute à la somme le produit entre la quantité sortie et le prix unitaire pour cette entrée
somme_prix_entrees = somme_prix_entrees + entree_produit['quantité']*entree_produit['prix_unitaire']
qte_restante = round(qte_restante - entree_produit['quantité'],7) # retranche au total des sorties la quantité sortie
del liste_entrees_produit[indice_entree] # supprime l'entrée à 0 de la liste
indice_entree = indice_entree + pas # décrémente la valeur d'indice des entrées si LIFO ou l'indice reste à 0 si FIFO
liste_sorties = liste_sorties + [mouv_produit] # ajoute la sortie entrant en compte dans le calcul du coût moyen

return (liste_entrees_produit, liste_sorties_valorisees)

Comme on le constate, on a juste besoin d'inverser la liste des entrées précédant chacune des sorties pour passer de la méthode FIFO à la méthode LIFO. Inutile donc de créer deux fonctions séparées quasiment identiques pour implémenter les deux méthodes de valorisation des stocks. Le code pourrait sûrement encore être optimisé mais ce faisant on risquerait aussi de le rendre moins lisible.

IV - Implémentation de la fonction de valorisation des sorties

Pour effectuer les tests, il faut tout d'abord copier les fonctions précédentes dans un module Python. On propose d'ailleurs à la fin du tutoriel un module complet permettant d'évaluer les sorties du stock avec la fonction valoriser_stocks.

IV-A - Test avec des données exemples

Comme vu précédemment, la fonction valoriser_stocks prend en arguments une liste représentant en fait des mouvements de stock enregistrés dans une base de données et la méthode de valorisation (CUMP, FIFO, LIFO).

Cette liste de dictionnaires passée en argument a comme structure :

[
{
"numéro_mouv":1,
"date_mouv":"2022/01/01",
"référence":"1824",
"quantité":2,
"prix_unitaire":100.98,
"type_mouv":"entrée"
},
{
"numéro_mouv":2,
"date_mouv":"2022/01/05",
"référence":"1824",
"quantité":10,
"prix_unitaire":102.76,
"type_mouv":"entrée"
},
...
]

Les numéros des mouvements sur le stock permettent de les classer, y compris s'il y a plusieurs entrées/sorties le même jour.

Exemple de test avec une liste de mouvements dont on souhaite évaluer les coûts moyens en sorties par la méthode FIFO :

# liste des mouvements sur le stock
liste_mouvements= [{'numéro_mouv':1, 'date_mouv':'2022/01/01', 'référence': '1824', 'quantité': 2, 'prix_unitaire': 100.98,'type_mouv':'entrée'},
{'numéro_mouv':2, 'date_mouv':'2022/01/05', 'référence': '1824', 'quantité': 10,  'prix_unitaire': 102.76,'type_mouv':'entrée'},
{'numéro_mouv':3, 'date_mouv':'2022/01/10', 'référence': '1824', 'quantité': 10, 'prix_unitaire': 90.54,'type_mouv':'entrée'},
{'numéro_mouv':4, 'date_mouv':'2022/01/12', 'référence': '1824', 'quantité': 5, 'prix_unitaire': 0,'type_mouv':'sortie'},
{'numéro_mouv':5, 'date_mouv':'2022/01/15', 'référence': '1824', 'quantité': 10, 'prix_unitaire': 0,'type_mouv':'sortie'},
{'numéro_mouv':6, 'date_mouv':'2022/01/20', 'référence': '1824', 'quantité': 20, 'prix_unitaire': 101.32,'type_mouv':'entrée'},
{'numéro_mouv':7, 'date_mouv':'2022/01/22', 'référence': '1824', 'quantité': 8, 'prix_unitaire': 0,'type_mouv':'sortie'}]

# appel de la fonction de valorisation des stocks qui renvoie le résultat dans une liste
liste_sorties_valorisees = valoriser_stocks(liste_mouvements,'FIFO')

# affiche les sorties avec leur coût moyen calculé en fonction de la méthode choisie
print(liste_sorties_valorisees)

Le résultat obtenu est sous la forme d'une liste de sorties, avec pour chacune d’entre elles le prix unitaire calculé et le détail des sorties (quantité sortie pour chaque prix unitaire) :

Résultat de la valorisation des stocks

[
{
"numéro_mouv":4,
"date_mouv":"2022/01/12",
"référence":"1824",
"quantité":5,
"prix_unitaire":102.048,
"type_mouv":"sortie",
"détail_sorties":[
{
"numéro_entrée":1,
"date_entrée":"2022/01/01",
"quantité_sortie":2,
"prix_unitaire":100.98
},
{
"numéro_entrée":2,
"date_entrée":"2022/01/05",
"quantité_sortie":3,
"prix_unitaire":102.76
}
]
},
{
"numéro_mouv":5,
"date_mouv":"2022/01/15",
"référence":"1824",
"quantité":10,
"prix_unitaire":99.094,
"type_mouv":"sortie",
"détail_sorties":[
{
"numéro_entrée":2,
"date_entrée":"2022/01/05",
"quantité_sortie":7,
"prix_unitaire":102.76
},
{
"numéro_entrée":3,
"date_entrée":"2022/01/10",
"quantité_sortie":3,
"prix_unitaire":90.54
}
]
},
{
"numéro_mouv":7,
"date_mouv":"2022/01/22",
"référence":"1824",
"quantité":8,
"prix_unitaire":91.8875,
"type_mouv":"sortie",
"détail_sorties":[
{
"numéro_entrée":3,
"date_entrée":"2022/01/10",
"quantité_sortie":7,
"prix_unitaire":90.54
},
{
"numéro_entrée":6,
"date_entrée":"2022/01/20",
"quantité_sortie":1,
"prix_unitaire":101.32
}
]
}
]

Ces données peuvent être ensuite facilement exportées dans une feuille Excel ou directement dans une base de données.

Les données sont issues du fichier Access de Claude Leloup disponible en téléchargement sur son tutoriel Évaluation des stocks avec ACCESS

IV-B - Test avec récupération des données contenues dans une table SQLite

On dispose d'une base de données SQLite contenant une table MOUVEMENTS_STOCK permettant d'enregistrer les entrées/sorties sur le stock :

Nom de la colonne

Type de données

Description

NUMERO_MOUV

INT

Numéro du mouvement sur le stock

DATE_MOUV

TEXT

Date du mouvement sur le stock

REFERENCE

TEXT

Référence du produit

QUANTITE

NUMERIC

Quantité de produit entrée ou sortie du stock

PRIX_UNITAIRE

REAL

Prix unitaire du produit

TYPE_MOUV

TEXT

Type de mouvement sur le stock : "entrée", "sortie".

Pour importer les données contenues dans la base, on doit d'abord ajouter en haut de notre module une référence à la librairie sqlite3 :

import sqlite3
from sqlite3 import Error

Puis, on écrit une fonction pour se connecter à la base SQLite :

fonction create_connection

def create_connection(db_file):
""" crée une connexion à la base de données SQLite
specifié par le chemin du fichier passé en argument
:param db_file: chemin du fichier db
:return: un objet connexion ou renvoie none
"""
conn = None
try:
conn = sqlite3.connect(db_file) # on crée l'objet connexion
return conn
except Error as e: # gestion de l'erreur
print(e) # affichage du message d'erreur

return conn

Enfin, on peut tester la fonction de valorisation avec une liste de mouvements issus d'une table SQLite :

test de la fonction de valorisation des stocks

database = r"C:\sqlite\db\stocks_data.db" # chemin de la base de données

# création de la connexion à la base de données sqlite
conn = create_connection(database)

# si la connexion a été réalisée
if conn is not None:

cur = conn.cursor()
cur.execute("SELECT * FROM MOUVEMENTS_STOCK")

# initialise la liste des mouvements sur le stock
liste_mouvements=[]

# récupère le contenu de la table dans une liste
liste_mouvs = cur.fetchall()

# parcours des mouvements de la liste
for mouv in liste_mouvs:
# copie des informations sur le mouvement dans un dictionnaire
mouv_produit = {'numéro_mouv':mouv[0], 'date_mouv':mouv[1], 'référence':mouv[2],
'quantité':mouv[3], 'prix_unitaire':mouv[4], 'type_mouv':mouv[5]}

# ajout du dictionnaire à la nouvelle liste
liste_mouvements=liste_mouvements + [mouv_produit]

# appel de la fonction de valorisation des stocks qui renvoie le résultat dans une liste
liste_sorties_valorisees = valoriser_stocks(liste_mouvements,'FIFO')

# affiche les sorties avec leur coût moyen calculé en fonction de la méthode choisie
print(liste_sorties_valorisees)

else:
print("Erreur! impossible de créer la connexion à la base !")

Vous devrez bien sûr faire correspondre les colonnes de votre base de données avec les clefs des dictionnaires pour pouvoir ensuite récupérer la liste des mouvements sur le stock, puis valoriser les sorties à l'aide de la fonction valoriser_stocks.

V - Conclusion

Après avoir présenté les trois méthodes d'évaluation des stocks (CUMP, FIFO et LIFO) à l'aide de tableaux, nous avons pu ensuite écrire l'algorithme, puis la fonction permettant de valoriser une liste de mouvements de stock par ces trois méthodes. Enfin, nous avons montré comment tester cette fonction sur une liste d'entrées/sorties avec la méthode FIFO.

VI - Module Python

Il contient le code complet permettant de valoriser une liste de mouvements de stocks en fonction des trois méthodes :

Module complet

def valoriser_stocks_cump(liste_mouvements):
# initialisation de la liste des sorties valorisées générée par la fonction
liste_mouvements_valorises = []

# filtre les sorties dans une liste
liste_references_produits = sorted(set([mouv['référence'] for mouv in liste_mouvements]))

# parcours de la liste des références des produits
for reference_produit in liste_references_produits:

# filtre les entrées/sorties en fonction de la référence du produit
liste_mouvs_produit = [mouv_produit for mouv_produit in liste_mouvements if (mouv_produit['référence']==reference_produit)]
# initialisation des quantités en stock et de la somme des prix en entrées
qte_stock = 0; somme_prix_entrees = 0; quantite_totale = 0;cump = 0 ; qte_stock_init=0; cump_init = 0

# parcours de la liste des mouvements du stock
for mouv_produit in liste_mouvs_produit:

if mouv_produit['type_mouv']=='entrée': # s'il s'agit d'une entrée dans le stock
# calcul de la somme des prix unitaires en entrées jusqu'à ce mouvement
somme_prix_entrees = somme_prix_entrees + mouv_produit['quantité']*mouv_produit['prix_unitaire']

# calcul de la quantité totale des entrées jusqu'à ce mouvement
quantite_totale = quantite_totale + mouv_produit['quantité']

# calcul du coût moyen pondéré (CUMP) avec correction des erreurs dans les résultats des opérations en virgule flottante
cump =  round((qte_stock_init*cump_init + somme_prix_entrees)/(qte_stock_init+quantite_totale),7)

mouv_produit['CUMP'] =  cump # mise à jour du champ CUMP

qte_stock = qte_stock + mouv_produit['quantité']
else: # sinon
somme_prix_entrees = 0 # on initialise la somme des prix unitaires des entrées
quantite_totale = 0 # on initialise la quantité totale des entrées
stock_initial = True
mouv_produit['CUMP'] = cump # mise à jour du champ CUMP
qte_stock = qte_stock - mouv_produit['quantité']
qte_stock_init = qte_stock; cump_init=cump # copie des valeurs du stock initial et du CUMP initial

liste_mouvements_valorises = liste_mouvements_valorises + [mouv_produit] # ajout du mouvement avec son coût moyen

return liste_mouvements_valorises # retourne la liste des mouvements valorisés

def valoriser_sortie(sortie_produit, liste_entrees_produit, liste_sorties_valorisees, methode_valorisation):
qte_restante = sortie_produit['quantité'] # quantité sortie
somme_prix_entrees = 0 # initialisation de la somme des prix
liste_sorties=[] # initialisation de la liste des sorties sur les différentes entrées
# on récupère les entrées qui précèdent chronologiquement la sortie
liste_entrees_prod = [entree_prod for entree_prod in liste_entrees_produit if entree_prod['numéro_mouv']<sortie_produit['numéro_mouv']]
indice_entree=0; pas=0 # indice de l'entrée et pas de la boucle. Par défaut pas d'incrément (méthode FIFO) : pas=0.
# si on a choisi la méthode de valorisation LIFO, alors on inverse les entrées de la liste obtenue
if methode_valorisation=='LIFO':
indice_entree=len(liste_entrees_prod)-1; pas=-1; liste_entrees_prod = reversed(liste_entrees_prod)

for entree_produit in liste_entrees_prod: # parcours de la liste des entrées précédentes
# si la quantité restante est inférieure ou égale à la quantité sur cette entrée
if (qte_restante <= entree_produit['quantité']):
mouv_produit = {'numéro_entrée': entree_produit['numéro_mouv'], 'date_entrée': entree_produit['date_mouv'],
'quantité_sortie' : qte_restante, 'prix_unitaire': entree_produit['prix_unitaire']}

# ôte à la quantité disponible sur cette entrée la quantité restant à sortir
liste_entrees_produit[indice_entree]['quantité'] = round(entree_produit['quantité'] - qte_restante,7)
if liste_entrees_produit[indice_entree]['quantité']==0:
del liste_entrees_produit[indice_entree] # supprime l'entrée si elle est à 0

# ajoute à la somme le produit entre la quantité sortie et le prix unitaire pour cette entrée
somme_prix_entrees = somme_prix_entrees + qte_restante*entree_produit['prix_unitaire']
liste_sorties = liste_sorties + [mouv_produit] # ajoute l'entrée entrant en compte dans le calcul du coût moyen
prix_unitaire =  somme_prix_entrees/sortie_produit['quantité'] # calcul du prix unitaire en utilisant la méthode LIFO ou FIFO

sortie_produit['prix_unitaire'] = round(prix_unitaire,7) # met à jour le prix unitaire
sortie_produit['détail_sorties'] = liste_sorties # met à jour le détail des sorties de produit sur les différentes entrées

liste_sorties_valorisees = liste_sorties_valorisees + [sortie_produit] # ajoute la sortie valorisée à la liste résultat

break # sort de la boucle

# si la quantité restante à retirer est supérieure à la quantité disponible pour cette entrée
mouv_produit = {'numéro_entrée': entree_produit['numéro_mouv'], 'date_entrée': entree_produit['date_mouv'],
'quantité_sortie' : entree_produit['quantité'], 'prix_unitaire': entree_produit['prix_unitaire']}
# ajoute à la somme le produit entre la quantité sortie et le prix unitaire pour cette entrée
somme_prix_entrees = somme_prix_entrees + entree_produit['quantité']*entree_produit['prix_unitaire']
qte_restante = round(qte_restante - entree_produit['quantité'],7) # retranche au total des sorties la quantité sortie
del liste_entrees_produit[indice_entree] # supprime l'entrée à 0 de la liste
indice_entree = indice_entree + pas # décrémente la valeur d'indice des entrées si méthode LIFO ou l'indice reste à 0 si FIFO
liste_sorties = liste_sorties + [mouv_produit] # ajoute la sortie entrant en compte dans le calcul du coût moyen

return (liste_entrees_produit, liste_sorties_valorisees)

def valoriser_stocks(liste_mouvements, methode_valorisation):
# tri des mouvements dans l'ordre de leur numéro
liste_mouvements = sorted(liste_mouvements,key=lambda d: d['numéro_mouv'])

if methode_valorisation=='CUMP': # si la méthodde choisie est CUMP
return valoriser_stocks_cump(liste_mouvements)
else: # sinon
# initialisation de la liste des sorties valorisées générée par la fonction
liste_sorties_valorisees = []

# récupère la liste des références des produits
liste_references_produits = sorted(set([mouv['référence'] for mouv in liste_mouvements]))

# parcours de la liste des références des produits
for reference_produit in liste_references_produits:

# filtre les entrées/sorties en fonction de la référence du produit
liste_sorties_produit = [mouv_produit for mouv_produit in liste_mouvements
if (mouv_produit['type_mouv']=='sortie') and (mouv_produit['référence']==reference_produit)]
liste_entrees_produit = [mouv_produit for mouv_produit in liste_mouvements
if (mouv_produit['type_mouv']=='entrée') and (mouv_produit['référence']==reference_produit)]

# parcours des sorties du produit dans l'ordre chronologique
for sortie_produit in liste_sorties_produit:
# valorise la sortie et ajoute le résultat à la liste
(liste_entrees_produit, liste_sorties_valorisees) = valoriser_sortie(sortie_produit, liste_entrees_produit,
liste_sorties_valorisees, methode_valorisation)

return liste_sorties_valorisees # retourne la liste des sorties valorisées

liste_mouvements= [{'numéro_mouv':1, 'date_mouv':'2017/01/01', 'référence': '1824', 'quantité': 2, 'prix_unitaire': 100.98,'type_mouv':'entrée'},
{'numéro_mouv':2, 'date_mouv':'2017/01/05', 'référence': '1824', 'quantité': 10,  'prix_unitaire': 102.76,'type_mouv':'entrée'},
{'numéro_mouv':3, 'date_mouv':'2017/01/10', 'référence': '1824', 'quantité': 10, 'prix_unitaire': 90.54,'type_mouv':'entrée'},
{'numéro_mouv':4, 'date_mouv':'2017/01/12', 'référence': '1824', 'quantité': 5, 'prix_unitaire': 0,'type_mouv':'sortie'},
{'numéro_mouv':5, 'date_mouv':'2017/01/15', 'référence': '1824', 'quantité': 10, 'prix_unitaire': 0,'type_mouv':'sortie'},
{'numéro_mouv':6, 'date_mouv':'2017/01/20', 'référence': '1824', 'quantité': 20, 'prix_unitaire': 101.32,'type_mouv':'entrée'},
{'numéro_mouv':7, 'date_mouv':'2017/01/22', 'référence': '1824', 'quantité': 8, 'prix_unitaire': 0,'type_mouv':'sortie'}]

# appel de la fonction de valorisation des stocks qui renvoie le résultat dans une liste
liste_sorties_valorisees = valoriser_stocks(liste_mouvements,'FIFO')

# affiche les sorties avec leur coût moyen calculé en fonction de la méthode choisie
print(liste_sorties_valorisees)

VII - Remerciements

Je tiens à remercier Claude Leloup pour son tutoriel et sa base de données, ainsi qu’escartefigue pour sa relecture.