287 lines
11 KiB
Python
287 lines
11 KiB
Python
"""
|
|
ERPNext Configuration Script for DiDi Project
|
|
Run with: docker exec didi-erpnext bench --site didi.localhost execute didi_setup
|
|
Or copy to container and run via bench.
|
|
"""
|
|
import frappe
|
|
|
|
def execute():
|
|
"""Main setup function - run all configurations."""
|
|
setup_company_details()
|
|
setup_tax_template()
|
|
setup_invoice_naming()
|
|
setup_crm_pipeline()
|
|
setup_subscription_items()
|
|
setup_email_templates()
|
|
frappe.db.commit()
|
|
print("\n=== DiDi ERPNext Configuration Complete ===\n")
|
|
|
|
|
|
def setup_company_details():
|
|
"""Configure company details - CUI, address, etc."""
|
|
print("[1/6] Configuring company details...")
|
|
|
|
company = frappe.get_doc("Company", "TOP CLOSSERS SRL")
|
|
company.tax_id = "36193026"
|
|
company.domain = "Services"
|
|
company.default_currency = "RON"
|
|
company.country = "Romania"
|
|
company.save(ignore_permissions=True)
|
|
|
|
# Create company address
|
|
if not frappe.db.exists("Address", {"address_title": "TOP CLOSSERS SRL - Sediu"}):
|
|
addr = frappe.get_doc({
|
|
"doctype": "Address",
|
|
"address_title": "TOP CLOSSERS SRL - Sediu",
|
|
"address_type": "Office",
|
|
"address_line1": "Str. Targovistei 15",
|
|
"address_line2": "Bl. 2 Et. 3 Ap. 22",
|
|
"city": "Ploiesti",
|
|
"state": "Prahova",
|
|
"pincode": "100299",
|
|
"country": "Romania",
|
|
"phone": "+40721063078",
|
|
"email_id": "office@clossers.com",
|
|
"is_primary_address": 1,
|
|
"links": [{"link_doctype": "Company", "link_name": "TOP CLOSSERS SRL"}]
|
|
})
|
|
addr.insert(ignore_permissions=True)
|
|
|
|
print(" Company details configured.")
|
|
|
|
|
|
def setup_tax_template():
|
|
"""Configure VAT 19% tax template for Romania."""
|
|
print("[2/6] Configuring tax templates...")
|
|
|
|
# Get or create default income account
|
|
company_abbr = "TC"
|
|
tax_account = f"TVA Colectata - {company_abbr}"
|
|
|
|
# Check if tax account exists, create if not
|
|
if not frappe.db.exists("Account", tax_account):
|
|
parent_account = frappe.db.get_value("Account",
|
|
{"company": "TOP CLOSSERS SRL", "account_type": "Tax", "is_group": 1},
|
|
"name"
|
|
)
|
|
if not parent_account:
|
|
parent_account = frappe.db.get_value("Account",
|
|
{"company": "TOP CLOSSERS SRL", "root_type": "Liability", "is_group": 1},
|
|
"name"
|
|
)
|
|
|
|
if parent_account:
|
|
tax_acc = frappe.get_doc({
|
|
"doctype": "Account",
|
|
"account_name": "TVA Colectata",
|
|
"parent_account": parent_account,
|
|
"account_type": "Tax",
|
|
"company": "TOP CLOSSERS SRL",
|
|
"tax_rate": 19.0
|
|
})
|
|
tax_acc.insert(ignore_permissions=True)
|
|
|
|
# Create Sales Tax Template
|
|
if not frappe.db.exists("Sales Taxes and Charges Template", {"title": "TVA 19% Romania"}):
|
|
template = frappe.get_doc({
|
|
"doctype": "Sales Taxes and Charges Template",
|
|
"title": "TVA 19% Romania",
|
|
"company": "TOP CLOSSERS SRL",
|
|
"is_default": 1,
|
|
"taxes": [{
|
|
"charge_type": "On Net Total",
|
|
"account_head": tax_account if frappe.db.exists("Account", tax_account) else "",
|
|
"description": "TVA 19%",
|
|
"rate": 19.0
|
|
}]
|
|
})
|
|
try:
|
|
template.insert(ignore_permissions=True)
|
|
print(" Tax template TVA 19% created.")
|
|
except Exception as e:
|
|
print(f" Tax template: {e}")
|
|
else:
|
|
print(" Tax template already exists.")
|
|
|
|
|
|
def setup_invoice_naming():
|
|
"""Configure Romanian invoice naming series."""
|
|
print("[3/6] Configuring invoice naming series...")
|
|
|
|
# Set naming series for Sales Invoice
|
|
if frappe.db.exists("DocType", "Sales Invoice"):
|
|
prop_setter_name = "Sales Invoice-naming_series-options"
|
|
if not frappe.db.exists("Property Setter", prop_setter_name):
|
|
try:
|
|
ps = frappe.get_doc({
|
|
"doctype": "Property Setter",
|
|
"doctype_or_field": "DocType",
|
|
"doc_type": "Sales Invoice",
|
|
"field_name": "naming_series",
|
|
"property": "options",
|
|
"value": "DIDI-INV-.YYYY.-.#####\nACC-SINV-.YYYY.-",
|
|
"property_type": "Text"
|
|
})
|
|
ps.insert(ignore_permissions=True)
|
|
print(" Invoice naming series configured: DIDI-INV-YYYY-#####")
|
|
except Exception as e:
|
|
print(f" Naming series: {e}")
|
|
else:
|
|
print(" Naming series already configured.")
|
|
|
|
|
|
def setup_crm_pipeline():
|
|
"""Configure CRM sales pipeline stages."""
|
|
print("[4/6] Configuring CRM pipeline...")
|
|
|
|
# CRM Sales Stages
|
|
stages = [
|
|
{"stage_name": "Lead", "department": ""},
|
|
{"stage_name": "Calificat", "department": ""},
|
|
{"stage_name": "Demo", "department": ""},
|
|
{"stage_name": "Client", "department": ""},
|
|
]
|
|
|
|
for stage_data in stages:
|
|
if not frappe.db.exists("Sales Stage", stage_data["stage_name"]):
|
|
stage = frappe.get_doc({
|
|
"doctype": "Sales Stage",
|
|
"stage_name": stage_data["stage_name"]
|
|
})
|
|
stage.insert(ignore_permissions=True)
|
|
print(f" Created stage: {stage_data['stage_name']}")
|
|
|
|
# Lead Source for website forms
|
|
sources = ["Website - Contact Form", "Website - Pricing Page", "Website - Demo Request"]
|
|
for source_name in sources:
|
|
if not frappe.db.exists("Lead Source", source_name):
|
|
source = frappe.get_doc({
|
|
"doctype": "Lead Source",
|
|
"source_name": source_name
|
|
})
|
|
source.insert(ignore_permissions=True)
|
|
|
|
print(" CRM pipeline configured: Lead > Calificat > Demo > Client")
|
|
|
|
|
|
def setup_subscription_items():
|
|
"""Create subscription plan items."""
|
|
print("[5/6] Creating subscription items and plans...")
|
|
|
|
# Item Group for services
|
|
if not frappe.db.exists("Item Group", "DiDi Services"):
|
|
ig = frappe.get_doc({
|
|
"doctype": "Item Group",
|
|
"item_group_name": "DiDi Services",
|
|
"parent_item_group": "All Item Groups"
|
|
})
|
|
ig.insert(ignore_permissions=True)
|
|
|
|
# Subscription Items
|
|
items = [
|
|
{
|
|
"item_code": "DIDI-FREE",
|
|
"item_name": "Abonament DiDi Free",
|
|
"description": "Plan gratuit - acces de baza la platforma DiDi pentru analiza dezinformarii",
|
|
"item_group": "DiDi Services",
|
|
"stock_uom": "Nos",
|
|
"is_stock_item": 0,
|
|
"standard_rate": 0
|
|
},
|
|
{
|
|
"item_code": "DIDI-PAID",
|
|
"item_name": "Abonament DiDi Paid",
|
|
"description": "Plan platit - acces complet la platforma DiDi cu credite lunare pentru analize avansate",
|
|
"item_group": "DiDi Services",
|
|
"stock_uom": "Nos",
|
|
"is_stock_item": 0,
|
|
"standard_rate": 99
|
|
},
|
|
{
|
|
"item_code": "DIDI-ENTERPRISE",
|
|
"item_name": "Abonament DiDi Enterprise",
|
|
"description": "Plan enterprise - acces nelimitat la platforma DiDi, suport dedicat, API avansat",
|
|
"item_group": "DiDi Services",
|
|
"stock_uom": "Nos",
|
|
"is_stock_item": 0,
|
|
"standard_rate": 499
|
|
},
|
|
]
|
|
|
|
for item_data in items:
|
|
if not frappe.db.exists("Item", item_data["item_code"]):
|
|
item = frappe.get_doc({"doctype": "Item", **item_data})
|
|
item.insert(ignore_permissions=True)
|
|
print(f" Created item: {item_data['item_code']} ({item_data['standard_rate']} RON)")
|
|
|
|
# Subscription Plans
|
|
plans = [
|
|
{"plan_name": "DiDi Free - Lunar", "item": "DIDI-FREE", "cost": 0, "billing_interval": "Month", "billing_interval_count": 1},
|
|
{"plan_name": "DiDi Paid - Lunar", "item": "DIDI-PAID", "cost": 99, "billing_interval": "Month", "billing_interval_count": 1},
|
|
{"plan_name": "DiDi Paid - Anual", "item": "DIDI-PAID", "cost": 999, "billing_interval": "Year", "billing_interval_count": 1},
|
|
{"plan_name": "DiDi Enterprise - Lunar", "item": "DIDI-ENTERPRISE", "cost": 499, "billing_interval": "Month", "billing_interval_count": 1},
|
|
{"plan_name": "DiDi Enterprise - Anual", "item": "DIDI-ENTERPRISE", "cost": 4990, "billing_interval": "Year", "billing_interval_count": 1},
|
|
]
|
|
|
|
for plan_data in plans:
|
|
if not frappe.db.exists("Subscription Plan", plan_data["plan_name"]):
|
|
plan = frappe.get_doc({
|
|
"doctype": "Subscription Plan",
|
|
"plan_name": plan_data["plan_name"],
|
|
"item": plan_data["item"],
|
|
"price_determination": "Fixed Rate",
|
|
"cost": plan_data["cost"],
|
|
"currency": "RON",
|
|
"billing_interval": plan_data["billing_interval"],
|
|
"billing_interval_count": plan_data["billing_interval_count"]
|
|
})
|
|
plan.insert(ignore_permissions=True)
|
|
print(f" Created plan: {plan_data['plan_name']} ({plan_data['cost']} RON/{plan_data['billing_interval']})")
|
|
|
|
print(" Subscription items and plans configured.")
|
|
|
|
|
|
def setup_email_templates():
|
|
"""Create email notification templates."""
|
|
print("[6/6] Creating email templates...")
|
|
|
|
templates = [
|
|
{
|
|
"name": "DiDi - Confirmare Plata",
|
|
"subject": "Plata confirmata - {{ doc.name }}",
|
|
"response": """<p>Stimate {{ doc.customer_name }},</p>
|
|
<p>Va confirmam ca plata pentru factura <strong>{{ doc.name }}</strong> in valoare de <strong>{{ doc.grand_total }} {{ doc.currency }}</strong> a fost procesata cu succes.</p>
|
|
<p>Puteti descarca factura din dashboard-ul contului dumneavoastra.</p>
|
|
<p>Va multumim,<br>Echipa DiDi</p>"""
|
|
},
|
|
{
|
|
"name": "DiDi - Expirare Abonament",
|
|
"subject": "Abonamentul dumneavoastra expira in curand",
|
|
"response": """<p>Stimate client,</p>
|
|
<p>Va informam ca abonamentul dumneavoastra DiDi expira in <strong>7 zile</strong>.</p>
|
|
<p>Pentru a continua sa beneficiati de serviciile noastre, va rugam sa verificati metoda de plata in dashboard-ul contului.</p>
|
|
<p>Va multumim,<br>Echipa DiDi</p>"""
|
|
},
|
|
{
|
|
"name": "DiDi - Esec Plata",
|
|
"subject": "Problema la procesarea platii",
|
|
"response": """<p>Stimate client,</p>
|
|
<p>Din pacate, nu am reusit sa procesam plata pentru abonamentul dumneavoastra DiDi.</p>
|
|
<p>Va rugam sa actualizati metoda de plata in dashboard-ul contului pentru a evita intreruperea serviciului.</p>
|
|
<p>Va multumim,<br>Echipa DiDi</p>"""
|
|
},
|
|
]
|
|
|
|
for tmpl in templates:
|
|
if not frappe.db.exists("Email Template", tmpl["name"]):
|
|
doc = frappe.get_doc({
|
|
"doctype": "Email Template",
|
|
"name": tmpl["name"],
|
|
"subject": tmpl["subject"],
|
|
"response": tmpl["response"],
|
|
"use_html": 1
|
|
})
|
|
doc.insert(ignore_permissions=True)
|
|
print(f" Created template: {tmpl['name']}")
|
|
|
|
print(" Email templates configured.")
|