Ajouter un champ date de livraison dans les commandes PrestaShop
Guide complet pour ajouter et modifier une date de livraison par produit dans le détail des commandes PrestaShop via AJAX. Code, SQL et bonnes pratiques.
En bref : Guide complet pour ajouter un champ date de livraison éditable par produit dans les commandes PrestaShop, avec table SQL dédiée, traitement AJAX sécurisé et approche module compatible 1.7 et 8.x.
Pourquoi ajouter une date de livraison par produit dans PrestaShop
Par défaut, PrestaShop gère un transporteur et une date d'expédition globale par commande, mais aucune date de livraison individuelle par ligne de produit. C'est un besoin fréquent pour les marchands qui vendent des produits avec des délais de livraison différents (meubles sur-mesure, produits frais, précommandes…).
L'objectif de ce guide est d'ajouter un champ date de livraison éditable directement dans la vue détail d'une commande en back-office, avec mise à jour en temps réel via AJAX — sans rechargement de page.
Architecture de la solution
La mise en place repose sur trois briques :
- **Une table SQL dédiée** pour stocker la date de livraison par ligne de commande
- **Un traitement AJAX côté contrôleur** pour recevoir et enregistrer la modification
- **Un champ date dans le template** de la vue commande avec le JavaScript associé
- **Testez la valeur JavaScript** — Remplacez temporairement la valeur dynamique par une chaîne fixe (`var DateLiv = "ok"`) et vérifiez que le contrôleur la reçoit
- **Vérifiez la console réseau** — Ouvrez l'onglet Network (XHR) de votre navigateur et inspectez la requête AJAX : URL, paramètres, réponse
- **Vérifiez le cache** — PrestaShop met en cache les fichiers JS. Faites `Ctrl+F5` ou videz le cache dans Paramètres avancés > Performances
- **Ajoutez un var_dump temporaire** — Dans votre méthode PHP, faites `var_dump(Tools::getValue('date_liv')); die();` pour confirmer la réception du paramètre
- **Vérifiez le sélecteur jQuery** — La cause n°1 d'un `undefined` est un sélecteur CSS qui ne correspond pas à la structure HTML réelle
Bonne pratique PrestaShop 8.x : Encapsulez toute cette logique dans un module plutôt que de modifier le cœur. Utilisez les hooks
displayAdminOrderTabContentetactionValidateOrderpour rester compatible avec les mises à jour.
Étape 1 : Créer la table SQL
Commencez par créer une table qui lie chaque ligne de commande (id_order_detail) à une date de livraison :
CREATE TABLE IF NOT EXISTS `ps_order_date_liv` (
`id_order_date_liv` INT(11) UNSIGNED NOT NULL AUTO_INCREMENT,
`id_order_detail` INT(11) UNSIGNED NOT NULL,
`date` DATE DEFAULT NULL,
`date_add` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
`date_upd` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id_order_date_liv`),
KEY `idx_order_detail` (`id_order_detail`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Placez cette requête dans la méthode install() de votre module pour qu'elle s'exécute automatiquement.
Étape 2 : Initialiser la date à la validation de commande
Utilisez le hook actionValidateOrder pour insérer automatiquement une ligne par produit commandé. Cela vous permet de pré-remplir la date à partir d'un champ personnalisé du produit si besoin :
public function hookActionValidateOrder($params)
{
$order = $params['order'];
$orderDetails = $order->getOrderDetailList();
foreach ($orderDetails as $detail) {
// Optionnel : récupérer une date prévisionnelle depuis le produit
$product = new Product((int) $detail['product_id']);
$dateLiv = Validate::isDate($product->available_date)
? $product->available_date
: null;
Db::getInstance()->insert('order_date_liv', [
'id_order_detail' => (int) $detail['id_order_detail'],
'date' => $dateLiv ? pSQL($dateLiv) : null,
]);
}
}
Étape 3 : Afficher le champ dans la vue commande
PrestaShop 1.7
Sur PrestaShop 1.7, le template de la vue commande se trouve dans admin-dev/themes/default/template/controllers/orders/helpers/view/. Vous pouvez overrider le template pour y ajouter une colonne dans le tableau des produits :
<td class="dateLiv">
<input type="date"
class="form-control input-date-liv"
value="{$detail.date_liv|default:''}"
data-id-order-detail="{$detail.id_order_detail}" />
</td>
PrestaShop 8.x (Symfony)
Sur PrestaShop 8.x, la page commande est entièrement portée sous Symfony. Privilégiez le hook displayAdminOrderTabContent pour injecter votre interface sans toucher au cœur :
public function hookDisplayAdminOrderTabContent($params)
{
$orderId = $params['id_order'];
$order = new Order((int) $orderId);
$orderDetails = $order->getOrderDetailList();
$datesLiv = [];
foreach ($orderDetails as $detail) {
$row = Db::getInstance()->getRow(
'SELECT `date` FROM `' . _DB_PREFIX_ . 'order_date_liv`
WHERE `id_order_detail` = ' . (int) $detail['id_order_detail']
);
$datesLiv[$detail['id_order_detail']] = $row ? $row['date'] : '';
}
$this->context->smarty->assign([
'orderDetails' => $orderDetails,
'datesLiv' => $datesLiv,
]);
return $this->display(__FILE__, 'views/templates/admin/date_livraison.tpl');
}
Étape 4 : Le JavaScript AJAX
Le JavaScript écoute les changements sur les champs date et envoie la nouvelle valeur au contrôleur en AJAX :
$(document).on('change', '.input-date-liv', function () {
var $input = $(this);
var idOrderDetail = $input.data('id-order-detail');
var dateLiv = $input.val();
var token = window.prestashop && window.prestashop.modules
? window.prestashop.modules.currentToken
: token; // PS 1.7 fallback
if (!idOrderDetail || !dateLiv) {
return;
}
$.ajax({
url: currentIndex,
type: 'POST',
dataType: 'json',
data: {
ajax: 1,
action: 'updateDateLivProd',
token: token,
id_order_detail: idOrderDetail,
date_liv: dateLiv
},
success: function (response) {
if (response.success) {
showSuccessMessage('Date de livraison mise à jour');
} else {
showErrorMessage('Erreur lors de la mise à jour');
}
},
error: function () {
showErrorMessage('Erreur de communication avec le serveur');
}
});
});
Point d'attention : Assurez-vous que votre Une requête SQL construite par concaténation directe expose votre boutique à des injections SQL : Utilisez toujours les méthodes Voici la structure recommandée pour un module propre : En PrestaShop 8.x, si vous souhaitez ajouter un contrôleur AJAX propre plutôt que surcharger Si votre appel AJAX ne fonctionne pas, procédez par élimination : Tout ce que vous devez savoir sur ce sujet. Un projet PrestaShop ? Discutons-en directement. 193 projets livrés 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. input se trouve bien dans un élément lui-même dans un . Si la structure HTML ne correspond pas au sélecteur jQuery, vous obtiendrez undefined en retour — c'est l'erreur la plus fréquente dans ce type d'implémentation.
Étape 5 : Le traitement côté contrôleur
Version sécurisée (à utiliser en production)
public function ajaxProcessUpdateDateLivProd()
{
$idOrderDetail = (int) Tools::getValue('id_order_detail');
$dateLiv = Tools::getValue('date_liv');
// Validation des entrées
if (!$idOrderDetail || !Validate::isDate($dateLiv)) {
die(json_encode([
'success' => false,
'message' => 'Paramètres invalides',
]));
}
// Vérifier que la ligne de commande existe
$orderDetail = new OrderDetail($idOrderDetail);
if (!Validate::isLoadedObject($orderDetail)) {
die(json_encode([
'success' => false,
'message' => 'Ligne de commande introuvable',
]));
}
$result = Db::getInstance()->update(
'order_date_liv',
['date' => pSQL($dateLiv)],
'id_order_detail = ' . $idOrderDetail
);
die(json_encode([
'success' => (bool) $result,
'message' => $result ? 'Date mise à jour' : 'Échec de la mise à jour',
]));
}
Ce qui ne va pas dans une approche naïve
// ❌ DANGEREUX — Ne jamais faire ça
$sql = 'UPDATE `' . _DB_PREFIX_ . 'order_date_liv` SET Date = ' . $date_liv . ' WHERE id_order_detail = ' . $id_order_detail;
Db::getInstance()->update() ou au minimum pSQL() et le cast (int) pour protéger vos requêtes.Étape 6 : Approche module complet (recommandée)
my_deliverydate/
├── my_deliverydate.php # Classe principale + hooks
├── sql/
│ ├── install.sql # CREATE TABLE
│ └── uninstall.sql # DROP TABLE
├── views/
│ ├── templates/
│ │ └── admin/
│ │ └── date_livraison.tpl
│ └── js/
│ └── admin-order.js # AJAX
└── controllers/
└── admin/
└── AdminDeliveryDateController.php # PS 8.x
AdminOrdersController, déclarez-le comme service Symfony dans votre module :
# my_deliverydate/config/routes.yml
my_deliverydate_update_date:
path: /my-deliverydate/update
methods: [POST]
defaults:
_controller: 'MyModule\Controller\Admin\DeliveryDateController::updateAction'
Déboguer l'AJAX : méthodologie pas à pas
Récapitulatif des points critiques
Point Détail Sécurité SQL Toujours utiliser `pSQL()` et `(int)` — jamais de concaténation directe Validation Vérifier `Validate::isDate()` avant toute insertion Cache JS Vider le cache navigateur ET le cache PrestaShop après modification Structure HTML Les sélecteurs jQuery doivent correspondre exactement aux classes CSS Réponse JSON Toujours retourner du JSON structuré avec un champ `success` Module vs override Privilégier un module avec hooks pour la maintenabilité Questions fréquentes
Lire sur le blog
