livrare website cu erp si crm
This commit is contained in:
parent
28773e3a72
commit
5c7bf7c295
257 changed files with 31929 additions and 0 deletions
76
erp_crm/scripts/archive/add-invoice-fields.py
Normal file
76
erp_crm/scripts/archive/add-invoice-fields.py
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
"""
|
||||
Add custom fields to Sales Invoice for analysis tracking.
|
||||
Run inside ERPNext container:
|
||||
docker exec -it didi-erpnext bench --site didi.localhost execute add-invoice-fields.add_fields
|
||||
Or via API (this script uses API approach).
|
||||
"""
|
||||
import requests
|
||||
import sys
|
||||
|
||||
ERPNEXT_URL = "http://localhost:8080"
|
||||
|
||||
# Login as Administrator (has permission for Custom Field)
|
||||
session = requests.Session()
|
||||
login_res = session.post(f"{ERPNEXT_URL}/api/method/login", data={"usr": "Administrator", "pwd": "admin"})
|
||||
if login_res.status_code != 200:
|
||||
print(f"Login failed: {login_res.status_code}")
|
||||
sys.exit(1)
|
||||
print("Logged in as Administrator")
|
||||
|
||||
HEADERS = {"Content-Type": "application/json"}
|
||||
|
||||
FIELDS = [
|
||||
{
|
||||
"dt": "Sales Invoice",
|
||||
"fieldname": "analysis_consumed",
|
||||
"fieldtype": "Check",
|
||||
"label": "Analysis Consumed",
|
||||
"insert_after": "amended_from",
|
||||
"default": "0",
|
||||
"allow_on_submit": 1,
|
||||
"description": "Checked when the purchased analysis has been used",
|
||||
},
|
||||
{
|
||||
"dt": "Sales Invoice",
|
||||
"fieldname": "analysis_session_id",
|
||||
"fieldtype": "Data",
|
||||
"label": "Analysis Session ID",
|
||||
"insert_after": "analysis_consumed",
|
||||
"read_only": 1,
|
||||
"allow_on_submit": 1,
|
||||
"description": "Session ID from DiDi API after analysis was submitted",
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def add_fields():
|
||||
for field in FIELDS:
|
||||
# Check if field already exists
|
||||
check = session.get(
|
||||
f"{ERPNEXT_URL}/api/resource/Custom Field",
|
||||
params={
|
||||
"filters": f'[["dt","=","{field["dt"]}"],["fieldname","=","{field["fieldname"]}"]]',
|
||||
"fields": '["name"]',
|
||||
},
|
||||
headers=HEADERS,
|
||||
)
|
||||
data = check.json()
|
||||
if data.get("data") and len(data["data"]) > 0:
|
||||
print(f" Field '{field['fieldname']}' already exists, skipping.")
|
||||
continue
|
||||
|
||||
res = session.post(
|
||||
f"{ERPNEXT_URL}/api/resource/Custom Field",
|
||||
json=field,
|
||||
headers=HEADERS,
|
||||
)
|
||||
if res.status_code in (200, 201):
|
||||
print(f" Created field '{field['fieldname']}' on {field['dt']}")
|
||||
else:
|
||||
print(f" ERROR creating '{field['fieldname']}': {res.status_code} {res.text}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("Adding custom fields to Sales Invoice...")
|
||||
add_fields()
|
||||
print("Done.")
|
||||
67
erp_crm/scripts/archive/fix-sidebar.py
Normal file
67
erp_crm/scripts/archive/fix-sidebar.py
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
import frappe
|
||||
|
||||
def execute():
|
||||
# Hide ALL public workspaces
|
||||
for ws in frappe.get_all("Workspace", filters={"public": 1}, fields=["name"]):
|
||||
doc = frappe.get_doc("Workspace", ws.name)
|
||||
doc.public = 0
|
||||
doc.save(ignore_permissions=True)
|
||||
|
||||
# Delete old DiDi workspaces
|
||||
for ws in frappe.get_all("Workspace", filters={"name": ["like", "%DiDi%"]}, fields=["name"]):
|
||||
frappe.delete_doc("Workspace", ws.name, force=True)
|
||||
|
||||
# Create sidebar workspaces - each one is a clean page
|
||||
create_workspace("Facturi", "invoice", 1, "Sales Invoice", [
|
||||
{"type": "DocType", "link_to": "Sales Invoice", "label": "Lista Facturi"},
|
||||
])
|
||||
|
||||
create_workspace("Clienti", "user", 2, "Customer", [
|
||||
{"type": "DocType", "link_to": "Customer", "label": "Lista Clienti"},
|
||||
])
|
||||
|
||||
create_workspace("CRM", "lead", 3, "Lead", [
|
||||
{"type": "DocType", "link_to": "Lead", "label": "Lead-uri"},
|
||||
{"type": "DocType", "link_to": "Sales Stage", "label": "Etape Pipeline"},
|
||||
{"type": "DocType", "link_to": "Lead Source", "label": "Surse Lead"},
|
||||
])
|
||||
|
||||
create_workspace("Servicii", "box", 4, "Item", [
|
||||
{"type": "DocType", "link_to": "Item", "label": "Produse / Servicii"},
|
||||
{"type": "DocType", "link_to": "Subscription Plan", "label": "Planuri Abonament"},
|
||||
])
|
||||
|
||||
create_workspace("Plati", "credit-card", 5, "Payment Log", [
|
||||
{"type": "DocType", "link_to": "Payment Log", "label": "Log Plati Stripe"},
|
||||
{"type": "DocType", "link_to": "Service Agreement", "label": "Acorduri Servicii"},
|
||||
])
|
||||
|
||||
create_workspace("Contabilitate", "calculator", 6, "Account", [
|
||||
{"type": "DocType", "link_to": "Account", "label": "Plan de Conturi"},
|
||||
{"type": "DocType", "link_to": "Sales Taxes and Charges Template", "label": "Template TVA"},
|
||||
{"type": "DocType", "link_to": "Supplier", "label": "Furnizori"},
|
||||
{"type": "DocType", "link_to": "Purchase Invoice", "label": "Facturi Furnizori"},
|
||||
])
|
||||
|
||||
create_workspace("Website CMS", "globe", 7, "Website Content", [
|
||||
{"type": "DocType", "link_to": "Website Content", "label": "Continut Pagini"},
|
||||
{"type": "DocType", "link_to": "Email Template", "label": "Template-uri Email"},
|
||||
])
|
||||
|
||||
frappe.db.commit()
|
||||
print("\n=== Sidebar creat: Facturi, Clienti, CRM, Servicii, Plati, Contabilitate, Website CMS ===")
|
||||
|
||||
|
||||
def create_workspace(label, icon, seq, module_doctype, shortcuts):
|
||||
ws = frappe.get_doc({
|
||||
"doctype": "Workspace",
|
||||
"label": label,
|
||||
"title": label,
|
||||
"module": "Didi Custom",
|
||||
"icon": icon,
|
||||
"public": 1,
|
||||
"sequence_id": seq,
|
||||
"shortcuts": shortcuts,
|
||||
})
|
||||
ws.insert(ignore_permissions=True)
|
||||
print(f" Created: {label}")
|
||||
295
erp_crm/scripts/archive/fix-translations.py
Normal file
295
erp_crm/scripts/archive/fix-translations.py
Normal file
|
|
@ -0,0 +1,295 @@
|
|||
"""Fix ALL remaining untranslated labels in ERPNext."""
|
||||
import sys, io, json, requests
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
URL = "http://localhost:8080"
|
||||
s = requests.Session()
|
||||
s.post(f"{URL}/api/method/login", data={"usr": "Administrator", "pwd": "admin"})
|
||||
print("Logged in")
|
||||
|
||||
T = {
|
||||
# ── Payment Entry ──
|
||||
"Party Name": "Nume Client",
|
||||
"Nume partid": "Nume Client",
|
||||
"Party": "Client",
|
||||
"Partener": "Client",
|
||||
"Party Type": "Tip Client",
|
||||
"Tip de partid": "Tip Client",
|
||||
"Party Balance": "Sold Client",
|
||||
"Balanța Party": "Sold Client",
|
||||
"Paid From": "Platit Din",
|
||||
"Contul plătit De la": "Platit Din",
|
||||
"Paid To": "Platit Catre",
|
||||
"Contul Plătite": "Platit Catre",
|
||||
"Account Balance (From)": "Sold Cont (Sursa)",
|
||||
"Account Balance (To)": "Sold Cont (Destinatie)",
|
||||
"Account Currency (From)": "Moneda Cont (Sursa)",
|
||||
"Account Currency (To)": "Moneda Cont (Destinatie)",
|
||||
"Paid Amount": "Suma Platita",
|
||||
"Paid Amount After Tax (RON)": "Suma Platita dupa Taxe (RON)",
|
||||
"Received Amount": "Suma Primita",
|
||||
"Received Amount After Tax (RON)": "Suma Primita dupa Taxe (RON)",
|
||||
"Suma primită (RON)": "Suma Primita (RON)",
|
||||
"Sumă Primită (RON)": "Suma Primita (RON)",
|
||||
"Reference No": "Nr. Referinta",
|
||||
"Cecul / de referință nr": "Nr. Referinta Plata",
|
||||
"Reference Date": "Data Referinta",
|
||||
"Cec/Dată de Referință": "Data Referinta Plata",
|
||||
"Payment References": "Referinte Plata",
|
||||
"Referințe de plată": "Referinte Plata",
|
||||
"Allocated": "Alocat",
|
||||
"Unallocated Amount": "Suma Nealocata",
|
||||
"Suma nealocată (RON)": "Suma Nealocata (RON)",
|
||||
"Total Allocated Amount": "Total Alocat",
|
||||
"Suma totală alocată (RON)": "Total Alocat (RON)",
|
||||
"Difference Amount": "Diferenta",
|
||||
"Diferența Sumă (RON)": "Diferenta (RON)",
|
||||
"Outstanding": "Restant",
|
||||
"remarcabil (RON)": "Restant (RON)",
|
||||
"outstanding (RON)": "Restant (RON)",
|
||||
"remarkable (RON)": "Restant (RON)",
|
||||
"Payment Type": "Tip Plata",
|
||||
"Tipul de plată": "Tip Plata",
|
||||
"Plata De la / la": "Plata De la / Catre",
|
||||
"Contact Person": "Persoana de Contact",
|
||||
"Persoana de Contact": "Persoana de Contact",
|
||||
"Transaction ID": "ID Tranzactie",
|
||||
"ID-ul de tranzacție": "ID Tranzactie",
|
||||
"Cheque/Reference No": "Nr. Referinta Plata",
|
||||
"Cheque/Reference Date": "Data Referinta Plata",
|
||||
"Source Exchange Rate": "Curs Valutar Sursa",
|
||||
"Target Exchange Rate": "Curs Valutar Destinatie",
|
||||
"Connections": "Legaturi",
|
||||
"Account Dimensions": "Dimensiuni Contabile",
|
||||
"Dimensiuni contabile": "Dimensiuni Contabile",
|
||||
"More Information": "Mai Multe Informatii",
|
||||
"Mai multe informatii": "Mai Multe Informatii",
|
||||
"Remarks": "Observatii",
|
||||
"Remarci": "Observatii",
|
||||
"In Words (Company Currency)": "In Litere (Moneda Companie)",
|
||||
"În cuvinte (Compania valutar)": "In Litere (Moneda Companie)",
|
||||
"In Words": "In Litere",
|
||||
"În cuvinte": "In Litere",
|
||||
"In Words (RON)": "In Litere (RON)",
|
||||
"În cuvinte (RON)": "In Litere (RON)",
|
||||
"Taxes and Charges": "Taxe si Impozite",
|
||||
"Impozite și Taxe": "Taxe si Impozite",
|
||||
"Total Taxes and Charges": "Total Taxe",
|
||||
"Total Impozite și Taxe (RON)": "Total Taxe (RON)",
|
||||
"Tax Withholding": "Retinere Taxe",
|
||||
"Descărcarea de impozite": "Retinere Taxe",
|
||||
"Deductions or Losses": "Deduceri sau Pierderi",
|
||||
"Deduceri sau Pierderi": "Deduceri sau Pierderi",
|
||||
"Naming Series": "Serie Numerotare",
|
||||
"Serii": "Serie Numerotare",
|
||||
"Account Holder": "Titular Cont",
|
||||
"Titularul Contului": "Titular Cont",
|
||||
"Section Subscriptions": "Sectiunea Abonamente",
|
||||
"Secțiunea de abonamente": "Sectiunea Abonamente",
|
||||
"Is Opening": "Este Deschidere",
|
||||
"Se deschide": "Este Deschidere",
|
||||
"Deschiderea este de intrare": "Inregistrare de Deschidere",
|
||||
"Tax Rate": "Cota Impozit",
|
||||
"Cota de impozitare": "Cota Impozit",
|
||||
"Statistics": "Statistici",
|
||||
"Statistici": "Statistici",
|
||||
"Graph": "Grafic",
|
||||
|
||||
# ── Sales Invoice ──
|
||||
"Additional Info": "Informatii Suplimentare",
|
||||
"Billing Address": "Adresa de Facturare",
|
||||
"Adresa De Facturare": "Adresa de Facturare",
|
||||
"Shipping Address": "Adresa de Livrare",
|
||||
"Adresa de livrare": "Adresa de Livrare",
|
||||
"Company Address": "Adresa Companie",
|
||||
"Adresă Companie": "Adresa Companie",
|
||||
"Rounding Adjustment": "Ajustare Rotunjire",
|
||||
"Ajustare Rotunjire (RON)": "Ajustare Rotunjire (RON)",
|
||||
"Rotunjire ajustare (RON)": "Ajustare Rotunjire (RON)",
|
||||
"Write Off Amount": "Suma Casare",
|
||||
"Anulați suma (RON)": "Suma Casare (RON)",
|
||||
"Scrie Off Suma (RON)": "Suma Casare (RON)",
|
||||
"Apply Additional Discount On": "Aplica Discount Suplimentar Pe",
|
||||
"Aplicați Discount suplimentare La": "Aplica Discount Suplimentar Pe",
|
||||
"Items": "Articole",
|
||||
"Articole": "Articole",
|
||||
"Total Quantity": "Cantitate Totala",
|
||||
"Cantitatea totala": "Cantitate Totala",
|
||||
"Commission": "Comision",
|
||||
"Comision": "Comision",
|
||||
"Company Tax ID": "CUI Companie",
|
||||
"Due Date": "Data Scadenta",
|
||||
"Data scadentă de plată": "Data Scadenta",
|
||||
"Base Change Amount (RON)": "Suma Modificare Baza (RON)",
|
||||
"De schimbare a bazei Suma (RON)": "Suma Modificare Baza (RON)",
|
||||
"Debit To": "Cont Debit",
|
||||
"Debit Pentru": "Cont Debit",
|
||||
"Accounting Details": "Detalii Contabilitate",
|
||||
"Detalii Contabilitate": "Detalii Contabilitate",
|
||||
"Customer PO Details": "Detalii Comanda Client",
|
||||
"Detalii PO pentru clienți": "Detalii Comanda Client",
|
||||
"Additional Discount": "Discount Suplimentar",
|
||||
"Discount suplimentar": "Discount Suplimentar",
|
||||
"Additional Discount Amount": "Suma Discount Suplimentar",
|
||||
"Discount suplimentar Suma (RON)": "Suma Discount Suplimentar (RON)",
|
||||
"Additional Discount Percentage": "Procent Discount Suplimentar",
|
||||
"Procent de reducere suplimentară": "Procent Discount Suplimentar",
|
||||
"Suma de reducere suplimentară (RON)": "Suma Discount Suplimentar (RON)",
|
||||
"Sales Team": "Echipa Vanzari",
|
||||
"Echipa de vânzări": "Echipa Vanzari",
|
||||
"Taxes and Charges Calculation": "Calcul Taxe",
|
||||
"Impozite și Taxe Calcul": "Calcul Taxe",
|
||||
"Print Language": "Limba Tiparire",
|
||||
"Limba de imprimare": "Limba Tiparire",
|
||||
"Price List": "Lista de Preturi",
|
||||
"Lista Prețuri": "Lista de Preturi",
|
||||
"Packing List": "Lista de Ambalare",
|
||||
"Lista de ambalare": "Lista de Ambalare",
|
||||
"Price List Currency": "Moneda Lista Preturi",
|
||||
"Lista de pret Valuta": "Moneda Lista Preturi",
|
||||
"Price List Exchange Rate": "Curs Valutar Lista Preturi",
|
||||
"Lista de schimb valutar": "Curs Valutar Lista Preturi",
|
||||
"Time Sheet List": "Lista Pontaj",
|
||||
"Listă de timp Sheet": "Lista Pontaj",
|
||||
"Net Total": "Total Net",
|
||||
"Net total (RON)": "Total Net (RON)",
|
||||
"Customer Name": "Nume Client",
|
||||
"Company Name": "Nume Companie",
|
||||
"Nume Companie": "Nume Companie",
|
||||
"Write Off": "Casare Creante",
|
||||
"Pierderi din Creante": "Casare Creante",
|
||||
"Advance Payments": "Plati in Avans",
|
||||
"Plățile în avans": "Plati in Avans",
|
||||
"Payments": "Plati",
|
||||
"Plăți": "Plati",
|
||||
"Posting Time": "Ora Inregistrare",
|
||||
"PostingTime": "Ora Inregistrare",
|
||||
"Postarea de timp": "Ora Inregistrare",
|
||||
"Pricing Rules": "Reguli de Pret",
|
||||
"Reguli privind prețurile": "Reguli de Pret",
|
||||
"Rounded Total": "Total Rotunjit",
|
||||
"Rotunjite total (RON)": "Total Rotunjit (RON)",
|
||||
"Redeem Loyalty Points": "Rascumparare Puncte Loialitate",
|
||||
"Răscumpărarea punctelor de loialitate": "Rascumparare Puncte Loialitate",
|
||||
"Exchange Rate": "Curs Valutar",
|
||||
"Rata de schimb": "Curs Valutar",
|
||||
"Print Settings": "Setari Tiparire",
|
||||
"Setări de imprimare": "Setari Tiparire",
|
||||
"Outstanding Amount": "Suma Restanta",
|
||||
"Suma Restanta (RON)": "Suma Restanta (RON)",
|
||||
"Payment Terms": "Termeni Plata",
|
||||
"Termeni de plată": "Termeni Plata",
|
||||
"Terms and Conditions": "Termeni si Conditii",
|
||||
"Termeni si conditii": "Termeni si Conditii",
|
||||
"Total Advance": "Total Avans",
|
||||
"Total de Advance (RON)": "Total Avans (RON)",
|
||||
"Totals": "Totaluri",
|
||||
"Totaluri": "Totaluri",
|
||||
"Currency and Price List": "Moneda si Lista de Preturi",
|
||||
"Valută și lista de prețuri": "Moneda si Lista de Preturi",
|
||||
"Subscription": "Abonament",
|
||||
"Changes": "Modificari",
|
||||
|
||||
# ── Customer ──
|
||||
"Primary Customer Address": "Adresa Principala Client",
|
||||
"Adresa primară a clientului": "Adresa Principala Client",
|
||||
"Address and Contact": "Adresa si Contact",
|
||||
"Adresa și Contact": "Adresa si Contact",
|
||||
"Tax Category": "Categorie Fiscala",
|
||||
"Categoria fiscală": "Categorie Fiscala",
|
||||
"Primary Customer Contact": "Contact Principal Client",
|
||||
"Contact primar client": "Contact Principal Client",
|
||||
"Default Accounts": "Conturi Implicite",
|
||||
"Conturi implicite": "Conturi Implicite",
|
||||
"Defaults": "Valori Implicite",
|
||||
"Implicite": "Valori Implicite",
|
||||
"Internal Customer": "Client Intern",
|
||||
"Credit Limit and Payment Terms": "Limita Credit si Termeni Plata",
|
||||
"Limita de credit și termenii de plată": "Limita Credit si Termeni Plata",
|
||||
"Primary Address and Contact": "Adresa si Contact Principal",
|
||||
"Loyalty Points": "Puncte Loialitate",
|
||||
"Puncte de loialitate": "Puncte Loialitate",
|
||||
"Default Payment Terms Template": "Sablon Termeni Plata Standard",
|
||||
"Șablonul Termenii de plată standard": "Sablon Termeni Plata Standard",
|
||||
"Tax ID": "Cod Fiscal (CUI)",
|
||||
"ID impozit": "Cod Fiscal (CUI)",
|
||||
"Email ID": "Adresa Email",
|
||||
"ID-ul de e-mail": "Adresa Email",
|
||||
|
||||
# ── Lead ──
|
||||
"Lead Name": "Nume Lead",
|
||||
"Email Address": "Adresa Email",
|
||||
"Lead Source": "Sursa Lead",
|
||||
"Campaign Name": "Nume Campanie",
|
||||
|
||||
# ── Common / Navigation ──
|
||||
"Activity": "Activitate",
|
||||
"Activitate": "Activitate",
|
||||
"Assigned To": "Atribuit Pentru",
|
||||
"Atribuit pentru": "Atribuit Pentru",
|
||||
"Attachments": "Atasamente",
|
||||
"Ataşamente": "Atasamente",
|
||||
"Tags": "Etichete",
|
||||
"Etichete": "Etichete",
|
||||
"Action": "Actiune",
|
||||
"Acțiune": "Actiune",
|
||||
"Follow": "Urmareste",
|
||||
"Urma": "Urmareste",
|
||||
"Comment": "Comentariu",
|
||||
"Comentarii": "Comentarii",
|
||||
"Comments": "Comentarii",
|
||||
"New Email": "Email Nou",
|
||||
"Email nou": "Email Nou",
|
||||
"Type a reply / comment": "Scrie un raspuns / comentariu",
|
||||
"No new notifications": "Nicio notificare noua",
|
||||
"Help Dropdown": "Meniu Ajutor",
|
||||
"Meniul drop-down Ajutor": "Meniu Ajutor",
|
||||
"User Menu": "Meniu Utilizator",
|
||||
"Toggle Sidebar": "Comuta Bara Laterala",
|
||||
"Comutați bara laterală": "Comuta Bara Laterala",
|
||||
"You last edited this": "Ultima editare",
|
||||
"You created this": "Creat de tine",
|
||||
"You submitted this document": "Document confirmat de tine",
|
||||
"yesterday": "ieri",
|
||||
"Bank Transaction": "Tranzactie Bancara",
|
||||
"Tranzacție bancară": "Tranzactie Bancara",
|
||||
"Settle": "Achita",
|
||||
"Achita": "Achita",
|
||||
"General Ledger": "Registru Contabil",
|
||||
"Registru Contabil": "Registru Contabil",
|
||||
}
|
||||
|
||||
created = 0
|
||||
skipped = 0
|
||||
for source, translated in T.items():
|
||||
check = s.get(f"{URL}/api/resource/Translation", params={
|
||||
"filters": json.dumps([["language", "=", "ro"], ["source_text", "=", source]]),
|
||||
"fields": json.dumps(["name", "translated_text"]),
|
||||
"limit_page_length": 1,
|
||||
})
|
||||
existing = check.json().get("data", [])
|
||||
|
||||
if existing:
|
||||
# Update if different
|
||||
if existing[0].get("translated_text") != translated:
|
||||
s.put(f"{URL}/api/resource/Translation/{existing[0]['name']}", json={"translated_text": translated})
|
||||
created += 1
|
||||
else:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
r = s.post(f"{URL}/api/resource/Translation", json={
|
||||
"language": "ro",
|
||||
"source_text": source,
|
||||
"translated_text": translated,
|
||||
})
|
||||
if r.status_code in (200, 201):
|
||||
created += 1
|
||||
else:
|
||||
skipped += 1
|
||||
|
||||
print(f"Created/Updated: {created}, Skipped: {skipped}")
|
||||
|
||||
# Clear cache
|
||||
s.post(f"{URL}/api/method/frappe.client.clear_cache")
|
||||
print("Cache cleared. Ctrl+Shift+R in browser.")
|
||||
42
erp_crm/scripts/archive/fix-workspace.py
Normal file
42
erp_crm/scripts/archive/fix-workspace.py
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
import frappe
|
||||
|
||||
def execute():
|
||||
# Delete old DiDi workspace
|
||||
if frappe.db.exists("Workspace", "DiDi"):
|
||||
frappe.delete_doc("Workspace", "DiDi", force=True)
|
||||
|
||||
# Hide ALL other workspaces
|
||||
for ws in frappe.get_all("Workspace", filters={"public": 1}, fields=["name"]):
|
||||
doc = frappe.get_doc("Workspace", ws.name)
|
||||
doc.public = 0
|
||||
doc.save(ignore_permissions=True)
|
||||
print(f" Hidden: {ws.name}")
|
||||
|
||||
# Create clean DiDi workspace
|
||||
ws = frappe.get_doc({
|
||||
"doctype": "Workspace",
|
||||
"name": "DiDi",
|
||||
"label": "DiDi",
|
||||
"title": "DiDi - Panou Principal",
|
||||
"module": "Didi Custom",
|
||||
"icon": "home",
|
||||
"public": 1,
|
||||
"sequence_id": 0,
|
||||
"shortcuts": [
|
||||
{"type": "DocType", "link_to": "Sales Invoice", "label": "FACTURI"},
|
||||
{"type": "DocType", "link_to": "Customer", "label": "CLIENTI"},
|
||||
{"type": "DocType", "link_to": "Lead", "label": "LEAD-URI CRM"},
|
||||
{"type": "DocType", "link_to": "Payment Log", "label": "LOG PLATI STRIPE"},
|
||||
{"type": "DocType", "link_to": "Service Agreement", "label": "ACORDURI SERVICII"},
|
||||
{"type": "DocType", "link_to": "Item", "label": "SERVICII / PRODUSE"},
|
||||
{"type": "DocType", "link_to": "Subscription Plan", "label": "PLANURI ABONAMENT"},
|
||||
{"type": "DocType", "link_to": "Website Content", "label": "CONTINUT WEBSITE (CMS)"},
|
||||
{"type": "DocType", "link_to": "Supplier", "label": "FURNIZORI"},
|
||||
{"type": "DocType", "link_to": "Email Template", "label": "TEMPLATE-URI EMAIL"},
|
||||
{"type": "DocType", "link_to": "Account", "label": "PLAN DE CONTURI"},
|
||||
],
|
||||
})
|
||||
ws.insert(ignore_permissions=True)
|
||||
print("DiDi workspace created with all shortcuts")
|
||||
|
||||
frappe.db.commit()
|
||||
291
erp_crm/scripts/archive/setup-sidebar.py
Normal file
291
erp_crm/scripts/archive/setup-sidebar.py
Normal file
|
|
@ -0,0 +1,291 @@
|
|||
"""
|
||||
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).")
|
||||
153
erp_crm/scripts/archive/translate-accounts.py
Normal file
153
erp_crm/scripts/archive/translate-accounts.py
Normal file
|
|
@ -0,0 +1,153 @@
|
|||
"""Rename all ERPNext accounts to Romanian."""
|
||||
import requests, json, sys, io, urllib.parse
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
URL = "http://localhost:8080"
|
||||
s = requests.Session()
|
||||
s.post(f"{URL}/api/method/login", data={"usr": "Administrator", "pwd": "admin"})
|
||||
print("Logged in")
|
||||
|
||||
RENAMES = {
|
||||
# Root groups (Level 1)
|
||||
"Application of Funds (Assets)": "Active",
|
||||
"Source of Funds (Liabilities)": "Pasive (Datorii)",
|
||||
"Equity": "Capitaluri Proprii",
|
||||
"Income": "Venituri",
|
||||
"Expenses": "Cheltuieli",
|
||||
|
||||
# Asset sub-groups
|
||||
"Current Assets": "Active Curente",
|
||||
"Cash In Hand": "Numerar",
|
||||
"Cash": "Casa",
|
||||
"Bank Accounts": "Conturi Bancare",
|
||||
"Accounts Receivable": "Creante Clienti",
|
||||
"Debtors": "Debitori",
|
||||
"Stock Assets": "Active Stocuri",
|
||||
"Stock In Hand": "Stoc",
|
||||
"Tax Assets": "Active Fiscale",
|
||||
"Loans and Advances (Assets)": "Imprumuturi si Avansuri (Active)",
|
||||
"Employee Advances": "Avansuri Angajati",
|
||||
"Securities and Deposits": "Garantii si Depozite",
|
||||
"Earnest Money": "Garantii",
|
||||
"Fixed Assets": "Imobilizari Corporale",
|
||||
"Capital Equipments": "Echipamente de Capital",
|
||||
"Electronic Equipments": "Echipamente Electronice",
|
||||
"Furnitures and Fixtures": "Mobilier si Dotari",
|
||||
"Office Equipments": "Echipamente Birou",
|
||||
"Plants and Machineries": "Utilaje si Masini",
|
||||
"Buildings": "Cladiri",
|
||||
"Softwares": "Software",
|
||||
"Accumulated Depreciation": "Amortizare Cumulata",
|
||||
"CWIP Account": "Lucrari in Curs",
|
||||
"Investments": "Investitii",
|
||||
"Temporary Accounts": "Conturi Temporare",
|
||||
"Temporary Opening": "Sold Initial Temporar",
|
||||
|
||||
# Liability sub-groups
|
||||
"Current Liabilities": "Datorii Curente",
|
||||
"Accounts Payable": "Datorii Furnizori",
|
||||
"Creditors": "Creditori",
|
||||
"Payroll Payable": "Salarii de Plata",
|
||||
"Stock Liabilities": "Datorii Stocuri",
|
||||
"Stock Received But Not Billed": "Stoc Receptionat Nefacturat",
|
||||
"Asset Received But Not Billed": "Active Receptionate Nefacturate",
|
||||
"Duties and Taxes": "Taxe si Impozite",
|
||||
"TDS Payable": "Taxe de Plata",
|
||||
"Loans (Liabilities)": "Imprumuturi (Datorii)",
|
||||
"Secured Loans": "Imprumuturi Garantate",
|
||||
"Unsecured Loans": "Imprumuturi Negarantate",
|
||||
"Bank Overdraft Account": "Descoperit de Cont",
|
||||
|
||||
# Equity
|
||||
"Capital Stock": "Capital Social",
|
||||
"Dividends Paid": "Dividende Platite",
|
||||
"Opening Balance Equity": "Sold Initial Capital",
|
||||
"Retained Earnings": "Rezultat Reportat",
|
||||
|
||||
# Income
|
||||
"Direct Income": "Venituri Directe",
|
||||
"Sales": "Vanzari",
|
||||
"Service": "Servicii",
|
||||
"Indirect Income": "Venituri Indirecte",
|
||||
|
||||
# Expenses
|
||||
"Direct Expenses": "Cheltuieli Directe",
|
||||
"Stock Expenses": "Cheltuieli Stocuri",
|
||||
"Cost of Goods Sold": "Costul Bunurilor Vandute",
|
||||
"Expenses Included In Asset Valuation": "Cheltuieli Incluse in Evaluarea Activelor",
|
||||
"Expenses Included In Valuation": "Cheltuieli Incluse in Evaluare",
|
||||
"Stock Adjustment": "Ajustare Stoc",
|
||||
"Indirect Expenses": "Cheltuieli Indirecte",
|
||||
"Administrative Expenses": "Cheltuieli Administrative",
|
||||
"Commission on Sales": "Comisioane Vanzari",
|
||||
"Depreciation": "Amortizare",
|
||||
"Entertainment Expenses": "Cheltuieli Reprezentare",
|
||||
"Freight and Forwarding Charges": "Cheltuieli Transport",
|
||||
"Legal Expenses": "Cheltuieli Juridice",
|
||||
"Marketing Expenses": "Cheltuieli Marketing",
|
||||
"Office Maintenance Expenses": "Cheltuieli Intretinere Birou",
|
||||
"Office Rent": "Chirie Birou",
|
||||
"Postal Expenses": "Cheltuieli Postale",
|
||||
"Print and Stationery": "Tiparituri si Papetarie",
|
||||
"Round Off": "Rotunjiri",
|
||||
"Salary": "Salarii",
|
||||
"Sales Expenses": "Cheltuieli Vanzari",
|
||||
"Telephone Expenses": "Cheltuieli Telefon",
|
||||
"Travel Expenses": "Cheltuieli Deplasare",
|
||||
"Utility Expenses": "Cheltuieli Utilitati",
|
||||
"Write Off": "Pierderi din Creante",
|
||||
"Exchange Gain/Loss": "Diferente de Curs Valutar",
|
||||
"Gain/Loss on Asset Disposal": "Castiguri/Pierderi din Casare Active",
|
||||
"Miscellaneous Expenses": "Cheltuieli Diverse",
|
||||
}
|
||||
|
||||
# Get all accounts
|
||||
r = s.get(f"{URL}/api/resource/Account", params={
|
||||
"filters": json.dumps([["company", "=", "TOP CLOSSERS SRL"]]),
|
||||
"fields": json.dumps(["name", "account_name"]),
|
||||
"limit_page_length": 200,
|
||||
})
|
||||
accounts = r.json().get("data", [])
|
||||
|
||||
renamed = 0
|
||||
skipped = 0
|
||||
errors = 0
|
||||
|
||||
for acc in accounts:
|
||||
old_name = acc["account_name"]
|
||||
if old_name not in RENAMES:
|
||||
continue
|
||||
|
||||
new_name = RENAMES[old_name]
|
||||
full_old = acc["name"] # e.g. "1000 - Application of Funds (Assets) - TC"
|
||||
|
||||
# Build new full name
|
||||
parts = full_old.split(" - ")
|
||||
if len(parts) >= 3:
|
||||
parts[1] = new_name
|
||||
full_new = " - ".join(parts)
|
||||
else:
|
||||
skipped += 1
|
||||
continue
|
||||
|
||||
# Rename via frappe.client.rename_doc
|
||||
r = s.post(f"{URL}/api/method/frappe.client.rename_doc", json={
|
||||
"doctype": "Account",
|
||||
"old": full_old,
|
||||
"new": full_new,
|
||||
"merge": 0,
|
||||
})
|
||||
|
||||
if r.status_code == 200:
|
||||
renamed += 1
|
||||
print(f" OK: {old_name} -> {new_name}")
|
||||
else:
|
||||
errors += 1
|
||||
err_msg = r.text[:150] if r.text else str(r.status_code)
|
||||
print(f" ERR: {old_name}: {err_msg}")
|
||||
|
||||
print(f"\nRenamed: {renamed}, Skipped: {skipped}, Errors: {errors}")
|
||||
|
||||
# Clear cache
|
||||
s.post(f"{URL}/api/method/frappe.client.clear_cache")
|
||||
print("Cache cleared. Refresh browser.")
|
||||
152
erp_crm/scripts/archive/translate-accounts2.py
Normal file
152
erp_crm/scripts/archive/translate-accounts2.py
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
"""Translate account names by updating account_name field + adding translations."""
|
||||
import requests, json, sys, io, urllib.parse
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
|
||||
|
||||
URL = "http://localhost:8080"
|
||||
s = requests.Session()
|
||||
s.post(f"{URL}/api/method/login", data={"usr": "Administrator", "pwd": "admin"})
|
||||
print("Logged in")
|
||||
|
||||
TRANSLATIONS = {
|
||||
"Application of Funds (Assets)": "Active",
|
||||
"Source of Funds (Liabilities)": "Pasive (Datorii)",
|
||||
"Equity": "Capitaluri Proprii",
|
||||
"Income": "Venituri",
|
||||
"Expenses": "Cheltuieli",
|
||||
"Current Assets": "Active Curente",
|
||||
"Cash In Hand": "Numerar",
|
||||
"Cash": "Casa",
|
||||
"Bank Accounts": "Conturi Bancare",
|
||||
"Accounts Receivable": "Creante Clienti",
|
||||
"Debtors": "Debitori",
|
||||
"Stock Assets": "Active Stocuri",
|
||||
"Stock In Hand": "Stoc",
|
||||
"Tax Assets": "Active Fiscale",
|
||||
"Loans and Advances (Assets)": "Imprumuturi si Avansuri",
|
||||
"Employee Advances": "Avansuri Angajati",
|
||||
"Securities and Deposits": "Garantii si Depozite",
|
||||
"Earnest Money": "Garantii",
|
||||
"Fixed Assets": "Imobilizari Corporale",
|
||||
"Capital Equipments": "Echipamente de Capital",
|
||||
"Electronic Equipments": "Echipamente Electronice",
|
||||
"Furnitures and Fixtures": "Mobilier si Dotari",
|
||||
"Office Equipments": "Echipamente Birou",
|
||||
"Plants and Machineries": "Utilaje si Masini",
|
||||
"Buildings": "Cladiri",
|
||||
"Softwares": "Software",
|
||||
"Accumulated Depreciation": "Amortizare Cumulata",
|
||||
"CWIP Account": "Lucrari in Curs",
|
||||
"Investments": "Investitii",
|
||||
"Temporary Accounts": "Conturi Temporare",
|
||||
"Temporary Opening": "Sold Initial Temporar",
|
||||
"Current Liabilities": "Datorii Curente",
|
||||
"Accounts Payable": "Datorii Furnizori",
|
||||
"Creditors": "Creditori",
|
||||
"Payroll Payable": "Salarii de Plata",
|
||||
"Stock Liabilities": "Datorii Stocuri",
|
||||
"Stock Received But Not Billed": "Stoc Receptionat Nefacturat",
|
||||
"Asset Received But Not Billed": "Active Receptionate Nefacturate",
|
||||
"Duties and Taxes": "Taxe si Impozite",
|
||||
"TDS Payable": "Taxe de Plata",
|
||||
"Loans (Liabilities)": "Imprumuturi (Datorii)",
|
||||
"Secured Loans": "Imprumuturi Garantate",
|
||||
"Unsecured Loans": "Imprumuturi Negarantate",
|
||||
"Bank Overdraft Account": "Descoperit de Cont",
|
||||
"Capital Stock": "Capital Social",
|
||||
"Dividends Paid": "Dividende Platite",
|
||||
"Opening Balance Equity": "Sold Initial Capital",
|
||||
"Retained Earnings": "Rezultat Reportat",
|
||||
"Direct Income": "Venituri Directe",
|
||||
"Sales": "Vanzari",
|
||||
"Service": "Servicii",
|
||||
"Indirect Income": "Venituri Indirecte",
|
||||
"Direct Expenses": "Cheltuieli Directe",
|
||||
"Stock Expenses": "Cheltuieli Stocuri",
|
||||
"Cost of Goods Sold": "Costul Bunurilor Vandute",
|
||||
"Expenses Included In Asset Valuation": "Cheltuieli in Evaluarea Activelor",
|
||||
"Expenses Included In Valuation": "Cheltuieli in Evaluare",
|
||||
"Stock Adjustment": "Ajustare Stoc",
|
||||
"Indirect Expenses": "Cheltuieli Indirecte",
|
||||
"Administrative Expenses": "Cheltuieli Administrative",
|
||||
"Commission on Sales": "Comisioane Vanzari",
|
||||
"Depreciation": "Amortizare",
|
||||
"Entertainment Expenses": "Cheltuieli Reprezentare",
|
||||
"Freight and Forwarding Charges": "Cheltuieli Transport",
|
||||
"Legal Expenses": "Cheltuieli Juridice",
|
||||
"Marketing Expenses": "Cheltuieli Marketing",
|
||||
"Office Maintenance Expenses": "Intretinere Birou",
|
||||
"Office Rent": "Chirie Birou",
|
||||
"Postal Expenses": "Cheltuieli Postale",
|
||||
"Print and Stationery": "Tiparituri si Papetarie",
|
||||
"Round Off": "Rotunjiri",
|
||||
"Salary": "Salarii",
|
||||
"Sales Expenses": "Cheltuieli Vanzari",
|
||||
"Telephone Expenses": "Cheltuieli Telefon",
|
||||
"Travel Expenses": "Cheltuieli Deplasare",
|
||||
"Utility Expenses": "Cheltuieli Utilitati",
|
||||
"Write Off": "Pierderi din Creante",
|
||||
"Exchange Gain/Loss": "Diferente Curs Valutar",
|
||||
"Gain/Loss on Asset Disposal": "Castig/Pierdere Casare Active",
|
||||
"Miscellaneous Expenses": "Cheltuieli Diverse",
|
||||
}
|
||||
|
||||
# Add all as Translation entries (for the UI)
|
||||
print("1. Adding account name translations...")
|
||||
created = 0
|
||||
for en, ro in TRANSLATIONS.items():
|
||||
check = s.get(f"{URL}/api/resource/Translation", params={
|
||||
"filters": json.dumps([["language", "=", "ro"], ["source_text", "=", en]]),
|
||||
"fields": json.dumps(["name"]),
|
||||
"limit_page_length": 1,
|
||||
})
|
||||
if check.json().get("data"):
|
||||
continue
|
||||
r = s.post(f"{URL}/api/resource/Translation", json={
|
||||
"language": "ro",
|
||||
"source_text": en,
|
||||
"translated_text": ro,
|
||||
})
|
||||
if r.status_code in (200, 201):
|
||||
created += 1
|
||||
|
||||
print(f" {created} traduceri noi")
|
||||
|
||||
# Now rename accounts using bench command via docker exec
|
||||
# Actually, let's use the proper rename API with positional args
|
||||
print("\n2. Renaming accounts...")
|
||||
renamed = 0
|
||||
errors = 0
|
||||
|
||||
r = s.get(f"{URL}/api/resource/Account", params={
|
||||
"filters": json.dumps([["company", "=", "TOP CLOSSERS SRL"]]),
|
||||
"fields": json.dumps(["name", "account_name"]),
|
||||
"limit_page_length": 200,
|
||||
})
|
||||
accounts = r.json().get("data", [])
|
||||
|
||||
for acc in accounts:
|
||||
old_account_name = acc["account_name"]
|
||||
if old_account_name not in TRANSLATIONS:
|
||||
continue
|
||||
|
||||
new_account_name = TRANSLATIONS[old_account_name]
|
||||
full_name = acc["name"]
|
||||
|
||||
# Update account_name field directly
|
||||
r = s.put(f"{URL}/api/resource/Account/{urllib.parse.quote(full_name, safe='')}", json={
|
||||
"account_name": new_account_name,
|
||||
})
|
||||
|
||||
if r.status_code == 200:
|
||||
renamed += 1
|
||||
else:
|
||||
errors += 1
|
||||
# Try to understand error
|
||||
msg = r.text[:100] if r.text else str(r.status_code)
|
||||
print(f" ERR {old_account_name}: {msg}")
|
||||
|
||||
print(f" Renamed: {renamed}, Errors: {errors}")
|
||||
|
||||
# Clear cache
|
||||
s.post(f"{URL}/api/method/frappe.client.clear_cache")
|
||||
print("\nDone! Refresh browser (Ctrl+Shift+R).")
|
||||
Loading…
Add table
Add a link
Reference in a new issue