{"id":8777,"date":"2026-08-17T17:51:49","date_gmt":"2026-08-17T17:51:49","guid":{"rendered":"https:\/\/proshopafrica.com\/certificates-and-analysis-reports\/"},"modified":"2026-08-21T12:10:42","modified_gmt":"2026-08-21T12:10:42","slug":"certificates-and-analysis-reports","status":"publish","type":"page","link":"https:\/\/proshopafrica.com\/en\/certificates-and-analysis-reports\/","title":{"rendered":"Certificates and analysis reports"},"content":{"rendered":"<div class=\"gxc\" id=\"gxc\">\n\n  <div class=\"gxc-tete\">\n    <h2 class=\"gxc-h\">Certificats et fiches d'analyse<\/h2>\n    <p class=\"gxc-sous\">Retrouvez le document d'analyse de votre lot.<\/p>\n  <\/div>\n\n  <div class=\"gxc-form\">\n    <p class=\"gxc-note-ref\" id=\"gxc-note-ref\" hidden><\/p>\n    <label for=\"gxc-lot\">Num&eacute;ro de lot<\/label>\n    <input type=\"text\" id=\"gxc-lot\" inputmode=\"text\" autocomplete=\"off\"\n           autocapitalize=\"off\" autocorrect=\"off\" spellcheck=\"false\"\n           placeholder=\"HYPC68 1108261216\">\n    <p class=\"gxc-aide\">Exemple&nbsp;: <span class=\"gxc-ex\">HYPC68 1108261216<\/span><br>\n       La casse et les espaces n'ont pas d'importance.<\/p>\n    <p class=\"gxc-aide\">Le num&eacute;ro de lot figure sur l'&eacute;tiquette du bidon\n       et sur votre bon de livraison.<\/p>\n\n    <label for=\"gxc-ref\" class=\"gxc-lbl2\">ou r&eacute;f&eacute;rence article (PS000&hellip;)<\/label>\n    <input type=\"text\" id=\"gxc-ref\" inputmode=\"text\" autocomplete=\"off\"\n           autocapitalize=\"off\" autocorrect=\"off\" spellcheck=\"false\"\n           placeholder=\"PS001170\">\n\n    <button type=\"button\" id=\"gxc-go\" class=\"gxc-btn\">Rechercher<\/button>\n  <\/div>\n\n  <div id=\"gxc-res\" class=\"gxc-res\" hidden><\/div>\n\n  <div class=\"gxc-pied\">\n    Un doute&nbsp;? &Eacute;crivez-nous &agrave;\n    <a href=\"mailto:commercial@mac2senegal.com\">commercial@mac2senegal.com<\/a>\n  <\/div>\n<\/div>\n\n<style id=\"gxc-css\">\n\/* Charte identique a l'ecran inox : orange #FCB800, noir #111, blanc.\n   AUCUNE dependance externe \u2014 ni police distante, ni CDN : le mutualise LWS\n   bloque l'externe, et une police qui ne charge pas casse la mise en page. *\/\n.gxc{max-width:620px;margin:24px auto;padding:22px;border:1px solid #e5e7eb;\n     border-radius:10px;background:#fff;color:#111;font-family:inherit;\n     box-shadow:0 1px 2px rgba(0,0,0,.04)}\n.gxc-h{margin:0;font-size:21px;font-weight:800;letter-spacing:-.2px;color:#111}\n.gxc-sous{margin:6px 0 18px;font-size:14.5px;color:#555;line-height:1.45}\n.gxc-form label{display:block;font-weight:700;font-size:14px;color:#111;margin:14px 0 6px}\n.gxc-form label.gxc-lbl2{font-weight:600;color:#555;font-size:13.5px;margin-top:18px}\n\/* 17px et non 16 : en dessous de 16px, iOS zoome au focus et casse la page. *\/\n.gxc-form input{width:100%;padding:12px 14px;font-size:17px;border:1px solid #ccc;\n     border-radius:8px;box-sizing:border-box;background:#fff;color:#111}\n.gxc-form input:focus{outline:2px solid #FCB800;border-color:#FCB800}\n.gxc-aide{font-size:13px;color:#777;margin:6px 0 0;line-height:1.45}\n.gxc-ex{font-family:ui-monospace,Consolas,monospace;color:#555}\n.gxc-btn{margin-top:20px;width:100%;padding:14px;font-size:16px;font-weight:800;\n     color:#111;background:#FCB800;border:0;border-radius:8px;cursor:pointer}\n.gxc-btn:hover{filter:brightness(.95)}\n.gxc-btn:disabled{opacity:.6;cursor:default;filter:none}\n.gxc-res{margin-top:22px}\n.gxc-carte{border:1px solid #e5e7eb;border-radius:8px;padding:18px}\n.gxc-ok{background:#f6faf6;border-color:#cfe3cf}\n.gxc-ko{background:#fdf7f4;border-color:#ecd9c9}\n.gxc-panne{background:#fdf4f4;border-color:#ecc9c9}\n.gxc-t{margin:0 0 4px;font-size:18px;font-weight:800;color:#111}\n.gxc-d{margin:0 0 14px;font-size:14.5px;color:#444;line-height:1.4}\n.gxc-champs{list-style:none;margin:0 0 16px;padding:0;font-size:14px;color:#333}\n.gxc-champs li{padding:5px 0;border-bottom:1px solid #ececec;display:flex;gap:10px}\n.gxc-champs li:last-child{border-bottom:0}\n.gxc-champs b{flex:0 0 128px;color:#666;font-weight:600}\n\/* La mention de variabilite : EN CLAIR, AU-DESSUS du bouton, dans un encadre\n   visible \u2014 jamais en note de bas de page. *\/\n.gxc-avert{background:#fff7e2;border:1px solid #f1dfae;border-radius:8px;\n     padding:13px 15px;font-size:14px;line-height:1.5;color:#5c4c1e;margin:0 0 16px}\n.gxc-lien{display:inline-block;padding:13px 18px;background:#111;color:#fff;\n     font-weight:700;font-size:15px;border-radius:8px;text-decoration:none}\n.gxc-lien:hover{color:#FCB800;text-decoration:none}\n.gxc-liste{list-style:none;margin:14px 0 0;padding:0}\n.gxc-liste li{margin:0 0 8px}\n.gxc-choix{width:100%;text-align:left;padding:12px 14px;border:1px solid #ddd;\n     border-radius:8px;background:#fff;cursor:pointer;font-size:14.5px;color:#111}\n.gxc-choix:hover{border-color:#FCB800;background:#fffdf6}\n.gxc-choix b{display:block;font-size:13px;color:#666;font-weight:600}\n.gxc-titre-liste{margin:18px 0 8px;font-size:14px;font-weight:700;color:#111}\n.gxc-note-ref{background:#fff7e2;border:1px solid #f1dfae;border-radius:8px;\n     padding:12px 14px;font-size:14px;line-height:1.5;color:#5c4c1e;margin:0 0 16px}\n.gxc-pied{margin-top:20px;font-size:13px;color:#777;line-height:1.5}\n.gxc-attente{display:inline-block;width:14px;height:14px;border:2px solid #111;\n     border-right-color:transparent;border-radius:50%;vertical-align:-2px;\n     margin-right:8px;animation:gxcspin .7s linear infinite}\n@keyframes gxcspin{to{transform:rotate(360deg)}}\n@media (max-width:620px){.gxc{margin:12px;padding:16px}\n  .gxc-champs b{flex:0 0 104px}}\n\/* ============================================================================\n   CORRECTIF v3 \u2014 LE THEME IMPOSE SES COULEURS DE TEXTE\n   ----------------------------------------------------------------------------\n   Constate le 17\/08 sur l'ecran en production : le sous-titre, les lignes\n   d'aide et la designation sortaient en bleu et en orange au lieu du gris\n   prevu. Le theme Martfury cible les paragraphes par des selecteurs plus\n   precis que les miens (du type `.entry-content p`), et il gagne.\n   On remonte la specificite en prefixant par #gxc \u2014 l'identifiant du\n   conteneur \u2014 et on verrouille la couleur, et elle seule.\n   ========================================================================== *\/\n#gxc .gxc-h           {color:#111 !important}\n#gxc .gxc-sous        {color:#555 !important}\n#gxc .gxc-aide        {color:#777 !important}\n#gxc .gxc-ex          {color:#555 !important}\n#gxc .gxc-t           {color:#111 !important}\n#gxc .gxc-d           {color:#444 !important}\n#gxc .gxc-champs      {color:#333 !important}\n#gxc .gxc-champs b    {color:#666 !important}\n#gxc .gxc-avert       {color:#5c4c1e !important}\n#gxc .gxc-note-ref    {color:#5c4c1e !important}\n#gxc .gxc-titre-liste {color:#111 !important}\n#gxc .gxc-choix       {color:#111 !important}\n#gxc .gxc-choix b     {color:#666 !important}\n#gxc .gxc-lien        {color:#fff !important}\n#gxc .gxc-lien:hover  {color:#FCB800 !important}\n<\/style>\n\n<script>\n(function(){\n  var CONF = {\"ajax\":\"https:\\\/\\\/proshopafrica.com\\\/wp-admin\\\/admin-ajax.php\",\"pub\":\"https:\\\/\\\/mac2senegal.com\",\"base\":\"https:\\\/\\\/mac2senegal.com\",\"contact\":\"commercial@mac2senegal.com\"};\n  \/* CONF ne contient PAS le secret : il n'existe qu'en PHP, dans l'en-tete de\n     wp_remote_get. Le navigateur ne le voit jamais. *\/\n\n  var E = {\n    lot: document.getElementById(\"gxc-lot\"),\n    ref: document.getElementById(\"gxc-ref\"),\n    go:  document.getElementById(\"gxc-go\"),\n    res: document.getElementById(\"gxc-res\"),\n    note: document.getElementById(\"gxc-note-ref\")\n  };\n  if (!E.lot || !E.go || !E.res) return;\n\n  function esc(s){\n    return String(s === null || s === undefined ? \"\" : s)\n      .replace(\/&\/g,\"&amp;\").replace(\/<\/g,\"&lt;\").replace(\/>\/g,\"&gt;\")\n      .replace(\/\"\/g,\"&quot;\");\n  }\n\n  \/* Un champ est affichable s'il porte une vraie valeur. Le tiret cadratin est\n     traite comme du vide : trois `coa_historique` portent batch = \"\u2014\", des\n     certificats edites sans numero de lot. Ecrire \u00ab Lot \u2014 \u00bb a un client, ce\n     serait lui montrer un defaut interne. On omet la ligne, on n'invente pas. *\/\n  function utile(v){\n    if (v === null || v === undefined) return false;\n    var t = String(v).trim();\n    return t !== \"\" && t !== \"\\u2014\" && t !== \"-\";\n  }\n\n  function ligne(lbl, val){\n    return utile(val) ? \"<li><b>\" + esc(lbl) + \"<\/b><span>\" + esc(val) + \"<\/span><\/li>\" : \"\";\n  }\n\n  function lienPdf(url, texte){\n    if (!url) return \"\";\n    \/* Le PDF NE PASSE PAS PAR LE RELAIS : le navigateur du client va le\n       chercher lui-meme. La page publique est bornee a 60 requetes \/ 10 min\n       \/ IP ; si le PHP telechargeait, tous les clients partageraient l'IP du\n       mutualise et le 61e telechargement d'une meme demi-heure serait refuse\n       pour tout le monde, sans que rien ne l'explique. *\/\n    \/* CONF.pub, PAS CONF.base : le lien part chez le CLIENT, il doit porter\n       l'adresse publique, jamais celle du relais. Voir la correction (2). *\/\n    return '<a class=\"gxc-lien\" target=\"_blank\" rel=\"noopener noreferrer\" href=\"'\n         + esc(CONF.pub + url) + '\">' + esc(texte) + \"<\/a>\";\n  }\n\n  function vider(){ E.res.innerHTML = \"\"; E.res.hidden = true; }\n\n  function poser(html){ E.res.innerHTML = html; E.res.hidden = false; }\n\n  \/* ---- LES QUATRE MODES -------------------------------------------------\n     Le titre, le texte du bouton et le libelle suivent le champ `mode` du\n     JSON, JAMAIS une valeur ecrite en dur. Le mot \u00ab certificat \u00bb n'apparait\n     nulle part quand mode != \"certificat\". *\/\n\n  function rendreCertificat(d){\n    var h = '<div class=\"gxc-carte gxc-ok\">';\n    h += '<p class=\"gxc-t\">Certificat d\\'analyse<\/p>';\n    if (utile(d.designation)) h += '<p class=\"gxc-d\">' + esc(d.designation) + \"<\/p>\";\n    var li = ligne(\"R\\u00e9f\\u00e9rence\", d.reference)\n           + ligne(\"Lot\", d.lot)\n           + ligne(\"Fabrication\", d.date_prod)\n           + ligne(\"Expiration\", d.date_exp);\n    if (li) h += '<ul class=\"gxc-champs\">' + li + \"<\/ul>\";\n    if (utile(d.message)) h += '<div class=\"gxc-avert\">' + esc(d.message) + \"<\/div>\";\n    h += lienPdf(d.url, \"Ouvrir le certificat (PDF)\");\n    h += listeLots(d);\n    return h + \"<\/div>\";\n  }\n\n  function rendreStandard(d){\n    var h = '<div class=\"gxc-carte gxc-ok\">';\n    \/* JAMAIS le mot \u00ab certificat \u00bb ici. `coa_spec` porte des valeurs typiques\n       PAR ARTICLE, pas des mesures PAR LOT : les servir sous le mot\n       \u00ab certificat \u00bb ferait certifier un controle qui n'a pas eu lieu.\n       Et cet etat n'est PAS un echec \u2014 il couvre la plus grande part du\n       perimetre. Il se presente comme un resultat positif. *\/\n    h += '<p class=\"gxc-t\">Fiche d\\'analyse standard<\/p>';\n    if (utile(d.designation)) h += '<p class=\"gxc-d\">' + esc(d.designation) + \"<\/p>\";\n    var li = ligne(\"R\\u00e9f\\u00e9rence\", d.reference) + ligne(\"Lot\", d.lot);\n    if (li) h += '<ul class=\"gxc-champs\">' + li + \"<\/ul>\";\n    h += '<div class=\"gxc-avert\">Valeurs standard pour cette r\\u00e9f\\u00e9rence '\n       + '&mdash; elles peuvent varier selon le lot. Pour les valeurs de VOTRE '\n       + 'lot, indiquez son num\\u00e9ro.<\/div>';\n    h += lienPdf(d.url, \"Ouvrir la fiche standard (PDF)\");\n    return h + \"<\/div>\";\n  }\n\n  \/* Etat DORMANT : l'ambiguite mesuree est de zero sur les lots reels. Il est\n     ecrit quand meme. Une branche qu'on remet a plus tard parce qu'elle ne\n     survient jamais est une branche qui plantera le jour ou elle surviendra. *\/\n  function rendreAmbigu(d){\n    var arts = d.articles || [];\n    var h = '<div class=\"gxc-carte\">';\n    h += '<p class=\"gxc-t\">Plusieurs produits portent ce num\\u00e9ro<\/p>';\n    h += '<p class=\"gxc-d\">Choisissez le v\\u00f4tre&nbsp;:<\/p><ul class=\"gxc-liste\">';\n    for (var i = 0; i < arts.length; i++){\n      var a = arts[i] || {};\n      h += '<li><button type=\"button\" class=\"gxc-choix\" data-ref=\"' + esc(a.reference) + '\">'\n         + \"<b>\" + esc(a.reference) + \"<\/b>\" + esc(a.designation || \"\") + \"<\/button><\/li>\";\n    }\n    return h + \"<\/ul><\/div>\";   \/* pas d'url, pas de bouton PDF *\/\n  }\n\n  function rendreRien(d){\n    var h = '<div class=\"gxc-carte gxc-ko\">';\n    h += '<p class=\"gxc-t\">Aucun document d\\'analyse<\/p>';\n    h += '<p class=\"gxc-d\">' + esc(utile(d.message) ? d.message\n       : \"Nous n'avons pas de document d'analyse pour cette saisie.\") + \"<\/p>\";\n    h += '<p class=\"gxc-d\">V\\u00e9rifiez le num\\u00e9ro, ou \\u00e9crivez \\u00e0 '\n       + '<a href=\"mailto:' + esc(CONF.contact) + '\">' + esc(CONF.contact) + '<\/a> '\n       + 'en indiquant votre r\\u00e9f\\u00e9rence et votre num\\u00e9ro de lot.<\/p>';\n    return h + \"<\/div>\";        \/* pas de bouton, pas de PDF, aucune promesse *\/\n  }\n\n  \/* \u26a0 \u00ab probleme technique \u00bb n'est PAS \u00ab aucun document trouve \u00bb. Un timeout\n     affiche en \u00ab rien trouve \u00bb ferait conclure au client, a tort, que son lot\n     n'existe pas. *\/\n  function rendrePanne(d){\n    return '<div class=\"gxc-carte gxc-panne\">'\n      + '<p class=\"gxc-t\">Probl\\u00e8me technique<\/p>'\n      + '<p class=\"gxc-d\">Nous n\\'avons pas pu interroger notre service qualit\\u00e9. '\n      + 'Cela ne veut pas dire que votre lot est inconnu&nbsp;: merci de r\\u00e9essayer '\n      + 'dans un instant, ou d\\'\\u00e9crire \\u00e0 '\n      + '<a href=\"mailto:' + esc(CONF.contact) + '\">' + esc(CONF.contact) + '<\/a>.<\/p>'\n      + \"<\/div>\";\n  }\n\n  \/* `lots_disponibles` : mesure le 17\/08, le champ EXISTE. Il n'apparait que\n     sur une interrogation PAR REFERENCE SEULE. C'est lui qui empeche le client\n     de croire que le certificat affiche est celui de SON lot. *\/\n  function listeLots(d){\n    var lots = d.lots_disponibles || [];\n    if (!lots.length) return \"\";\n    var h = '<p class=\"gxc-titre-liste\">Ces lots ont un certificat. '\n          + 'Le v\\u00f4tre n\\'y est pas&nbsp;? Indiquez-le.<\/p><ul class=\"gxc-liste\">';\n    for (var i = 0; i < lots.length; i++){\n      h += '<li><button type=\"button\" class=\"gxc-choix\" data-lot=\"' + esc(lots[i]) + '\">'\n         + esc(lots[i]) + \"<\/button><\/li>\";\n    }\n    return h + \"<\/ul>\";\n  }\n\n  function afficher(d){\n    vider();\n    if (!d || d.ok === false) { poser(rendrePanne(d)); return; }\n    var m = d.mode;\n    if (m === \"certificat\")    poser(rendreCertificat(d));\n    else if (m === \"standard\") poser(rendreStandard(d));\n    else if (m === \"ambigu\")   poser(rendreAmbigu(d));\n    else                       poser(rendreRien(d));\n  }\n\n  var occupe = false;\n\n  function chercher(lot, ref){\n    if (occupe) return;\n    lot = lot === undefined ? E.lot.value : lot;\n    ref = ref === undefined ? E.ref.value : ref;\n    \/* Le SEUL traitement autorise sur la saisie : refuser une chaine vide.\n       On envoie au serveur EXACTEMENT ce que le client a tape, espaces et\n       casse compris. *\/\n    if (!String(lot).trim() && !String(ref).trim()) { E.lot.focus(); return; }\n\n    occupe = true;\n    E.go.disabled = true;\n    var libelle = E.go.textContent;\n    E.go.innerHTML = '<span class=\"gxc-attente\"><\/span>Recherche&hellip;';\n    vider();\n\n    var corps = new URLSearchParams();\n    corps.append(\"action\", \"gestock_coa_lookup\");\n    corps.append(\"lot\",    lot);\n    corps.append(\"ref\",    ref);\n\n    fetch(CONF.ajax, {\n      method: \"POST\",\n      credentials: \"same-origin\",\n      headers: {\"Content-Type\": \"application\/x-www-form-urlencoded; charset=UTF-8\"},\n      body: corps.toString()\n    })\n    .then(function(r){ return r.json(); })\n    .then(function(d){ afficher(d); })\n    .catch(function(){ vider(); poser(rendrePanne(null)); })\n    .then(function(){\n      occupe = false;\n      E.go.disabled = false;\n      E.go.textContent = libelle;\n    });\n  }\n\n  E.go.addEventListener(\"click\", function(){ chercher(); });\n\n  \/* Entree = Rechercher. Pas de recherche a la frappe : le lot se tape en\n     entier, l'anti-rebond n'a pas de sens ici et multiplierait les appels\n     contre le quota. *\/\n  function surEntree(ev){ if (ev.key === \"Enter\"){ ev.preventDefault(); chercher(); } }\n  E.lot.addEventListener(\"keydown\", surEntree);\n  E.ref.addEventListener(\"keydown\", surEntree);\n\n  \/* Un clic dans une liste relance la recherche : par lot pour\n     `lots_disponibles`, par reference pour le mode ambigu. *\/\n  E.res.addEventListener(\"click\", function(ev){\n    var b = ev.target.closest ? ev.target.closest(\".gxc-choix\") : null;\n    if (!b) return;\n    if (b.getAttribute(\"data-lot\")){\n      E.lot.value = b.getAttribute(\"data-lot\");\n      E.ref.value = \"\";\n      chercher(E.lot.value, \"\");\n    } else if (b.getAttribute(\"data-ref\")){\n      E.ref.value = b.getAttribute(\"data-ref\");\n      E.lot.value = \"\";\n      chercher(\"\", E.ref.value);\n    }\n  });\n\n  \/* ---- ARRIVEE DEPUIS UNE FICHE PRODUIT (v5) ---------------------------\n     \/certificats-et-fiches-danalyse\/?ref=PS000016\n     On pre-remplit la REFERENCE, on met le curseur dans le champ LOT, et on\n     NE LANCE PAS la recherche : sans lot, le serveur rendrait le certificat du\n     lot le plus recent, qui n'est pas forcement celui du client. *\/\n  (function(){\n    var p;\n    try { p = new URLSearchParams(window.location.search); } catch(e){ return; }\n    var r = p.get(\"ref\"), l = p.get(\"lot\");\n    if (r) E.ref.value = r;\n    if (l) E.lot.value = l;\n    if (r && !l && E.note){\n      \/* textContent, pas innerHTML : la valeur vient de l'URL, on ne l'interprete\n         jamais comme du HTML. *\/\n      E.note.textContent = \"Nous savons de quel produit il s'agit \\u2014 \" + r\n        + \". Indiquez votre num\\u00e9ro de lot pour obtenir le certificat de VOTRE lot. \"\n        + \"Sans num\\u00e9ro, vous obtiendrez la fiche d'analyse standard du produit.\";\n      E.note.hidden = false;\n    }\n  })();\n\n  \/* Aucun stockage : ni localStorage, ni historique de recherche. Un numero de\n     lot n'a pas a rester dans un navigateur partage. *\/\n  try { E.lot.focus(); } catch(e){}\n})();\n<\/script>\n\t\n","protected":false},"excerpt":{"rendered":"","protected":false},"author":15,"featured_media":0,"parent":0,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"","meta":{"footnotes":""},"class_list":["post-8777","page","type-page","status-publish","hentry"],"_links":{"self":[{"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/pages\/8777","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/users\/15"}],"replies":[{"embeddable":true,"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/comments?post=8777"}],"version-history":[{"count":1,"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/pages\/8777\/revisions"}],"predecessor-version":[{"id":8778,"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/pages\/8777\/revisions\/8778"}],"wp:attachment":[{"href":"https:\/\/proshopafrica.com\/en\/wp-json\/wp\/v2\/media?parent=8777"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}