From a4629f0ef8e8a2beee87ff2be899af2ca98fdd14 Mon Sep 17 00:00:00 2001 From: Liberty Mupotsa Date: Fri, 29 Jan 2021 13:48:29 -0500 Subject: [PATCH 01/51] modifying the lsf model --- app/models/laborStatusForm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/models/laborStatusForm.py b/app/models/laborStatusForm.py index 7178ba278..43d11803a 100755 --- a/app/models/laborStatusForm.py +++ b/app/models/laborStatusForm.py @@ -24,7 +24,7 @@ class LaborStatusForm (baseModel): endDate = DateField(null=True) supervisorNotes = TextField(null=True) laborDepartmentNotes = TextField(null=True) - + jobDescription = TextField(null=True) def __str__(self): return str(self.__dict__) From 3c7c3b52a9618605fa86b653f2cc004f53fe586b Mon Sep 17 00:00:00 2001 From: Liberty Mupotsa Date: Fri, 29 Jan 2021 14:26:35 -0500 Subject: [PATCH 02/51] modified models --- app/models/laborStatusForm.py | 2 +- app/models/positionDescription.py | 7 +++++++ 2 files changed, 8 insertions(+), 1 deletion(-) create mode 100644 app/models/positionDescription.py diff --git a/app/models/laborStatusForm.py b/app/models/laborStatusForm.py index 43d11803a..b2e0c0ec4 100755 --- a/app/models/laborStatusForm.py +++ b/app/models/laborStatusForm.py @@ -24,7 +24,7 @@ class LaborStatusForm (baseModel): endDate = DateField(null=True) supervisorNotes = TextField(null=True) laborDepartmentNotes = TextField(null=True) - jobDescription = TextField(null=True) + jobDescription = ForeignKeyField(null=True) def __str__(self): return str(self.__dict__) diff --git a/app/models/positionDescription.py b/app/models/positionDescription.py new file mode 100644 index 000000000..dc3c28cc4 --- /dev/null +++ b/app/models/positionDescription.py @@ -0,0 +1,7 @@ +from app.models import * +from app.models.term import term + +class PositionDescription: + positionDescriptionID = PrimaryKeyField() + termCode = ForeignKeyField(null=False) + positionDescription = TextField(null=True) From bc6791bb070e7f3e967c90110f77e160fd06d268 Mon Sep 17 00:00:00 2001 From: Alex Bryant Date: Tue, 2 Feb 2021 14:07:00 -0500 Subject: [PATCH 03/51] updated positionDescription model and added it to the migration file --- app/models/laborStatusForm.py | 3 +-- app/models/positionDescription.py | 15 ++++++++++----- database/demo_data.py | 21 ++++++++++++++++++++- database/migrate_db.sh | 1 + 4 files changed, 32 insertions(+), 8 deletions(-) diff --git a/app/models/laborStatusForm.py b/app/models/laborStatusForm.py index b2e0c0ec4..aee1ced75 100755 --- a/app/models/laborStatusForm.py +++ b/app/models/laborStatusForm.py @@ -4,6 +4,7 @@ from app.models.user import User from app.models.department import Department from app.models.supervisor import Supervisor +from app.models.positionDescription import PositionDescription # All caps fields are pulled from TRACY @@ -24,7 +25,5 @@ class LaborStatusForm (baseModel): endDate = DateField(null=True) supervisorNotes = TextField(null=True) laborDepartmentNotes = TextField(null=True) - jobDescription = ForeignKeyField(null=True) - def __str__(self): return str(self.__dict__) diff --git a/app/models/positionDescription.py b/app/models/positionDescription.py index dc3c28cc4..1381151f3 100644 --- a/app/models/positionDescription.py +++ b/app/models/positionDescription.py @@ -1,7 +1,12 @@ from app.models import * -from app.models.term import term +from app.models.laborStatusForm import LaborStatusForm -class PositionDescription: - positionDescriptionID = PrimaryKeyField() - termCode = ForeignKeyField(null=False) - positionDescription = TextField(null=True) + +class PositionDescription (baseModel): + positionDescriptionPrimaryKey = CompositeKey("LaborStatusForm.termCode", "LaborStatusForm.POSN_CODE") + termID = PrimaryKeyField() + POSN_CODE = PrimaryKeyField() + positionDescription = TextField(null=True) + + def __str__(self): + return str(self.__dict__) diff --git a/database/demo_data.py b/database/demo_data.py index 5826e27fa..b4309b86c 100644 --- a/database/demo_data.py +++ b/database/demo_data.py @@ -15,6 +15,7 @@ from app.models.laborStatusForm import LaborStatusForm from app.models.formHistory import FormHistory from app.models.notes import Notes +from app.models.positionDescription import PositionDescription print("Inserting data for demo and testing purposes") @@ -436,7 +437,7 @@ "POSN_CODE": "S61407", "weeklyHours": 10, "startDate": "2020-04-01", - "endDate": "2020-09-01" + "endDate": "2020-09-01", }]).on_conflict_replace().execute() FormHistory.insert([{ "formHistoryID": 2, @@ -471,3 +472,21 @@ ] Notes.insert_many(notes).on_conflict_replace().execute() print(" * laborOfficeNotes added") + +############################# +# Position Descritpion +############################# +positionDescriptions = [ + { + "termID": "202000", + "POSN_CODE": "S61407", + "positionDescription": "Working in a team of student software developers" + }, + { + "termID": "202001", + "POSN_CODE": "S61407", + "positionDescription": "Working in a team of student software developers again." + } + ] +PositionDescription.insert_many(positionDescriptions).on_conflict_replace().execute() +print(" * positionDescriptions added") diff --git a/database/migrate_db.sh b/database/migrate_db.sh index 82b056a48..e799dc32c 100755 --- a/database/migrate_db.sh +++ b/database/migrate_db.sh @@ -27,5 +27,6 @@ pem add app.models.visitTracker.VisitTracker pem add app.models.emailTracker.EmailTracker pem add app.models.notes.Notes pem add app.models.supervisor.Supervisor +pem add app.models.positionDescription.PositionDescription pem watch pem migrate From ff76a71d9883de6153e1877b69a060c9dc0db0a0 Mon Sep 17 00:00:00 2001 From: Elaheh Jamali Date: Wed, 17 Feb 2021 18:29:02 -0500 Subject: [PATCH 04/51] UI build for position description --- app/controllers/main_routes/__init__.py | 1 + .../main_routes/termPositionDescription.py | 49 ++++++++++++++ app/models/laborStatusForm.py | 4 +- app/models/position.py | 13 ++++ app/models/positionDescription.py | 12 ---- app/models/termPositionDescription.py | 12 ++++ app/static/css/termPositionDescription.css | 56 ++++++++++++++++ app/static/js/termPositionDescription.js | 0 .../main/termPositionDescription.html | 57 ++++++++++++++++ database/demo_data.py | 67 +++++++++++++------ database/migrate_db.sh | 3 +- 11 files changed, 241 insertions(+), 33 deletions(-) create mode 100644 app/controllers/main_routes/termPositionDescription.py create mode 100644 app/models/position.py delete mode 100644 app/models/positionDescription.py create mode 100644 app/models/termPositionDescription.py create mode 100644 app/static/css/termPositionDescription.css create mode 100644 app/static/js/termPositionDescription.js create mode 100644 app/templates/main/termPositionDescription.html diff --git a/app/controllers/main_routes/__init__.py b/app/controllers/main_routes/__init__.py index 1cc229b63..d58d6586b 100755 --- a/app/controllers/main_routes/__init__.py +++ b/app/controllers/main_routes/__init__.py @@ -22,3 +22,4 @@ def injectGlobalData(): from app.controllers.main_routes import download from app.controllers.main_routes import laborReleaseForm from app.controllers.main_routes import contributors +from app.controllers.main_routes import termPositionDescription diff --git a/app/controllers/main_routes/termPositionDescription.py b/app/controllers/main_routes/termPositionDescription.py new file mode 100644 index 000000000..1fbd4ddd6 --- /dev/null +++ b/app/controllers/main_routes/termPositionDescription.py @@ -0,0 +1,49 @@ +from flask_login import login_required +from app.controllers.main_routes import * +from app.login_manager import require_login +from app.models.user import * +from app.models.formHistory import * +from flask import json, jsonify +from flask import request +from datetime import datetime, date, timedelta +from flask import Flask, redirect, url_for, flash +from app import cfg +from app.logic.emailHandler import* +from app.logic.userInsertFunctions import* + +@main_bp.route('/termpositiondescription', methods=['GET']) +def termPositionDescription(): + """ Render Position Description Form""" + currentUser = require_login() + if not currentUser: # Not logged in + return render_template('errors/403.html'), 403 + if not currentUser.isLaborAdmin: + if currentUser.student and not currentUser.supervisor: + return redirect('/laborHistory/' + currentUser.student.ID) + if not currentUser.student and currentUser.supervisor: + # Checks all the forms where the current user has been the creator or the supervisor, and grabs all the departments associated with those forms. Will only grab each department once. + departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME) \ + .join_from(FormHistory, LaborStatusForm) \ + .join_from(LaborStatusForm, Department) \ + .where((FormHistory.formID.supervisor == currentUser.supervisor.ID) | (FormHistory.createdBy == currentUser)) \ + .order_by(FormHistory.formID.department.DEPT_NAME.asc()) \ + .distinct() + + if currentUser.isLaborAdmin: + # Grabs every single department that currently has at least one labor status form in it + departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME) \ + .join_from(FormHistory, LaborStatusForm) \ + .join_from(LaborStatusForm, Department) \ + .order_by(FormHistory.formID.department.DEPT_NAME.asc()) \ + .distinct() + + # Logged in + openTerms = Term.select().where(Term.termState == "open") # changed to term state, open, closed, inactive + closedTerms = Term.select().where(Term.termState == "closed") + + return render_template( 'main/termPositionDescription.html', + title=('Position Description'), + UserID = currentUser, + openTerms = openTerms, + closedTerms = closedTerms, + departments = departments) diff --git a/app/models/laborStatusForm.py b/app/models/laborStatusForm.py index aee1ced75..fcceaeaa3 100755 --- a/app/models/laborStatusForm.py +++ b/app/models/laborStatusForm.py @@ -4,7 +4,7 @@ from app.models.user import User from app.models.department import Department from app.models.supervisor import Supervisor -from app.models.positionDescription import PositionDescription +from app.models.termPositionDescription import TermPositionDescription # All caps fields are pulled from TRACY @@ -15,10 +15,12 @@ class LaborStatusForm (baseModel): studentSupervisee = ForeignKeyField(Student, on_delete="cascade") # foreign key to student supervisor = ForeignKeyField(Supervisor, on_delete="cascade") # foreign key to supervisor department = ForeignKeyField(Department, on_delete="cascade") # Foreign key to department + termPositionDescription = ForeignKeyField(TermPositionDescription, null=True, on_delete="cascade") jobType = CharField() # Primary or secondary WLS = CharField() POSN_TITLE = CharField() # eg. student programmer, customer engagement specialist, receptionist, teaching assistant POSN_CODE = CharField() + positionDescription = CharField(null=True) contractHours = IntegerField(null=True) # total hours for break terms weeklyHours = IntegerField(null=True) # weekly hours 10,12,15... startDate = DateField(null=True) # in case they start different than term start date diff --git a/app/models/position.py b/app/models/position.py new file mode 100644 index 000000000..fe8430e08 --- /dev/null +++ b/app/models/position.py @@ -0,0 +1,13 @@ +from app.models import * + +class Position (baseModel): + + POSN_CODE = CharField(primary_key=True) + POSN_TITLE = CharField() + WLS = CharField() + ORG = CharField() + ACCOUNT = CharField() + DEPT_NAME = CharField() + + def __str__(self): + return str(self.__dict__) diff --git a/app/models/positionDescription.py b/app/models/positionDescription.py deleted file mode 100644 index 1381151f3..000000000 --- a/app/models/positionDescription.py +++ /dev/null @@ -1,12 +0,0 @@ -from app.models import * -from app.models.laborStatusForm import LaborStatusForm - - -class PositionDescription (baseModel): - positionDescriptionPrimaryKey = CompositeKey("LaborStatusForm.termCode", "LaborStatusForm.POSN_CODE") - termID = PrimaryKeyField() - POSN_CODE = PrimaryKeyField() - positionDescription = TextField(null=True) - - def __str__(self): - return str(self.__dict__) diff --git a/app/models/termPositionDescription.py b/app/models/termPositionDescription.py new file mode 100644 index 000000000..3150879f7 --- /dev/null +++ b/app/models/termPositionDescription.py @@ -0,0 +1,12 @@ +from app.models import * +from app.models.term import Term +from app.models.position import Position + +class TermPositionDescription (baseModel): + temrpositionDescriptionID = PrimaryKeyField() + termCode = ForeignKeyField(Term, on_delete="cascade") + POSN_CODE = ForeignKeyField(Position, on_delete="cascade") + positionDescription = TextField(null=True) + + def __str__(self): + return str(self.__dict__) diff --git a/app/static/css/termPositionDescription.css b/app/static/css/termPositionDescription.css new file mode 100644 index 000000000..e0e7b1ed9 --- /dev/null +++ b/app/static/css/termPositionDescription.css @@ -0,0 +1,56 @@ +@media(min-width:970px) and (max-width:2500px) { + .container { + width: 83%; + } +} + +.bootstrap-select>.dropdown-toggle.bs-placeholder, +.bootstrap-select>.dropdown-toggle.bs-placeholder:active, +.bootstrap-select>.dropdown-toggle.bs-placeholder:focus, +.bootstrap-select>.dropdown-toggle.bs-placeholder:hover { + color: #757575; +} + +.dropdown-menu>.disabled>a, +.dropdown-menu>.disabled>a:focus, +.dropdown-menu>.disabled>a:hover { + color: #000; +} + +.floatleft { +float: left; +width: 47%; +height: 310px; +} + +.floatright { +float: right; +width: 47%; +height: 310px; +} + +#titleGlyphicon{ + font-size: 29px; + color: #337ab7; +} + +selectpicker, label { + display: block; +} + +.col-xs-12 { + padding-left: 0px; + padding-right: 0px; +} + +#glyphicon_note{ + font-size: 29px; + color: #337ab7; + padding-right: 0px; + padding-left: 26px; +} + +#flash_container { + width: 87%; + height: 55px; +} diff --git a/app/static/js/termPositionDescription.js b/app/static/js/termPositionDescription.js new file mode 100644 index 000000000..e69de29bb diff --git a/app/templates/main/termPositionDescription.html b/app/templates/main/termPositionDescription.html new file mode 100644 index 000000000..9e32cfb1e --- /dev/null +++ b/app/templates/main/termPositionDescription.html @@ -0,0 +1,57 @@ +{% extends "base.html" %} + +{% block scripts %} +{{super()}} + +{% endblock %} + +{% block styles %} +{{super()}} + +{% endblock %} + +{% block app_content %} + +
+

Position Description + + +

+
+ +
+
+
+

* Marked fields are required

+
+ +
+ +
+ + + +
+ +
+
+
+ +{% endblock %} diff --git a/database/demo_data.py b/database/demo_data.py index b4309b86c..e9fd6f65a 100644 --- a/database/demo_data.py +++ b/database/demo_data.py @@ -15,7 +15,8 @@ from app.models.laborStatusForm import LaborStatusForm from app.models.formHistory import FormHistory from app.models.notes import Notes -from app.models.positionDescription import PositionDescription +from app.models.termPositionDescription import TermPositionDescription +from app.models.position import Position print("Inserting data for demo and testing purposes") @@ -421,6 +422,50 @@ Term.insert_many(terms).on_conflict_replace().execute() print(" * terms added") +############################# +# Positions +############################# +positions = [ + { + "POSN_CODE": "S61407", + "POSN_TITLE": "Student Programmer", + "WLS": "1", + "ORG" : "2114", + "ACCOUNT":"6740", + "DEPT_NAME":"Computer Science" + }, + { + "POSN_CODE": "S61408", + "POSN_TITLE": "Research Associate", + "WLS": "5", + "ORG" : "2114", + "ACCOUNT":"6740", + "DEPT_NAME":"Computer Science" + } + ] +Position.insert_many(positions).on_conflict_replace().execute() +print(" * positionsadded") + +############################# +# Position Descritpion +############################# +termPositionDescriptions = [ + { + "temrpositionDescriptionID": 1, + "termCode": "202000", + "POSN_CODE": "S61407", + "positionDescription": "Working in a team of student software developers" + }, + { + "temrpositionDescriptionID": 2, + "termCode": "202001", + "POSN_CODE": "S61408", + "positionDescription": "Working in a team of student software developers again." + } + ] +TermPositionDescription.insert_many(termPositionDescriptions).on_conflict_replace().execute() +print(" * positionDescriptions added") + ############################# # Create a Pending Labor Status Form ############################# @@ -431,10 +476,12 @@ "studentSupervisee_id": "B00841417", "supervisor_id": "B12361006", "department_id": 1, + "termPositionDescription_id":1, "jobType": "Primary", "WLS": 1, "POSN_TITLE": "Student Programmer", "POSN_CODE": "S61407", + "positionDescription": "Working in a team of student software developers", "weeklyHours": 10, "startDate": "2020-04-01", "endDate": "2020-09-01", @@ -472,21 +519,3 @@ ] Notes.insert_many(notes).on_conflict_replace().execute() print(" * laborOfficeNotes added") - -############################# -# Position Descritpion -############################# -positionDescriptions = [ - { - "termID": "202000", - "POSN_CODE": "S61407", - "positionDescription": "Working in a team of student software developers" - }, - { - "termID": "202001", - "POSN_CODE": "S61407", - "positionDescription": "Working in a team of student software developers again." - } - ] -PositionDescription.insert_many(positionDescriptions).on_conflict_replace().execute() -print(" * positionDescriptions added") diff --git a/database/migrate_db.sh b/database/migrate_db.sh index e799dc32c..17ea41208 100755 --- a/database/migrate_db.sh +++ b/database/migrate_db.sh @@ -27,6 +27,7 @@ pem add app.models.visitTracker.VisitTracker pem add app.models.emailTracker.EmailTracker pem add app.models.notes.Notes pem add app.models.supervisor.Supervisor -pem add app.models.positionDescription.PositionDescription +pem add app.models.termPositionDescription.TermPositionDescription +pem add app.models.position.Position pem watch pem migrate From a01960b2bc34328520bd1a9fdea4bbc4f9b82f6a Mon Sep 17 00:00:00 2001 From: Elaheh Jamali Date: Thu, 18 Feb 2021 13:01:52 -0500 Subject: [PATCH 05/51] added all the selectpickers and all working --- .../main_routes/termPositionDescription.py | 19 ++++- app/static/js/termPositionDescription.js | 37 +++++++++ .../main/termPositionDescription.html | 78 ++++++++++++++++++- database/reset_database.sh | 14 ++-- setup.sh | 2 +- 5 files changed, 135 insertions(+), 15 deletions(-) diff --git a/app/controllers/main_routes/termPositionDescription.py b/app/controllers/main_routes/termPositionDescription.py index 1fbd4ddd6..6742e531a 100644 --- a/app/controllers/main_routes/termPositionDescription.py +++ b/app/controllers/main_routes/termPositionDescription.py @@ -22,7 +22,7 @@ def termPositionDescription(): return redirect('/laborHistory/' + currentUser.student.ID) if not currentUser.student and currentUser.supervisor: # Checks all the forms where the current user has been the creator or the supervisor, and grabs all the departments associated with those forms. Will only grab each department once. - departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME) \ + departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME, FormHistory.formID.department.ACCOUNT, FormHistory.formID.department.ORG) \ .join_from(FormHistory, LaborStatusForm) \ .join_from(LaborStatusForm, Department) \ .where((FormHistory.formID.supervisor == currentUser.supervisor.ID) | (FormHistory.createdBy == currentUser)) \ @@ -31,15 +31,17 @@ def termPositionDescription(): if currentUser.isLaborAdmin: # Grabs every single department that currently has at least one labor status form in it - departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME) \ + departments = FormHistory.select(FormHistory.formID.department.DEPT_NAME, FormHistory.formID.department.ACCOUNT, FormHistory.formID.department.ORG) \ .join_from(FormHistory, LaborStatusForm) \ .join_from(LaborStatusForm, Department) \ .order_by(FormHistory.formID.department.DEPT_NAME.asc()) \ .distinct() # Logged in - openTerms = Term.select().where(Term.termState == "open") # changed to term state, open, closed, inactive - closedTerms = Term.select().where(Term.termState == "closed") + todayDate = date.today() + print(todayDate) + openTerms = Term.select().where(Term.termEnd > todayDate) + closedTerms = Term.select().where(Term.termEnd < todayDate) return render_template( 'main/termPositionDescription.html', title=('Position Description'), @@ -47,3 +49,12 @@ def termPositionDescription(): openTerms = openTerms, closedTerms = closedTerms, departments = departments) + +@main_bp.route("/termpositiondescription/getPositions//", methods=['GET']) +def getDepartmentPositions(departmentOrg, departmentAcct): + """ Get all of the positions that are in the selected department """ + positions = Tracy().getPositionsFromDepartment(departmentOrg,departmentAcct) + positionDict = {} + for position in positions: + positionDict[position.POSN_CODE] = {"position": position.POSN_TITLE, "WLS":position.WLS, "positionCode":position.POSN_CODE} + return json.dumps(positionDict) diff --git a/app/static/js/termPositionDescription.js b/app/static/js/termPositionDescription.js index e69de29bb..50c5ed8d5 100644 --- a/app/static/js/termPositionDescription.js +++ b/app/static/js/termPositionDescription.js @@ -0,0 +1,37 @@ +function getDepartmentPositions(object, stopSelectRefresh="") { // get department from select picker + var departmentOrg = $(object).val(); + var departmentAcct = $(object).find('option:selected').attr('value-account'); + var url = "/termpositiondescription/getPositions/" + departmentOrg + "/" + departmentAcct; + $.ajax({ + url: url, + dataType: "json", + success: function (response){ + + fillPositions(response, stopSelectRefresh); + } + }); + } + +function fillPositions(response, stopSelectRefresh="") { // prefill Position select picker with the positions of the selected department + var selectedPositions = $("#position"); + $("#position").empty(); + $("#position").prop("disabled", false); + for (var key in response) { + selectedPositions.append( + $("