OSS-BSS-Field-Dispatch/frappe-setup/setup_dispatch_custom_fields.py
louispaulb fa1172a495 Dispatch Job booking_status: ajout option 'À reporter' (file reschedule)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 13:28:47 -04:00

61 lines
3.4 KiB
Python

"""
Custom Fields pour la planification (Roster AI) + prise de RDV — idempotent.
==========================================================================
Consolide tous les champs ajoutés à Dispatch Technician et Dispatch Job pour
le module Roster/Planification et le booking. Remplace les scripts épars.
Exécution :
docker cp setup_dispatch_custom_fields.py erpnext-backend-1:/tmp/
docker exec erpnext-backend-1 sh -lc \
"cd /home/frappe/frappe-bench && env/bin/python /tmp/setup_dispatch_custom_fields.py"
(créer d'abord /home/frappe/logs si frappe.init s'en plaint — cf.
reference_frappe_hr_postgres.md §Pièges scripts)
"""
import frappe
frappe.init(site="erp.gigafibre.ca", sites_path="sites")
frappe.connect()
frappe.flags.ignore_permissions = True
# (dt, fieldname, label, fieldtype, options, default, insert_after, extra)
FIELDS = [
# ── Dispatch Technician : cadence, coût chargé, compétences ──
("Dispatch Technician", "efficiency", "Cadence (facteur temps)", "Float", None, "1.0", "tech_group",
{"description": "1.0 = normal · 1.10 = +10% (plus lent) · 0.90 = -10% (plus rapide)"}),
("Dispatch Technician", "skills", "Compétences", "Data", None, None, "tech_group",
{"description": "Séparées par des virgules, ex: fibre,cuivre,aerien"}),
("Dispatch Technician", "cost_salary_h", "Salaire horaire ($/h)", "Float", None, "0", "efficiency", {}),
("Dispatch Technician", "cost_charges_pct", "Charges sociales (%)", "Float", None, "0", "cost_salary_h", {}),
("Dispatch Technician", "cost_other_h", "Autres coûts/h ($ véhicule, outils, frais)", "Float", None, "0", "cost_charges_pct", {}),
# ── Dispatch Job : prise de RDV ──
("Dispatch Job", "booking_prefs", "Préférences RDV (JSON)", "Small Text", None, None, "status", {}),
("Dispatch Job", "booking_status", "Statut RDV", "Select", "À planifier\nProposé\nConfirmé\nAnnulé\nÀ reporter", "À planifier", "booking_prefs", {}),
("Dispatch Job", "booking_token", "Jeton RDV client", "Data", None, None, "booking_status",
{"read_only": 1, "no_copy": 1}),
# ── Service Contract : installation financée (conformité CRTC 2026-43, pas de clawback) ──
("Service Contract", "monthly_regular", "Forfait — prix original (barré)", "Currency", None, None, "monthly_rate",
{"description": "Prix mensuel de référence barré (marketing). Le montant facturé reste monthly_rate. Vide/≤ = aucun barré."}),
("Service Contract", "install_fee", "Installation financée ($)", "Currency", None, None, "monthly_regular",
{"description": "Install financée sur la durée (vraie créance, pas une promo). Ex: 240 standard / 120 simple."}),
("Service Contract", "install_regular", "Installation — valeur affichée (barrée)", "Currency", None, None, "install_fee",
{"description": "Prix de référence barré (marketing), ex. 360. Le montant réellement financé/dû reste install_fee (ex. 240)."}),
]
for dt, fn, label, ft, opts, default, after, extra in FIELDS:
cf = f"{dt}-{fn}"
if frappe.db.exists("Custom Field", cf):
print("EXISTS", cf)
continue
doc = {"doctype": "Custom Field", "dt": dt, "fieldname": fn, "label": label,
"fieldtype": ft, "insert_after": after}
if opts:
doc["options"] = opts
if default is not None:
doc["default"] = default
doc.update(extra or {})
frappe.get_doc(doc).insert()
print("CREATED", cf)
frappe.db.commit()
print("DONE")