205 lines
8.8 KiB
Python
205 lines
8.8 KiB
Python
"""Fix sidebar workspaces — use simple names without spaces."""
|
|
import requests
|
|
import json
|
|
|
|
ERPNEXT_URL = "http://localhost:8080"
|
|
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"); exit(1)
|
|
print("Logged in")
|
|
|
|
|
|
def api_post(endpoint, data):
|
|
return session.post(f"{ERPNEXT_URL}{endpoint}", json=data)
|
|
|
|
def api_put(endpoint, data):
|
|
return session.put(f"{ERPNEXT_URL}{endpoint}", json=data)
|
|
|
|
def api_get(endpoint):
|
|
return session.get(f"{ERPNEXT_URL}{endpoint}")
|
|
|
|
def api_delete(endpoint):
|
|
return session.delete(f"{ERPNEXT_URL}{endpoint}")
|
|
|
|
|
|
# Delete broken workspaces first
|
|
print("\n1. Cleaning broken workspaces...")
|
|
for name in ["Clienti", "CRM DiDi", "Servicii DiDi", "Plati DiDi", "Contabilitate DiDi", "Website CMS DiDi"]:
|
|
r = api_delete(f"/api/resource/Workspace/{requests.utils.quote(name)}")
|
|
print(f" Delete {name}: {r.status_code}")
|
|
|
|
# Workspace definitions — simple slugified names
|
|
WORKSPACES = [
|
|
{
|
|
"label": "Facturi",
|
|
"title": "Facturi",
|
|
"icon": "file-text",
|
|
"indicator_color": "green",
|
|
"sequence_id": 10,
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Sales Invoice", "label": "Toate Facturile", "color": "Green", "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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "Clienti",
|
|
"title": "Clienti",
|
|
"icon": "users",
|
|
"indicator_color": "blue",
|
|
"sequence_id": 20,
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Customer", "label": "Toti Clientii", "color": "Blue", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Service Agreement", "label": "Acorduri Servicii", "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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "CRM-DiDi",
|
|
"title": "CRM",
|
|
"icon": "share",
|
|
"indicator_color": "orange",
|
|
"sequence_id": 30,
|
|
"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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "Servicii",
|
|
"title": "Servicii",
|
|
"icon": "box",
|
|
"indicator_color": "purple",
|
|
"sequence_id": 40,
|
|
"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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "Plati",
|
|
"title": "Plati",
|
|
"icon": "credit-card",
|
|
"indicator_color": "yellow",
|
|
"sequence_id": 50,
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Payment Log", "label": "Payment Log", "color": "Yellow", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Analysis Report", "label": "Rapoarte Analiza", "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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "Contabilitate",
|
|
"title": "Contabilitate",
|
|
"icon": "calculator",
|
|
"indicator_color": "",
|
|
"sequence_id": 60,
|
|
"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"},
|
|
],
|
|
},
|
|
{
|
|
"label": "Website-CMS",
|
|
"title": "Website CMS",
|
|
"icon": "globe",
|
|
"indicator_color": "cyan",
|
|
"sequence_id": 70,
|
|
"shortcuts": [
|
|
{"type": "DocType", "link_to": "Website Content", "label": "Continut Website", "color": "Cyan", "doc_view": "List"},
|
|
{"type": "DocType", "link_to": "Email Template", "label": "Template Email", "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"},
|
|
],
|
|
},
|
|
]
|
|
|
|
print("\n2. Creating workspaces...")
|
|
for ws in WORKSPACES:
|
|
label = ws["label"]
|
|
# Check if already exists
|
|
check = api_get(f"/api/resource/Workspace/{requests.utils.quote(label)}")
|
|
|
|
payload = {
|
|
"label": label,
|
|
"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": json.dumps([
|
|
{"id": "h1", "type": "header", "data": {"text": f"<span class=\"h4\"><b>{ws['title']}</b></span>", "col": 12}},
|
|
] + [
|
|
{"id": f"s{i}", "type": "shortcut", "data": {"shortcut_name": s["label"], "col": 4}}
|
|
for i, s in enumerate(ws["shortcuts"])
|
|
]),
|
|
"shortcuts": ws["shortcuts"],
|
|
"links": ws["links"],
|
|
}
|
|
|
|
if check.status_code == 200:
|
|
r = api_put(f"/api/resource/Workspace/{requests.utils.quote(label)}", payload)
|
|
status = "Updated" if r.status_code == 200 else f"Error {r.status_code}"
|
|
else:
|
|
r = api_post("/api/resource/Workspace", payload)
|
|
status = "Created" if r.status_code in (200, 201) else f"Error {r.status_code}"
|
|
if r.status_code not in (200, 201):
|
|
print(f" {label}: {status} — {r.text[:200]}")
|
|
continue
|
|
|
|
print(f" {label}: {status}")
|
|
|
|
# Verify
|
|
print("\n3. Final sidebar:")
|
|
r = session.post(f"{ERPNEXT_URL}/api/method/frappe.client.get_list", json={
|
|
"doctype": "Workspace",
|
|
"filters": [["public", "=", 1], ["is_hidden", "=", 0]],
|
|
"fields": ["name", "title", "icon", "sequence_id"],
|
|
"order_by": "sequence_id asc",
|
|
"limit_page_length": 20,
|
|
})
|
|
for ws in r.json().get("message", []):
|
|
print(f" [{ws.get('sequence_id', '?'):>3}] {ws.get('icon', '?'):15s} {ws['title']:20s} → /app/{ws['name'].lower().replace(' ', '-')}")
|
|
|
|
print("\nDone! Ctrl+Shift+R in browser.")
|