291 lines
13 KiB
Python
291 lines
13 KiB
Python
"""
|
|
Create clean sidebar workspaces for DiDi ERPNext.
|
|
Run: python setup-sidebar.py
|
|
"""
|
|
import requests
|
|
import json
|
|
|
|
ERPNEXT_URL = "http://localhost:8080"
|
|
|
|
# Login as Administrator
|
|
session = requests.Session()
|
|
login = session.post(f"{ERPNEXT_URL}/api/method/login", data={"usr": "Administrator", "pwd": "admin"})
|
|
if login.status_code != 200:
|
|
print(f"Login failed: {login.status_code}")
|
|
exit(1)
|
|
print("Logged in as Administrator")
|
|
|
|
|
|
def api(method, endpoint, data=None):
|
|
url = f"{ERPNEXT_URL}{endpoint}"
|
|
if method == "GET":
|
|
r = session.get(url, params=data)
|
|
elif method == "POST":
|
|
r = session.post(url, json=data)
|
|
elif method == "PUT":
|
|
r = session.put(url, json=data)
|
|
elif method == "DELETE":
|
|
r = session.delete(url)
|
|
else:
|
|
return None
|
|
return r
|
|
|
|
|
|
# ─── 1. Give API user Workspace Manager role ───
|
|
print("\n1. Adding Workspace Manager role to API user...")
|
|
try:
|
|
r = session.post(f"{ERPNEXT_URL}/api/method/frappe.client.get_list", json={
|
|
"doctype": "Has Role",
|
|
"filters": {"parent": "website_api@didi-erp", "role": "Workspace Manager"},
|
|
"fields": ["name"],
|
|
})
|
|
existing = r.json().get("message", [])
|
|
if not existing:
|
|
user_doc = session.get(f"{ERPNEXT_URL}/api/resource/User/website_api@didi-erp").json()["data"]
|
|
roles = user_doc.get("roles", [])
|
|
roles.append({"role": "Workspace Manager"})
|
|
session.put(f"{ERPNEXT_URL}/api/resource/User/website_api@didi-erp", json={"roles": roles})
|
|
print(" Added Workspace Manager role")
|
|
else:
|
|
print(" Already has Workspace Manager role")
|
|
except Exception as e:
|
|
print(f" Warning: {e}")
|
|
|
|
# ─── 2. Hide old workspaces ───
|
|
print("\n2. Hiding old/unused workspaces...")
|
|
to_hide = [
|
|
"DiDi Platform", "DiDi", "Accounting", "CRM", "Selling",
|
|
"Assets", "Build", "Buying", "ERPNext Integrations", "ERPNext Settings",
|
|
"Financial Reports", "Integrations", "Manufacturing", "Payables",
|
|
"Projects", "Quality", "Receivables", "Stock", "Support",
|
|
]
|
|
for ws_name in to_hide:
|
|
try:
|
|
r = api("PUT", f"/api/resource/Workspace/{requests.utils.quote(ws_name)}", {"is_hidden": 1})
|
|
if r.status_code == 200:
|
|
print(f" Hidden: {ws_name}")
|
|
else:
|
|
print(f" Skip (not found or error): {ws_name}")
|
|
except:
|
|
pass
|
|
|
|
# ─── 3. Create new sidebar workspaces ───
|
|
print("\n3. Creating sidebar workspaces...")
|
|
|
|
WORKSPACES = [
|
|
{
|
|
"name": "Facturi",
|
|
"title": "Facturi",
|
|
"icon": "file-text",
|
|
"indicator_color": "green",
|
|
"sequence_id": 10,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Facturare</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Toate Facturile", "col": 4}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Facturi Platite", "col": 4}},
|
|
{"id": "s3", "type": "shortcut", "data": {"shortcut_name": "Payment Entry", "col": 4}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Sales Invoice", "label": "Toate Facturile", "color": "Green", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Sales Invoice", "label": "Facturi Platite", "color": "Blue", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Payment Entry", "label": "Payment Entry", "color": "Yellow", "doc_view": "List"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "Facturi"},
|
|
{"type": "Link", "label": "Sales Invoice", "link_to": "Sales Invoice", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Payment Entry", "link_to": "Payment Entry", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Taxe (TVA)", "link_to": "Sales Taxes and Charges Template", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "Clienti",
|
|
"title": "Clienti",
|
|
"icon": "user",
|
|
"indicator_color": "blue",
|
|
"sequence_id": 20,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Clienti</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Toti Clientii", "col": 6}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Service Agreement", "col": 6}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Customer", "label": "Toti Clientii", "color": "Blue", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Service Agreement", "label": "Service Agreement", "color": "Purple", "doc_view": "List"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "Clienti"},
|
|
{"type": "Link", "label": "Customer", "link_to": "Customer", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Service Agreement", "link_to": "Service Agreement", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Subscription Plan", "link_to": "Subscription Plan", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "CRM DiDi",
|
|
"title": "CRM",
|
|
"icon": "share",
|
|
"indicator_color": "orange",
|
|
"sequence_id": 30,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>CRM & Lead Management</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Lead-uri", "col": 4}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Sales Stage", "col": 4}},
|
|
{"id": "s3", "type": "shortcut", "data": {"shortcut_name": "Lead Source", "col": 4}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Lead", "label": "Lead-uri", "color": "Orange", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Sales Stage", "label": "Sales Stage", "color": "Yellow"},
|
|
{"type": "DocType", "link_to": "Lead Source", "label": "Lead Source", "color": "Grey"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "CRM"},
|
|
{"type": "Link", "label": "Lead", "link_to": "Lead", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Sales Stage", "link_to": "Sales Stage", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Lead Source", "link_to": "Lead Source", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "Servicii DiDi",
|
|
"title": "Servicii",
|
|
"icon": "box",
|
|
"indicator_color": "purple",
|
|
"sequence_id": 40,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Servicii & Produse</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Articole", "col": 6}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Planuri Abonament", "col": 6}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Item", "label": "Articole", "color": "Purple", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Subscription Plan", "label": "Planuri Abonament", "color": "Cyan"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "Catalog"},
|
|
{"type": "Link", "label": "Item", "link_to": "Item", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Item Group", "link_to": "Item Group", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Subscription Plan", "link_to": "Subscription Plan", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "Plati DiDi",
|
|
"title": "Plati",
|
|
"icon": "credit-card",
|
|
"indicator_color": "yellow",
|
|
"sequence_id": 50,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Plati Stripe & Log</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Payment Log", "col": 6}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Analysis Report", "col": 6}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Payment Log", "label": "Payment Log", "color": "Yellow", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Analysis Report", "label": "Analysis Report", "color": "Pink", "doc_view": "List"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "Plati"},
|
|
{"type": "Link", "label": "Payment Log", "link_to": "Payment Log", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Analysis Report", "link_to": "Analysis Report", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "Contabilitate DiDi",
|
|
"title": "Contabilitate",
|
|
"icon": "calculator",
|
|
"indicator_color": "grey",
|
|
"sequence_id": 60,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Contabilitate</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Plan Conturi", "col": 4}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Furnizori", "col": 4}},
|
|
{"id": "s3", "type": "shortcut", "data": {"shortcut_name": "Companie", "col": 4}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Account", "label": "Plan Conturi", "color": "Grey", "doc_view": "Tree"},
|
|
{"type": "DocType", "link_to": "Supplier", "label": "Furnizori", "color": "Blue"},
|
|
{"type": "DocType", "link_to": "Company", "label": "Companie", "color": "Green"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "Contabilitate"},
|
|
{"type": "Link", "label": "Account", "link_to": "Account", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Company", "link_to": "Company", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Supplier", "link_to": "Supplier", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Purchase Invoice", "link_to": "Purchase Invoice", "link_type": "DocType"},
|
|
{"type": "Link", "label": "Sales Taxes Template", "link_to": "Sales Taxes and Charges Template", "link_type": "DocType"},
|
|
],
|
|
},
|
|
{
|
|
"name": "Website CMS DiDi",
|
|
"title": "Website CMS",
|
|
"icon": "globe",
|
|
"indicator_color": "cyan",
|
|
"sequence_id": 70,
|
|
"content": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": "<span class=\"h4\"><b>Continut Website</b></span>", "col": 12}},
|
|
{"id": "s1", "type": "shortcut", "data": {"shortcut_name": "Website Content", "col": 6}},
|
|
{"id": "s2", "type": "shortcut", "data": {"shortcut_name": "Email Template", "col": 6}},
|
|
]),
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Website Content", "label": "Website Content", "color": "Cyan", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Email Template", "label": "Email Template", "color": "Grey"},
|
|
],
|
|
"links": [
|
|
{"type": "Card Break", "label": "CMS"},
|
|
{"type": "Link", "label": "Website Content", "link_to": "Website Content", "link_type": "DocType", "onboard": 1},
|
|
{"type": "Link", "label": "Email Template", "link_to": "Email Template", "link_type": "DocType"},
|
|
],
|
|
},
|
|
]
|
|
|
|
for ws in WORKSPACES:
|
|
name = ws["name"]
|
|
# Check if exists
|
|
check = session.get(f"{ERPNEXT_URL}/api/resource/Workspace/{requests.utils.quote(name)}")
|
|
if check.status_code == 200:
|
|
# Update it
|
|
r = api("PUT", f"/api/resource/Workspace/{requests.utils.quote(name)}", {
|
|
"title": ws["title"],
|
|
"icon": ws["icon"],
|
|
"indicator_color": ws["indicator_color"],
|
|
"is_hidden": 0,
|
|
"public": 1,
|
|
"module": "Didi Custom",
|
|
"sequence_id": ws["sequence_id"],
|
|
"content": ws["content"],
|
|
"shortcuts": ws["shortcuts"],
|
|
"links": ws["links"],
|
|
})
|
|
if r.status_code == 200:
|
|
print(f" Updated: {name}")
|
|
else:
|
|
print(f" Error updating {name}: {r.status_code} {r.text[:200]}")
|
|
else:
|
|
# Create it
|
|
r = api("POST", "/api/resource/Workspace", {
|
|
"name": name,
|
|
"label": name,
|
|
"title": ws["title"],
|
|
"icon": ws["icon"],
|
|
"indicator_color": ws["indicator_color"],
|
|
"is_hidden": 0,
|
|
"public": 1,
|
|
"module": "Didi Custom",
|
|
"sequence_id": ws["sequence_id"],
|
|
"content": ws["content"],
|
|
"shortcuts": ws["shortcuts"],
|
|
"links": ws["links"],
|
|
})
|
|
if r.status_code in (200, 201):
|
|
print(f" Created: {name}")
|
|
else:
|
|
print(f" Error creating {name}: {r.status_code} {r.text[:200]}")
|
|
|
|
print("\n4. Verifying sidebar...")
|
|
r = session.get(f"{ERPNEXT_URL}/api/resource/Workspace", params={
|
|
"filters": json.dumps([["public", "=", 1], ["is_hidden", "=", 0]]),
|
|
"fields": json.dumps(["name", "title", "icon", "sequence_id"]),
|
|
"order_by": "sequence_id asc",
|
|
"limit_page_length": 20,
|
|
})
|
|
for ws in r.json().get("data", []):
|
|
print(f" [{ws.get('sequence_id', '?')}] {ws['icon'] or '?'} {ws['title']}")
|
|
|
|
print("\nDone! Refresh ERPNext in browser (Ctrl+Shift+R).")
|