Rapport de stage
Sostrene Grene Poitiers - du 18 Mars au 27 Juin 2025
Sostrene Grene Poitiers
Du 18 Mars au 27 Juin 2025
Sommaire
Présentation du projet
Description du projet
Mon stage s’est déroulé au sein du magasin Søstrene Grene de Poitiers. L’objectif principal était la conception et le développement d’un site web destiné à la gestion des stocks alimentaires. Ce site, présenté sous forme de tableau interactif, a été conçu pour remplacer le système manuel précédemment en place, basé sur un carnet papier.
Le site est composé de deux pages distinctes :
- Page principale : La page principale, dédiée à la gestion des produits en stock, affiche pour chaque article des informations complètes : nom, code-barres, date de péremption, statut, prix, poids, catégorie et type. Les produits sont présentés sous forme de tableau, une ligne par produit. Les statuts disponibles sont : à venir, en stock, indisponible, étiqueté, non reçu.
- Page des modèles : La page des modèles, utilisée comme base de référence, regroupe les produits récurrents fréquemment livrés au magasin. Elle permet de préremplir automatiquement les formulaires lors de la réception, évitant ainsi les saisies répétitives. Elle ne gère pas les stocks directement et contient un nombre réduit d’informations.
Le site a été principalement développé en JavaScript et en PHP. Le langage PHP a été utilisé pour l’ensemble des fonctions liées à la communication avec la base de données. Toutes les fonctionnalités de gestion automatique des produits, comme les calculs dynamiques ou la mise à jour des statuts, ont été implémentées en JavaScript.
Mon role dans le projet
Durant ce stage, j’ai occupé un rôle complet de développeur. J’étais responsable de la conception de l’interface, de l’implémentation des fonctionnalités, ainsi que du développement et des tests de l’ensemble du site.
Le projet m’a été entièrement confié : j’ai conçu et développé l’ensemble de la solution, aussi bien côté front-end que back-end. J’ai également conçu et développé les fonctionnalités principales du site, notamment la gestion centralisée des modèles de produits, la mise à jour automatisée des dates de péremption, la synchronisation des informations entre produits similaires, ainsi que des filtres d’affichage dynamiques et un système de détection des doublons pour garantir la cohérence des données.
Mon maître de stage m’a accompagné en me fournissant un cadre de travail structuré et en m’orientant sur les grandes étapes du projet. Des points hebdomadaires permettaient de faire le suivi de l’avancement et des nouvelles fonctionnalités à intégrer. Un employé impliqué dans le projet m’a également apporté des retours et suggestions d’amélioration afin de rendre l’outil plus pratique pour les utilisateurs du magasin.
L’intégralité du développement : conception, ergonomie, structure du code et fonctionnalités, a été réalisée par moi-même. Cette autonomie m’a permis de développer mes compétences en organisation, en gestion de projet, en manipulation de bases de données, et de répondre à un besoin concret dans un environnement professionnel réel.
Fonctionnement du site
Avant la mise en place du site, la gestion des produits alimentaires se faisait à l’aide d’un carnet papier. Chaque semaine, le magasin recevait un bon de livraison listant les produits prévus pour la semaine suivante. Ces produits étaient inscrits dans le carnet. Une fois la livraison réceptionnée, la date de péremption était ajoutée à la main, et chaque produit était coché pour indiquer sa bonne réception.
L’objectif du site était donc de simplifier ce fonctionnement manuel tout en ajoutant de nouvelles fonctionnalités pour une gestion plus efficace et structurée.
Ajout d'un produit
Lors de la réception du bon de livraison, l’ajout d’un produit dans le tableau peut se faire de deux manières via un formulaire :
- Ajout manuel : l’utilisateur renseigne manuellement les champs du formulaire (sans indiquer la date de péremption). Le produit est alors ajouté au tableau avec :
- un statut “à venir”
- la date du jour comme date de création
- Ajout par suggestion : l’utilisateur commence à taper le nom du produit dans le champ correspondant. Des suggestions issues des modèles existants apparaissent. En sélectionnant l’un d’eux, le produit est automatiquement ajouté au tableau avec le statut "à venir" et la date du jour.
Si le produit n’existe pas encore dans les modèles, une fenêtre modale s’ouvre pour proposer à l’utilisateur d’ajouter ce produit dans la page des modèles, en prévision de livraisons récurrentes.
Réception des produits
Lorsque la livraison est réceptionnée, il est nécessaire de vérifier que tous les produits indiqués sur le bon de livraison ont bien été reçus, puis de renseigner leur date de péremption.
Un bouton “Livraison” permet d’ouvrir un champ de formulaire pour indiquer le produit reçu. Seuls les produits avec le statut “à venir” et la date la plus ancienne de ce statut sont sélectionnables, afin d’éviter les erreurs entre différentes livraisons.
- Code-barres disponible : il peut être scanné : une fenêtre modale s’ouvre alors pour saisir la date de péremption. Une fois validée, la date est enregistrée et le statut passe automatiquement à “en stock”.
- Code-barres non renseigné : il est possible de taper le nom du produit : des suggestions de produits “à venir” s’affichent. En sélectionnant un produit, la fenêtre modale permet de saisir la date de péremption. Une fois validée, le produit est mis à jour de la même manière.
Il arrive que certaines informations (prix, poids, code-barres) soient absentes du bon de livraison. Dans le cas d’un produit jamais reçu auparavant, ces données ne sont disponibles qu’après réception physique du produit. Il est donc possible d’ajouter un produit sans ces informations, et de l’enregistrer dans les modèles.
Au moment de la saisie de la date de péremption, la fenêtre modale propose également de compléter les informations manquantes (prix, poids, code-barres). Une fois validées :
- le produit est mis à jour dans le tableau,
- le modèle correspondant est modifié,
- toutes les lignes existantes associées à ce modèle dans le tableau sont également mises à jour.
Gestion des produits
Lorsqu’un produit arrive à moins d’un mois de sa date de péremption, une réduction de 30 % doit être
appliquée et une étiquette indiquant ce nouveau prix doit être posée. Dans ce cas, la ligne du produit
s’affiche en orange et celui-ci est automatiquement remonté visuellement dans le tableau afin de
signaler qu’une action est nécessaire.
Une fois l’étiquette posée, l’utilisateur change
manuellement le statut du produit en "étiqueté". Cette modification fait disparaître la couleur
orange, et le produit reprend sa position normale dans le tableau, classé selon sa date de péremption.
Lorsqu’un produit devient périmé, il conserve le statut "étiqueté" mais sa ligne passe en rouge. Cela indique qu’il doit être retiré du magasin. L’utilisateur modifie alors son statut en "indisponible", ce qui retire la couleur rouge et déplace la ligne tout en bas du tableau.
Les produits marqués comme "indisponibles" sont conservés dans le tableau pendant trois mois. Passé ce délai, ils sont automatiquement supprimés afin de ne pas encombrer l’interface.
Autres fonctionnalités
Une barre de recherche est disponible sur les deux pages du site. Elle permet de retrouver un produit à partir de son nom ou de son code-barres.
Des filtres permettent d’affiner l’affichage :
- Tous les produits (filtre activé par défaut)
- Produits bientôt périmés : affiche les produits périmant dans moins d’un mois, avec le statut "en stock" ou "étiqueté"
- Produits périmés : affiche tous les produits dont la date est dépassée, avec les statuts "étiqueté" ou "indisponible"
Sur la page des modèles, chaque modèle peut être modifié. En cliquant sur un bouton, une fenêtre modale s’ouvre, permettant de modifier chaque champ. Une fois la modification validée :
- le modèle est mis à jour
- toutes les lignes correspondantes dans la page des produits sont automatiquement mises à jour également (par exemple, un changement de prix dans le modèle impactera directement tous les produits associés).
Le prix et le poids sont indiqués dans le tableau, permettant d’afficher dans des cellules distinctes le prix au kilo, calculé automatiquement même après modification du prix ou du poids. Une cellule affiche également le prix réduit : lorsqu’un produit est périmé dans un mois, une remise de 30 % est appliquée en magasin, et ce prix réduit est visible dans le tableau.
Le type (solide ou liquide) adapte l’unité du poids en grammes ou millilitres, facilitant ainsi la lecture et la mise en place des prix en rayon.
Missions réalisées
Ergonomie du site
L’une des tâches principales du projet a été de réfléchir aux différentes actions que les utilisateurs seraient amenés à effectuer régulièrement, et de rendre ces actions aussi simples et rapides que possible. L’objectif était de concevoir une interface intuitive et facile à prendre en main. Une recherche sur les principes d’ergonomie a donc été menée afin de trouver les meilleures solutions pour faciliter l’usage du site. Plusieurs mises en page ont été testées avec l’équipe afin d’identifier celle qui correspondait le mieux aux usages réels.
Page des produits
La page des produits constitue la page centrale du site. Elle regroupe les fonctions principales : ajout de produit, mode de livraison et affichage du tableau des produits. Le formulaire d’ajout, ainsi que les boutons les plus utilisés, sont placés sur la même ligne en haut de la page pour un accès rapide. Ce formulaire est classique, mais intègre un champ intelligent qui propose automatiquement une liste de modèles existants dès que l’utilisateur commence à taper un nom. Cela permet d’ajouter un produit sans avoir à renseigner toutes ses informations à nouveau, ce qui fait gagner un temps précieux.
Un bouton “Livraison”, situé à droite du formulaire, permet d’activer le mode spécifique. Lorsqu’il est cliqué, une barre de recherche s’affiche juste au-dessus du tableau, et le bouton change de couleur pour indiquer clairement que le mode livraison est actif. Ce mode peut être désactivé à tout moment.
Au-dessus du tableau se trouve une barre de recherche dynamique permettant de filtrer en temps réel les produits en fonction du texte saisi. Des filtres sont également présents sous forme d’onglets, permettant d’afficher uniquement les produits proches de la date de péremption ou déjà périmés. Un léger changement de couleur sur l’onglet actif permet à l’utilisateur d’identifier rapidement le filtre appliqué.
Le tableau lui-même est conçu pour être lisible facilement dans des conditions de travail : l’en-tête comporte un intitulé et une icône pour chaque colonne, et les lignes alternent entre deux couleurs pour faciliter la lecture horizontale. Lorsqu’un utilisateur souhaite modifier la date d’un produit, la date actuelle est automatiquement sélectionnée pour éviter un clic supplémentaire, et la saisie accepte différents formats simplifiés (par exemple “120625” ou “12/06/25”). Les statuts peuvent être modifiés directement depuis le tableau en cliquant dessus : un petit menu s’ouvre alors avec toutes les options disponibles. Tous les champs modifiables ont été conçus pour être facilement utilisables sur écran tactile, avec des zones suffisamment larges pour limiter les erreurs de sélection.

Page des modèles
La page des modèles reprend globalement la structure de celle des produits, mais avec une interface allégée, car elle nécessite beaucoup moins d’interactions de la part de l’utilisateur. Un formulaire d’ajout reste présent en haut de la page, avec tous les champs nécessaires à la création d’un nouveau modèle. Une barre de recherche est également disponible pour retrouver rapidement un modèle existant.
Deux différences principales distinguent cette page de celle des produits. Tout d’abord, la suppression d’un modèle ne s’effectue pas immédiatement : une confirmation est demandée à l’utilisateur avant de valider, afin d’éviter toute suppression accidentelle. Ensuite, chaque ligne du tableau dispose d’un bouton de modification situé dans la colonne « Action ». Ce bouton, identifiable par une icône spécifique, permet d’ouvrir une fenêtre modale dans laquelle toutes les informations du modèle peuvent être modifiées.
Les actions disponibles sur cette page sont accompagnées d’icônes aux couleurs vives, afin de signaler clairement qu’une modification va être effectuée et de guider l’utilisateur dans ses choix.

Fenêtres modales
Dans les deux tableaux, plusieurs actions s’effectuent à l’aide de fenêtres modales, conçues pour interagir de manière ciblée avec l’utilisateur. On distingue deux types de modales selon l’objectif de l’action attendue.
Le premier type concerne les actions nécessitant une validation obligatoire de l’utilisateur, comme la confirmation d’une suppression. Dans ce cas, la fenêtre modale reste affichée tant qu’aucune décision explicite n’a été prise ; l’utilisateur doit cliquer sur un bouton de confirmation ou d’annulation pour que la modale se ferme.
Le second type est utilisé pour les opérations de modification, comme la mise à jour des informations d’un produit. Ces fenêtres peuvent être fermées librement, soit en cliquant sur la croix prévue à cet effet, soit en cliquant en dehors de la fenêtre. Dans ce cas, toutes les modifications en cours sont annulées. Les changements ne sont enregistrés que si l’utilisateur clique sur le bouton de validation à l’intérieur de la modale.


Responsive
Le site a été conçu pour être entièrement responsive, afin de s’adapter à tous les supports utilisés en magasin, notamment les tablettes, très couramment employées pour les tâches numériques. L’objectif est de garantir une navigation fluide et intuitive, que ce soit sur ordinateur, tablette ou téléphone.
Tous les champs du formulaire sont compatibles avec une utilisation tactile. Pour ceux nécessitant une saisie numérique (prix, poids, code-barres, etc.), le clavier affiché est automatiquement limité à un pavé numérique, ce qui facilite et accélère la saisie sur écran tactile.
L’ergonomie du site s’adapte également selon l’orientation de l’écran. En mode portrait, certaines actions initialement disposées en ligne passent en colonne pour améliorer la lisibilité et l’accessibilité. Par ailleurs, le tableau principal étant trop large pour tenir entièrement sur les petits écrans, il a été rendu horizontalement scrollable : l’utilisateur peut ainsi le faire défiler latéralement pour consulter l’ensemble des informations sans perte de fonctionnalité.

Base de données
Pourquoi SQLite
Dans le cadre de ce projet, la base de données utilisée est SQLite. Ce choix s’est imposé naturellement compte tenu des besoins fonctionnels limités et du contexte d’utilisation. SQLite est une base de données relationnelle légère, qui fonctionne directement à partir d’un fichier sans nécessiter l’installation ou la configuration d’un serveur de gestion de base de données comme MySQL ou PostgreSQL. Cette caractéristique permet une intégration simple et rapide au sein du projet, sans dépendance extérieure ni configuration réseau particulière.
L’un des avantages majeurs de SQLite réside dans sa légèreté : la base tient dans un seul fichier, ce qui facilite considérablement son déploiement, sa sauvegarde et son transfert. Cette approche est bien adaptée à une application déployée sur un serveur, dès lors que la charge prévue reste modérée et que les accès simultanés sont rares. En termes de performances, SQLite répond pleinement aux besoins d’un tel projet, caractérisé par un volume de données limité et une fréquence d’accès peu intensive. Le moteur assure par ailleurs la cohérence et l’intégrité des données grâce à sa conformité au modèle ACID (Atomicité, Cohérence, Isolation, Durabilité), qui garantit que chaque transaction est exécutée de manière fiable, complète et sans compromettre l’état de la base, même en environnement serveur, tant que les contraintes d’accès concurrent restent faibles.
Bien que SQLite présente certaines limitations, notamment en matière de gestion de la concurrence puisqu’il ne permet qu’une seule opération d’écriture à la fois, ces contraintes ne posent pas de problème dans ce contexte. Le projet n’est pas destiné à être utilisé simultanément par plusieurs utilisateurs. De même, l’absence de fonctionnalités avancées telles que la gestion des rôles utilisateurs ou la réplication ne compromet pas les objectifs visés.
Structure et fonctionnement
La base de données utilisée dans ce projet repose sur un schéma relationnel simple, composé de deux tables principales : models et products. Ces deux entités permettent de structurer et de distinguer les données de référence des produits disponibles de celles correspondant aux unités physiques effectivement présentes en stock.
La table models représente les fiches produits de base. Chaque enregistrement correspond à un modèle de produit générique, indépendant d’un lot particulier ou d’une date de péremption. Cette table contient les informations stables du produit telles que son nom (name), son code-barres (barcode), son prix unitaire (price), son poids (weight), sa catégorie (category) et son type (type). Des contraintes sont définies pour garantir la cohérence des données, notamment des listes de valeurs autorisées sur les champs category et type via l’instruction CHECK(...).
La table products, quant à elle, correspond aux unités concrètes du stock. Chaque ligne représente un produit effectivement présent ou attendu, avec des informations dynamiques comme la date de péremption (expiry_date), le statut (status), le prix remisé (discount_price), et le prix au kilo (price_per_kg), calculé à partir du poids et du prix. Elle reprend également les attributs communs du modèle (name, barcode, price, weight, etc.), ce qui permet un fonctionnement indépendant même sans jointure directe avec la table models.
Dans les deux tables, le champ id est défini comme clé primaire avec auto-incrémentation (INTEGER PRIMARY KEY AUTOINCREMENT), ce qui garantit l’unicité de chaque enregistrement et facilite la gestion des références internes. Aucune clé étrangère n’est formellement définie entre models et products, ce qui permet une certaine souplesse, mais nécessite de gérer les correspondances logiques au niveau applicatif.
L’ensemble des contraintes définies dans le schéma SQL (types de données, NOT NULL, CHECK, clés primaires) vise à garantir une intégrité minimale des données et à réduire les erreurs d’insertion lors de l’utilisation de l’application. Ce modèle relationnel est volontairement restreint, mais il répond pleinement aux besoins de l’application : gestion simple, consultation rapide et maintien d’un niveau de cohérence suffisant dans un contexte à faible concurrence et à usage maîtrisé.

Arborescence du site
Le site s’appuie sur un fichier principal, index.php, situé à la racine. Ce fichier constitue le point d’entrée de l’application et affiche la page contenant tous les produits. Le dossier assets regroupe les ressources statiques : le sous-dossier css contient la feuille de style style.css qui gère la présentation visuelle, le sous-dossier js comprend les scripts JavaScript modele.js et produits.js, chacun dédié à la gestion des interactions dynamiques sur une page spécifique, et le dossier images stocke les éléments graphiques utilisés sur le site.
La base de données SQLite est centralisée dans le dossier bdd sous le fichier produits.bd, ce qui simplifie la gestion des données.
Le dossier fonctions contient l’ensemble des fichiers PHP regroupant les fonctions nécessaires au fonctionnement de l’application, facilitant ainsi la maintenance et la modularité du code.
Enfin, le dossier pages regroupe les pages accessibles du site, avec actuellement uniquement modeles.php, correspondant à la deuxième page dédiée à la gestion des modèles de produits.
Cette organisation claire distingue nettement les ressources statiques, les données, les fonctions et les pages, améliorant la lisibilité et la modularité du projet. Cette structure simple offre une vision globale du projet et facilite l’ajout ou la modification future de pages et de fonctionnalités, permettant ainsi une évolution durable du site.

Phase de test
La phase de test a permis d’examiner exhaustivement les différentes interactions possibles des utilisateurs avec le site et d’identifier les problèmes restants, notamment des erreurs de validation de formulaire. Avec mon maître de stage et un employé n’ayant pas participé au développement, nous avons simulé l’ensemble des actions courantes réalisées lors d’une utilisation normale du site. J’ai également réalisé des tests ciblés pour reproduire et anticiper les erreurs potentielles pouvant survenir en conditions réelles.
Cette étape a été cruciale pour découvrir des cas d’usage ou des scénarios imprévus lors du développement. Elle a permis d’ajuster le code afin de gérer correctement ces situations, améliorant ainsi la robustesse et la fiabilité de l’application. De plus, cette phase a contribué à optimiser l’expérience utilisateur en corrigeant les dysfonctionnements et en affinant les validations et les retours visuels.
Intégration des produits
Une des dernières étapes réalisées lors de ce stage a consisté à intégrer l’ensemble des produits dans le tableau de gestion. Après avoir effectué les tests fonctionnels nécessaires, il a fallu enregistrer les produits récurrents en les associant à des modèles, notamment via le scan de leurs codes-barres. Par la suite, tous les produits présents en magasin ainsi que ceux notés manuellement dans le carnet de suivi ont été saisis dans le système afin de centraliser toutes les informations dans le site.
Cette tâche, bien que longue et répétitive, n’était pas techniquement complexe, mais elle s’est révélée indispensable pour finaliser le projet. Elle a permis d’obtenir une base complète et opérationnelle, rendant le site immédiatement utilisable pour la gestion quotidienne. Cette phase a également permis de vérifier la cohérence des données et d’identifier d’éventuelles erreurs à corriger avant la mise en production.
Fonctionnalités
Ajout dynamique d'un produit
La fonction addProduct(formData) est chargée d’ajouter un produit à la fois dans la base de données et dans le tableau HTML affiché à l’écran, le tout sans rechargement de page. Elle repose sur une requête AJAX avec fetch, qui envoie les données du formulaire à un script PHP nommé add_product.php.
Concrètement, les données saisies sont encapsulées dans un objet FormData, puis converties en URLSearchParams pour être transmises via POST. Le script PHP côté serveur traite ces données, enregistre le produit dans la base, puis renvoie une réponse au format JSON contenant un indicateur de succès (data.success) ainsi que l’ID du produit nouvellement créé.
Si l’ajout en base est validé, la fonction construit alors une nouvelle ligne HTML (<tr>) représentant ce produit. Les valeurs du formulaire sont insérées dans les bonnes colonnes : nom, code-barres, date de péremption, prix, poids, catégorie, type. Une interface de sélection personnalisée est également insérée dans la cellule du statut, avec plusieurs options colorées (ex. : en stock, à venir, etc.). Une cellule supplémentaire est prévue pour la suppression du produit.
Une fois cette ligne complétée, elle est ajoutée dynamiquement au <tbody> du tableau via appendChild(). Plusieurs fonctions sont ensuite appelées pour finaliser l’intégration :
- formatPriceAndWeightForRow(newRow) applique le formatage numérique du prix et du poids sur la ligne ajoutée ;
- updateRowStylesByDate() recalcule les styles visuels selon la date de péremption (ex. : couleurs pour produits périmés ou bientôt périmés) ;
- advancedSortTable() relance le tri du tableau si un tri actif est en cours ;
- applyFilter() réapplique les filtres éventuels (par catégorie, statut, etc.) ;
- attachEditableEvents(newRow) permet la modification directe de certaines cellules comme la date de péremption ;
- attachCustomSelectEvents(newRow) rend le menu déroulant du statut interactif ;
- attachDeleteEvent(newRow) associe le comportement de suppression au bouton correspondant.
Enfin, addForm.reset() réinitialise le formulaire afin de pouvoir enchaîner l’ajout d’un nouveau produit sans action supplémentaire de la part de l’utilisateur.


Suggestions de produits lors de la saisie
Le champ de saisie du nom de produit est enrichi d’un système de suggestions dynamiques permettant d’afficher, en temps réel, les modèles déjà existants en base de données. Cette fonctionnalité vise à faciliter la sélection d’un produit existant et accélérer la saisie pour l’utilisateur.
Le mécanisme repose sur un écouteur d’événement input appliqué à l’élément modelSearchInput. À chaque caractère saisi dans ce champ, la valeur courante est récupérée, nettoyée avec .trim(), puis utilisée pour déclencher une requête AJAX via fetch. Si la saisie comporte moins de deux caractères, aucune recherche n’est lancée et la liste de suggestions est masquée (modelSuggestions.style.display = "none").
Lorsque la condition est remplie (au moins deux caractères), la fonction envoie une requête GET à search_models.php, en passant le terme tapé dans l’URL (q=...). Le script PHP prépare alors une requête SQL de type LIKE sur la table models, afin de retrouver tous les modèles dont le nom contient la chaîne saisie.
Le fichier search_models.php ouvre la base de données SQLite, exécute la requête, puis renvoie les résultats sous forme de tableau JSON. Ces données sont récupérées côté JavaScript puis exploitées pour générer dynamiquement des éléments <li> correspondant à chaque suggestion. Chaque élément de la liste est interactif : un clic sur une suggestion remplit automatiquement le champ avec le nom du modèle sélectionné et masque la liste (modelSuggestions.style.display = "none").
Ce système améliore l’expérience utilisateur en réduisant les erreurs de saisie, en favorisant la réutilisation des modèles déjà présents en base. Il s’agit d’une fonctionnalité simple mais essentielle pour la cohérence des données et l’ergonomie de l’interface.


Réception d'un produit
Cette fonctionnalité permet de gérer la réception d’un produit livré en complétant les informations manquantes telles que le code-barres, le prix ou le poids, et en mettant à jour le produit concerné ainsi que, si nécessaire, son modèle de référence dans la base de données. Elle repose sur trois blocs principaux : l’affichage de la modale de livraison (en JavaScript), le traitement du formulaire avec requêtes AJAX, et la mise à jour d’un modele en PHP.
Affichage de la modale de livraison
La première étape se déroule lors de l’ouverture de la modale de livraison, déclenchée par la fonction openDeliveryModal(productRow). Cette fonction est appelée lorsqu’on souhaite traiter la réception d’un produit sélectionné dans le tableau. Elle commence par extraire les informations présentes dans la ligne HTML correspondant au produit : l’identifiant (via l’attribut data-id), le nom, la date de péremption actuelle, ainsi que le code-barres, le prix et le poids. Ces données sont ensuite utilisées pour remplir dynamiquement le contenu de la modale affichée à l’écran.
Une vérification est ensuite effectuée pour détecter les champs manquants ou incomplets. Si le code-barres est vide ou nul, ou si le prix ou le poids sont égaux à zéro, des champs de saisie sont automatiquement ajoutés à la modale (via des éléments <input> injectés dynamiquement) afin que l’utilisateur puisse compléter les informations nécessaires. La date de péremption est quant à elle préremplie avec la valeur existante. Un mécanisme de focus automatique est prévu pour placer le curseur dans le premier champ vide détecté, ou à défaut dans le champ de date, afin de guider l’utilisateur dans la saisie.
Cette première phase a donc pour objectif de préparer la correction ou la complétion du produit avant que celui-ci ne soit validé comme “reçu”.

Traitement du formulaire
Lors de la validation du formulaire de livraison (élément deliveryForm), un événement submit est intercepté et traité en JavaScript. Le processus commence par une vérification de la date saisie : la valeur du champ est d’abord nettoyée de tout caractère non numérique (comme les slashs ou espaces), puis transformée dans un format standardisé via la fonction normalizeDate(). Si cette conversion échoue et que la date est jugée invalide, un message d’erreur est immédiatement affiché et la validation est interrompue.
Une fois la date considérée comme valide, le script prépare une liste appelée updates[] qui recense tous les champs devant être mis à jour pour le produit concerné. Cette liste contient systématiquement la date de péremption (expiry_date) mais peut également inclure d’autres champs manquants renseignés par l’utilisateur, tels que le code-barres, le prix ou le poids.
Si l’un de ces champs manquants est renseigné au moment de la validation par exemple, un code-barres nouvellement saisi, une requête fetch() est envoyée en arrière-plan vers le fichier update_model_from_product.php. Ce mécanisme permet de synchroniser les informations au niveau du modèle associé à ce produit, en se basant sur le nom (name) comme clé d’identification. Une fois le modèle mis à jour avec la nouvelle donnée (comme le code-barres), le script parcourt ensuite toutes les lignes du tableau HTML représentant les produits et applique la nouvelle valeur à ceux partageant le même nom, assurant ainsi une cohérence visuelle et fonctionnelle dans l’interface.
Les mises à jour du produit sont ensuite réalisées de manière séquentielle grâce à une fonction récursive appelée updateNextField(index). Celle-ci envoie successivement les mises à jour listées dans updates[] via des requêtes fetch() adressées à update_product.php. Une fois que tous les champs ont été traités, le statut du produit est automatiquement mis à jour en “en stock”. Le tableau HTML est alors actualisé dynamiquement : la date de péremption, le code-barres et le statut visuel sont modifiés en conséquence. Des fonctions supplémentaires comme formatPriceAndWeightForRow(), updateRowStylesByDate() ou applyFilter() sont relancées pour rafraîchir l’affichage et garantir que les données soient correctement formatées et triées.
Enfin, si une tentative de mise à jour échoue parce qu’un produit identique existe déjà pour la même date (cas de doublon détecté côté serveur), la ligne correspondante est supprimée du tableau, la modale est refermée automatiquement et un message d’information temporaire est affiché à l’utilisateur.


Mise à jour d'un modèle
Le fichier update_model_from_product.php est appelé en backend chaque fois qu’un champ manquant est complété pour un produit via l’interface. Ce script PHP traite les requêtes envoyées en AJAX par le JavaScript afin de mettre à jour le modèle associé au produit concerné.
Le traitement commence par la vérification de l’existence d’un modèle correspondant, en se basant sur le champ name du produit. Si un modèle est bien identifié dans la base de données, le script met à jour le champ précisé dans la requête (qu’il s’agisse du code-barres, du prix ou du poids), en remplaçant la valeur existante par la nouvelle.
Une fois cette mise à jour effectuée sur le modèle, le script propage automatiquement cette modification à tous les produits enregistrés dans la base qui partagent le même nom. Cette synchronisation permet de garantir une cohérence entre le modèle de référence et ses déclinaisons en stock. Dans le cas où le champ modifié est le prix ou le poids, le script effectue également un recalcul du prix au kilo (price_per_kg) ainsi que du prix remisé à -30 % (discount_price), afin que toutes les informations dérivées restent à jour.

Résumé du fonctionnement
Lorsque l’utilisateur clique sur un produit à livrer, la modale de livraison s’ouvre automatiquement. Le système analyse alors les données du produit sélectionné et détecte les éventuels champs manquants, comme le code-barres, le prix ou le poids. Ces informations incomplètes sont immédiatement proposées à la saisie via des champs dynamiques dans l’interface.
Une fois le formulaire validé, la date de péremption ainsi que tous les champs renseignés sont mis à jour dans la base de données pour ce produit précis. Son statut est simultanément modifié pour passer à “en stock”. Si des données structurelles comme le code-barres, le poids ou le prix ont été complétées, elles sont également transmises au modèle de référence associé, puis propagées à l’ensemble des produits similaires portant le même nom.
L’interface du tableau HTML se met à jour dynamiquement sans nécessiter de rechargement de la page, garantissant une expérience fluide. L’ensemble du processus assure ainsi une gestion rigoureuse des livraisons, tout en maintenant l’uniformité des informations entre les produits et leurs modèles, et en limitant les risques de doublons ou d’incohérences dans la base de données.
Filtres
Les filtres d’affichage permettent à l’utilisateur de visualiser uniquement certains produits selon leur situation : périmés, bientôt périmés ou tous confondus. Le système repose sur des boutons radio qui déclenchent une mise à jour dynamique du tableau en fonction de la date de péremption et du statut du produit.
Lorsqu’un filtre est sélectionné, la fonction applyFilter() est appelée. Elle compare, pour chaque ligne du tableau, la date de péremption du produit avec la date du jour et celle un mois plus tard. La date est extraite depuis la cellule correspondante et convertie en objet Date afin de permettre les comparaisons. Le statut actuel est récupéré via un attribut data-current-status.
Si l’utilisateur choisit le filtre « bientôt périmé », seuls les produits dont la date de péremption est comprise entre aujourd’hui et un mois plus tard, et qui ne sont pas marqués “à venir”, restent visibles. Le filtre « périmés » affiche uniquement ceux dont la date est antérieure à aujourd’hui. Les lignes ne correspondant pas au critère sélectionné sont masquées.
Un appel initial à applyFilter() est également exécuté pour appliquer automatiquement un filtre par défaut dès le chargement de la page.

Modication d'un modèle
La modification d’un modèle permet de synchroniser automatiquement tous les produits qui lui sont associés, en assurant une cohérence immédiate entre les données de référence et les instances en stock. Cette fonctionnalité repose sur un traitement côté serveur en PHP, suivi d’un rafraîchissement du tableau via JavaScript.
Lorsque l’utilisateur valide une modification dans le formulaire dédié, une requête fetch() est envoyée à update_model.php. Ce script met à jour les informations du modèle dans la base de données (models) puis applique les mêmes valeurs (nom, code-barres, prix, poids, catégorie, type) à tous les produits ayant le même nom ou code-barres. Les champs dérivés comme le prix au kilo (price_per_kg) et le prix remisé à -30% (discount_price) sont ensuite recalculés pour chaque produit concerné.
Une fois la mise à jour terminée, un second appel AJAX recharge le tableau HTML des produits depuis reload_products.php. Le tableau est vidé puis reconstruit avec les données actualisées.



Planning du projet
La planification initiale définie dans le rapport de lancement a été modifiée en cours de stage. Des maquettes de l’interface étaient prévues afin d’anticiper l’ergonomie du site. Finalement, mon maître de stage et moi-même avons décidé de ne pas les réaliser, estimant qu’elles n’étaient pas nécessaires pour un projet centré sur un tableau de gestion, et dans lequel l’aspect graphique n’était pas prioritaire. Ce choix nous a permis de consacrer davantage de temps au développement fonctionnel.
Un autre ajustement a concerné l’importation des produits du magasin dans le site. Initialement prévue plus tôt, cette étape a été repoussée en fin de projet, afin de garantir que le site soit totalement opérationnel avant d’y intégrer l’ensemble des références. En cas de retard, cette décision permettait de prioriser le bon fonctionnement du système.
Je n’ai pas eu le temps de réaliser un tutoriel PDF expliquant le fonctionnement du site durant la période du stage. Cependant, travaillant également dans ce magasin, je prévois de le rédiger prochainement. Ce document servira de support pour l’équipe actuelle, mais pourra également être utile dans le cadre d’un éventuel déploiement du site dans d’autres magasins de l’enseigne en France.
Voici donc le planning des tâches réalisées au cours de ce stage :
SEMAINE | TÂCHES EFFECTUÉES |
---|---|
Semaine 1 | Observation des méthodes de gestion en place (support papier), échanges avec l’équipe pour identifier les besoins fonctionnels, recensement des fonctionnalités nécessaires au bon fonctionnement du site. Veille technologique sur les outils adaptés, les langages à utiliser et les éventuelles limitations de certaines technologies. |
Semaine 2-3 | Définition claire des fonctionnalités essentielles, découpage du projet en modules. Préparation de l’environnement de développement, création de l’arborescence des fichiers. Conception et création de la base de données SQLite ainsi que des scripts de lecture associés. Mise en place du tableau d’affichage des données et des premières modifications dynamiques sur certains champs. |
Semaine 4-5 | Développement de la page principale : gestions des champs éditables, gestion des statuts, ajout manuel de produits via un formulaire, gestion des dates de péremption et des statuts associés. |
Semaine 6-7 | Développement de la page des modèles : affichage du tableau, ajout de modèles via formulaire, intégration des suggestions dans le formulaire de la page produit, mise en place de la modification de produits sur les deux pages. |
Semaine 8-9 | Implémentation des barres de recherche, des filtres pour le tableau principal, des calculs dynamiques pour le prix et le poids. Vérification des doublons, affichage de messages d’erreur, contrôle global du bon fonctionnement des différentes fonctions. Mise en place du système de suppression automatique des produits indisponibles au bout de 3 mois. Tests globaux et corrections de bugs. |
Semaine 10-11 | Implémentation de la fonctionnalité de livraison, création de la fenêtre modale pour la modification de produits. Ajout des suggestions de produits "à venir". Propagation dynamique des modifications sur toutes les pages. Vérification de l’unicité des dates lors de l’ajout. |
Semaine 12 | Intégration complète du CSS. Ajout d’un bouton de suppression pour les produits. Adaptation responsive des deux pages. Vérification de la compatibilité tactile et configuration du pavé numérique pour les zones concernées. |
Semaine 13 | Tests globaux, corrections de bugs, prise en compte des retours de l’équipe pour améliorer l’ergonomie. Finalisation des derniers ajustements responsive. |
Semaine 14 | Ajout des produits du magasin et création des modèles de produits récurrents. Nettoyage du code et tests finaux. Hébergement du site. |
Analyse du projet
Points forts
Simplicité d'utilisation
L’interface du site a été conçue pour être la plus intuitive possible, même pour des utilisateurs sans compétences particulières en informatique. L’organisation sous forme de tableau facilite la lecture et la navigation, tandis que le choix des couleurs permet d’identifier rapidement les statuts des produits et les actions à réaliser. L’ensemble des fonctionnalités est accessible sans connaissance technique avancée, ce qui en fait un outil immédiatement exploitable par tous les membres de l’équipe.
Gain de temps significatif
L’un des objectifs principaux du projet était d’automatiser et d’accélérer la gestion des produits alimentaires. Cet objectif a été atteint : là où la consultation du carnet papier nécessitait une vérification manuelle page par page, il suffit désormais d’un simple coup d’œil pour identifier les produits concernés. Ce gain de temps permet à l’équipe de se recentrer sur ses tâches principales liées à la gestion du magasin, les produits alimentaires ne représentant qu’une petite partie de l’ensemble du stock.
Réduction des erreurs humaines
Le passage d’un système manuel à un système informatisé a permis de limiter les erreurs fréquentes comme les doublons, les oublis de produits ou les dates mal lisibles. Grâce aux contrôles intégrés, un produit avec une date de péremption identique ne peut pas être enregistré en double. La lisibilité est améliorée et le système de statuts permet de traiter rapidement toute anomalie ou oubli lors de la réception ou du suivi des produits.
Fonctionnalités pratiques intégrées
Plusieurs fonctionnalités ont été ajoutées pour optimiser l’usage quotidien du site. Le poids et le prix sont calculés automatiquement pour chaque produit, ce qui évite les calculs manuels, notamment pour les réductions ou l’affichage des prix au kilo. Il est également possible de scanner un code-barres pour retrouver un produit rapidement ou l’ajouter directement lors de sa réception. De plus, la modification d’un modèle de produit permet de mettre à jour automatiquement toutes les occurrences de ce produit, ce qui représente un gain de temps notable lors des ajustements de prix ou de caractéristiques.
Points d'amélioration
Optimisation de l'ergonomie et du responsive
Bien que le site soit déjà pensé pour une utilisation intuitive et qu’il fonctionne correctement sur différents types d’écrans, notamment tactiles, des améliorations peuvent toujours être envisagées. Il serait possible d’affiner encore certains détails ergonomiques pour gagner en clarté et en rapidité d’utilisation, notamment sur les supports mobiles. Des ajustements d’interface ou une refonte partielle de certains éléments pourraient améliorer davantage le confort de navigation.
Filtres plus avancés
Actuellement, les filtres permettent de cibler les produits selon leur statut de péremption (proches, périmés, etc.), ce qui constitue une fonctionnalité essentielle. Cependant, des filtres plus complets pourraient être ajoutés, comme la possibilité de trier les produits par catégories (ex. : “bonbons”, “thés”, etc.), ou encore de trier les colonnes (par ordre alphabétique, par date, par prix). Cela offrirait à l’utilisateur un contrôle plus fin sur l’affichage des données et permettrait une consultation encore plus rapide et ciblée.
Optimisation du code
Même si le projet fonctionne correctement et que le code a été relu à plusieurs reprises, sa structure pourrait encore être améliorée pour gagner en clarté, en maintenabilité et en performance. Certaines fonctions sont regroupées de manière peu cohérente ou répétées entre plusieurs fichiers, ce qui nuit à la lisibilité globale. Il serait pertinent de revoir l’organisation du code en séparant plus nettement les fonctions, la présentation et les interactions utilisateur. Une centralisation des fonctions redondantes, une normalisation du nommage des variables et une meilleure répartition des responsabilités dans les fichiers contribueraient à rendre le code plus propre.
Je suis conscient que le code produit n’est pas parfaitement structuré selon les standards professionnels. En tant qu’étudiant en cours de formation, certaines bonnes pratiques m’échappent encore, faute d’expérience et de recul suffisant. Toutefois, ce projet m’a justement permis de prendre conscience de l’importance de l’organisation du code et m’a aidé à progresser sur ces aspects. L’ajout de commentaires clairs dans les parties complexes et la rédaction d’une documentation technique sommaire permettraient également de faciliter la prise en main par un autre développeur. Ces améliorations seraient d’autant plus importantes si le projet devait être partagé ou maintenu à long terme par un tiers.
Actions correctives
Pendant le développement du projet, plusieurs bugs ont été identifiés et corrigés afin d’assurer un fonctionnement fiable et complet. Ces problèmes étaient ciblés et n’ont pas affecté globalement le projet.
Dynamisme des fonctions
Toutes les fonctions du projet ont été conçues pour être dynamiques, évitant ainsi le rechargement complet de la page à chaque modification dans les tableaux. Cependant, cette approche a parfois engendré des difficultés techniques.
Par exemple, lors de l’ajout d’un produit dans les modèles, les boutons d’action ne s’affichaient pas immédiatement. Pour résoudre ce problème, j’ai implémenté une solution consistant à insérer ces boutons au moment même de l’ajout, ce qui les rendait utilisables immédiatement. Lors du rechargement de la page, les boutons étaient alors correctement intégrés au code principal.
Un autre problème est survenu lors de la modification des dates dans le tableau des produits. La mise à jour dynamique ne reflétait pas immédiatement les changements, notamment pour l’affichage des statuts visuels (couleurs indiquant les produits périmés ou bientôt périmés). Pour corriger cela, j’ai amélioré la gestion AJAX afin que toutes les fonctions dépendantes de la date soient rappelées à chaque modification. Cette correction a introduit quelques doublons dans le code, mais a permis de résoudre efficacement le bug.
Utilisation de la scannette
Lors de l’utilisation de la scannette sur des formulaires contenant des boutons <submit>, la scannette validait automatiquement le formulaire dès qu’elle lisait un code, même si l’utilisateur n’avait pas terminé de remplir les autres champs. En effet, la scannette est reconnue comme un clavier par le système : elle saisit les caractères lus puis envoie automatiquement une touche « Entrée », ce qui déclenche la soumission du formulaire. Pour éviter ce comportement, j’ai intercepté l’événement « keydown » sur les champs nécessaires. Lorsque la touche « Entrée » est détectée, l’action par défaut est annulée, et le focus est déplacé vers le champ suivant du formulaire, simulant ainsi une touche « Tab ». Cela permet à l’utilisateur de remplir les champs un à un sans que le formulaire soit soumis prématurément.
Le code utilisé pour cela détecte la touche « Entrée » sur le formulaire, empêche son comportement par défaut, puis fait passer le focus au prochain élément interactif (input, select, textarea, bouton) non désactivé. Ainsi, la saisie avec la scannette est plus fluide et évite des erreurs dues à une validation anticipée.

Perspective d'évolution
Extension à d'autres magasins
Une évolution naturelle du projet serait son déploiement dans d’autres magasins de l’enseigne, en commençant par les points de vente français. Søstrene Grene compte actuellement environ 300 magasins dans le monde, dont 14 en France. À ce jour, chaque magasin gère les produits alimentaires selon ses propres méthodes, souvent encore manuelles, notamment à l’aide de carnets papier.
L’idée du projet est née d’échanges avec le manager, également maître de stage, qui constatait les limites de la gestion papier dans le magasin. Après plusieurs discussions sur ce sujet, il m’a proposé de réaliser un stage afin de commencer à développer une solution numérique adaptée. L’objectif initial était de tester ce projet au sein du magasin de Poitiers, avec la volonté claire de le déployer rapidement si les résultats étaient concluants. En plus de ses fonctions de manager, il est responsable de la maintenance informatique pour l’ensemble des magasins en France, ce qui lui permet d’avoir une vision globale des besoins et des possibilités d’extension.
Dans ce cadre, le site développé pourrait constituer une réponse concrète aux besoins communs des magasins en matière de gestion des produits alimentaires. Après une phase de test approfondie à Poitiers, l’objectif à court terme serait de dupliquer simplement le projet afin que chaque magasin français puisse disposer d’un outil personnalisé adapté à son stock local.
À moyen ou long terme, le projet serait transmis au service informatique centralisé situé au Danemark, où se trouve le siège de l’enseigne. Ce service pourrait alors professionnaliser, reprendre et intégrer officiellement la solution à l’échelle internationale.
Simplification de l'ajout des produits
Chaque semaine, nous recevons un bon de livraison listant tous les produits à venir pour la semaine suivante, classés par catégorie. Ce document contient des codes courts, qui sont des références produits correspondant à des codes-barres plus longs. Nous recevons ce bon de livraison au format PDF ainsi qu’en tableau Excel.
L’idée serait d’ajouter une fonctionnalité au site permettant d’importer directement ce bon de livraison. Celui-ci serait automatiquement converti en fichier CSV, puis analysé afin d’identifier tous les produits alimentaires et de les ajouter automatiquement dans le tableau avec le statut « à venir ».
Cela simplifierait grandement l’ajout des produits à venir, tout en réduisant les erreurs humaines liées à la saisie manuelle. Pour que cette fonctionnalité fonctionne correctement, il serait nécessaire d’associer à chaque produit une nouvelle donnée correspondant au code court, afin de retrouver facilement les produits dans les modèles existants ou de les ajouter automatiquement s’ils n’existent pas encore.
Produits oubliés
Il peut arriver, à cause d’une erreur humaine, qu’un produit prévu à la livraison soit oublié lors de son ajout dans le tableau. Actuellement, cette omission est détectée uniquement lors de la réception des produits. Si une ligne manque dans le tableau, il faut alors ajouter manuellement le produit, ainsi que modifier sa date de péremption et son statut, ce qui peut entraîner des erreurs, même mineures.
Pour simplifier la gestion de ce type d’erreur, il serait utile de mettre en place une fonctionnalité spécifique. Lorsqu’un produit est scanné ou recherché par son nom et qu’il ne figure pas dans la liste des produits à venir, une fenêtre modale s’ouvrirait automatiquement.
Si le produit existe dans les modèles, la fenêtre proposerait de l’ajouter directement dans le tableau, en demandant la date de péremption. Le produit serait alors ajouté avec le statut « en stock ».
Si le produit n’existe pas dans les modèles, la fenêtre inviterait à saisir les informations nécessaires pour créer ce nouveau produit, avec la possibilité de l’ajouter aux modèles. Ensuite, comme précédemment, la date de péremption serait demandée et le produit serait ajouté au tableau avec le statut « en stock ».
Cette fonctionnalité permettrait de gagner du temps et de limiter les erreurs en évitant l’ajout manuel fastidieux, tout en maintenant un flux fluide lors de la réception et de l’enregistrement des produits.
Bilan personnel
J’ai essentiellement travaillé de façon indépendante, ce qui m’a permis de renforcer mes compétences en gestion de projet, développement web, ainsi qu’en résolution de problèmes techniques. Ce stage m’a donné l’opportunité d’approfondir mes connaissances en PHP et en gestion de bases de données. J’ai également découvert de nouvelles approches pour optimiser mon code, même si celui-ci reste perfectible. Par ailleurs, j’ai pu appliquer mes acquis en ergonomie, domaine qui m’intéresse particulièrement, notamment en ce qui concerne l’expérience utilisateur. Ce projet était d’autant plus pertinent qu’il est destiné à un usage professionnel par plusieurs personnes.
Ma relation avec mon maître de stage a été constructive et positive. Il s’est montré disponible tout au long du projet, avec des points hebdomadaires pour faire le suivi de l’avancement, définir les prochaines étapes, et me conseiller sur les technologies et les méthodes à adopter. En tant que manager du magasin, il ne pouvait pas toujours être présent, ce qui m’a conduit à travailler principalement en autonomie. Cependant, il restait accessible dès que j’avais une question ou un doute.
Travaillant déjà dans l’entreprise comme conseiller de vente, mon intégration s’est faite naturellement. Plusieurs employés se sont également investis pour me fournir des retours sur le projet et des suggestions afin d’améliorer l’ergonomie et l’utilisation du site.
Habitué à m’organiser seul lors de travaux académiques, j’ai trouvé bénéfique d’être encadré par un maître de stage qui orientait la planification des tâches. Cela m’a aidé à me concentrer davantage sur le projet sans dispersion, à développer ma rigueur, et à apprendre à ne pas passer à autre chose avant d’avoir achevé une tâche. Cette expérience a été enrichissante, me permettant d’exploiter mes compétences dans un contexte concret et de progresser dans mes apprentissages tout en évoluant hors du cadre universitaire.