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