[{"data":1,"prerenderedAt":598},["ShallowReactive",2],{"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fhooks":3,"section:\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fhooks":597},{"id":4,"title":5,"body":6,"description":578,"extension":579,"meta":580,"navigation":582,"path":593,"seo":594,"stem":595,"__hash__":596},"docs\u002F2.next\u002F3.dodock\u002F10.developpeurs\u002Fhooks.md","Référence des hooks",{"type":7,"value":8,"toc":571},"minimark",[9,13,48,123,128,142,149,184,197,200,204,209,216,233,247,284,287,294,303,307,315,325,340,343,351,355,362,538,542,567],[10,11,5],"h1",{"id":12},"référence-des-hooks",[14,15,16,17,21,22,25,26,29,30,29,33,29,36,39,40,47],"p",{},"Un hook est une variable du fichier ",[18,19,20],"code",{},"hooks.py"," d'une application. Dodock lit les hooks de toutes les applications installées avec ",[18,23,24],{},"frappe.get_hooks()",". Cette page décrit les hooks propres à Dodock. Pour les hooks standard de Frappe (",[18,27,28],{},"doc_events",", ",[18,31,32],{},"scheduler_events",[18,34,35],{},"has_permission",[18,37,38],{},"permission_query_conditions","…), voir la ",[41,42,46],"a",{"href":43,"rel":44},"https:\u002F\u002Fdocs.frappe.io\u002Fframework\u002Fuser\u002Fen\u002Fpython-api\u002Fhooks",[45],"nofollow","documentation des hooks de Frappe"," (en anglais).",[49,50,51,67],"table",{},[52,53,54],"thead",{},[55,56,57,61,64],"tr",{},[58,59,60],"th",{},"Hook",[58,62,63],{},"Valeur",[58,65,66],{},"Effet",[68,69,70,87,104],"tbody",{},[55,71,72,78,81],{},[73,74,75],"td",{},[18,76,77],{},"never_skip_patches",[73,79,80],{},"Liste de chemins de correctifs",[73,82,83,84],{},"Ces correctifs arrêtent la migration s'ils échouent, même avec ",[18,85,86],{},"--skip-failing",[55,88,89,94,97],{},[73,90,91],{},[18,92,93],{},"after_app_build",[73,95,96],{},"Chemin d'une fonction (ou liste)",[73,98,99,100,103],{},"Appelé après chaque ",[18,101,102],{},"bench build",", avec la liste des applications compilées",[55,105,106,111,116],{},[73,107,108],{},[18,109,110],{},"ignore_file_permissions",[73,112,113],{},[18,114,115],{},"True",[73,117,118,119],{},"Désactive les contrôles d'accès sur les documents ",[120,121,122],"strong",{},"Fichier",[124,125,126],"h2",{"id":77},[18,127,77],{},[14,129,130,131,134,135,138,139,141],{},"Avec ",[18,132,133],{},"bench migrate --skip-failing",", Dodock enregistre un correctif qui échoue dans le ",[120,136,137],{},"Journal de Patch"," comme ignoré, puis passe aux correctifs suivants. Un correctif listé dans ",[18,140,77],{}," n'est jamais ignoré : s'il échoue, la migration s'arrête.",[14,143,144,145,148],{},"Chaque entrée est le chemin du correctif tel qu'il figure dans le fichier ",[18,146,147],{},"patches.txt"," de l'application.",[150,151,156],"pre",{"className":152,"code":153,"language":154,"meta":155,"style":155},"language-python shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","# mon_app\u002Fhooks.py\nnever_skip_patches = [\n    \"mon_app.patches.v5_0.restructurer_ecritures_comptables\",\n]\n","python","",[18,157,158,166,172,178],{"__ignoreMap":155},[159,160,163],"span",{"class":161,"line":162},"line",1,[159,164,165],{},"# mon_app\u002Fhooks.py\n",[159,167,169],{"class":161,"line":168},2,[159,170,171],{},"never_skip_patches = [\n",[159,173,175],{"class":161,"line":174},3,[159,176,177],{},"    \"mon_app.patches.v5_0.restructurer_ecritures_comptables\",\n",[159,179,181],{"class":161,"line":180},4,[159,182,183],{},"]\n",[14,185,186,189,190,193,194,196],{},[120,187,188],{},"Exemple"," : le correctif ",[18,191,192],{},"restructurer_ecritures_comptables"," réécrit les écritures d'une société. L'ignorer laisserait la comptabilité dans un état incohérent. Avec ce hook, si le correctif échoue pendant ",[18,195,133],{},", la migration s'arrête. L'administrateur corrige la cause, puis relance la migration.",[14,198,199],{},"Réservez ce hook aux correctifs dont l'échec rend les données incohérentes.",[124,201,202],{"id":93},[18,203,93],{},[14,205,206,208],{},[18,207,93],{}," permet à une application de réagir à la compilation des assets d'une autre application. Par exemple, une application compile les ressources qu'elle gère pour le compte d'une autre application.",[14,210,211,212,215],{},"Il diffère de ",[18,213,214],{},"after_build"," :",[217,218,219,225],"ul",{},[220,221,222,224],"li",{},[18,223,214],{}," s'exécute uniquement pour les applications qui viennent d'être compilées. Dodock appelle la fonction sans argument.",[220,226,227,229,230,232],{},[18,228,93],{}," s'exécute pour toutes les applications du banc, après les ",[18,231,214],{},". Dodock appelle la fonction avec la liste des applications compilées.",[150,234,236],{"className":152,"code":235,"language":154,"meta":155,"style":155},"# mon_app\u002Fhooks.py\nafter_app_build = \"mon_app.build.after_app_build\"\n",[18,237,238,242],{"__ignoreMap":155},[159,239,240],{"class":161,"line":162},[159,241,165],{},[159,243,244],{"class":161,"line":168},[159,245,246],{},"after_app_build = \"mon_app.build.after_app_build\"\n",[150,248,250],{"className":152,"code":249,"language":154,"meta":155,"style":155},"# mon_app\u002Fbuild.py\ndef after_app_build(built_apps: list[str]) -> None:\n    if \"autre_app\" not in built_apps:\n        return\n    # Compiler les ressources de « autre_app » gérées par « mon_app »\n    ...\n",[18,251,252,257,262,267,272,278],{"__ignoreMap":155},[159,253,254],{"class":161,"line":162},[159,255,256],{},"# mon_app\u002Fbuild.py\n",[159,258,259],{"class":161,"line":168},[159,260,261],{},"def after_app_build(built_apps: list[str]) -> None:\n",[159,263,264],{"class":161,"line":174},[159,265,266],{},"    if \"autre_app\" not in built_apps:\n",[159,268,269],{"class":161,"line":180},[159,270,271],{},"        return\n",[159,273,275],{"class":161,"line":274},5,[159,276,277],{},"    # Compiler les ressources de « autre_app » gérées par « mon_app »\n",[159,279,281],{"class":161,"line":280},6,[159,282,283],{},"    ...\n",[14,285,286],{},"La valeur de retour n'est pas utilisée. Dodock lui-même déclare ce hook : il compile ainsi les îlots des pages d'interface et les applications Studio exportées après chaque build.",[14,288,289,290,293],{},"Le modèle d'application créé par ",[18,291,292],{},"bench new-app"," contient la ligne à adapter, en commentaire :",[150,295,297],{"className":152,"code":296,"language":154,"meta":155,"style":155},"# after_app_build = \"{app_name}.build.after_app_build\"\n",[18,298,299],{"__ignoreMap":155},[159,300,301],{"class":161,"line":162},[159,302,296],{},[124,304,305],{"id":110},[18,306,110],{},[14,308,309,310,312,313,215],{},"Si une application installée déclare ",[18,311,110],{}," avec une valeur vraie, Dodock ne contrôle plus l'accès aux documents ",[120,314,122],{},[217,316,317,322],{},[220,318,319,321],{},[18,320,35],{}," sur un fichier renvoie toujours vrai, pour tous les utilisateurs, y compris les invités ;",[220,323,324],{},"la liste des fichiers n'est plus filtrée par utilisateur.",[150,326,328],{"className":152,"code":327,"language":154,"meta":155,"style":155},"# hooks.py d'une application qui gère elle-même l'accès aux fichiers\nignore_file_permissions = True\n",[18,329,330,335],{"__ignoreMap":155},[159,331,332],{"class":161,"line":162},[159,333,334],{},"# hooks.py d'une application qui gère elle-même l'accès aux fichiers\n",[159,336,337],{"class":161,"line":168},[159,338,339],{},"ignore_file_permissions = True\n",[14,341,342],{},"Il suffit qu'une seule application déclare une valeur vraie pour que le contournement s'applique à tout le site. Réservez-le à une application qui applique ses propres règles de partage des fichiers.",[344,345,348],"callout",{"color":346,"icon":347},"amber","i-mdi-alert-outline",[14,349,350],{},"Ce hook peut exposer des fichiers privés à des utilisateurs non autorisés. Déclarez-le uniquement dans une application qui contrôle elle-même l'accès aux fichiers, et testez-le d'abord sur un site de test.",[124,352,354],{"id":353},"hooks-standard-les-plus-utilisés","Hooks standard les plus utilisés",[14,356,357,358,47],{},"Ces hooks viennent de Frappe. Leur nom exact est vérifié dans le code de Dodock ; leur détail est dans la ",[41,359,361],{"href":43,"rel":360},[45],"documentation de Frappe",[49,363,364,373],{},[52,365,366],{},[55,367,368,370],{},[58,369,60],{},[58,371,372],{},"Usage",[68,374,375,400,421,431,441,451,470,480,493,506,522],{},[55,376,377,381],{},[73,378,379],{},[18,380,28],{},[73,382,383,384,29,387,29,390,29,393,29,396,399],{},"Appeler une fonction aux événements d'un type de document (",[18,385,386],{},"validate",[18,388,389],{},"on_update",[18,391,392],{},"on_submit",[18,394,395],{},"on_cancel",[18,397,398],{},"on_trash","…)",[55,401,402,406],{},[73,403,404],{},[18,405,32],{},[73,407,408,409,29,412,29,415,29,418,399],{},"Tâches planifiées (",[18,410,411],{},"daily",[18,413,414],{},"hourly",[18,416,417],{},"weekly",[18,419,420],{},"cron",[55,422,423,428],{},[73,424,425],{},[18,426,427],{},"override_doctype_class",[73,429,430],{},"Remplacer la classe Python d'un type de document",[55,432,433,438],{},[73,434,435],{},[18,436,437],{},"extend_doctype_class",[73,439,440],{},"Ajouter des méthodes à la classe Python d'un type de document, sans la remplacer. Plusieurs applications peuvent étendre la même classe",[55,442,443,448],{},[73,444,445],{},[18,446,447],{},"override_whitelisted_methods",[73,449,450],{},"Remplacer une méthode appelable par l'API",[55,452,453,467],{},[73,454,455,29,458,29,461,29,464],{},[18,456,457],{},"doctype_js",[18,459,460],{},"doctype_list_js",[18,462,463],{},"doctype_tree_js",[18,465,466],{},"doctype_calendar_js",[73,468,469],{},"Ajouter du JavaScript au formulaire, à la liste, à l'arborescence ou au calendrier d'un type de document",[55,471,472,477],{},[73,473,474],{},[18,475,476],{},"boot_session",[73,478,479],{},"Ajouter des données à la session chargée au démarrage du bureau",[55,481,482,490],{},[73,483,484,29,487],{},[18,485,486],{},"on_login",[18,488,489],{},"on_logout",[73,491,492],{},"Réagir à la connexion et à la déconnexion",[55,494,495,503],{},[73,496,497,29,500],{},[18,498,499],{},"before_request",[18,501,502],{},"after_request",[73,504,505],{},"Exécuter du code avant et après chaque requête HTTP",[55,507,508,516],{},[73,509,510,29,513],{},[18,511,512],{},"before_migrate",[18,514,515],{},"after_migrate",[73,517,518,519],{},"Exécuter du code avant et après ",[18,520,521],{},"bench migrate",[55,523,524,535],{},[73,525,526,29,529,29,532],{},[18,527,528],{},"after_install",[18,530,531],{},"after_app_install",[18,533,534],{},"before_app_uninstall",[73,536,537],{},"Réagir à l'installation de l'application, à l'installation d'une autre application, à la désinstallation",[124,539,541],{"id":540},"autres-hooks-documentés","Autres hooks documentés",[217,543,544,555,561],{},[220,545,546,550,551,554],{},[41,547,549],{"href":548},"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fresolveurs-base-taxable","Résolveurs de base taxable"," : le hook ",[18,552,553],{},"erpnext_taxable_base_resolvers"," de Dokos.",[220,556,557],{},[41,558,560],{"href":559},"\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fhook-regional-cotisations-employeur","Hook régional pour les cotisations employeur",[220,562,563],{},[41,564,566],{"href":565},"\u002Fnext\u002Fadministrer\u002Fperformance\u002Fanalyse-des-hooks-dans-les-performances","Analyse des hooks dans les performances",[568,569,570],"style",{},"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":155,"searchDepth":162,"depth":168,"links":572},[573,574,575,576,577],{"id":77,"depth":168,"text":77},{"id":93,"depth":168,"text":93},{"id":110,"depth":168,"text":110},{"id":353,"depth":168,"text":354},{"id":540,"depth":168,"text":541},"Hooks propres à Dodock déclarés dans le fichier hooks.py d'une application : never_skip_patches, after_app_build et ignore_file_permissions.","md",{"icon":581,"reviewed":582,"last_verified":583,"sources":584},"i-mdi-hook",true,"2026-11-03",[585,586,587,588,589,590,591,592],"dodock@develop:frappe\u002Fboot.py","dodock@develop:frappe\u002Finstaller.py","dodock@develop:frappe\u002Fmodel\u002Fbase_document.py","dodock@develop:frappe\u002Fmodules\u002Fpatch_handler.py","dodock@develop:frappe\u002Fcommands\u002Futils.py","dodock@develop:frappe\u002Futils\u002Fboilerplate.py","dodock@develop:frappe\u002Fhooks.py","dodock@develop:frappe\u002Fcore\u002Fdoctype\u002Ffile\u002Ffile.py","\u002Fnext\u002Fdodock\u002Fdeveloppeurs\u002Fhooks",{"title":5,"description":578},"2.next\u002F3.dodock\u002F10.developpeurs\u002Fhooks","nhVQZCqvzSUF4VIPkWYsw9XKFS1yX0UOuafxVQGmbBE",{},1793871744954]