From 49721eae8e0c168f253462eabe8466076ffb4d12 Mon Sep 17 00:00:00 2001 From: louispaulb Date: Thu, 4 Jun 2026 07:07:50 -0400 Subject: [PATCH] =?UTF-8?q?Item:=20bouton=20raccourci=20'=F0=9F=92=B2=20Pr?= =?UTF-8?q?ix=20de=20vente'=20(Client=20Script)=20=E2=86=92=20ouvre/cr?= =?UTF-8?q?=C3=A9e=20l'Item=20Price=20Standard=20Selling=20en=201=20clic?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Contourne l'UX peu intuitive d'ERPNext (prix dans doctype séparé). Variantes → bouton 'Variantes & prix'. Stocké en base (survit aux recreate). Co-Authored-By: Claude Opus 4.8 (1M context) --- frappe-setup/setup_item_price_button.py | 66 +++++++++++++++++++++++++ 1 file changed, 66 insertions(+) create mode 100644 frappe-setup/setup_item_price_button.py diff --git a/frappe-setup/setup_item_price_button.py b/frappe-setup/setup_item_price_button.py new file mode 100644 index 0000000..a777e24 --- /dev/null +++ b/frappe-setup/setup_item_price_button.py @@ -0,0 +1,66 @@ +""" +Raccourci prix sur la fiche Item (Client Script) — idempotent. +============================================================== +ERPNext stocke le prix de vente dans un doctype séparé (Item Price), pas en +champ direct → peu intuitif. Ce Client Script ajoute un bouton sur la fiche Item : + + • Item simple / bundle → « 💲 Prix de vente » : ouvre l'Item Price (Standard + Selling) existant, ou en crée un pré-rempli (item_code + price_list + selling). + • Item template variantes → « Variantes & prix » : liste les variantes (chacune + a son propre prix via le même bouton). + +Stocké en base (doctype Client Script) → survit aux recreate de conteneur +(contrairement aux patchs de fichiers). S'applique sans rebuild ni restart ; +recharger la fiche Item (hard refresh) suffit. + +Exécution : + docker cp setup_item_price_button.py erpnext-backend-1:/tmp/ + docker exec erpnext-backend-1 sh -lc \ + "cd /home/frappe/frappe-bench && env/bin/python /tmp/setup_item_price_button.py" +""" +import frappe + +frappe.init(site="erp.gigafibre.ca", sites_path="sites") +frappe.connect() +frappe.flags.ignore_permissions = True + +CS_NAME = "Item - Prix de vente (bouton)" +JS = r""" +// PRIX_VENTE_BTN — raccourci vers l'Item Price (Standard Selling) depuis la fiche Item +frappe.ui.form.on('Item', { + refresh(frm) { + if (frm.is_new()) return; + if (frm.doc.has_variants) { + frm.add_custom_button('Variantes & prix', function() { + frappe.set_route('List', 'Item', { variant_of: frm.doc.name }); + }); + return; + } + frm.add_custom_button('💲 Prix de vente', function() { + frappe.db.get_value('Item Price', + { item_code: frm.doc.name, price_list: 'Standard Selling', selling: 1 }, 'name' + ).then(function(r) { + var name = r.message && r.message.name; + if (name) { frappe.set_route('Form', 'Item Price', name); return; } + frappe.model.with_doctype('Item Price', function() { + var d = frappe.model.get_new_doc('Item Price'); + d.item_code = frm.doc.name; + d.price_list = 'Standard Selling'; + d.selling = 1; + frappe.set_route('Form', 'Item Price', d.name); + }); + }); + }).addClass('btn-primary'); + } +}); +""" + +if frappe.db.exists("Client Script", CS_NAME): + frappe.db.set_value("Client Script", CS_NAME, {"script": JS, "enabled": 1}) + print("MAJ:", CS_NAME) +else: + frappe.get_doc({"doctype": "Client Script", "name": CS_NAME, "dt": "Item", + "view": "Form", "enabled": 1, "script": JS}).insert() + print("CRÉÉ:", CS_NAME) +frappe.db.commit() +print("DONE")