Ajouter un champ date personnalisé aux détails de commande PrestaShop
Guide complet pour ajouter une date de livraison aux lignes de commande PrestaShop : override OrderDetail, requêtes SQL, AJAX et bonnes pratiques ObjectModel.
En bref : Pour ajouter une date personnalisée aux lignes de commande PrestaShop, ajoutez une colonne à ps_order_detail, créez un override d'OrderDetail pour déclarer le champ dans l'ObjectModel, puis mettez à jour via AJAX avec instanciation propre de l'objet et casting systématique des identifiants en (int).
Pourquoi ajouter une date personnalisée aux lignes de commande ?
Dans de nombreux contextes e-commerce — livraison planifiée, production sur-mesure, précommande — il est indispensable d'associer une date spécifique à chaque ligne de commande (et non à la commande globale). PrestaShop ne propose pas cette fonctionnalité nativement : la table ps_order_detail ne contient aucun champ de date personnalisable.
Cet article détaille la méthode propre pour ajouter un champ date_livraison aux détails de commande, avec mise à jour via AJAX depuis le back-office.
Étape 1 : Ajouter la colonne en base de données
Avant toute chose, on ajoute le champ dans la table ps_order_detail :
ALTER TABLE `ps_order_detail`
ADD COLUMN `date_livraison` DATETIME NULL DEFAULT NULL
AFTER `product_quantity`;
Pourquoi ne pas créer une table séparée ? Sauf besoin d'historiser les changements de date, ajouter un champ directement dans ps_order_detail est plus simple et plus performant. Une table séparée n'est justifiée que si vous devez conserver un journal des modifications (audit trail).
PrestaShop 8.x : La structure de
ps_order_detailest identique. Cette requête fonctionne sur toutes les versions 1.7+ et 8.x.
Étape 2 : Override de la classe OrderDetail
Pour que PrestaShop reconnaisse le nouveau champ via son ORM (ObjectModel), il faut créer un override :
Fichier : override/classes/order/OrderDetail.php
<?php
/**
* Override OrderDetail — Ajout du champ date_livraison
*/
class OrderDetail extends OrderDetailCore
{
/** @var string Date de livraison prévue */
public $date_livraison;
public function __construct($id = null, $id_lang = null, $context = null)
{
// Déclaration du champ AVANT l'appel au constructeur parent
self::$definition['fields']['date_livraison'] = [
'type' => self::TYPE_DATE,
'validate' => 'isDate',
];
parent::__construct($id, $id_lang, $context);
}
}
Point critique : après avoir créé cet override, supprimez le fichier var/cache/dev/class_index.php et var/cache/prod/class_index.php (ou cache/class_index.php en 1.7) pour forcer PrestaShop à recharger l'index des classes.
rm -f var/cache/dev/class_index.php var/cache/prod/class_index.php
PrestaShop 8.x : Le système d'override fonctionne toujours, mais Symfony encourage les décorateurs de service pour les classes injectées.
OrderDetailétant un ObjectModel legacy, l'override reste la méthode recommandée.
Étape 3 : Mise à jour via ObjectModel (la bonne méthode)
Une erreur fréquente consiste à écrire des requêtes SQL brutes (INSERT INTO, UPDATE) pour modifier les données. PrestaShop fournit un ORM natif — utilisez-le :
// Récupérer tous les détails d'une commande
$orderDetails = Db::getInstance()->executeS(
'SELECT `id_order_detail`
FROM `' . _DB_PREFIX_ . 'order_detail`
WHERE `id_order` = ' . (int) $idOrder
);
// Mettre à jour la date sur chaque ligne
foreach ($orderDetails as $row) {
$detail = new OrderDetail((int) $row['id_order_detail']);
$detail->date_livraison = pSQL($dateLivraison); // Format: 'Y-m-d H:i:s'
$detail->update();
}
Pourquoi ObjectModel plutôt que du SQL brut ?
Pour des mises à jour massives (centaines de lignes), le SQL direct avec pSQL() reste acceptable. Pour le back-office classique, ObjectModel est la voie propre.
Étape 4 : Appel AJAX depuis le back-office
Côté JavaScript, dans le template de la page commande :
document.getElementById('btn-save-date').addEventListener('click', function () {
const idOrder = parseInt(document.getElementById('id_order').value, 10);
const dateLiv = document.getElementById('date_livraison').value;
if (!idOrder || !dateLiv) {
console.error('ID commande ou date manquante');
return;
}
fetch(ajaxUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
ajax: 1,
action: 'updateDateLivraison',
id_order: idOrder,
date_livraison: dateLiv,
}),
})
.then(response => response.json())
.then(data => {
if (data.success) {
// Feedback visuel
alert('Date enregistrée');
}
})
.catch(err => console.error('Erreur AJAX:', err));
});
Pièges courants de l'appel AJAX
- **`console.log(id_order)` en premier** — Toujours vérifier que la valeur est bien récupérée avant d'envoyer la requête.
- **Vérifier le type** — `id_order` doit être un entier. Si vous récupérez une chaîne depuis le DOM, castez-la avec `parseInt()` côté JS et `(int)` côté PHP.
- **Format de date** — MySQL attend `Y-m-d H:i:s`. Un datepicker HTML5 renvoie `Y-m-d` : ajoutez ` 00:00:00` si nécessaire.
- **`getValue` vs `executeS`** : `getValue` retourne une seule valeur. Pour récupérer plusieurs lignes (une commande a potentiellement plusieurs produits), utilisez `executeS` qui retourne un tableau.
- **Le `return` dans le `foreach`** : une erreur classique consiste à placer le traitement SQL en dehors de la boucle. La requête ne s'exécute alors que pour la dernière ligne. Chaque itération doit traiter sa propre ligne.
- **Casting `(int)`** : indispensable pour tout identifiant passé dans une requête SQL. Sans cela, vous envoyez une chaîne là où la base attend un entier, ce qui provoque des erreurs silencieuses.
- Historiser chaque modification de date (qui a changé quoi, quand)
- Stocker plusieurs dates par ligne (date prévue, date réelle, date reportée)
- Ajouter des métadonnées complexes (commentaire, statut de livraison)
- L'`id` primaire est en **auto-increment**
- Vous créez une classe ObjectModel complète (pas du SQL brut)
- Un index existe sur `id_order_detail` pour les performances de jointure
Étape 5 : Traitement côté contrôleur
Dans votre module ou contrôleur admin :
public function ajaxProcessUpdateDateLivraison()
{
$idOrder = (int) Tools::getValue('id_order');
$dateLivraison = pSQL(Tools::getValue('date_livraison'));
if (!$idOrder || !Validate::isDate($dateLivraison)) {
die(json_encode(['success' => false, 'error' => 'Paramètres invalides']));
}
$orderDetails = Db::getInstance()->executeS(
'SELECT `id_order_detail`
FROM `' . _DB_PREFIX_ . 'order_detail`
WHERE `id_order` = ' . $idOrder
);
foreach ($orderDetails as $row) {
$detail = new OrderDetail((int) $row['id_order_detail']);
$detail->date_livraison = $dateLivraison;
$detail->update();
}
die(json_encode(['success' => true]));
}
Points d'attention
Techniques de débogage essentielles
Quand une requête ne fonctionne pas, voici la méthodologie systématique :
1. Vérifier les variables avec var_dump
foreach ($orderDetails as $row) {
var_dump($row['id_order_detail']); // Vérifier le type et la valeur
echo '<br/>';
var_dump($dateLivraison); // Vérifier le format de date
die(); // Arrêter après la première itération
}
2. Tester la requête dans phpMyAdmin
Avant d'encapsuler une requête en PHP, testez-la en SQL pur :
UPDATE ps_order_detail
SET date_livraison = '2026-03-15 00:00:00'
WHERE id_order_detail = 285;
phpMyAdmin vous indiquera immédiatement si le nom de colonne est incorrect, si le type est incompatible, ou si une contrainte bloque l'opération.
3. Vérifier le retour de la requête
$result = Db::getInstance()->execute($sql);
var_dump($result); // true = succès, false = erreur SQL
die();
Erreurs fréquentes et solutions
Bonne pratique : faut-il une table séparée ?
Si votre besoin est simplement de stocker une date par ligne de commande, ajoutez un champ à ps_order_detail avec un override. C'est simple, performant et maintenable.
En revanche, si vous devez :
Alors créez une table dédiée avec son propre ObjectModel. Dans ce cas, assurez-vous que :
Questions fréquentes
Tout ce que vous devez savoir sur ce sujet.
Un projet PrestaShop ?
Discutons-en directement.
193 projets livrés
Lire sur le blog

Alexandre Carette
Expert PrestaShop & Architecture E-commerce
Développeur PrestaShop depuis 2014, 193 projets livrés. Je conçois des architectures headless Nuxt + PrestaShop et des outils d'automatisation IA pour les e-commerçants.