Item: bouton raccourci '💲 Prix de vente' (Client Script) → ouvre/crée l'Item Price Standard Selling en 1 clic

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) <noreply@anthropic.com>
This commit is contained in:
louispaulb 2026-06-04 07:07:50 -04:00
parent aad579d8bb
commit 49721eae8e

View File

@ -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")