405 lines
11 KiB
Dart
405 lines
11 KiB
Dart
import 'package:flutter/material.dart';
|
|
|
|
/// RBAC permission actions shown in the permission matrix.
|
|
enum RbacAction {
|
|
read('read', 'VIEW'),
|
|
create('create', 'CREATE'),
|
|
update('update', 'EDIT'),
|
|
delete('delete', 'DELETE'),
|
|
approve('approve', 'APPROVE'),
|
|
export('export', 'EXPORT');
|
|
|
|
const RbacAction(this.value, this.label);
|
|
final String value;
|
|
final String label;
|
|
}
|
|
|
|
/// Modules available in the permission matrix.
|
|
class RbacModule {
|
|
const RbacModule({
|
|
required this.key,
|
|
required this.label,
|
|
required this.icon,
|
|
required this.color,
|
|
});
|
|
|
|
final String key;
|
|
final String label;
|
|
final IconData icon;
|
|
final Color color;
|
|
}
|
|
|
|
const rbacModules = [
|
|
RbacModule(
|
|
key: 'users',
|
|
label: 'User Management',
|
|
icon: Icons.people_outline,
|
|
color: Color(0xFF2563EB),
|
|
),
|
|
RbacModule(
|
|
key: 'roles',
|
|
label: 'Roles & Permissions',
|
|
icon: Icons.shield_outlined,
|
|
color: Color(0xFF16A34A),
|
|
),
|
|
RbacModule(
|
|
key: 'masters',
|
|
label: 'Master Data',
|
|
icon: Icons.dataset_outlined,
|
|
color: Color(0xFFEA580C),
|
|
),
|
|
RbacModule(
|
|
key: 'vendors',
|
|
label: 'Vendor Management',
|
|
icon: Icons.storefront_outlined,
|
|
color: Color(0xFF7C3AED),
|
|
),
|
|
RbacModule(
|
|
key: 'purchase_orders',
|
|
label: 'Purchase Orders',
|
|
icon: Icons.receipt_long_outlined,
|
|
color: Color(0xFFCA8A04),
|
|
),
|
|
RbacModule(
|
|
key: 'grn',
|
|
label: 'Purchase Receipt',
|
|
icon: Icons.inventory_outlined,
|
|
color: Color(0xFF0891B2),
|
|
),
|
|
RbacModule(
|
|
key: 'assets',
|
|
label: 'Asset Management',
|
|
icon: Icons.inventory_2_outlined,
|
|
color: Color(0xFFDC2626),
|
|
),
|
|
];
|
|
|
|
class ManagedUser {
|
|
const ManagedUser({
|
|
required this.id,
|
|
required this.name,
|
|
required this.email,
|
|
required this.employeeCode,
|
|
required this.roleId,
|
|
required this.roleName,
|
|
required this.department,
|
|
required this.plant,
|
|
required this.lastLogin,
|
|
required this.status,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String email;
|
|
final String employeeCode;
|
|
final String roleId;
|
|
final String roleName;
|
|
final String department;
|
|
final String plant;
|
|
final String lastLogin;
|
|
final UserAccountStatus status;
|
|
|
|
String get initials {
|
|
final parts = name.trim().split(RegExp(r'\s+'));
|
|
if (parts.length >= 2) {
|
|
return '${parts.first[0]}${parts[1][0]}'.toUpperCase();
|
|
}
|
|
return name.isNotEmpty ? name[0].toUpperCase() : 'U';
|
|
}
|
|
|
|
ManagedUser copyWith({
|
|
String? id,
|
|
String? name,
|
|
String? email,
|
|
String? employeeCode,
|
|
String? roleId,
|
|
String? roleName,
|
|
String? department,
|
|
String? plant,
|
|
String? lastLogin,
|
|
UserAccountStatus? status,
|
|
}) {
|
|
return ManagedUser(
|
|
id: id ?? this.id,
|
|
name: name ?? this.name,
|
|
email: email ?? this.email,
|
|
employeeCode: employeeCode ?? this.employeeCode,
|
|
roleId: roleId ?? this.roleId,
|
|
roleName: roleName ?? this.roleName,
|
|
department: department ?? this.department,
|
|
plant: plant ?? this.plant,
|
|
lastLogin: lastLogin ?? this.lastLogin,
|
|
status: status ?? this.status,
|
|
);
|
|
}
|
|
}
|
|
|
|
enum UserAccountStatus {
|
|
active('Active', Color(0xFF16A34A)),
|
|
inactive('Inactive', Color(0xFF6B7280)),
|
|
locked('Locked', Color(0xFFDC2626));
|
|
|
|
const UserAccountStatus(this.label, this.color);
|
|
final String label;
|
|
final Color color;
|
|
}
|
|
|
|
UserAccountStatus userStatusFromApi(String status) => switch (status.toLowerCase()) {
|
|
'active' => UserAccountStatus.active,
|
|
'inactive' => UserAccountStatus.inactive,
|
|
'locked' => UserAccountStatus.locked,
|
|
_ => UserAccountStatus.inactive,
|
|
};
|
|
|
|
class ManagedRole {
|
|
const ManagedRole({
|
|
required this.id,
|
|
required this.name,
|
|
required this.description,
|
|
required this.icon,
|
|
required this.color,
|
|
required this.userCount,
|
|
required this.permissions,
|
|
});
|
|
|
|
final String id;
|
|
final String name;
|
|
final String description;
|
|
final IconData icon;
|
|
final Color color;
|
|
final int userCount;
|
|
final Set<String> permissions;
|
|
|
|
int get permissionCount => permissions.length;
|
|
|
|
ManagedRole copyWith({
|
|
String? id,
|
|
String? name,
|
|
String? description,
|
|
IconData? icon,
|
|
Color? color,
|
|
int? userCount,
|
|
Set<String>? permissions,
|
|
}) {
|
|
return ManagedRole(
|
|
id: id ?? this.id,
|
|
name: name ?? this.name,
|
|
description: description ?? this.description,
|
|
icon: icon ?? this.icon,
|
|
color: color ?? this.color,
|
|
userCount: userCount ?? this.userCount,
|
|
permissions: permissions ?? this.permissions,
|
|
);
|
|
}
|
|
|
|
bool hasPermission(String module, RbacAction action) =>
|
|
permissions.contains('$module.${action.value}');
|
|
}
|
|
|
|
String permissionKey(String module, RbacAction action) =>
|
|
'$module.${action.value}';
|
|
|
|
Set<String> allPermissionsForRole(String roleId) {
|
|
final all = <String>{};
|
|
for (final module in rbacModules) {
|
|
for (final action in RbacAction.values) {
|
|
all.add(permissionKey(module.key, action));
|
|
}
|
|
}
|
|
|
|
Set<String> modulePerms(
|
|
String module, {
|
|
bool create = false,
|
|
bool edit = false,
|
|
bool delete = false,
|
|
bool approve = false,
|
|
bool export = false,
|
|
bool view = true,
|
|
}) {
|
|
final perms = <String>{};
|
|
if (view) perms.add(permissionKey(module, RbacAction.read));
|
|
if (create) perms.add(permissionKey(module, RbacAction.create));
|
|
if (edit) perms.add(permissionKey(module, RbacAction.update));
|
|
if (delete) perms.add(permissionKey(module, RbacAction.delete));
|
|
if (approve) perms.add(permissionKey(module, RbacAction.approve));
|
|
if (export) perms.add(permissionKey(module, RbacAction.export));
|
|
return perms;
|
|
}
|
|
|
|
return switch (roleId) {
|
|
'super_admin' => all,
|
|
'admin' => all.where((p) => !p.startsWith('settings.')).toSet(),
|
|
'purchase_manager' => {
|
|
...modulePerms('users', view: true),
|
|
...modulePerms('masters', view: true, create: true, edit: true),
|
|
...modulePerms('vendors', view: true, create: true, edit: true),
|
|
...modulePerms('purchase_orders',
|
|
view: true, create: true, edit: true, approve: true, export: true),
|
|
...modulePerms('grn', view: true),
|
|
...modulePerms('assets', view: true),
|
|
},
|
|
'store_manager' => {
|
|
...modulePerms('masters', view: true),
|
|
...modulePerms('grn', view: true, create: true, edit: true),
|
|
...modulePerms('assets', view: true),
|
|
},
|
|
'accounts' => {
|
|
...modulePerms('vendors', view: true),
|
|
...modulePerms('purchase_orders', view: true, export: true),
|
|
...modulePerms('grn', view: true),
|
|
},
|
|
'asset_manager' => {
|
|
...modulePerms('assets',
|
|
view: true, create: true, edit: true, delete: true, export: true),
|
|
...modulePerms('masters', view: true),
|
|
},
|
|
_ => {permissionKey('assets', RbacAction.read)},
|
|
};
|
|
}
|
|
|
|
List<ManagedRole> defaultRoles = [
|
|
ManagedRole(
|
|
id: 'super_admin',
|
|
name: 'Super Admin',
|
|
description: 'Full access to all modules',
|
|
icon: Icons.admin_panel_settings_outlined,
|
|
color: const Color(0xFF2563EB),
|
|
userCount: 1,
|
|
permissions: allPermissionsForRole('super_admin'),
|
|
),
|
|
ManagedRole(
|
|
id: 'admin',
|
|
name: 'Admin',
|
|
description: 'Administrative access, no system config',
|
|
icon: Icons.shield_outlined,
|
|
color: const Color(0xFF16A34A),
|
|
userCount: 2,
|
|
permissions: allPermissionsForRole('admin'),
|
|
),
|
|
ManagedRole(
|
|
id: 'purchase_manager',
|
|
name: 'Purchase Manager',
|
|
description: 'Full PO lifecycle and vendor management',
|
|
icon: Icons.receipt_long_outlined,
|
|
color: const Color(0xFFCA8A04),
|
|
userCount: 8,
|
|
permissions: allPermissionsForRole('purchase_manager'),
|
|
),
|
|
ManagedRole(
|
|
id: 'store_manager',
|
|
name: 'Store Manager',
|
|
description: 'Purchase Receipt, warehouse receipts, stock view',
|
|
icon: Icons.warehouse_outlined,
|
|
color: const Color(0xFF0891B2),
|
|
userCount: 12,
|
|
permissions: allPermissionsForRole('store_manager'),
|
|
),
|
|
ManagedRole(
|
|
id: 'accounts',
|
|
name: 'Accounts',
|
|
description: 'View PO, Purchase Receipt, vendor financial details',
|
|
icon: Icons.account_balance_wallet_outlined,
|
|
color: const Color(0xFF7C3AED),
|
|
userCount: 8,
|
|
permissions: allPermissionsForRole('accounts'),
|
|
),
|
|
ManagedRole(
|
|
id: 'asset_manager',
|
|
name: 'Asset Manager',
|
|
description: 'Full asset register and transfer mgmt',
|
|
icon: Icons.inventory_2_outlined,
|
|
color: const Color(0xFFEA580C),
|
|
userCount: 4,
|
|
permissions: allPermissionsForRole('asset_manager'),
|
|
),
|
|
];
|
|
|
|
List<ManagedUser> buildDefaultUsers() {
|
|
const seeds = [
|
|
('Gowtham S', 'gowtham@bharaterp.com', 'super_admin', 'Super Admin',
|
|
'Administration', 'Unit 1 - Soap', 'Today 10:24 AM', UserAccountStatus.active),
|
|
('Ravi Kumar', 'ravi@bharaterp.com', 'purchase_manager', 'Purchase Manager',
|
|
'Procurement', 'Unit 1 - Soap', 'Yesterday', UserAccountStatus.active),
|
|
('Priya Sharma', 'priya@bharaterp.com', 'store_manager', 'Store Manager',
|
|
'Stores / Warehouse', 'Unit 2 - Powder', '2 days ago', UserAccountStatus.active),
|
|
('Anil Mehta', 'anil@bharaterp.com', 'accounts', 'Accounts',
|
|
'Finance', 'Unit 1 - Soap', '1 week ago', UserAccountStatus.inactive),
|
|
('Deepak Singh', 'deepak@bharaterp.com', 'asset_manager', 'Asset Manager',
|
|
'Asset Management', 'Unit 1 - Soap', '3 days ago', UserAccountStatus.locked),
|
|
];
|
|
|
|
final users = <ManagedUser>[];
|
|
final roleIds = [
|
|
'purchase_manager',
|
|
'store_manager',
|
|
'accounts',
|
|
'asset_manager',
|
|
'admin',
|
|
];
|
|
final roleNames = {
|
|
'purchase_manager': 'Purchase Manager',
|
|
'store_manager': 'Store Manager',
|
|
'accounts': 'Accounts',
|
|
'asset_manager': 'Asset Manager',
|
|
'admin': 'Admin',
|
|
};
|
|
final departments = [
|
|
'Procurement',
|
|
'Stores / Warehouse',
|
|
'Finance',
|
|
'Asset Management',
|
|
'Administration',
|
|
'Production',
|
|
];
|
|
final plants = ['Unit 1 - Soap', 'Unit 2 - Powder', 'Head Office'];
|
|
final logins = ['Today 09:15 AM', 'Yesterday', '2 days ago', '3 days ago', '1 week ago'];
|
|
final statuses = [
|
|
UserAccountStatus.active,
|
|
UserAccountStatus.active,
|
|
UserAccountStatus.active,
|
|
UserAccountStatus.inactive,
|
|
UserAccountStatus.locked,
|
|
];
|
|
|
|
for (var i = 0; i < 38; i++) {
|
|
if (i < seeds.length) {
|
|
final s = seeds[i];
|
|
users.add(
|
|
ManagedUser(
|
|
id: '${i + 1}',
|
|
name: s.$1,
|
|
email: s.$2,
|
|
employeeCode: 'EMP-${(i + 1).toString().padLeft(3, '0')}',
|
|
roleId: s.$3,
|
|
roleName: s.$4,
|
|
department: s.$5,
|
|
plant: s.$6,
|
|
lastLogin: s.$7,
|
|
status: s.$8,
|
|
),
|
|
);
|
|
continue;
|
|
}
|
|
|
|
final roleId = roleIds[i % roleIds.length];
|
|
users.add(
|
|
ManagedUser(
|
|
id: '${i + 1}',
|
|
name: 'User ${i + 1}',
|
|
email: 'user${i + 1}@bharaterp.com',
|
|
employeeCode: 'EMP-${(i + 1).toString().padLeft(3, '0')}',
|
|
roleId: roleId,
|
|
roleName: roleNames[roleId]!,
|
|
department: departments[i % departments.length],
|
|
plant: plants[i % plants.length],
|
|
lastLogin: logins[i % logins.length],
|
|
status: statuses[i % statuses.length],
|
|
),
|
|
);
|
|
}
|
|
|
|
return users;
|
|
}
|
|
|
|
List<ManagedUser> get defaultUsers => buildDefaultUsers();
|