""" ERPNext Phase 2 Final Setup: Buying, API User, Reports """ import frappe import json def execute(): setup_buying() setup_api_user() setup_print_format() frappe.db.commit() print("\n=== Phase 2 Final Setup Complete ===\n") def setup_buying(): """2.6 - Configure suppliers and expense categories.""" print("[1/3] Configuring suppliers and expenses...") company_abbr = "TC" # Create expense accounts under existing parent expenses_parent = frappe.db.get_value("Account", {"company": "TOP CLOSSERS SRL", "root_type": "Expense", "is_group": 1, "parent_account": ["like", "%Expenses%"]}, "name" ) if not expenses_parent: expenses_parent = frappe.db.get_value("Account", {"company": "TOP CLOSSERS SRL", "root_type": "Expense", "is_group": 1}, "name" ) if expenses_parent: expense_accounts = [ {"account_name": "Hosting si Infrastructura", "account_type": "Expense Account"}, {"account_name": "Servicii Software", "account_type": "Expense Account"}, {"account_name": "Marketing si Publicitate", "account_type": "Expense Account"}, {"account_name": "Servicii Plati (Stripe)", "account_type": "Expense Account"}, ] for acc in expense_accounts: full_name = f"{acc['account_name']} - {company_abbr}" if not frappe.db.exists("Account", full_name): try: a = frappe.get_doc({ "doctype": "Account", "account_name": acc["account_name"], "parent_account": expenses_parent, "account_type": acc["account_type"], "company": "TOP CLOSSERS SRL", }) a.insert(ignore_permissions=True) print(f" Created account: {acc['account_name']}") except Exception as e: print(f" Account {acc['account_name']}: {e}") # Create suppliers suppliers = [ {"supplier_name": "Hetzner Online GmbH", "supplier_group": "Services", "country": "Germany", "supplier_type": "Company"}, {"supplier_name": "Stripe Payments Europe", "supplier_group": "Services", "country": "Ireland", "supplier_type": "Company"}, {"supplier_name": "Twilio SendGrid", "supplier_group": "Services", "country": "United States", "supplier_type": "Company"}, ] # Ensure supplier group exists if not frappe.db.exists("Supplier Group", "Services"): sg = frappe.get_doc({"doctype": "Supplier Group", "supplier_group_name": "Services"}) sg.insert(ignore_permissions=True) for s in suppliers: if not frappe.db.exists("Supplier", s["supplier_name"]): doc = frappe.get_doc({"doctype": "Supplier", **s}) doc.insert(ignore_permissions=True) print(f" Created supplier: {s['supplier_name']}") print(" Buying configured.") def setup_api_user(): """2.9 - Create dedicated API user for website integration.""" print("[2/3] Creating API user and role...") # Create custom role if not frappe.db.exists("Role", "Website Integration"): role = frappe.get_doc({ "doctype": "Role", "role_name": "Website Integration", "desk_access": 0, "is_custom": 1 }) role.insert(ignore_permissions=True) print(" Created role: Website Integration") # Set permissions for the role doctypes_read_write = [ "Customer", "Lead", "Sales Invoice", "Payment Entry", "Subscription", "Subscription Plan", "Website Content", "Service Agreement", "Analysis Report", "Payment Log", "Item", "Address" ] doctypes_read_only = [ "Company", "Account", "Sales Taxes and Charges Template", "Email Template", "Sales Stage" ] for dt in doctypes_read_write: try: # Check if DocType exists if not frappe.db.exists("DocType", dt): continue existing_name = frappe.db.exists("Custom DocPerm", {"parent": dt, "role": "Website Integration"}) values = { "read": 1, "write": 1, "create": 1, "delete": 0, "email": 0, "print": 1, "export": 1, "submit": 1 if dt in ("Sales Invoice", "Payment Entry") else 0, } if existing_name: frappe.db.set_value("Custom DocPerm", existing_name, values, update_modified=False) else: perm = frappe.get_doc({ "doctype": "Custom DocPerm", "parent": dt, "parenttype": "DocType", "parentfield": "permissions", "role": "Website Integration", **values, }) perm.insert(ignore_permissions=True) except Exception: pass for dt in doctypes_read_only: if not frappe.db.exists("Custom DocPerm", {"parent": dt, "role": "Website Integration"}): try: if frappe.db.exists("DocType", dt): perm = frappe.get_doc({ "doctype": "Custom DocPerm", "parent": dt, "parenttype": "DocType", "parentfield": "permissions", "role": "Website Integration", "read": 1, "write": 0, "create": 0, }) perm.insert(ignore_permissions=True) except Exception: pass # Create API user api_user_email = "website_api@didi.localhost" if not frappe.db.exists("User", api_user_email): user = frappe.get_doc({ "doctype": "User", "email": api_user_email, "first_name": "Website", "last_name": "API", "enabled": 1, "user_type": "System User", "roles": [ {"role": "Website Integration"}, ], "new_password": "didi_api_secure_pwd_2026!", "send_welcome_email": 0, }) user.insert(ignore_permissions=True) print(f" Created API user: {api_user_email}") # Generate API keys api_secret = frappe.generate_hash(length=15) user.reload() user.api_key = frappe.generate_hash(length=15) user.api_secret = api_secret user.save(ignore_permissions=True) print(f" API Key: {user.api_key}") print(f" API Secret: {api_secret}") print(f" >>> Save these credentials in website/.env.local <<<") else: user = frappe.get_doc("User", api_user_email) print(f" API user already exists: {api_user_email}") print(f" API Key: {user.api_key}") print(" API user configured.") def setup_print_format(): """2.3.2 - Create custom invoice PDF print format.""" print("[3/3] Creating custom invoice print format...") if frappe.db.exists("Print Format", "DiDi Invoice"): print(" Already exists, skipping.") return html = """
FACTURA
{{ doc.name }}
Data: {{ doc.posting_date }}
Scadenta: {{ doc.due_date }}
{{ doc.company }}
CUI: {{ frappe.db.get_value("Company", doc.company, "tax_id") }}
{{ frappe.db.get_value("Company", doc.company, "address") or "Str. Targovistei 15, Ploiesti" }}
Catre:
{{ doc.customer_name }}
{% if doc.tax_id %}CUI: {{ doc.tax_id }}
{% endif %} {{ doc.address_display or "" }}
{% for item in doc.items %} {% endfor %}
Nr. Descriere Cant. Pret unitar Total
{{ loop.index }} {{ item.item_name }}
{{ item.description or "" }}
{{ item.qty }} {{ frappe.format(item.rate, {"fieldtype": "Currency", "currency": doc.currency}) }} {{ frappe.format(item.amount, {"fieldtype": "Currency", "currency": doc.currency}) }}
{% for tax in doc.taxes %} {% endfor %}
Subtotal:{{ frappe.format(doc.net_total, {"fieldtype": "Currency", "currency": doc.currency}) }}
{{ tax.description }}:{{ frappe.format(tax.tax_amount, {"fieldtype": "Currency", "currency": doc.currency}) }}
TOTAL:{{ frappe.format(doc.grand_total, {"fieldtype": "Currency", "currency": doc.currency}) }}
""" pf = frappe.get_doc({ "doctype": "Print Format", "name": "DiDi Invoice", "doc_type": "Sales Invoice", "module": "Didi Custom", "html": html, "print_format_type": "Jinja", "standard": "No", "custom_format": 1, "default_print_language": "ro", }) pf.insert(ignore_permissions=True) print(" DiDi Invoice print format created.")