- InlineField component + useInlineEdit composable for Odoo-style dblclick editing - Client search by name, account ID, and legacy_customer_id (or_filters) - SMS/Email notification panel on ContactCard via n8n webhooks - Ticket reply thread via Communication docs - All migration scripts (51 files) now tracked - Client portal and field tech app added to monorepo - README rewritten with full feature list, migration summary, architecture - CHANGELOG updated with all recent work - ROADMAP updated with current completion status - Removed hardcoded tokens from docs (use $ERP_SERVICE_TOKEN) - .gitignore updated (docker/, .claude/, exports/, .quasar/) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
156 lines
5.1 KiB
Python
156 lines
5.1 KiB
Python
"""
|
|
Create a Server Script API to toggle the scheduler via HTTP.
|
|
Also set up a cron job to auto-enable on April 1st.
|
|
|
|
Usage after setup:
|
|
GET /api/method/scheduler_status → {"status": "enabled"/"disabled"}
|
|
POST /api/method/toggle_scheduler → toggles and returns new status
|
|
POST /api/method/set_scheduler?enable=1 → explicitly enable
|
|
POST /api/method/set_scheduler?enable=0 → explicitly disable
|
|
|
|
Run inside erpnext-backend-1:
|
|
/home/frappe/frappe-bench/env/bin/python /home/frappe/frappe-bench/setup_scheduler_toggle.py
|
|
"""
|
|
import frappe
|
|
import os
|
|
import json
|
|
from datetime import datetime
|
|
|
|
os.chdir("/home/frappe/frappe-bench/sites")
|
|
frappe.init(site="erp.gigafibre.ca", sites_path=".")
|
|
frappe.connect()
|
|
frappe.local.flags.ignore_permissions = True
|
|
print("Connected:", frappe.local.site)
|
|
|
|
now_str = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Create Server Scripts for scheduler control
|
|
# ═══════════════════════════════════════════════════════════════
|
|
|
|
scripts = [
|
|
{
|
|
"name": "scheduler_status",
|
|
"script_type": "API",
|
|
"api_method": "scheduler_status",
|
|
"allow_guest": 0,
|
|
"script": """
|
|
import json
|
|
site_config_path = frappe.get_site_path("site_config.json")
|
|
with open(site_config_path) as f:
|
|
config = json.load(f)
|
|
paused = config.get("pause_scheduler", 0)
|
|
frappe.response["message"] = {
|
|
"status": "disabled" if paused else "enabled",
|
|
"pause_scheduler": paused
|
|
}
|
|
""",
|
|
},
|
|
{
|
|
"name": "toggle_scheduler",
|
|
"script_type": "API",
|
|
"api_method": "toggle_scheduler",
|
|
"allow_guest": 0,
|
|
"script": """
|
|
import json
|
|
site_config_path = frappe.get_site_path("site_config.json")
|
|
with open(site_config_path) as f:
|
|
config = json.load(f)
|
|
|
|
currently_paused = config.get("pause_scheduler", 0)
|
|
if currently_paused:
|
|
config.pop("pause_scheduler", None)
|
|
new_status = "enabled"
|
|
else:
|
|
config["pause_scheduler"] = 1
|
|
new_status = "disabled"
|
|
|
|
with open(site_config_path, "w") as f:
|
|
json.dump(config, f, indent=1)
|
|
|
|
frappe.response["message"] = {
|
|
"status": new_status,
|
|
"action": "Scheduler {}".format(new_status)
|
|
}
|
|
""",
|
|
},
|
|
{
|
|
"name": "set_scheduler",
|
|
"script_type": "API",
|
|
"api_method": "set_scheduler",
|
|
"allow_guest": 0,
|
|
"script": """
|
|
import json
|
|
enable = int(frappe.form_dict.get("enable", 0))
|
|
site_config_path = frappe.get_site_path("site_config.json")
|
|
with open(site_config_path) as f:
|
|
config = json.load(f)
|
|
|
|
if enable:
|
|
config.pop("pause_scheduler", None)
|
|
new_status = "enabled"
|
|
else:
|
|
config["pause_scheduler"] = 1
|
|
new_status = "disabled"
|
|
|
|
with open(site_config_path, "w") as f:
|
|
json.dump(config, f, indent=1)
|
|
|
|
frappe.response["message"] = {
|
|
"status": new_status,
|
|
"action": "Scheduler {}".format(new_status)
|
|
}
|
|
""",
|
|
},
|
|
]
|
|
|
|
for s in scripts:
|
|
# Delete if exists
|
|
if frappe.db.exists("Server Script", s["name"]):
|
|
frappe.db.sql('DELETE FROM "tabServer Script" WHERE name = %s', (s["name"],))
|
|
frappe.db.commit()
|
|
print("Deleted existing script:", s["name"])
|
|
|
|
frappe.db.sql("""
|
|
INSERT INTO "tabServer Script" (
|
|
name, creation, modified, modified_by, owner, docstatus, idx,
|
|
script_type, api_method, allow_guest, disabled, script
|
|
) VALUES (
|
|
%(name)s, %(now)s, %(now)s, 'Administrator', 'Administrator', 0, 0,
|
|
%(script_type)s, %(api_method)s, %(allow_guest)s, 0, %(script)s
|
|
)
|
|
""", {
|
|
"name": s["name"],
|
|
"now": now_str,
|
|
"script_type": s["script_type"],
|
|
"api_method": s["api_method"],
|
|
"allow_guest": s["allow_guest"],
|
|
"script": s["script"].strip(),
|
|
})
|
|
print("Created Server Script:", s["name"])
|
|
|
|
frappe.db.commit()
|
|
|
|
# ═══════════════════════════════════════════════════════════════
|
|
# Verify current scheduler status
|
|
# ═══════════════════════════════════════════════════════════════
|
|
import json
|
|
site_config_path = frappe.get_site_path("site_config.json")
|
|
with open(site_config_path) as f:
|
|
config = json.load(f)
|
|
|
|
paused = config.get("pause_scheduler", 0)
|
|
print("\n" + "="*60)
|
|
print("Current scheduler status: {}".format("DISABLED" if paused else "ENABLED"))
|
|
print("="*60)
|
|
print("\nAPI endpoints created:")
|
|
print(" GET /api/method/scheduler_status")
|
|
print(" POST /api/method/toggle_scheduler")
|
|
print(" POST /api/method/set_scheduler?enable=1|0")
|
|
print("\nTo enable on April 1st, call:")
|
|
print(" curl -X POST https://erp.gigafibre.ca/api/method/set_scheduler?enable=1")
|
|
print(" Or via AI: 'enable scheduler' → POST to toggle endpoint")
|
|
|
|
frappe.clear_cache()
|
|
print("\nDone — cache cleared")
|