Added new role Accounting
This commit is contained in:
@@ -218,10 +218,10 @@ def cache_coordinates(address, lat, lng, accuracy):
|
||||
print(f"⚠️ Error caching coordinates: {e}")
|
||||
|
||||
# Valid user roles with new additions
|
||||
VALID_ROLES = ['admin', 'staff', 'payroll', 'project_manager']
|
||||
VALID_ROLES = ['admin', 'staff', 'payroll', 'project_manager', 'accounting']
|
||||
|
||||
# Roles that have staff-level permissions (non-admin roles)
|
||||
STAFF_LEVEL_ROLES = ['staff', 'payroll', 'project_manager']
|
||||
STAFF_LEVEL_ROLES = ['staff', 'payroll', 'project_manager', 'accounting']
|
||||
|
||||
# Import and initialize models
|
||||
from models import set_db
|
||||
@@ -303,6 +303,24 @@ def get_role_permissions(role):
|
||||
'Cannot manage other users',
|
||||
'Cannot access admin settings'
|
||||
]
|
||||
},
|
||||
'accounting': {
|
||||
'title': 'Accounting Specialist Permissions',
|
||||
'permissions': [
|
||||
'View and modify employee records',
|
||||
'Access attendance reports and analytics',
|
||||
'View and manage time attendance data',
|
||||
'Export payroll and attendance data',
|
||||
'Access financial reports and statistics',
|
||||
'Update personal profile information',
|
||||
'Delete attendance records (same as payroll)'
|
||||
],
|
||||
'restrictions': [
|
||||
'Cannot create or delete QR codes',
|
||||
'Cannot manage other users',
|
||||
'Cannot access admin settings',
|
||||
'Cannot manage projects'
|
||||
]
|
||||
}
|
||||
}
|
||||
return permissions.get(role, {})
|
||||
@@ -2659,6 +2677,7 @@ def user_stats_api():
|
||||
staff_users = User.query.filter_by(role='staff', active_status=True).count()
|
||||
payroll_users = User.query.filter_by(role='payroll', active_status=True).count()
|
||||
project_manager_users = User.query.filter_by(role='project_manager', active_status=True).count()
|
||||
accounting_users = User.query.filter_by(role='accounting', active_status=True).count()
|
||||
inactive_users = User.query.filter_by(active_status=False).count()
|
||||
|
||||
recent_registrations = User.query.filter(
|
||||
@@ -2676,6 +2695,7 @@ def user_stats_api():
|
||||
'staff_users': staff_users,
|
||||
'payroll_users': payroll_users,
|
||||
'project_manager_users': project_manager_users,
|
||||
'accounting_users': accounting_users,
|
||||
'inactive_users': inactive_users,
|
||||
'recent_registrations': recent_registrations,
|
||||
'recent_logins': recent_logins
|
||||
@@ -5132,7 +5152,7 @@ def attendance_report():
|
||||
def edit_attendance(record_id):
|
||||
"""Edit attendance record (Admin and Payroll only)"""
|
||||
# Check if user has permission to edit attendance records
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
flash('Access denied. Only administrators and payroll staff can edit attendance records.', 'error')
|
||||
return redirect(url_for('attendance_report'))
|
||||
|
||||
@@ -5252,7 +5272,7 @@ def edit_attendance(record_id):
|
||||
def delete_attendance(record_id):
|
||||
"""Delete attendance record (Admin and Payroll only)"""
|
||||
# Check if user has permission to delete attendance records
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
if request.headers.get('X-Requested-With') == 'XMLHttpRequest':
|
||||
return jsonify({
|
||||
'success': False,
|
||||
@@ -5320,7 +5340,7 @@ def verification_review():
|
||||
"""Admin page to review pending photo verifications"""
|
||||
try:
|
||||
# Only admins can access
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
flash('Unauthorized access.', 'error')
|
||||
return redirect(url_for('dashboard'))
|
||||
|
||||
@@ -5382,7 +5402,7 @@ def update_verification_status(record_id):
|
||||
"""Update verification status (approve/reject)"""
|
||||
try:
|
||||
# Only admins can update
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Unauthorized access'
|
||||
@@ -5448,7 +5468,7 @@ def get_verification_details(record_id):
|
||||
|
||||
# Check if user has permission to view
|
||||
# Allow admin and payroll staff to view verification details
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Unauthorized access'
|
||||
@@ -5567,7 +5587,7 @@ def export_configuration():
|
||||
"""Display export configuration page for customizing Excel exports"""
|
||||
try:
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted unauthorized access to export configuration")
|
||||
flash('Access denied. Only administrators and payroll staff can access export configuration.', 'error')
|
||||
return redirect(url_for('attendance_report'))
|
||||
@@ -5654,7 +5674,7 @@ def generate_excel_export():
|
||||
"""Generate and download Excel file with selected columns in specified order"""
|
||||
try:
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted unauthorized Excel export")
|
||||
flash('Access denied. Only administrators and payroll staff can export data.', 'error')
|
||||
return redirect(url_for('attendance_report'))
|
||||
@@ -6293,7 +6313,7 @@ def payroll_dashboard():
|
||||
try:
|
||||
# Check if user has payroll access
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted to access payroll dashboard without permissions")
|
||||
flash('Access denied. Only administrators and payroll staff can access payroll features.', 'error')
|
||||
return redirect(url_for('dashboard'))
|
||||
@@ -6440,7 +6460,7 @@ def export_payroll_excel():
|
||||
try:
|
||||
# Check permissions
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
logger_handler.logger.warning(f"User {session.get('username', 'unknown')} (role: {user_role}) attempted unauthorized payroll Excel export")
|
||||
flash('Access denied. Only administrators and payroll staff can export payroll data.', 'error')
|
||||
return redirect(url_for('payroll_dashboard'))
|
||||
@@ -6681,7 +6701,7 @@ def calculate_working_hours_api():
|
||||
try:
|
||||
# Check permissions
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Access denied. Insufficient permissions.'
|
||||
@@ -6758,7 +6778,7 @@ def get_miss_punch_details(employee_id):
|
||||
try:
|
||||
# Check permissions
|
||||
user_role = session.get('role')
|
||||
if user_role not in ['admin', 'payroll']:
|
||||
if user_role not in ['admin', 'payroll', 'accounting']:
|
||||
return jsonify({
|
||||
'success': False,
|
||||
'message': 'Access denied. Insufficient permissions.'
|
||||
@@ -7152,7 +7172,7 @@ def export_statistics():
|
||||
"""Export statistics data to CSV/Excel"""
|
||||
try:
|
||||
# Check permissions
|
||||
if session.get('role') not in ['admin', 'payroll']:
|
||||
if session.get('role') not in ['admin', 'payroll', 'accounting']:
|
||||
return jsonify({'error': 'Access denied'}), 403
|
||||
|
||||
# Log export attempt
|
||||
|
||||
+3
-2
@@ -10,7 +10,7 @@ from werkzeug.security import generate_password_hash, check_password_hash
|
||||
from datetime import datetime
|
||||
|
||||
# Valid user roles (kept in sync with app.py)
|
||||
STAFF_LEVEL_ROLES = ['staff', 'payroll', 'project_manager']
|
||||
STAFF_LEVEL_ROLES = ['staff', 'payroll', 'project_manager', 'accounting']
|
||||
|
||||
# Import db from app - this works because app.py imports this file after db is created
|
||||
import sys
|
||||
@@ -63,6 +63,7 @@ class User(base.db.Model):
|
||||
'admin': 'Administrator',
|
||||
'staff': 'Staff User',
|
||||
'payroll': 'Payroll Specialist',
|
||||
'project_manager': 'Project Manager'
|
||||
'project_manager': 'Project Manager',
|
||||
'accounting': 'Accounting Specialist'
|
||||
}
|
||||
return role_names.get(self.role, self.role.title())
|
||||
@@ -107,6 +107,10 @@
|
||||
background: linear-gradient(90deg, #17a2b8, #138496);
|
||||
}
|
||||
|
||||
.stat-card.accounting::before {
|
||||
background: linear-gradient(90deg, #059669, #047857);
|
||||
}
|
||||
|
||||
.stat-card.project-manager::before {
|
||||
background: linear-gradient(90deg, #6f42c1, #5a2d91);
|
||||
}
|
||||
@@ -149,6 +153,10 @@
|
||||
background: linear-gradient(135deg, #17a2b8, #138496);
|
||||
}
|
||||
|
||||
.stat-icon.accounting {
|
||||
background: linear-gradient(135deg, #059669, #047857);
|
||||
}
|
||||
|
||||
.stat-icon.project-manager {
|
||||
background: linear-gradient(135deg, #6f42c1, #5a2d91);
|
||||
}
|
||||
@@ -385,6 +393,12 @@
|
||||
border: 1px solid rgba(23, 162, 184, 0.3);
|
||||
}
|
||||
|
||||
.user-role.accounting {
|
||||
background-color: rgba(5, 150, 105, 0.1);
|
||||
color: #047857;
|
||||
border: 1px solid rgba(5, 150, 105, 0.3);
|
||||
}
|
||||
|
||||
.user-role.project_manager {
|
||||
background-color: rgba(111, 66, 193, 0.1);
|
||||
color: #5a2d91;
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
<i class="fas fa-clipboard-list"></i>
|
||||
<span class="menu-text">System Logs</span>
|
||||
</a>
|
||||
{% elif session.role in ['payroll'] %}
|
||||
{% elif session.role in ['payroll', 'accounting'] %}
|
||||
<a href="{{ url_for('employees') }}" class="menu-item">
|
||||
<i class="fas fa-user"></i>
|
||||
<span class="menu-text">Employees</span>
|
||||
|
||||
@@ -82,6 +82,7 @@ Code Management{% endblock %} {% block content %}
|
||||
<option value="">Select Role</option>
|
||||
<option value="staff">Staff User</option>
|
||||
<option value="payroll">Payroll Specialist</option>
|
||||
<option value="accounting">Accounting Specialist</option>
|
||||
<option value="project_manager">Project Manager</option>
|
||||
<option value="admin">Administrator</option>
|
||||
</select>
|
||||
|
||||
@@ -64,6 +64,7 @@
|
||||
<select id="role" name="role" required>
|
||||
<option value="staff" {{ 'selected' if user.role == 'staff' else '' }}>Staff User</option>
|
||||
<option value="payroll" {{ 'selected' if user.role == 'payroll' else '' }}>Payroll Specialist</option>
|
||||
<option value="accounting" {{ 'selected' if user.role == 'accounting' else '' }}>Accounting Specialist</option>
|
||||
<option value="project_manager" {{ 'selected' if user.role == 'project_manager' else '' }}>Project Manager</option>
|
||||
<option value="admin" {{ 'selected' if user.role == 'admin' else '' }}>Administrator</option>
|
||||
</select>
|
||||
@@ -586,7 +587,8 @@
|
||||
function getRoleDisplayName(role) {
|
||||
const roleNames = {
|
||||
'staff': 'Staff User',
|
||||
'payroll': 'Payroll Specialist',
|
||||
'payroll': 'Payroll Specialist',
|
||||
'accounting': 'Accounting Specialist',
|
||||
'project_manager': 'Project Manager',
|
||||
'admin': 'Administrator'
|
||||
};
|
||||
|
||||
@@ -65,6 +65,19 @@ Code Management{% endblock %} {% block extra_head %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card accounting">
|
||||
<div class="stat-icon accounting">
|
||||
<i class="fas fa-file-invoice-dollar"></i>
|
||||
</div>
|
||||
<div class="stat-info">
|
||||
<h3>
|
||||
{{ users|selectattr('role', 'equalto',
|
||||
'accounting')|selectattr('active_status', 'equalto', True)|list|length }}
|
||||
</h3>
|
||||
<p>Accounting Specialists</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="stat-card project-manager">
|
||||
<div class="stat-icon project-manager">
|
||||
<i class="fas fa-project-diagram"></i>
|
||||
|
||||
Reference in New Issue
Block a user