"""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).")