[{"data":1,"prerenderedAt":676},["ShallowReactive",2],{"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futiliser-les-points-d-extension-client":3,"section:\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futiliser-les-points-d-extension-client":675},{"id":4,"title":5,"body":6,"description":664,"extension":665,"meta":666,"navigation":308,"path":671,"seo":672,"stem":673,"__hash__":674},"docs\u002F2.next\u002F3.dodock\u002F10.developpeurs\u002F03.composants-ui\u002Futiliser-les-points-d-extension-client.md","Utiliser les points d'extension client",{"type":7,"value":8,"toc":658},"minimark",[9,13,22,25,30,84,91,129,142,146,150,175,179,190,619,625,629,654],[10,11,5],"h1",{"id":12},"utiliser-les-points-dextension-client",[14,15,16,17,21],"p",{},"Un document « mappé » est créé à partir d'un autre : une facture depuis une commande, un bon de livraison depuis une commande… Le desk appelle ",[18,19,20],"code",{},"frappe.model.open_mapped_doc",". Le serveur prépare le nouveau document sans l'enregistrer, puis le desk l'ouvre.",[14,23,24],{},"Une garde est une fonction JavaScript appelée entre ces deux étapes. Elle peut empêcher l'ouverture du nouveau document.",[26,27,29],"h2",{"id":28},"fonctions","Fonctions",[31,32,33,46],"table",{},[34,35,36],"thead",{},[37,38,39,43],"tr",{},[40,41,42],"th",{},"Fonction",[40,44,45],{},"Rôle",[47,48,49,60,70],"tbody",{},[37,50,51,57],{},[52,53,54],"td",{},[18,55,56],{},"frappe.model.add_mapped_doc_guard(fn)",[52,58,59],{},"Enregistre une garde. La même fonction n'est enregistrée qu'une fois.",[37,61,62,67],{},[52,63,64],{},[18,65,66],{},"frappe.model.remove_mapped_doc_guard(fn)",[52,68,69],{},"Retire une garde.",[37,71,72,77],{},[52,73,74],{},[18,75,76],{},"frappe.model.should_open_mapped_doc(mapped_doc, opts)",[52,78,79,80,83],{},"Exécute les gardes dans l'ordre. Renvoie une promesse de ",[18,81,82],{},"true"," si aucune ne bloque.",[14,85,86,87,90],{},"Une garde reçoit ",[18,88,89],{},"(mapped_doc, opts)"," :",[92,93,94,105],"ul",{},[95,96,97,100,101,104],"li",{},[18,98,99],{},"mapped_doc"," : le nouveau document, pas encore enregistré. Son ",[18,102,103],{},"name"," est provisoire.",[95,106,107,110,111,114,115,118,119,118,122,118,125,128],{},[18,108,109],{},"opts"," : les options passées à ",[18,112,113],{},"open_mapped_doc"," (",[18,116,117],{},"method",", ",[18,120,121],{},"frm",[18,123,124],{},"source_name",[18,126,127],{},"args","…).",[14,130,131,132,134,135,137,138,141],{},"Elle renvoie ",[18,133,82],{}," (ou une promesse de ",[18,136,82],{},") pour laisser ouvrir le document, ",[18,139,140],{},"false"," pour bloquer.",[26,143,145],{"id":144},"déroulement","Déroulement",[147,148,149],"mermaid",{},"\nsequenceDiagram\n  participant U as Utilisateur\n  participant D as Desk\n  participant S as Serveur\n  U->>D: Créer > Bon de livraison\n  D->>S: make_mapped_doc\n  S-->>D: Nouveau document (non enregistré)\n  D->>D: Gardes, dans l'ordre d'enregistrement\n  alt Une garde renvoie false\n    D-->>U: Reste sur le document source\n  else Toutes renvoient true\n    D-->>U: Ouvre le nouveau document\n  end\n",[92,151,152,158,161,164],{},[95,153,154,155,157],{},"La première garde qui renvoie ",[18,156,140],{}," arrête la suite. Le desk reste sur le document source.",[95,159,160],{},"Une garde qui lève une erreur est ignorée. L'erreur s'affiche dans la console. Une garde en erreur ne bloque donc jamais la création.",[95,162,163],{},"Pendant l'exécution des gardes, l'écran n'est pas gelé : une garde peut ouvrir une boîte de dialogue. Un nouveau clic sur « Créer » est ignoré jusqu'à la fin des gardes.",[95,165,166,167,169,170,174],{},"Les gardes ne concernent que ",[18,168,113],{},". Un document créé avec ",[171,172,173],"strong",{},"Nouveau"," ne passe pas par elles.",[26,176,178],{"id":177},"exemple-confirmer-avant-de-créer-un-deuxième-bon-de-livraison","Exemple : confirmer avant de créer un deuxième bon de livraison",[14,180,181,182,185,186,189],{},"Placez le code dans un fichier JavaScript chargé par le desk (",[18,183,184],{},"app_include_js"," dans le ",[18,187,188],{},"hooks.py"," de votre application).",[191,192,197],"pre",{"className":193,"code":194,"language":195,"meta":196,"style":196},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","frappe.model.add_mapped_doc_guard(async (mapped_doc, opts) => {\n    if (mapped_doc.doctype !== \"Delivery Note\" || !opts.frm) return true;\n\n    const count = await frappe.db.count(\"Delivery Note\", {\n        filters: [\n            [\"Delivery Note Item\", \"against_sales_order\", \"=\", opts.frm.doc.name],\n            [\"Delivery Note\", \"docstatus\", \"!=\", 2],\n        ],\n    });\n    if (!count) return true;\n\n    return new Promise((resolve) => {\n        frappe.confirm(\n            __(\"Un bon de livraison existe déjà pour cette commande. Continuer ?\"),\n            () => resolve(true),\n            () => resolve(false)\n        );\n    });\n});\n","js","",[18,198,199,248,303,310,350,362,416,455,463,473,493,498,524,538,557,576,592,600,609],{"__ignoreMap":196},[200,201,204,208,212,215,217,221,224,228,230,233,236,239,242,245],"span",{"class":202,"line":203},"line",1,[200,205,207],{"class":206},"sTEyZ","frappe",[200,209,211],{"class":210},"sMK4o",".",[200,213,214],{"class":206},"model",[200,216,211],{"class":210},[200,218,220],{"class":219},"s2Zo4","add_mapped_doc_guard",[200,222,223],{"class":206},"(",[200,225,227],{"class":226},"spNyl","async",[200,229,114],{"class":210},[200,231,99],{"class":232},"sHdIc",[200,234,235],{"class":210},",",[200,237,238],{"class":232}," opts",[200,240,241],{"class":210},")",[200,243,244],{"class":226}," =>",[200,246,247],{"class":210}," {\n",[200,249,251,255,258,260,262,265,268,271,275,278,281,284,286,288,290,293,296,300],{"class":202,"line":250},2,[200,252,254],{"class":253},"s7zQu","    if",[200,256,114],{"class":257},"swJcz",[200,259,99],{"class":206},[200,261,211],{"class":210},[200,263,264],{"class":206},"doctype",[200,266,267],{"class":210}," !==",[200,269,270],{"class":210}," \"",[200,272,274],{"class":273},"sfazB","Delivery Note",[200,276,277],{"class":210},"\"",[200,279,280],{"class":210}," ||",[200,282,283],{"class":210}," !",[200,285,109],{"class":206},[200,287,211],{"class":210},[200,289,121],{"class":206},[200,291,292],{"class":257},") ",[200,294,295],{"class":253},"return",[200,297,299],{"class":298},"sfNiH"," true",[200,301,302],{"class":210},";\n",[200,304,306],{"class":202,"line":305},3,[200,307,309],{"emptyLinePlaceholder":308},true,"\n",[200,311,313,316,319,322,325,328,330,333,335,338,340,342,344,346,348],{"class":202,"line":312},4,[200,314,315],{"class":226},"    const",[200,317,318],{"class":206}," count",[200,320,321],{"class":210}," =",[200,323,324],{"class":253}," await",[200,326,327],{"class":206}," frappe",[200,329,211],{"class":210},[200,331,332],{"class":206},"db",[200,334,211],{"class":210},[200,336,337],{"class":219},"count",[200,339,223],{"class":257},[200,341,277],{"class":210},[200,343,274],{"class":273},[200,345,277],{"class":210},[200,347,235],{"class":210},[200,349,247],{"class":210},[200,351,353,356,359],{"class":202,"line":352},5,[200,354,355],{"class":257},"        filters",[200,357,358],{"class":210},":",[200,360,361],{"class":257}," [\n",[200,363,365,368,370,373,375,377,379,382,384,386,388,391,393,395,397,399,401,403,406,408,410,413],{"class":202,"line":364},6,[200,366,367],{"class":257},"            [",[200,369,277],{"class":210},[200,371,372],{"class":273},"Delivery Note Item",[200,374,277],{"class":210},[200,376,235],{"class":210},[200,378,270],{"class":210},[200,380,381],{"class":273},"against_sales_order",[200,383,277],{"class":210},[200,385,235],{"class":210},[200,387,270],{"class":210},[200,389,390],{"class":273},"=",[200,392,277],{"class":210},[200,394,235],{"class":210},[200,396,238],{"class":206},[200,398,211],{"class":210},[200,400,121],{"class":206},[200,402,211],{"class":210},[200,404,405],{"class":206},"doc",[200,407,211],{"class":210},[200,409,103],{"class":206},[200,411,412],{"class":257},"]",[200,414,415],{"class":210},",\n",[200,417,419,421,423,425,427,429,431,434,436,438,440,443,445,447,451,453],{"class":202,"line":418},7,[200,420,367],{"class":257},[200,422,277],{"class":210},[200,424,274],{"class":273},[200,426,277],{"class":210},[200,428,235],{"class":210},[200,430,270],{"class":210},[200,432,433],{"class":273},"docstatus",[200,435,277],{"class":210},[200,437,235],{"class":210},[200,439,270],{"class":210},[200,441,442],{"class":273},"!=",[200,444,277],{"class":210},[200,446,235],{"class":210},[200,448,450],{"class":449},"sbssI"," 2",[200,452,412],{"class":257},[200,454,415],{"class":210},[200,456,458,461],{"class":202,"line":457},8,[200,459,460],{"class":257},"        ]",[200,462,415],{"class":210},[200,464,466,469,471],{"class":202,"line":465},9,[200,467,468],{"class":210},"    }",[200,470,241],{"class":257},[200,472,302],{"class":210},[200,474,476,478,480,483,485,487,489,491],{"class":202,"line":475},10,[200,477,254],{"class":253},[200,479,114],{"class":257},[200,481,482],{"class":210},"!",[200,484,337],{"class":206},[200,486,292],{"class":257},[200,488,295],{"class":253},[200,490,299],{"class":298},[200,492,302],{"class":210},[200,494,496],{"class":202,"line":495},11,[200,497,309],{"emptyLinePlaceholder":308},[200,499,501,504,507,511,513,515,518,520,522],{"class":202,"line":500},12,[200,502,503],{"class":253},"    return",[200,505,506],{"class":210}," new",[200,508,510],{"class":509},"sBMFI"," Promise",[200,512,223],{"class":257},[200,514,223],{"class":210},[200,516,517],{"class":232},"resolve",[200,519,241],{"class":210},[200,521,244],{"class":226},[200,523,247],{"class":210},[200,525,527,530,532,535],{"class":202,"line":526},13,[200,528,529],{"class":206},"        frappe",[200,531,211],{"class":210},[200,533,534],{"class":219},"confirm",[200,536,537],{"class":257},"(\n",[200,539,541,544,546,548,551,553,555],{"class":202,"line":540},14,[200,542,543],{"class":219},"            __",[200,545,223],{"class":257},[200,547,277],{"class":210},[200,549,550],{"class":273},"Un bon de livraison existe déjà pour cette commande. Continuer ?",[200,552,277],{"class":210},[200,554,241],{"class":257},[200,556,415],{"class":210},[200,558,560,563,565,568,570,572,574],{"class":202,"line":559},15,[200,561,562],{"class":210},"            ()",[200,564,244],{"class":226},[200,566,567],{"class":219}," resolve",[200,569,223],{"class":257},[200,571,82],{"class":298},[200,573,241],{"class":257},[200,575,415],{"class":210},[200,577,579,581,583,585,587,589],{"class":202,"line":578},16,[200,580,562],{"class":210},[200,582,244],{"class":226},[200,584,567],{"class":219},[200,586,223],{"class":257},[200,588,140],{"class":298},[200,590,591],{"class":257},")\n",[200,593,595,598],{"class":202,"line":594},17,[200,596,597],{"class":257},"        )",[200,599,302],{"class":210},[200,601,603,605,607],{"class":202,"line":602},18,[200,604,468],{"class":210},[200,606,241],{"class":257},[200,608,302],{"class":210},[200,610,612,615,617],{"class":202,"line":611},19,[200,613,614],{"class":210},"}",[200,616,241],{"class":206},[200,618,302],{"class":210},[14,620,621,624],{},[18,622,623],{},"frappe.confirm"," ne renvoie pas de promesse. Enveloppez-la dans une promesse comme ci-dessus. La fonction de refus est appelée aussi quand l'utilisateur ferme la boîte.",[26,626,628],{"id":627},"bonnes-pratiques","Bonnes pratiques",[92,630,631,638,651],{},[95,632,633,634,637],{},"Testez ",[18,635,636],{},"mapped_doc.doctype"," en premier : une garde s'applique à tous les mappings.",[95,639,640,641,643,644,118,647,650],{},"Une garde ne doit pas modifier ",[18,642,99],{},". Pour préremplir des champs, utilisez le script client du document cible (",[18,645,646],{},"onload",[18,648,649],{},"refresh",") ou la méthode de mapping côté serveur.",[95,652,653],{},"Résolvez toujours la promesse. Sinon, les clics suivants sur « Créer » restent ignorés.",[655,656,657],"style",{},"html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sHdIc, html code.shiki .sHdIc{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#EEFFFF;--shiki-default-font-style:italic;--shiki-dark:#BABED8;--shiki-dark-font-style:italic}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .swJcz, html code.shiki .swJcz{--shiki-light:#E53935;--shiki-default:#F07178;--shiki-dark:#F07178}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}html pre.shiki code .sfNiH, html code.shiki .sfNiH{--shiki-light:#FF5370;--shiki-default:#FF9CAC;--shiki-dark:#FF9CAC}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":196,"searchDepth":203,"depth":250,"links":659},[660,661,662,663],{"id":28,"depth":250,"text":29},{"id":144,"depth":250,"text":145},{"id":177,"depth":250,"text":178},{"id":627,"depth":250,"text":628},"Bloquer ou confirmer l'ouverture d'un document créé par mapping (bouton « Créer ») avec les gardes JavaScript frappe.model.add_mapped_doc_guard.","md",{"icon":667,"reviewed":308,"last_verified":668,"sources":669},"i-mdi-hook","2026-11-03",[670],"dodock@develop:frappe\u002Fpublic\u002Fjs\u002Ffrappe\u002Fmodel\u002Fcreate_new.js","\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fcomposants-ui\u002Futiliser-les-points-d-extension-client",{"title":5,"description":664},"2.next\u002F3.dodock\u002F10.developpeurs\u002F03.composants-ui\u002Futiliser-les-points-d-extension-client","iMHrM9Q4KKFtM4-61TcTSQS6HHaLnkQXL8Ktx5oUdSE",{},1793871741591]