diff --git a/app/controllers/admin_routes/manageDepartments.py b/app/controllers/admin_routes/manageDepartments.py
index c202513a..ec9ce2f5 100644
--- a/app/controllers/admin_routes/manageDepartments.py
+++ b/app/controllers/admin_routes/manageDepartments.py
@@ -17,7 +17,7 @@
from app.logic.manageDepartments import *
-
+from playhouse.shortcuts import model_to_dict
@admin.route('/admin/manageDepartments/', methods=['GET'])
def manageDepartments(academicYear = None):
@@ -25,7 +25,6 @@ def manageDepartments(academicYear = None):
Returns the Manage Departments page, which allows the admin to view all the departments
and their allocations.
"""
-
# Checking Admin Rights
currentUser = require_login()
if not currentUser: # If the current user is not logged in
@@ -36,42 +35,25 @@ def manageDepartments(academicYear = None):
elif currentUser.supervisor:
return render_template('errors/403.html'), 403
-
- # The condition below may be deleted if the routing to the Manage Departments page is changed.
- if academicYear == None:
- academicYear = g.openTerm.termCode
- else:
- academicYear = int(academicYear)
-
-
- currentAY, nextAY = generateAdjacentYears(academicYear)
- chosenAY = Term.get(Term.termCode == academicYear)
-
- breakHoursByDepartment = {row["department"]: str(row["totalHours"] or 0) for row in getUsedBreakHours(chosenAY)}
-
- activeDepartments = getActiveDepartmentsWithAllocation(chosenAY)
- inactiveDepartments = Department.select().where(Department.isActive == False)
+ currentAY, nextAY = generateAdjacentYears(g.openTerm.termCode)
- allocationStatus = {
- department.departmentID: getAllocationStatus(chosenAY, department)
- for department in activeDepartments
- }
+ inactiveDepartments = Department.select().where(Department.isActive == False)
+ allSupervisors = Supervisor.select().order_by(Supervisor.LAST_NAME)
- allSupervisors= Supervisor.select().order_by(Supervisor.LAST_NAME)
+ breakHoursByDepartment = {row["department"]: str(row["totalHours"] or 0) for row in getUsedBreakHours(currentAY)}
+
+ activeDepartmentsAllocations = getActiveDepartmentsAllocations(currentAY,nextAY)
return render_template( 'admin/manageDepartments.html',
- activeDepartments = activeDepartments,
+ activeDepartmentsAllocations = activeDepartmentsAllocations,
inactiveDepartments = inactiveDepartments,
- allSupervisors = allSupervisors,
+ allSupervisors = allSupervisors,
currentAY = currentAY,
nextAY = nextAY,
- academicYear = chosenAY.termName,
breakHoursByDepartment = breakHoursByDepartment,
- allocationStatus = allocationStatus
)
-
@admin.route('/admin/complianceStatus', methods=['POST'])
def complianceStatusCheck():
"""
diff --git a/app/logic/manageDepartments.py b/app/logic/manageDepartments.py
index 4f3fbb9d..6feeec2a 100644
--- a/app/logic/manageDepartments.py
+++ b/app/logic/manageDepartments.py
@@ -12,17 +12,17 @@
from app.login_manager import require_login
+from playhouse.shortcuts import model_to_dict
+
def generateAdjacentYears(academicYearTermCode=None):
"""
- Generates the current, the previous, and the following academic years.
+ Generates the current, and the following academic years.
"""
-
currentYear = g.openTerm.termCode // 100
nextYear = currentYear + 1
-
currentAYCode = currentYear * 100
nextAYCode = nextYear * 100
@@ -50,9 +50,6 @@ def generateAdjacentYears(academicYearTermCode=None):
# Everything below this line will eventually be deleted
-
-
-
def getUsedBreakHours(term):
"""
Returns the total number of break hours used by each department for a given term.
@@ -109,7 +106,7 @@ def getLSFCountSecondaries(currentTerm, department):
-def getActiveDepartmentsWithAllocation(term):
+def getActiveDepartmentsWithAllocation(term,isFinal = True):
"""
Returns a list of active departments with allocations for the given term.
"""
@@ -118,24 +115,61 @@ def getActiveDepartmentsWithAllocation(term):
# activeDepartments = Department.select().where(Department.isActive == True)
# allAllocations = Allocation.select().where(Allocation.termCode == currentAY)
- activeDepartments = (Department
+ activeDepartments = (Allocation
.select(Department, Allocation)
- .join(Allocation)
+ .join(Department)
.where(
Department.isActive == True,
- Allocation.termCode == term.termCode
- )
+ Allocation.termCode == term.termCode,
+ Allocation.isFinal == isFinal,
+ )
)
- for dept in activeDepartments:
- dept.totalPrimaries = (dept.allocation.primary_10 + dept.allocation.primary_12 + dept.allocation.primary_15 + dept.allocation.primary_20)
- dept.totalSecondaries = (dept.allocation.secondary_5 + dept.allocation.secondary_10)
+
+ for allocation in activeDepartments:
+ allocation.totalPrimaries = (allocation.primary_10 + allocation.primary_12 + allocation.primary_15 + allocation.primary_20)
+ allocation.totalSecondaries = (allocation.secondary_5 + allocation.secondary_10)
+
+ if isFinal: # do not need to count them for requested allocations
+ allocation.lsfCountPrimaries = getLSFCountPrimaries(term, allocation.department)
+ allocation.lsfCountSecondaries = getLSFCountSecondaries(term, allocation.department)
+
+ return activeDepartments
- dept.lsfCountPrimaries = getLSFCountPrimaries(term, dept)
- dept.lsfCountSecondaries = getLSFCountSecondaries(term, dept)
- return activeDepartments
+def getActiveDepartmentsAllocations(term,nextTerm):
+ """
+ This function gets active departments, active allocations for the current AY and future AY.
+ It returns a dictionary which contains three objects grouped by the departmentID
+ """
+
+ activeDepartments = Department.select().where(Department.isActive == True)
+
+ allocations = getActiveDepartmentsWithAllocation(term)
+
+ allocByDeptId = {}
+
+ # index allocations by department ID
+ for alloc in allocations:
+ allocByDeptId[alloc.department.departmentID] = alloc
+ requestedAllocations = getActiveDepartmentsWithAllocation(nextTerm, False)
+
+ # index requested allocations by department ID
+ reqAllocByDeptId = {}
+ for alloc in requestedAllocations:
+ reqAllocByDeptId[alloc.department.departmentID] = alloc
+
+ # build combined dictionary for active departments
+ activeDepartmentsAllocations = {}
+
+ for dept in activeDepartments:
+ activeDepartmentsAllocations[dept.departmentID] = {
+ "department": dept,
+ "allocation": allocByDeptId.get(dept.departmentID), # None if no allocation
+ "requestedAllocation": reqAllocByDeptId.get(dept.departmentID), # None if no requested allocation
+ }
+ return activeDepartmentsAllocations
def getAllocationStatus(term, department):
diff --git a/app/templates/admin/manageDepartments.html b/app/templates/admin/manageDepartments.html
index 88fcf297..abb4db22 100755
--- a/app/templates/admin/manageDepartments.html
+++ b/app/templates/admin/manageDepartments.html
@@ -91,69 +91,79 @@
Manage Departments
| Department |
-
Status |
- Current Allocations ({{ academicYear }}) |
+ Current Allocations ({{ currentAY.termName }}) |
Requested Allocations ({{ nextAY.termName }}) |
Actions |
- {% for department in activeDepartments %}
+ {% for entry in activeDepartmentsAllocations.values() %}
- {{department.DEPT_NAME}} ({{department.ORG}},
- {{department.ACCOUNT}})
+ {{entry.department.DEPT_NAME}} ({{entry.department.ORG}},
+ {{entry.department.ACCOUNT}})
|
-
- |
- {% endfor %}
+ {%endfor%}
diff --git a/database/demo_data.py b/database/demo_data.py
index b7a59297..13128f7c 100644
--- a/database/demo_data.py
+++ b/database/demo_data.py
@@ -637,6 +637,16 @@
"adjustmentCutOff": f"2025-09-01",
"isBreak": 1,
},
+ {
+ "termCode": f"202600",
+ "termName": f"AY 2026-2027",
+ "termStart": f"2026-08-01",
+ "termEnd": f"2027-05-01",
+ "termState": 0,
+ "primaryCutOff": f"2026-09-01",
+ "adjustmentCutOff": f"2026-09-01",
+ "isBreak": 0,
+ },
]
Term.insert_many(terms).on_conflict_replace().execute()
@@ -1105,10 +1115,12 @@
############################
# Allocation Dummy Data:
###########################
+
+# Active Allocations for 2025
allocations = [
{
"termCode": 202500,
- "department": 3,
+ "department": 1,
"isFinal": False,
"approvedOn": None,
"approvedBy": None,
@@ -1138,7 +1150,7 @@
},
{
"termCode": 202500,
- "department": 1,
+ "department": 3,
"isFinal": True,
"approvedOn": None,
"approvedBy": None,
@@ -1154,7 +1166,7 @@
{
"termCode": 202500,
"department": 4,
- "isFinal": False,
+ "isFinal": True,
"approvedOn": None,
"approvedBy": None,
"justification": "Downscaling the number of students in the department due to budget cuts",
@@ -1181,7 +1193,160 @@
"secondary_10": 1,
"breakHours": 900,
},
-
+
+ # Active Allocations for 2026
+ {
+ "termCode": 202600,
+ "department": 5,
+ "isFinal": True,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 8,
+ "primary_12": 10,
+ "primary_15": 7,
+ "primary_20": 4,
+ "secondary_5": 5,
+ "secondary_10": 1,
+ "breakHours": 900,
+ },
+ {
+ "termCode": 202600,
+ "department": 4,
+ "isFinal": True,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 8,
+ "primary_12": 10,
+ "primary_15": 7,
+ "primary_20": 4,
+ "secondary_5": 5,
+ "secondary_10": 1,
+ "breakHours": 900,
+ },
+ {
+ "termCode": 202600,
+ "department": 3,
+ "isFinal": True,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 8,
+ "primary_12": 10,
+ "primary_15": 7,
+ "primary_20": 4,
+ "secondary_5": 5,
+ "secondary_10": 1,
+ "breakHours": 900,
+ },
+ {
+ "termCode": 202600,
+ "department": 2,
+ "isFinal": True,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 8,
+ "primary_12": 10,
+ "primary_15": 7,
+ "primary_20": 4,
+ "secondary_5": 5,
+ "secondary_10": 1,
+ "breakHours": 900,
+ },
+ {
+ "termCode": 202600,
+ "department": 1,
+ "isFinal": True,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 8,
+ "primary_12": 10,
+ "primary_15": 7,
+ "primary_20": 4,
+ "secondary_5": 5,
+ "secondary_10": 1,
+ "breakHours": 900,
+ },
+
+ # Requested Allocations for 2026-2027 (isFinal = False)
+ {
+ "termCode": 202600,
+ "department": 5,
+ "isFinal": False,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 1,
+ "primary_12": 22,
+ "primary_15": 3,
+ "primary_20": 4,
+ "secondary_5": 1,
+ "secondary_10": 1,
+ "breakHours": 89,
+ },
+ {
+ "termCode": 202600,
+ "department": 4,
+ "isFinal": False,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 11,
+ "primary_12": 2,
+ "primary_15": 3,
+ "primary_20": 4,
+ "secondary_5": 1,
+ "secondary_10": 1,
+ "breakHours": 293,
+ },
+ {
+ "termCode": 202600,
+ "department": 3,
+ "isFinal": False,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 1,
+ "primary_12": 23,
+ "primary_15": 3,
+ "primary_20": 4,
+ "secondary_5": 1,
+ "secondary_10": 1,
+ "breakHours": 999,
+ },
+ {
+ "termCode": 202600,
+ "department": 2,
+ "isFinal": False,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 10,
+ "primary_12": 2,
+ "primary_15": 3,
+ "primary_20": 13,
+ "secondary_5": 1,
+ "secondary_10": 19,
+ "breakHours": 1000,
+ },
+ {
+ "termCode": 202600,
+ "department": 1,
+ "isFinal": False,
+ "approvedOn": None,
+ "approvedBy": None,
+ "justification": "Due to rapid department growth, we need to hire more students to help with the increased workload",
+ "primary_10": 1,
+ "primary_12": 2,
+ "primary_15": 3,
+ "primary_20": 4,
+ "secondary_5": 1,
+ "secondary_10": 1,
+ "breakHours": 100,
+ },
]
Allocation.insert_many(allocations).on_conflict_replace().execute()