[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":22,"$fUE6A1pkUjNiN74Pxa2x_wS7MFpNgO1ecYhnN8mE4-tk":103,"megamenu":141,"footer-db":197,"header-db":215,"$f9LP92AyTIGaoQCkpWPW75MciIYfW0YKYdl7mGzbRqaM":226},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"columns":23},[24,40,70,91],{"title":25,"links":26},"Plateforme",[27,31,34,37],{"label":28,"href":29,"external":30},"Offre Starter (2 500 €)","\u002Foffre-starter",false,{"label":32,"href":33,"external":30},"Devenir Ambassadeur","\u002Fambassadeur",{"label":35,"href":36,"external":30},"Modules PrestaShop","\u002Fmodules",{"label":38,"href":39,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":41,"links":42},"Le Synedre",[43,46,49,52,55,58,61,64,67],{"label":44,"href":45,"external":30},"L'histoire","\u002Fsynedre",{"label":47,"href":48,"external":30},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":50,"href":51,"external":30},"L'équipe","\u002Fequipe",{"label":53,"href":54,"external":30},"Le réacteur en direct","\u002Freacteur",{"label":56,"href":57,"external":30},"Le Drill (entraînement)","\u002Fdrill",{"label":59,"href":60,"external":30},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":62,"href":63,"external":30},"Les agents IA","\u002Fagents-ia",{"label":65,"href":66,"external":30},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":68,"href":69,"external":30},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":71,"links":72},"Ressources",[73,76,79,82,85,88],{"label":74,"href":75,"external":30},"Blog","\u002Fblog",{"label":77,"href":78,"external":30},"Academy","\u002Facademy",{"label":80,"href":81,"external":30},"Dictionnaire","\u002Fdictionnaire",{"label":83,"href":84,"external":30},"Expertise PrestaShop","\u002Fexpertise",{"label":86,"href":87,"external":30},"Flywheel","\u002Fflywheel",{"label":89,"href":90,"external":30},"Manifeste","\u002Fmanifeste",{"title":92,"links":93},"À propos",[94,97,100],{"label":95,"href":96,"external":30},"Alexandre Carette","\u002Fa-propos",{"label":98,"href":99,"external":30},"Dossier de presse","\u002Fpresse",{"label":101,"href":102,"external":30},"Contact","\u002Fcontact",{"title":104,"slug":105,"metaDescription":106,"category":107,"tags":108,"difficulty":115,"psVersions":116,"content":119,"faq":120,"tldr":136,"readingTime":137,"generatedAt":138,"publishDate":138,"relatedArticles":139,"sourceCategory":140},"Afficher delivery_out_stock dans le panier PrestaShop","afficher-delivery-out-stock-panier-prestashop","Comment ajouter et afficher la variable delivery_out_stock dans le panier PrestaShop. Override Cart.php, requête SQL et piège classique des langues.","developpement",[109,110,111,112,113,114],"override","cart","delivery_out_stock","smarty","product_lang","langues","intermediaire",[117,118],"1.7","8.x","\u003Ch2>Le besoin : afficher le délai de livraison hors stock dans le panier\u003C\u002Fh2>\n\u003Cp>Par défaut, PrestaShop stocke deux informations de livraison pour chaque produit : le délai en stock (\u003Ccode>delivery_in_stock\u003C\u002Fcode>) et le délai hors stock (\u003Ccode>delivery_out_stock\u003C\u002Fcode>). Ces champs sont enregistrés dans la table \u003Ccode>ps_product_lang\u003C\u002Fcode> car ils sont traduisibles.\u003C\u002Fp>\n\u003Cp>Sur la fiche produit, ces informations s'affichent nativement. En revanche, \u003Cstrong>dans le panier, la variable \u003Ccode>{$product.delivery_out_stock}\u003C\u002Fcode> n'est pas disponible par défaut\u003C\u002Fstrong>. Pour l'exposer, il faut intervenir sur la classe \u003Ccode>Cart\u003C\u002Fcode> via un override.\u003C\u002Fp>\n\u003Ch2>Étape 1 : créer l'override de Cart.php\u003C\u002Fh2>\n\u003Cp>La méthode à surcharger est \u003Ccode>getProducts()\u003C\u002Fcode>, qui construit la requête SQL récupérant les produits du panier. Il faut y ajouter le champ \u003Ccode>delivery_out_stock\u003C\u002Fcode> dans le \u003Ccode>SELECT\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Créez le fichier \u003Ccode>override\u002Fclasses\u002FCart.php\u003C\u002Fcode> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n&lt;?php\n\u002F**\n * @author Alexandre Carette &lt;contact@alexandrecarette.fr&gt;\n * @copyright 2026 Alexandre Carette\n * @license Propriétaire et Confidentiel\n *\u002F\n\nclass Cart extends CartCore\n{\n    public function getProducts($refresh = false, $id_product = false, $id_country = null, $fullInfos = true)\n    {\n        \u002F\u002F Appel de la méthode parente\n        $products = parent::getProducts($refresh, $id_product, $id_country, $fullInfos);\n\n        if (!empty($products)) {\n            foreach ($products as &$product) {\n                \u002F\u002F Récupération du champ delivery_out_stock depuis product_lang\n                $delivery = Db::getInstance()-&gt;getValue(\n                    'SELECT `delivery_out_stock`\n                     FROM `' . _DB_PREFIX_ . 'product_lang`\n                     WHERE `id_product` = ' . (int) $product['id_product'] . '\n                     AND `id_lang` = ' . (int) $this-&gt;id_lang . '\n                     AND `id_shop` = ' . (int) Context::getContext()-&gt;shop-&gt;id\n                );\n                $product['delivery_out_stock'] = $delivery ?: '';\n            }\n        }\n\n        return $products;\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cblockquote>\u003Cp>\u003Cstrong>PrestaShop 8.x\u003C\u002Fstrong> : le mécanisme d'override reste fonctionnel mais Symfony encourage les décorateurs de service. Pour un champ simple comme celui-ci, l'override reste la solution la plus pragmatique.\u003C\u002Fp>\u003C\u002Fblockquote>\n\u003Cp>Après création du fichier, \u003Cstrong>supprimez le cache des classes\u003C\u002Fstrong> :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-bash\">\nrm var\u002Fcache\u002Fprod\u002Fclass_index.php\nrm var\u002Fcache\u002Fdev\u002Fclass_index.php\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Étape 2 : utiliser la variable dans le template du panier\u003C\u002Fh2>\n\u003Cp>Une fois l'override en place, la variable est accessible dans les templates Smarty du panier :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-smarty\">\n{if $product.delivery_out_stock}\n    &lt;span class=\"delivery-out-stock\"&gt;\n        {$product.delivery_out_stock}\n    &lt;\u002Fspan&gt;\n{\u002Fif}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Le fichier à modifier dépend de votre thème. Dans le thème classic, c'est typiquement :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-\">\nthemes\u002Fvotre-theme\u002Ftemplates\u002Fcheckout\u002F_partials\u002Fcart-detailed-product-line.tpl\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Le piège classique : l'id_lang incorrect\u003C\u002Fh2>\n\u003Cp>C'est \u003Cstrong>le problème le plus fréquent\u003C\u002Fstrong> lors de cet override, et il est particulièrement vicieux : la variable reste vide alors que le code semble correct.\u003C\u002Fp>\n\u003Ch3>Pourquoi ça arrive\u003C\u002Fh3>\n\u003Cp>La table \u003Ccode>ps_product_lang\u003C\u002Fcode> stocke les traductions avec un \u003Ccode>id_lang\u003C\u002Fcode>. Si votre requête SQL utilise un \u003Ccode>id_lang\u003C\u002Fcode> qui ne correspond pas à celui où le contenu a été saisi, le résultat sera vide.\u003C\u002Fp>\n\u003Cp>Ce décalage survient typiquement quand :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**Plusieurs langues sont installées** mais le contenu n'est rempli que dans une seule\u003C\u002Fli>\n\u003Cli>**L'id_lang par défaut n'est pas 1** — sur certaines installations, le français peut être `id_lang = 2` ou `3` selon l'historique d'installation\u003C\u002Fli>\n\u003Cli>**La langue active du contexte** ne correspond pas à celle attendue dans la jointure SQL\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch3>Comment diagnostiquer\u003C\u002Fh3>\n\u003Cp>Pour vérifier quel \u003Ccode>id_lang\u003C\u002Fcode> est utilisé dans votre contexte :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Dans votre override, temporairement :\nerror_log('Cart id_lang: ' . $this-&gt;id_lang);\nerror_log('Context id_lang: ' . Context::getContext()-&gt;language-&gt;id);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Puis vérifiez en base quelles langues contiennent effectivement la donnée :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\nSELECT id_lang, delivery_out_stock\nFROM ps_product_lang\nWHERE id_product = 123;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>Si le champ est vide pour certaines langues, c'est la source du problème.\u003C\u002Fp>\n\u003Ch3>La solution\u003C\u002Fh3>\n\u003Cp>Deux approches :\u003C\u002Fp>\n\u003Col>\n\u003Cli>**Remplir le champ pour toutes les langues actives** dans le back-office (Catalogue > Produits > onglet Livraison). C'est la solution propre.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Col>\n\u003Cli>**Forcer un fallback** dans le code si le champ est vide pour la langue courante :\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cpre>\u003Ccode class=\"language-php\">\n$delivery = Db::getInstance()-&gt;getValue(\n    'SELECT `delivery_out_stock`\n     FROM `' . _DB_PREFIX_ . 'product_lang`\n     WHERE `id_product` = ' . (int) $product['id_product'] . '\n     AND `id_lang` = ' . (int) $this-&gt;id_lang . '\n     AND `id_shop` = ' . (int) Context::getContext()-&gt;shop-&gt;id\n);\n\n\u002F\u002F Fallback : langue par défaut si vide\nif (empty($delivery)) {\n    $delivery = Db::getInstance()-&gt;getValue(\n        'SELECT `delivery_out_stock`\n         FROM `' . _DB_PREFIX_ . 'product_lang`\n         WHERE `id_product` = ' . (int) $product['id_product'] . '\n         AND `id_lang` = ' . (int) Configuration::get('PS_LANG_DEFAULT') . '\n         AND `id_shop` = ' . (int) Context::getContext()-&gt;shop-&gt;id\n    );\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Approche alternative : modifier directement la requête SQL de getProducts\u003C\u002Fh2>\n\u003Cp>Si vous préférez éviter les requêtes supplémentaires dans une boucle, vous pouvez copier intégralement la méthode \u003Ccode>getProducts()\u003C\u002Fcode> dans votre override et ajouter \u003Ccode>pl.delivery_out_stock\u003C\u002Fcode> dans le \u003Ccode>SELECT\u003C\u002Fcode> de la requête principale.\u003C\u002Fp>\n\u003Cp>Cette approche est plus performante (une seule requête au lieu de N+1) mais plus fragile : chaque mise à jour de PrestaShop risque de modifier la méthode originale, rendant votre override obsolète.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Dans la requête SQL de getProducts(), ajoutez dans le SELECT :\n\u002F\u002F pl.delivery_out_stock,\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Conseil\u003C\u002Fstrong> : si vous choisissez cette voie, documentez la version de PrestaShop sur laquelle l'override a été créé pour faciliter la maintenance lors des mises à jour.\u003C\u002Fp>\n\u003Ch2>Vérification en base de données\u003C\u002Fh2>\n\u003Cp>Avant de toucher au code, vérifiez toujours que vos données sont cohérentes :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-sql\">\n-- Vérifier les langues actives\nSELECT id_lang, iso_code, name, active\nFROM ps_lang\nWHERE active = 1;\n\n-- Vérifier que delivery_out_stock est rempli pour toutes les langues\nSELECT pl.id_product, pl.id_lang, l.iso_code, pl.delivery_out_stock\nFROM ps_product_lang pl\nJOIN ps_lang l ON l.id_lang = pl.id_lang\nWHERE pl.id_product = 123\nORDER BY pl.id_lang;\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Récapitulatif des fichiers impactés\u003C\u002Fh2>\n\u003Ctr>\u003Cth>Fichier\u003C\u002Fth>\u003Cth>Action\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`override\u002Fclasses\u002FCart.php`\u003C\u002Fth>\u003Cth>Ajout du champ `delivery_out_stock`\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`themes\u002Fvotre-theme\u002Ftemplates\u002Fcheckout\u002F_partials\u002Fcart-detailed-product-line.tpl`\u003C\u002Fth>\u003Cth>Affichage de la variable\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>`var\u002Fcache\u002F*\u002Fclass_index.php`\u003C\u002Fth>\u003Cth>À supprimer après l'override\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Back-office > Produits > Livraison\u003C\u002Fth>\u003Cth>Remplir le champ pour toutes les langues\u003C\u002Fth>\u003C\u002Ftr>",[121,124,127,130,133],{"q":122,"a":123},"Pourquoi la variable delivery_out_stock est vide dans le panier alors qu'elle s'affiche sur la fiche produit ?","Par défaut, la méthode getProducts() de la classe Cart ne récupère pas le champ delivery_out_stock depuis la table product_lang. Il faut créer un override de Cart.php pour ajouter ce champ à la requête SQL ou le récupérer via une requête complémentaire.",{"q":125,"a":126},"Comment identifier le bon id_lang dans PrestaShop ?","L'id_lang par défaut n'est pas toujours 1. Il varie selon l'historique d'installation et les langues ajoutées ou supprimées. Vérifiez avec la requête SQL SELECT id_lang, iso_code FROM ps_lang WHERE active = 1, ou dans le back-office via International > Localisation > Langues.",{"q":128,"a":129},"Faut-il remplir delivery_out_stock dans toutes les langues ?","Oui. La table ps_product_lang stocke une valeur par langue. Si le champ n'est rempli que pour une langue et que le client navigue dans une autre, la valeur sera vide. Remplissez le champ pour toutes les langues actives ou implémentez un fallback vers la langue par défaut dans votre code.",{"q":131,"a":132},"L'override de Cart.php fonctionne-t-il sur PrestaShop 8 ?","Oui, le système d'override par héritage de classe reste supporté sur PrestaShop 8.x. Cependant, pensez à supprimer le fichier var\u002Fcache\u002Fprod\u002Fclass_index.php après avoir créé l'override pour que PrestaShop le détecte.",{"q":134,"a":135},"Comment afficher delivery_in_stock et delivery_out_stock conditionnellement selon le stock ?","Dans votre template Smarty, combinez la vérification du stock avec l'affichage du bon message : utilisez {if $product.quantity > 0} pour afficher delivery_in_stock, et {else} pour delivery_out_stock. Les deux champs doivent être disponibles via l'override de Cart.php.","Pour afficher delivery_out_stock dans le panier PrestaShop, il faut overrider Cart.php pour ajouter ce champ à la requête SQL de getProducts(). Le piège principal est un décalage d'id_lang qui rend la variable vide — vérifiez que le contenu est rempli pour toutes les langues actives.",5,"2026-03-21T13:44:43.000Z",[],"PrestaShop pour les développeurs",{"items":142},[143,152,158,164,172,180,185,191],{"id":144,"type":145,"label":146,"href":84,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":149,"children":150,"psChildren":151},41,"link",{"fr":147},"Expertise",null,0,[],[],{"id":153,"type":145,"label":154,"href":75,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":155,"children":156,"psChildren":157},42,{"fr":74},1,[],[],{"id":159,"type":145,"label":160,"href":36,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":161,"children":162,"psChildren":163},43,{"fr":35},2,[],[],{"id":165,"type":145,"label":166,"href":168,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":169,"children":170,"psChildren":171},44,{"fr":167},"Outils IA","\u002Foutils-ia",3,[],[],{"id":173,"type":145,"label":174,"href":29,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":176,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":177,"children":178,"psChildren":179},45,{"fr":175},"Offre Starter ✨",{"highlight":20},4,[],[],{"id":181,"type":145,"label":182,"href":78,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":137,"children":183,"psChildren":184},46,{"fr":77},[],[],{"id":186,"type":145,"label":187,"href":96,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":188,"children":189,"psChildren":190},47,{"fr":92},6,[],[],{"id":192,"type":145,"label":193,"href":102,"icon":148,"description":148,"badge":148,"groupTitle":148,"style":148,"gridColumns":148,"cssClass":148,"psCategoryId":148,"showPsChildren":30,"position":194,"children":195,"psChildren":196},48,{"fr":101},7,[],[],{"footer":198},{"theme":199,"description":148,"hours":148,"logo":200,"contact":203,"social":204,"bottomBar":214},"dark",{"src":201,"href":202,"alt":95},"\u002Flogo-ac.svg","\u002F",{"email":148,"phone":148,"address":148,"cta":148},[205,208,211],{"platform":206,"href":207,"label":206},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":209,"href":210,"label":209},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":212,"href":213,"label":212},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":148},{"header":216},{"logo":217,"topBar":220,"contactEmail":223,"features":224,"navBar":148},{"src":201,"alt":218,"text":95,"href":202,"class":219},"Alexandre Carette — Architecte E-commerce Souverain","h-10 w-10",{"message":148,"showLanguages":30,"align":221,"languages":222},"left",[],"contact@alexandrecarette.fr",{"showSearch":30,"showWishlist":30,"showLogin":20,"showContact":30,"showCart":30,"stickyHeader":20,"headerLayout":225},"inline",{"academy":227,"blog":228,"expertise":239},[],[229,233,236],{"title":230,"url":231,"score":155,"type":232},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back","blog",{"title":234,"url":235,"score":155,"type":232},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":237,"url":238,"score":155,"type":232},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[]]