2026-10-09 12:16:48 +05:30

279 lines
12 KiB
Python

import frappe
def fix_indicator_permlevel():
"""Set actor-visible fields in Progress indicators to permlevel 0 so all roles can read them."""
visible_fields = ['name1', 'target', 'minimum', 'maximum', 'actual_value', 'cycle_comment', 'cycle_status', 'cycle_date', 'status']
for f in visible_fields:
frappe.db.sql(
"UPDATE `tabDocField` SET permlevel=0 WHERE parent='Progress indicators' AND fieldname=%s",
f
)
print(f' Set permlevel=0: {f}')
frappe.db.commit()
frappe.clear_cache(doctype='Progress indicators')
frappe.clear_cache(doctype='SB Process')
print('Done.')
def check_process_perms():
rows = frappe.db.sql(
'SELECT role, permlevel, `read`, `write`, `create` FROM `tabDocPerm` WHERE parent="SB Process" ORDER BY permlevel, role',
as_dict=True
)
print("=== SB Process Permissions ===")
for r in rows:
print(r)
flds = frappe.db.sql(
'SELECT fieldname, label, permlevel FROM `tabDocField` WHERE parent="Progress indicators" ORDER BY idx',
as_dict=True
)
print("\n=== Progress indicators field permlevel ===")
for f in flds:
print(f)
print("\n=== SB Process child table field ===")
ct = frappe.db.sql(
'SELECT fieldname, label, options FROM `tabDocField` WHERE parent="SB Process" AND fieldtype="Table"',
as_dict=True
)
for f in ct:
print(f)
def seed_brd_statuses():
"""Seed all BRD-specified status master records (idempotent)."""
brd_statuses = {
'Idea Statuses': [
'New', 'Initial Evaluation', 'Rejected',
'Accept & Under Progress', 'Executed & Closed', 'Moved to Study',
],
'Incident Statuses': [
'New', 'Initial Evaluation', 'Rejected',
'Accept & Under Progress', 'Executed & Closed',
],
'Order Statuses': ['New', 'In Progress', 'Closed'],
'Process Statuses': ['Pass', 'Fail', 'Unknown', 'Active'],
}
for doctype, names in brd_statuses.items():
for name in names:
if not frappe.db.exists(doctype, name):
doc = frappe.new_doc(doctype)
doc.name1 = name
doc.insert(ignore_permissions=True)
print(f'Created {doctype}: {name}')
else:
print(f'Already exists {doctype}: {name}')
frappe.db.commit()
print('BRD statuses seeded.')
def create_roles():
roles = ['CEO', 'Ceo', 'SB CEO', 'SB Admin', 'SB Owner', 'SB Manager', 'SB Auditor', 'SB X-Auditor', 'SB Employee']
for role in roles:
if not frappe.db.exists('Role', role):
doc = frappe.new_doc('Role')
doc.role_name = role
doc.insert(ignore_permissions=True)
print(f'Created role: {role}')
else:
print(f'Role already exists: {role}')
frappe.db.commit()
def create_test_users():
users = [
{'email': 'manager@sidrah.com', 'first_name': 'Sara', 'last_name': 'Manager', 'role': 'SB Manager'},
{'email': 'auditor@sidrah.com', 'first_name': 'Omar', 'last_name': 'Auditor', 'role': 'SB Auditor'},
{'email': 'employee@sidrah.com', 'first_name': 'Ali', 'last_name': 'Employee', 'role': 'SB Employee'},
]
for u in users:
if not frappe.db.exists('User', u['email']):
doc = frappe.new_doc('User')
doc.email = u['email']
doc.first_name = u['first_name']
doc.last_name = u['last_name']
doc.new_password = 'sidrah123'
doc.send_welcome_email = 0
doc.insert(ignore_permissions=True)
frappe.db.commit()
user_doc = frappe.get_doc('User', u['email'])
user_doc.add_roles(u['role'])
print(f"Created user: {u['email']}")
else:
print(f"User already exists: {u['email']}")
frappe.db.commit()
def check_statuses():
for dt in ['Incident Statuses', 'Idea Statuses', 'Order Statuses', 'Process Statuses']:
rows = frappe.db.sql(f'SELECT name, name1 FROM `tab{dt}`', as_dict=True)
print(f'\n=== {dt} ===')
for r in rows:
print(f' name={r.name!r} name1={r.name1!r}')
def cleanup_statuses():
"""
Remove all non-BRD status records and migrate documents to the correct BRD values.
BRD sources: Section 6 (lookup tables), 9.4 (Incident), 10.2 (Idea).
Run once; safe to re-run (idempotent).
"""
# ── BRD-approved values ───────────────────────────────────────────────────
BRD = {
'Incident Statuses': ['New', 'Initial Evaluation', 'Rejected', 'Accept & Under Progress', 'Executed & Closed'],
'Idea Statuses': ['New', 'Initial Evaluation', 'Rejected', 'Accept & Under Progress', 'Executed & Closed', 'Moved to Study'],
'Order Statuses': ['Bidding', 'Execution', 'Validation', 'Payment', 'Completion', 'Closed'],
'Process Statuses': ['Pass', 'Fail', 'Unknown'],
}
# ── Migration maps (old value → BRD value) ────────────────────────────────
INC_MAP = {
'Under progress': 'Accept & Under Progress',
'Executed': 'Executed & Closed',
'Pending Auditor': 'Initial Evaluation',
'Pending Manager': 'Accept & Under Progress',
'Pending Comment': 'Accept & Under Progress',
'Review': 'Accept & Under Progress',
'In Study': 'Executed & Closed',
}
IDEA_MAP = {
'Accepted & under progress': 'Accept & Under Progress',
'Being studied': 'Moved to Study',
'Executed': 'Executed & Closed',
'Executed & closed': 'Executed & Closed',
'Under Progress': 'Accept & Under Progress',
'Pending Auditor': 'Initial Evaluation',
'Pending Manager': 'Accept & Under Progress',
'Pending Comment': 'Accept & Under Progress',
'Review': 'Accept & Under Progress',
'In Outsourcing': 'Executed & Closed',
'Moved to Study': 'Moved to Study',
}
ORD_MAP = {
'New': 'Bidding',
'Deviation': 'Execution',
'In Progress':'Execution',
'Precision': 'Validation',
}
PROC_MAP = {
'Active': 'Unknown',
'Failures': 'Fail',
'Success': 'Pass',
}
STAGE_TO_STATUS = {1: 'Bidding', 2: 'Execution', 3: 'Validation', 4: 'Payment', 5: 'Completion'}
# ── Step 1: Migrate SB Incident documents ────────────────────────────────
print('\n--- Migrating SB Incident status ---')
for old, new in INC_MAP.items():
count = frappe.db.count('SB Incident', {'status': old})
if count:
frappe.db.sql("UPDATE `tabSB Incident` SET status=%s WHERE status=%s", (new, old))
print(f' Incident: "{old}" → "{new}" ({count} docs)')
# ── Step 2: Migrate SB Idea documents ────────────────────────────────────
print('\n--- Migrating SB Idea status ---')
for old, new in IDEA_MAP.items():
count = frappe.db.count('SB Idea', {'status': old})
if count:
frappe.db.sql("UPDATE `tabSB Idea` SET status=%s WHERE status=%s", (new, old))
print(f' Idea: "{old}" → "{new}" ({count} docs)')
# ── Step 3: Migrate SB Order — use stage to drive status ────────────────
print('\n--- Migrating SB Order status (stage-based) ---')
all_orders = frappe.db.sql(
"SELECT name, stage, workflow_state, status FROM `tabSB Order`", as_dict=True
)
for o in all_orders:
if o.workflow_state == 'Closed' or o.status == 'Closed':
correct = 'Closed'
else:
correct = STAGE_TO_STATUS.get(int(o.stage or 1), 'Bidding')
if o.status != correct:
frappe.db.sql("UPDATE `tabSB Order` SET status=%s WHERE name=%s", (correct, o.name))
print(f' Order {o.name}: "{o.status}" → "{correct}" (stage={o.stage})')
# Also handle non-stage-based old mappings for any remaining
for old, new in ORD_MAP.items():
count = frappe.db.count('SB Order', {'status': old})
if count:
frappe.db.sql("UPDATE `tabSB Order` SET status=%s WHERE status=%s", (new, old))
print(f' Order: "{old}" → "{new}" ({count} docs)')
# ── Step 4: Migrate SB Process documents ─────────────────────────────────
print('\n--- Migrating SB Process status ---')
for old, new in PROC_MAP.items():
count = frappe.db.count('SB Process', {'status': old})
if count:
frappe.db.sql("UPDATE `tabSB Process` SET status=%s WHERE status=%s", (new, old))
print(f' Process: "{old}" → "{new}" ({count} docs)')
frappe.db.commit()
# ── Step 5: Delete non-BRD master records ────────────────────────────────
print('\n--- Cleaning status master records ---')
for dt, allowed in BRD.items():
existing = frappe.db.sql(f"SELECT name FROM `tab{dt}`", as_dict=True)
for row in existing:
if row.name not in allowed:
frappe.db.sql(f"DELETE FROM `tab{dt}` WHERE name=%s", row.name)
print(f' Deleted {dt}: "{row.name}"')
# ── Step 6: Ensure all BRD records exist (with exact names) ──────────────
print('\n--- Ensuring BRD statuses exist ---')
for dt, names in BRD.items():
for n in names:
exists = frappe.db.sql(f"SELECT name FROM `tab{dt}` WHERE name=%s", n)
if not exists:
frappe.db.sql(f"INSERT INTO `tab{dt}` (name, name1, creation, modified, modified_by, owner, docstatus) VALUES (%s,%s,NOW(),NOW(),'Administrator','Administrator',0)", (n, n))
print(f' Created {dt}: "{n}"')
else:
frappe.db.sql(f"UPDATE `tab{dt}` SET name1=%s WHERE name=%s", (n, n))
frappe.db.commit()
print('\nStatus cleanup complete.')
def sync_workflows():
"""Sync all Frappe Workflows from workflow.json fixture into Frappe DB."""
import json
import os
fixture_path = frappe.get_app_path('sidrah_business', 'fixtures', 'workflow.json')
if not os.path.exists(fixture_path):
print('workflow.json not found')
return
with open(fixture_path, 'r') as f:
workflows = json.load(f)
for wf_data in workflows:
wf_name = wf_data.get('name')
if not wf_name:
continue
if frappe.db.exists('Workflow', wf_name):
doc = frappe.get_doc('Workflow', wf_name)
else:
doc = frappe.new_doc('Workflow')
doc.name = wf_name
doc.workflow_name = wf_data.get('workflow_name', wf_name)
doc.document_type = wf_data.get('document_type')
doc.workflow_state_field = wf_data.get('workflow_state_field', 'workflow_state')
doc.is_active = wf_data.get('is_active', 1)
doc.set('states', [])
for st in wf_data.get('states', []):
doc.append('states', st)
doc.set('transitions', [])
for tr in wf_data.get('transitions', []):
doc.append('transitions', tr)
doc.flags.ignore_permissions = True
doc.save(ignore_permissions=True)
print(f"Synced Workflow in Frappe DB: {wf_name}")
frappe.db.commit()
print("All Workflows synced to Frappe DB successfully.")