#!/usr/bin/env python3 """Re-sync employee_permissions with role defaults / configured role permissions. Useful when an employee's permissions get out of sync with the role they belong to (e.g. after a role change or a buggy save). Example: python3 scripts/sync_employee_permissions.py --db tenant_refaccionaria_rached """ import argparse import json import os import sys import psycopg2 # Keep in sync with pos/blueprints/config_bp.py _DEFAULT_ROLE_PERMISSIONS = { 'owner': [], 'admin': [ 'config.view', 'config.edit', 'config.edit_prices', 'config.delete', 'pos.view', 'pos.sell', 'pos.cancel', 'pos.remission', 'inventory.view', 'inventory.create', 'inventory.edit', 'inventory.adjust', 'inventory.transfer', 'customers.view', 'customers.create', 'customers.edit', 'customers.delete', 'catalog.view', 'catalog.edit', 'workshop.view', 'workshop.edit', 'workshop.delete', 'invoicing.view', 'invoicing.create', 'reports.view', ], 'manager': [ 'pos.view', 'pos.sell', 'pos.cancel', 'pos.remission', 'inventory.view', 'inventory.create', 'inventory.edit', 'inventory.adjust', 'inventory.transfer', 'customers.view', 'customers.create', 'customers.edit', 'catalog.view', 'catalog.edit', 'workshop.view', 'workshop.edit', 'invoicing.view', 'invoicing.create', 'reports.view', ], 'warehouse': [ 'inventory.view', 'inventory.create', 'inventory.edit', 'inventory.adjust', 'inventory.transfer', 'pos.view', ], 'counter': [ 'pos.sell', 'pos.view', 'pos.remission', 'inventory.view', 'customers.view', 'catalog.view', ], 'cashier': [ 'pos.sell', 'pos.view', 'pos.remission', 'inventory.view', 'customers.view', 'catalog.view', 'invoicing.view', ], 'workshop': [ 'workshop.view', 'customers.view', 'customers.create', 'inventory.view', ], 'mechanic': [ 'workshop.view', 'customers.view', 'customers.create', 'inventory.view', ], } def _get_role_permissions(cur, role): cur.execute("SELECT value FROM tenant_config WHERE key = 'role_permissions'") row = cur.fetchone() if row and row[0]: try: configured = json.loads(row[0]) if isinstance(configured, dict) and role in configured: return list(configured.get(role, [])) except (ValueError, TypeError): pass return list(_DEFAULT_ROLE_PERMISSIONS.get(role, [])) def sync(db_url): conn = psycopg2.connect(db_url) cur = conn.cursor() cur.execute("SELECT id, name, role FROM employees ORDER BY id") employees = cur.fetchall() total = 0 for emp_id, name, role in employees: perms = _get_role_permissions(cur, role) cur.execute("DELETE FROM employee_permissions WHERE employee_id = %s", (emp_id,)) for perm in perms: cur.execute( "INSERT INTO employee_permissions (employee_id, permission) VALUES (%s, %s) ON CONFLICT DO NOTHING", (emp_id, perm) ) total += 1 print(f" [{emp_id:>3}] {name:<30} role={role:<10} perms={len(perms)}") conn.commit() cur.close() conn.close() print(f"\nSynced {total} employees.") def main(): parser = argparse.ArgumentParser(description="Sync employee_permissions with role defaults/config") parser.add_argument('--db', required=True, help='PostgreSQL database name or full connection URL') args = parser.parse_args() db = args.db if db.startswith('postgresql://'): db_url = db else: db_url = f"postgresql://postgres@/{db}" sync(db_url) if __name__ == '__main__': main()