started adding employee functionality
This commit is contained in:
parent
1aee89b425
commit
842b57520a
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
BIN
employee_module/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
BIN
employee_module/__pycache__/admin.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/admin.cpython-38.pyc
Normal file
Binary file not shown.
BIN
employee_module/__pycache__/apps.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/apps.cpython-38.pyc
Normal file
Binary file not shown.
BIN
employee_module/__pycache__/models.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/models.cpython-38.pyc
Normal file
Binary file not shown.
BIN
employee_module/__pycache__/urls.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/urls.cpython-38.pyc
Normal file
Binary file not shown.
BIN
employee_module/__pycache__/views.cpython-38.pyc
Normal file
BIN
employee_module/__pycache__/views.cpython-38.pyc
Normal file
Binary file not shown.
62
employee_module/handling_functions/data_import_functions.py
Normal file
62
employee_module/handling_functions/data_import_functions.py
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
import pandas as pd
|
||||
from django.conf import settings
|
||||
import datetime
|
||||
from sqlalchemy import create_engine
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
||||
def create_connection(db_file, type=1):
|
||||
""" create a database connection to the SQLite database
|
||||
specified by the db_file
|
||||
:param db_file: database file
|
||||
:return: Connection object or None
|
||||
"""
|
||||
conn = None
|
||||
try:
|
||||
path = 'sqlite:///' + str(db_file)
|
||||
if type == 1:
|
||||
return create_engine(path)
|
||||
else:
|
||||
return create_engine(path).connect()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return None
|
||||
|
||||
|
||||
|
||||
def read_and_parse_excel(file):
|
||||
df = pd.read_excel(file)
|
||||
path_temp = settings.TMP_FILE_STORAGE + file.name.split('.')[0] + '.csv'
|
||||
df.to_csv(path_temp)
|
||||
html = df.to_html(index=False, na_rep='')
|
||||
return {'df_html': html, 'df_path': path_temp}
|
||||
|
||||
|
||||
def insert_excel(df):
|
||||
conn = create_connection(settings.DATABASES['default']['NAME'])
|
||||
df['date_joined'] = datetime.date.today()
|
||||
df['password'] = make_password('start')
|
||||
|
||||
df_to_user_model = df[['username',
|
||||
'first_name',
|
||||
'last_name',
|
||||
'email',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'date_joined',
|
||||
'is_superuser',
|
||||
'password']]
|
||||
|
||||
df_to_user_model.to_sql(name='auth_user',
|
||||
con=conn,
|
||||
if_exists='append', index=False)
|
||||
|
||||
df_to_employee = df[['username',
|
||||
'department',
|
||||
'manager_username',
|
||||
'time_model_id',
|
||||
'manager_flag']]
|
||||
|
||||
df_to_employee.to_sql(name='hr_module_employee',
|
||||
con=conn,
|
||||
if_exists='append', index=False)
|
8
employee_module/handling_functions/misc.py
Normal file
8
employee_module/handling_functions/misc.py
Normal file
@ -0,0 +1,8 @@
|
||||
|
||||
def dictfetchall(cursor):
|
||||
"Return all rows from a cursor as a dict"
|
||||
columns = [col[0] for col in cursor.description]
|
||||
return [
|
||||
dict(zip(columns, row))
|
||||
for row in cursor.fetchall()
|
||||
]
|
@ -0,0 +1,85 @@
|
||||
|
||||
|
||||
from django.conf import settings
|
||||
import pandas as pd
|
||||
from ..models import Employee, Plan
|
||||
import datetime
|
||||
|
||||
|
||||
def time_timedelta(time, timedelta):
|
||||
start = datetime.datetime(2020, 1, 1, time.hour, time.minute)
|
||||
end = start + timedelta
|
||||
return end.time()
|
||||
|
||||
def insert_into_plan(user, start_date, end_date, start_time, daily_hours, activity_type, timemodel):
|
||||
|
||||
start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
|
||||
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d')
|
||||
start_time = datetime.datetime.strptime(start_time, '%H:%M').time()
|
||||
|
||||
username = Employee.objects.get(username=user)
|
||||
|
||||
daily_hours = int(daily_hours * 60)
|
||||
end_time = time_timedelta(start_time, datetime.timedelta(minutes=daily_hours))
|
||||
|
||||
timemodel_pattern = {0: timemodel['mon'],
|
||||
1: timemodel['tue'],
|
||||
2: timemodel['wed'],
|
||||
3: timemodel['thu'],
|
||||
4: timemodel['fri'],
|
||||
5: timemodel['sat'],
|
||||
6: timemodel['sun']}
|
||||
|
||||
days = (end_date - start_date).days
|
||||
log = []
|
||||
for day in range(days + 1):
|
||||
date_to_add = start_date + datetime.timedelta(days=day)
|
||||
overlap = check_conflicting_records(username, date_to_add, start_time, end_time)
|
||||
print(overlap)
|
||||
if timemodel_pattern[date_to_add.weekday()] and not overlap:
|
||||
print(date_to_add, start_time, end_time, overlap)
|
||||
plan = Plan(username=username,
|
||||
date=date_to_add,
|
||||
begin_time=start_time,
|
||||
end_time=end_time,
|
||||
activity_type=activity_type)
|
||||
plan.save()
|
||||
log.append({'username': username.pk,
|
||||
'date': date_to_add,
|
||||
'begin_time': start_time,
|
||||
'end_time': end_time,
|
||||
'activity_type': activity_type,
|
||||
'status': 'imported'})
|
||||
else:
|
||||
|
||||
log.append({'username': username.pk,
|
||||
'date': date_to_add,
|
||||
'begin_time': start_time,
|
||||
'end_time': end_time,
|
||||
'activity_type': activity_type,
|
||||
'status': 'failed due to conflicting overlap'})
|
||||
return log
|
||||
|
||||
|
||||
def check_conflicting_records(username, date, start_time, end_time):
|
||||
plan = Plan.objects.filter(username=username, date=date)
|
||||
|
||||
if len(plan) > 0:
|
||||
for day in plan:
|
||||
planned_time_start = day.begin_time
|
||||
planned_time_end = day.end_time
|
||||
|
||||
if planned_time_start <= end_time and planned_time_end >= start_time:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def create_planning_operation_report(dict_, current_user):
|
||||
df = pd.DataFrame(dict_)
|
||||
filename = current_user + '_' + datetime.datetime.now().isoformat() + '.xlsx'
|
||||
path_temp = settings.IMPORT_REPORT_STORAGE + filename
|
||||
df.to_excel(path_temp, index=False)
|
||||
return filename
|
BIN
employee_module/migrations/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
employee_module/migrations/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
108
employee_module/static/css/calendar.css
Normal file
108
employee_module/static/css/calendar.css
Normal file
@ -0,0 +1,108 @@
|
||||
|
||||
|
||||
div.month_container table,
|
||||
div.month_container th,
|
||||
div.month_container td {
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
border-width: thin;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
th {
|
||||
background-color: darkred;
|
||||
color: white;
|
||||
border: solid 1px white;
|
||||
border-width: thin;
|
||||
}
|
||||
|
||||
#calendar_container {
|
||||
height: 257px;
|
||||
}
|
||||
|
||||
#months_block {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.month_container {
|
||||
float: left;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
.calendar_button:hover {
|
||||
background-color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.calendar_button {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
height: 271px;
|
||||
width: 30px;
|
||||
background-color: lightgray;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#date_selector {
|
||||
clear: both;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
#year_selector, #month_selector {
|
||||
margin-right: 5px;
|
||||
margin-left: 5px;
|
||||
height: 25px;
|
||||
|
||||
}
|
||||
|
||||
#button_load_selected_months{
|
||||
height: 25px;
|
||||
margin-left: 5px;
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.days_of_month {
|
||||
font-size: 15px;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: auto;
|
||||
vertical-align:middle;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.days_of_month_current {
|
||||
background-color: #ab9898;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.days_of_month_not_current {
|
||||
background-color: #dbd7d7;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.days_of_month_today{
|
||||
background-color: darkred;
|
||||
}
|
||||
|
||||
.month_header {
|
||||
font-size: 15px;
|
||||
height: 28px;
|
||||
margin: auto;
|
||||
vertical-align:middle;
|
||||
display: table-cell;
|
||||
}
|
||||
|
||||
.weekday_header {
|
||||
font-size: 15px;
|
||||
height: 32px;
|
||||
text-transform: capitalize;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
}
|
5
employee_module/static/css/calendar_local.css
Normal file
5
employee_module/static/css/calendar_local.css
Normal file
@ -0,0 +1,5 @@
|
||||
|
||||
|
||||
.days_of_month_work {
|
||||
background-color: darkslateblue;
|
||||
}
|
23
employee_module/static/css/hr_import_validation.css
Normal file
23
employee_module/static/css/hr_import_validation.css
Normal file
@ -0,0 +1,23 @@
|
||||
|
||||
|
||||
.import_table {
|
||||
float:left;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
border-width: thin;
|
||||
}
|
||||
|
||||
table tr:nth-child(even){
|
||||
background-color: #f2f2f2;
|
||||
}
|
||||
|
||||
tr:hover {
|
||||
|
||||
}
|
30
employee_module/static/css/hr_module_base.css
Normal file
30
employee_module/static/css/hr_module_base.css
Normal file
@ -0,0 +1,30 @@
|
||||
|
||||
#hr_module_main_container {
|
||||
padding: 1%;
|
||||
float: left;
|
||||
width: 80%;
|
||||
height: 100%;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
.sidebar {
|
||||
background-color: #8b0000;
|
||||
width: 18%;
|
||||
height: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.sidebar_item {
|
||||
background-color: navajowhite;
|
||||
margin-right: 6px;
|
||||
margin-left: 6px;
|
||||
margin-top: 6px;
|
||||
padding: 10px;
|
||||
font-size: 20px;
|
||||
|
||||
}
|
||||
|
||||
.sidebar_item:hover {
|
||||
background-color: white;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
@ -0,0 +1,25 @@
|
||||
|
||||
#search_results {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
div#search_results label {
|
||||
text-transform: capitalize;
|
||||
clear: both;
|
||||
width: 200px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.field_container {
|
||||
width: 400px;
|
||||
margin-top: 10px;
|
||||
display: flex;
|
||||
height: 30px;
|
||||
border: thin;
|
||||
border-bottom: 1px solid lightgray;
|
||||
}
|
||||
|
||||
.database_field {
|
||||
text-align: center;
|
||||
}
|
||||
|
38
employee_module/static/css/hr_module_create_schedule.css
Normal file
38
employee_module/static/css/hr_module_create_schedule.css
Normal file
@ -0,0 +1,38 @@
|
||||
|
||||
.scheduleSearchRow {
|
||||
height: 35px;
|
||||
|
||||
}
|
||||
|
||||
.search_element {
|
||||
float: left;
|
||||
width: 20%;
|
||||
}
|
||||
|
||||
#schedule_filter_category {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
.day_of_week_checkbox {
|
||||
float: left;
|
||||
height: 36px;
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
input, label{
|
||||
display: block;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
border-width: thin;
|
||||
}
|
||||
|
||||
.date_select_row {
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
94
employee_module/static/css/hr_module_import.css
vendored
Normal file
94
employee_module/static/css/hr_module_import.css
vendored
Normal file
@ -0,0 +1,94 @@
|
||||
|
||||
|
||||
label {
|
||||
width: 40%;
|
||||
display:inline-block;
|
||||
}
|
||||
|
||||
table {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
table, th, td {
|
||||
border: 1px solid lightgray;
|
||||
padding: 5px;
|
||||
width: auto;
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
border-width: thin;
|
||||
}
|
||||
|
||||
.import_container {
|
||||
float: left;
|
||||
width: 40%;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
|
||||
.form_element, .import_text {
|
||||
height: 30px;
|
||||
}
|
||||
|
||||
.separator {
|
||||
position: relative;
|
||||
float: left;
|
||||
width: 10%;
|
||||
height: 70%;
|
||||
}
|
||||
|
||||
.separatorline {
|
||||
position: absolute;
|
||||
left: 49%;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
width: 1px;
|
||||
background: black;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.wordwrapper {
|
||||
text-align: center;
|
||||
height: 12px;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
margin-top: -12px;
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.word {
|
||||
color: #cccccc;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: 1px;
|
||||
padding: 3px;
|
||||
font: bold 12px;
|
||||
background-color: whitesmoke;
|
||||
}
|
||||
|
||||
.import_execute {
|
||||
padding: 5px;
|
||||
width: 30%;
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
#import_filepicker {
|
||||
padding: 5px;
|
||||
width: 90%;
|
||||
text-align: center;
|
||||
margin: 10px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
44
employee_module/static/css/hr_module_show_schedule.css
Normal file
44
employee_module/static/css/hr_module_show_schedule.css
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
input[readonly] {
|
||||
color: black;
|
||||
background-color: lightgray;
|
||||
}
|
||||
|
||||
table#detailed_plan_records {
|
||||
width: 100%;
|
||||
font-size: 15px;
|
||||
vertical-align:middle;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
table#detailed_plan_records th {
|
||||
height: 25px;
|
||||
font-weight: lighter;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
table#detailed_plan_records td {
|
||||
text-align: center;
|
||||
padding: 0px;
|
||||
}
|
||||
|
||||
tr:nth-child(even) {
|
||||
background-color: #6DDCBD;
|
||||
}
|
||||
|
||||
div#detailed_plan_records input {
|
||||
width: 97%;
|
||||
display: block;
|
||||
border: solid thin black;
|
||||
}
|
||||
|
||||
.detailed_plan_records {
|
||||
text-align: center;
|
||||
border-collapse: collapse;
|
||||
border-width: thin;
|
||||
font-weight: lighter;
|
||||
}
|
||||
|
||||
.begin_time, .end_time {
|
||||
display: block;
|
||||
}
|
267
employee_module/static/js/calendar.js
Normal file
267
employee_module/static/js/calendar.js
Normal file
@ -0,0 +1,267 @@
|
||||
|
||||
const monthsStrings = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']
|
||||
var today = new Date()
|
||||
|
||||
function addCalendar(monthsAhead = 1, currentMonth = new Date().getMonth() + 1, currentYear= new Date().getFullYear(), weekStart=1){
|
||||
|
||||
var calendarContainer = document.createElement('div')
|
||||
calendarContainer.id = 'calendar_container'
|
||||
|
||||
|
||||
var monthsBlock = document.createElement('div')
|
||||
monthsBlock.id = 'months_block'
|
||||
|
||||
renderCalendarFor(calendarContainer, monthsBlock, currentYear, currentMonth, monthsAhead, weekStart)
|
||||
|
||||
calendarContainer.appendChild(createButtonBack(calendarContainer, monthsBlock, monthsAhead, weekStart))
|
||||
calendarContainer.appendChild(monthsBlock)
|
||||
calendarContainer.appendChild(createButtonForwards(calendarContainer, monthsBlock, monthsAhead, weekStart))
|
||||
calendarContainer.appendChild(createDateSelector(calendarContainer, monthsBlock, monthsAhead, weekStart))
|
||||
|
||||
return calendarContainer
|
||||
}
|
||||
|
||||
function createButtonBack(calendarContainer, monthsBlock, monthsAhead, weekStart){
|
||||
var buttonBack = createButton('calendar_button_back', 'calendar_button', '<')
|
||||
buttonBack.addEventListener('click', function(){
|
||||
var currentMonth = parseInt(calendarContainer.getAttribute('month_shown'))
|
||||
var currentYear = parseInt(calendarContainer.getAttribute('year_shown'))
|
||||
|
||||
if (currentMonth == 1){
|
||||
currentMonth = 12
|
||||
currentYear = currentYear - 1
|
||||
} else {
|
||||
currentMonth = currentMonth - 1
|
||||
}
|
||||
renderCalendarFor(calendarContainer, monthsBlock, currentYear, currentMonth, monthsAhead, weekStart)
|
||||
})
|
||||
return buttonBack
|
||||
}
|
||||
|
||||
function createButtonForwards(calendarContainer, monthsBlock, monthsAhead, weekStart){
|
||||
var buttonForwards = createButton('calendar_button_forwards', 'calendar_button', '>')
|
||||
buttonForwards.addEventListener('click', function(){
|
||||
var currentMonth = parseInt(calendarContainer.getAttribute('month_shown'))
|
||||
var currentYear = parseInt(calendarContainer.getAttribute('year_shown'))
|
||||
|
||||
if (currentMonth == 12){
|
||||
currentMonth = 1
|
||||
currentYear = currentYear + 1
|
||||
} else {
|
||||
currentMonth = currentMonth + 1
|
||||
}
|
||||
console.log(currentYear, currentMonth, monthsAhead)
|
||||
renderCalendarFor(calendarContainer,monthsBlock, currentYear, currentMonth, monthsAhead, weekStart)
|
||||
})
|
||||
return buttonForwards
|
||||
}
|
||||
|
||||
function createDateSelector(calendarContainer, monthsBlock, monthsAhead, weekStart){
|
||||
var dateSelector = createDateSelectionHTML()
|
||||
|
||||
var buttonGoToDate = dateSelector.querySelector('#button_load_selected_months')
|
||||
buttonGoToDate.addEventListener('click', function(){
|
||||
var currentYear = parseInt(dateSelector.querySelector('#year_selector').value)
|
||||
var currentMonth = parseInt(dateSelector.querySelector('#month_selector').value) + 1
|
||||
console.log(currentMonth, currentYear)
|
||||
renderCalendarFor(calendarContainer,monthsBlock, currentYear, currentMonth, monthsAhead, weekStart)
|
||||
})
|
||||
return dateSelector
|
||||
}
|
||||
|
||||
|
||||
function renderCalendarFor(calendarContainer, monthsBlock, year, month, nMonths, weekStart){
|
||||
|
||||
monthsBlock.innerHTML = ''
|
||||
calendarContainer.setAttribute('month_shown', month.toString())
|
||||
calendarContainer.setAttribute('year_shown', year.toString())
|
||||
var monthToCreate = month - 1
|
||||
for (var i = 0; i < nMonths; i++){
|
||||
monthToCreate = monthToCreate + 1
|
||||
if (monthToCreate == 13){
|
||||
monthToCreate = 1;
|
||||
year = year + 1;
|
||||
// console.log(monthToCreate, month, year, nMonths)
|
||||
}
|
||||
|
||||
var monthContainer = document.createElement('div')
|
||||
monthContainer.className = 'month_container'
|
||||
|
||||
monthContainer.appendChild(renderMonth(year, monthToCreate, weekStart))
|
||||
monthsBlock.appendChild(monthContainer)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function renderMonth(year, month, weekStart = 0, daysOfWeekNumeric){
|
||||
var daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat']
|
||||
var daysOfWeekNumeric = [0, 1, 2, 3, 4, 5, 6]
|
||||
for (var i = 0; i < weekStart; i++){
|
||||
daysOfWeek.push(daysOfWeek.shift())
|
||||
daysOfWeekNumeric.push(daysOfWeekNumeric.shift())
|
||||
}
|
||||
|
||||
var table = document.createElement('table')
|
||||
var monthString = monthsStrings[month - 1]
|
||||
createHeaders(table, year, monthString, daysOfWeek)
|
||||
createDates(table, year, month, daysOfWeekNumeric)
|
||||
|
||||
return table
|
||||
}
|
||||
|
||||
|
||||
function createHeaders(table, year, month, daysOfWeek){
|
||||
let monthHeaderRow = document.createElement('tr')
|
||||
let monthHeader = document.createElement('th')
|
||||
monthHeader.innerText = month + ' ' + year
|
||||
monthHeader.className = "month_header"
|
||||
monthHeader.colSpan = 7
|
||||
monthHeaderRow.appendChild(monthHeader)
|
||||
table.appendChild(monthHeaderRow)
|
||||
|
||||
let header = document.createElement('tr')
|
||||
for (var i = 0; i < daysOfWeek.length; i++){
|
||||
var headerDay = document.createElement('th')
|
||||
var headerText = document.createElement('div')
|
||||
headerText.innerText = daysOfWeek[i]
|
||||
headerText.className = 'weekday_header'
|
||||
headerDay.appendChild(headerText)
|
||||
header.appendChild(headerDay)
|
||||
table.appendChild(header)
|
||||
}
|
||||
}
|
||||
|
||||
function createDates(table, year, month, daysOfWeekNumeric){
|
||||
var weekEnd = daysOfWeekNumeric[daysOfWeekNumeric.length - 1]
|
||||
|
||||
var daysOfMonth = daysArray(year, month, daysOfWeekNumeric)
|
||||
var row = document.createElement('tr')
|
||||
for (var i = 0; i < daysOfMonth.length; i++){
|
||||
var date = daysOfMonth[i]
|
||||
var dayNr = date.getDate()
|
||||
var cell = document.createElement('td')
|
||||
var dateString = new Date(date.getTime() - (date.getTimezoneOffset() * 60000 ))
|
||||
.toISOString()
|
||||
.split("T")[0];
|
||||
|
||||
var dateContainer = document.createElement('div')
|
||||
dateContainer.innerText = dayNr
|
||||
dateContainer.className = 'days_of_month'
|
||||
|
||||
if (month - 1 == date.getMonth()){
|
||||
dateContainer.classList.add('days_of_month_current')
|
||||
dateContainer.id = 'date_' + dateString
|
||||
today.setHours(0, 0, 0, 0)
|
||||
if(today.getTime()==date.getTime()){
|
||||
dateContainer.classList.add('days_of_month_today')
|
||||
}
|
||||
} else {
|
||||
dateContainer.classList.add('days_of_month_not_current')
|
||||
}
|
||||
|
||||
|
||||
dateContainer.setAttribute('date', dateString)
|
||||
|
||||
cell.appendChild(dateContainer)
|
||||
|
||||
row.appendChild(cell)
|
||||
|
||||
|
||||
if (date.getDay() == weekEnd) {
|
||||
table.appendChild(row)
|
||||
var row = document.createElement('tr')
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
table.appendChild(row)
|
||||
}
|
||||
|
||||
function daysArray(year, month, daysOfWeekNumeric) {
|
||||
month = month - 1
|
||||
|
||||
var arr = []
|
||||
var daysInCurrentMonth = daysInMonth(year, month + 1)
|
||||
|
||||
var firstDayOfMonth = new Date(year, month, 1).getDay()
|
||||
var blankDaysStart = daysOfWeekNumeric.indexOf(firstDayOfMonth) * -1
|
||||
|
||||
for (var i = blankDaysStart + 1; i < 1; i++){
|
||||
var date = new Date(year, month, i)
|
||||
arr.push(date)
|
||||
}
|
||||
|
||||
for (var i = 1; i < daysInCurrentMonth + 1; i++){
|
||||
var date = new Date(year, month, i)
|
||||
arr.push(date)
|
||||
}
|
||||
|
||||
var daysToFill = arr.length
|
||||
for (var i = 1; i < 42 - daysToFill + 1; i++){
|
||||
var date = new Date(year, month + 1, i)
|
||||
arr.push(date)
|
||||
}
|
||||
|
||||
return arr
|
||||
}
|
||||
|
||||
function daysInMonth (year, month) {
|
||||
return new Date(year, month, 0).getDate();
|
||||
}
|
||||
|
||||
|
||||
function createDateSelectionHTML(){
|
||||
|
||||
var container = document.createElement('div')
|
||||
container.id = 'date_selector'
|
||||
|
||||
var goButton = document.createElement('button')
|
||||
goButton.innerText = 'Go'
|
||||
goButton.id = 'button_load_selected_months'
|
||||
|
||||
var label = document.createElement('label')
|
||||
label.setAttribute('for', 'years')
|
||||
label.innerText = 'Go to: '
|
||||
|
||||
var selectYear = document.createElement('select')
|
||||
selectYear.name='years'
|
||||
selectYear.id = 'year_selector'
|
||||
|
||||
spanBegin = 1990
|
||||
spanEnd = 2030
|
||||
yearsSpan = spanEnd - spanBegin
|
||||
for (var i = 0; i < yearsSpan; i++){
|
||||
var option = document.createElement('option')
|
||||
option.value = spanBegin + i
|
||||
option.innerText = option.value
|
||||
selectYear.appendChild(option)
|
||||
}
|
||||
selectYear.value = today.getFullYear()
|
||||
|
||||
var selectMonth = document.createElement('select')
|
||||
selectMonth.name='months'
|
||||
selectMonth.id = 'month_selector'
|
||||
for (var i = 0; i < 12; i++){
|
||||
var option = document.createElement('option')
|
||||
option.value = i;
|
||||
option.innerText = monthsStrings[i]
|
||||
selectMonth.appendChild(option)
|
||||
}
|
||||
|
||||
selectMonth.value = today.getMonth()
|
||||
|
||||
container.appendChild(label)
|
||||
container.appendChild(selectYear)
|
||||
container.appendChild(selectMonth)
|
||||
container.appendChild(goButton)
|
||||
return container
|
||||
}
|
||||
|
||||
|
||||
function createButton(id, className, innerText){
|
||||
var button = document.createElement('div')
|
||||
button.id = id
|
||||
button.className = className
|
||||
button.innerText = innerText
|
||||
return button
|
||||
}
|
17
employee_module/static/js/csrf_token.js
Normal file
17
employee_module/static/js/csrf_token.js
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
let cookies = document.cookie.split(';');
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
let cookie = cookies[i].trim();
|
||||
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
const csrftoken = getCookie('csrftoken');
|
||||
|
||||
var searchEmployeeButton = document.getElementById('load_employee_data_button')
|
||||
searchEmployeeButton.addEventListener('click', function(){
|
||||
fetchSearchEmployeeData()
|
||||
})
|
||||
|
||||
function fetchSearchEmployeeData() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/change_employee_data_api'
|
||||
var username = document.getElementById('username_input').value
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"username": username
|
||||
}),
|
||||
}).then((response) => {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
loadValuesIntoPage(data)
|
||||
});
|
||||
}
|
||||
|
||||
function loadValuesIntoPage(data){
|
||||
var order = ['username', 'first_name', 'last_name', 'email', 'department', 'manager_username', 'time_model_id', 'manager_flag', 'is_active', 'is_staff', 'is_superuser']
|
||||
|
||||
var informationContainer = document.getElementById('search_results')
|
||||
|
||||
for (var i = 0; i < order.length; i++){
|
||||
var field = order[i]
|
||||
var value = data[field]
|
||||
|
||||
var fieldContainer = document.createElement('div')
|
||||
fieldContainer.className = 'field_container'
|
||||
|
||||
if (typeof(value) === 'boolean'){
|
||||
var httpfield = document.createElement('input')
|
||||
httpfield.type = 'checkbox'
|
||||
httpfield.checked = value
|
||||
httpfield.setAttribute('disabled', 'disabled')
|
||||
} else {
|
||||
var httpfield = document.createElement('div')
|
||||
httpfield.innerHTML = value
|
||||
}
|
||||
var label = document.createElement('label')
|
||||
label.setAttribute('for', field)
|
||||
label.innerText = field.replace('_', ' ')
|
||||
httpfield.id = field
|
||||
httpfield.className = 'database_field'
|
||||
|
||||
fieldContainer.appendChild(label)
|
||||
fieldContainer.appendChild(httpfield)
|
||||
informationContainer.appendChild(fieldContainer)
|
||||
}
|
||||
}
|
173
employee_module/static/js/employee_module_show_schedule.js
Normal file
173
employee_module/static/js/employee_module_show_schedule.js
Normal file
@ -0,0 +1,173 @@
|
||||
|
||||
const csrftoken = getCookie('csrftoken');
|
||||
|
||||
|
||||
// document.onload = parent.appendChild(addCalendar(monthsAhead=3))
|
||||
|
||||
window.addEventListener('load', function(){
|
||||
var parent = document.getElementById('calendar_box')
|
||||
parent.appendChild(addCalendar(monthsAhead=3))
|
||||
fetchDays()
|
||||
formatCalendarContainerSize(document.getElementById('calendar_container'))
|
||||
document.getElementById('calendar_button_back').addEventListener('click', function(){
|
||||
fetchDays()
|
||||
})
|
||||
document.getElementById('calendar_button_forwards').addEventListener('click', function(){
|
||||
fetchDays()
|
||||
})
|
||||
document.getElementById('button_load_selected_months').addEventListener('click', function(){
|
||||
fetchDays()
|
||||
})
|
||||
|
||||
})
|
||||
|
||||
|
||||
|
||||
function fetchDays(){
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/employee_module/show_employee_plan_api'
|
||||
|
||||
var range = searchedDateRange()
|
||||
var startDate = range['min']
|
||||
var endDate = range['max']
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"start_date": startDate,
|
||||
"end_date" : endDate
|
||||
}),
|
||||
}).then((response) => {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
addClassToWorkingDays(data);
|
||||
|
||||
var parent = document.getElementById('hr_module_main_container')
|
||||
|
||||
var listContainer = document.getElementById('list_container')
|
||||
if (listContainer == null){
|
||||
var listContainer = document.createElement('div')
|
||||
listContainer.id = 'list_container'
|
||||
} else {
|
||||
listContainer.innerHTML = ''
|
||||
}
|
||||
listContainer.appendChild(createDetailedCalendarRecords(data))
|
||||
parent.appendChild(listContainer)
|
||||
formatTableSize()
|
||||
});
|
||||
}
|
||||
|
||||
function addClassToWorkingDays(data){
|
||||
for (var i = 0; i < data.length; i++){
|
||||
var processedDate = data[i]['date']
|
||||
var processedActivityType = data[i]['activity_type']
|
||||
var nodeToChange = document.getElementById('date_' + processedDate)
|
||||
nodeToChange.classList.add('days_of_month_' + processedActivityType)
|
||||
}
|
||||
}
|
||||
|
||||
function createDetailedCalendarRecords(data){
|
||||
var table = createDetailedHeaders()
|
||||
|
||||
for (var i = 0; i < data.length; i++){
|
||||
var index = data[i]['id']
|
||||
var username = data[i]['username_id']
|
||||
|
||||
var row = table.insertRow(-1)
|
||||
row.id = 'database_id_' + index.toString()
|
||||
row.setAttribute('database_username', username)
|
||||
|
||||
appendCell(row, 'div', 'date', data[i]['date'], 0)
|
||||
appendCell(row, 'div', 'begin_time', data[i]['begin_time'], 1)
|
||||
appendCell(row, 'div', 'end_time', data[i]['end_time'], 2)
|
||||
appendCell(row, 'div', 'activity_type', data[i]['activity_type'], 3)
|
||||
}
|
||||
return table
|
||||
}
|
||||
|
||||
function appendCell(tableRow, tag, tagName, tagText, cellIndex){
|
||||
var cell = tableRow.insertCell(cellIndex)
|
||||
var textInput = document.createElement(tag)
|
||||
textInput.innerText = tagText
|
||||
textInput.name = tagName
|
||||
cell.appendChild(textInput)
|
||||
}
|
||||
|
||||
function createDetailedHeaders(){
|
||||
var table = document.createElement('table')
|
||||
let headerRow = document.createElement('tr')
|
||||
let columns = ['Date', 'Start time', 'End time', 'Activity type']
|
||||
for (let i = 0; i < columns.length; i++){
|
||||
var headerCell = document.createElement('th')
|
||||
var headerText = document.createElement('div')
|
||||
headerText.innerText = columns[i]
|
||||
headerCell.appendChild(headerText)
|
||||
headerRow.appendChild(headerCell)
|
||||
|
||||
}
|
||||
table.appendChild(headerRow)
|
||||
table.id = 'detailed_plan_records'
|
||||
return table
|
||||
}
|
||||
|
||||
function formatCalendarContainerSize(calendarContainer){
|
||||
|
||||
var monthsBlock = calendarContainer.querySelector('#months_block')
|
||||
var calendarButton = calendarContainer.querySelector('#calendar_button_back')
|
||||
var dateSelector = calendarContainer.querySelector('#date_selector')
|
||||
|
||||
var widthMonths = monthsBlock.offsetWidth
|
||||
var heightMonths = monthsBlock.offsetHeight
|
||||
var heightDateSelector = dateSelector.offsetHeight
|
||||
var widthCalendarButton = calendarButton.offsetWidth * 2
|
||||
|
||||
var widthTotal = widthMonths + widthCalendarButton
|
||||
var heightTotal = heightMonths + heightDateSelector
|
||||
|
||||
calendarContainer.setAttribute('style','height:' + heightTotal +'px; width:' + widthTotal + 'px');
|
||||
}
|
||||
|
||||
function formatTableSize(){
|
||||
var calendar = document.getElementById('calendar_container')
|
||||
var tableDiv = document.getElementById('list_container')
|
||||
var width = calendar.offsetWidth
|
||||
tableDiv.setAttribute('style', 'width:' + width + 'px')
|
||||
}
|
||||
|
||||
function searchedDateRange(){
|
||||
var dates = document.getElementsByClassName('days_of_month_current')
|
||||
|
||||
var datesArray = []
|
||||
for (var i = 0; i < dates.length; i++){
|
||||
var dateAttr = new Date(dates[i].getAttribute('date'))
|
||||
datesArray.push(dateAttr)
|
||||
}
|
||||
var minDate = new Date(Math.min.apply(null, datesArray))
|
||||
var maxDate = new Date(Math.max.apply(null, datesArray))
|
||||
var out = {'min' : minDate,
|
||||
'max': maxDate}
|
||||
console.log(out)
|
||||
return out
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
let cookieValue = null;
|
||||
if (document.cookie && document.cookie !== '') {
|
||||
let cookies = document.cookie.split(';');
|
||||
for (let i = 0; i < cookies.length; i++) {
|
||||
let cookie = cookies[i].trim();
|
||||
|
||||
if (cookie.substring(0, name.length + 1) === (name + '=')) {
|
||||
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cookieValue;
|
||||
}
|
39
employee_module/templates/employee_module_base.html
Normal file
39
employee_module/templates/employee_module_base.html
Normal file
@ -0,0 +1,39 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block stylesheet_hr_module_base %}
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_base.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block core_content %}
|
||||
<script src="{% static '/js/csrf_token.js' %}"></script>
|
||||
|
||||
<div class="sidebar">
|
||||
|
||||
<a href="{% url 'employee_module:show_schedule' %}">
|
||||
<div class="sidebar_item">Show schedule
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'hr_module:change_employee_data' %}">
|
||||
<div class="sidebar_item">Show time tracking history
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="{% url 'hr_module:create_employees' %}">
|
||||
<div class="sidebar_item">Show your data
|
||||
</div>
|
||||
</a>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="hr_module_main_container">
|
||||
{% block action_panel %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
{% endblock %}
|
@ -0,0 +1,20 @@
|
||||
{% extends 'employee_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_change_employee_data.css' %}">
|
||||
|
||||
<div>
|
||||
<label for="username_input">Person username: </label>
|
||||
<input id="username_input" type="text" value="kowalskija">
|
||||
<button type="button" id="load_employee_data_button">Search</button>
|
||||
</div>
|
||||
<div id="search_results">
|
||||
|
||||
</div>
|
||||
|
||||
<script src="{% static '/js/hr_module_change_employee_data.js' %}"></script>
|
||||
|
||||
{% endblock %}
|
9
employee_module/templates/employee_module_home.html
Normal file
9
employee_module/templates/employee_module_home.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends 'employee_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
|
||||
<h2>Welcome to Timefall - time tracking application, employee section </h2>
|
||||
|
||||
{% endblock %}
|
16
employee_module/templates/employee_module_login.html
Normal file
16
employee_module/templates/employee_module_login.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block core_content %}
|
||||
|
||||
|
||||
<h4>Please login</h4>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -0,0 +1,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block core_content %}
|
||||
|
||||
|
||||
<h4>Please change your password</h4>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
19
employee_module/templates/employee_module_show_schedule.html
Normal file
19
employee_module/templates/employee_module_show_schedule.html
Normal file
@ -0,0 +1,19 @@
|
||||
{% extends 'employee_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
<link rel="stylesheet" href="{% static '/css/calendar.css' %}">
|
||||
<link rel="stylesheet" href="{% static '/css/calendar_local.css' %}">
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_show_schedule.css' %}">
|
||||
|
||||
<div>
|
||||
<div id="username" username="{{ user }}"></div>
|
||||
</div>
|
||||
<div id="calendar_box"></div>
|
||||
|
||||
<script src="{% static '/js/calendar.js' %}"></script>
|
||||
<script src="{% static '/js/employee_module_show_schedule.js' %}"></script>
|
||||
|
||||
|
||||
{% endblock %}
|
17
employee_module/urls.py
Normal file
17
employee_module/urls.py
Normal file
@ -0,0 +1,17 @@
|
||||
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from django.contrib.auth import views as auth_views
|
||||
|
||||
app_name = 'employee_module'
|
||||
|
||||
urlpatterns = [
|
||||
path('login', auth_views.LoginView.as_view(template_name='hr_module_login.html'), name='login'),
|
||||
path('logout', auth_views.LogoutView.as_view(), name='logout'),
|
||||
path('change_password', auth_views.PasswordChangeView.as_view(template_name='hr_module_password_change.html'), name='change_password'),
|
||||
path('home', views.homepage, name='homepage'),
|
||||
path('show_schedule', views.manage_schedule, name='show_schedule'),
|
||||
path('show_employee_plan_api', views.show_employee_plan_api, name='show_employee_plan_api'),
|
||||
path('change_employee_data', views.change_employee_data, name='change_employee_data'),
|
||||
path('change_employee_data_api', views.change_employee_data_api, name='change_employee_data_api'),
|
||||
]
|
@ -1,5 +1,66 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from hr_module.handling_functions.data_import_functions import read_and_parse_excel, insert_excel
|
||||
from hr_module.handling_functions.monthly_planning_functions import insert_into_plan, create_planning_operation_report
|
||||
from hr_module.handling_functions.misc import dictfetchall
|
||||
import pandas as pd
|
||||
import json
|
||||
from hr_module.models import Employee, PlanCreationLog, Plan
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse, JsonResponse, Http404
|
||||
from django.db import connection
|
||||
import datetime
|
||||
|
||||
|
||||
login_url = '/hr_module/login'
|
||||
# Create your views here.
|
||||
@login_required(login_url=login_url)
|
||||
def homepage(request):
|
||||
template_name = 'employee_module_home.html'
|
||||
return render(request, template_name)
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def change_employee_data(request):
|
||||
template_name = 'employee_module_change_employee_data.html'
|
||||
return render(request, template_name)
|
||||
|
||||
def change_employee_data_api(request):
|
||||
if request.method == 'POST':
|
||||
if request.user.is_authenticated:
|
||||
username = request.user.username
|
||||
empl = User.objects.select_related('employee').get(username=username)
|
||||
record_employee = empl.employee.__dict__
|
||||
record_user = empl.__dict__
|
||||
response_dict = dict(record_user, **record_employee)
|
||||
for i in ['_state', 'password']:
|
||||
response_dict.pop(i)
|
||||
print(response_dict)
|
||||
return JsonResponse(response_dict, safe=False)
|
||||
else:
|
||||
return JsonResponse({'error': 'not_authenticated'})
|
||||
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def manage_schedule(request):
|
||||
template = 'employee_module_show_schedule.html'
|
||||
return render(request, template)
|
||||
|
||||
|
||||
def show_employee_plan_api(request):
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
username = request.user.username
|
||||
start_date = body['start_date'].split('T')[0]
|
||||
end_date = body['end_date'].split('T')[0]
|
||||
|
||||
start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d')
|
||||
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d')
|
||||
|
||||
print(username, start_date, end_date)
|
||||
|
||||
user_obj = Employee.objects.get(pk=username)
|
||||
|
||||
query_result = Plan.objects.filter(username=user_obj, date__range= [start_date, end_date])
|
||||
response = list(query_result.values())
|
||||
return JsonResponse(response, safe=False)
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -3,6 +3,7 @@ import pandas as pd
|
||||
from django.conf import settings
|
||||
import datetime
|
||||
from sqlalchemy import create_engine
|
||||
from django.contrib.auth.hashers import make_password
|
||||
|
||||
def create_connection(db_file, type=1):
|
||||
""" create a database connection to the SQLite database
|
||||
@ -34,7 +35,7 @@ def read_and_parse_excel(file):
|
||||
def insert_excel(df):
|
||||
conn = create_connection(settings.DATABASES['default']['NAME'])
|
||||
df['date_joined'] = datetime.date.today()
|
||||
df['password'] = 'start'
|
||||
df['password'] = make_password('start')
|
||||
|
||||
df_to_user_model = df[['username',
|
||||
'first_name',
|
||||
|
@ -214,7 +214,7 @@ function buildPlanJson(){
|
||||
|
||||
function postPlanToDb(){
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/plan_api'
|
||||
var fetch_url = host + '/hr_module/new_plan_api'
|
||||
var json = buildPlanJson()
|
||||
|
||||
fetch(fetch_url,
|
||||
|
9
hr_module/templates/hr_module_home.html
Normal file
9
hr_module/templates/hr_module_home.html
Normal file
@ -0,0 +1,9 @@
|
||||
{% extends 'hr_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
|
||||
<h2>Welcome to Timefall - time tracking application</h2>
|
||||
|
||||
{% endblock %}
|
16
hr_module/templates/hr_module_login.html
Normal file
16
hr_module/templates/hr_module_login.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block core_content %}
|
||||
|
||||
|
||||
<h4>Please login</h4>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
16
hr_module/templates/hr_module_password_change.html
Normal file
16
hr_module/templates/hr_module_password_change.html
Normal file
@ -0,0 +1,16 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block core_content %}
|
||||
|
||||
|
||||
<h4>Please change your password</h4>
|
||||
|
||||
<form method="post">
|
||||
{% csrf_token %}
|
||||
{{ form.as_p }}
|
||||
|
||||
<input type="submit" value="Submit">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
@ -1,10 +1,15 @@
|
||||
|
||||
from django.urls import path
|
||||
from . import views
|
||||
from django.contrib.auth import views as auth_views
|
||||
|
||||
app_name = 'hr_module'
|
||||
|
||||
urlpatterns = [
|
||||
path('login', auth_views.LoginView.as_view(template_name='hr_module_login.html'), name='login'),
|
||||
path('logout', auth_views.LogoutView.as_view(), name='logout'),
|
||||
path('change_password', auth_views.PasswordChangeView.as_view(template_name='hr_module_password_change.html'), name='change_password'),
|
||||
path('home', views.homepage, name='homepage'),
|
||||
path('create_schedule', views.create_schedule, name='create_schedule'),
|
||||
path('create_employees', views.create_employees, name='create_employees'),
|
||||
path('search_api', views.search_users_api, name='search_users_api'),
|
||||
|
@ -1,4 +1,5 @@
|
||||
from django.shortcuts import render, redirect
|
||||
from django.contrib.auth.decorators import login_required
|
||||
from .forms import UploadFileForm, NewUserForm
|
||||
from hr_module.handling_functions.data_import_functions import read_and_parse_excel, insert_excel
|
||||
from hr_module.handling_functions.monthly_planning_functions import insert_into_plan, create_planning_operation_report
|
||||
@ -12,11 +13,19 @@ from django.db import connection
|
||||
import datetime
|
||||
|
||||
|
||||
login_url = '/hr_module/login'
|
||||
# Create your views here.
|
||||
@login_required(login_url=login_url)
|
||||
def create_schedule(request):
|
||||
template_name = 'hr_module_create_schedule.html'
|
||||
return render(request, template_name)
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def homepage(request):
|
||||
template_name = 'hr_module_home.html'
|
||||
return render(request, template_name)
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def change_employee_data(request):
|
||||
template_name = 'hr_module_change_employee_data.html'
|
||||
return render(request, template_name)
|
||||
@ -62,7 +71,7 @@ def change_employee_data_api(request):
|
||||
else:
|
||||
return JsonResponse({'error': 'not_authenticated'})
|
||||
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def create_employees(request):
|
||||
if request.method == 'POST':
|
||||
if 'import_preview' in request.POST:
|
||||
@ -75,7 +84,7 @@ def create_employees(request):
|
||||
request.session['df_path'] = df_dict['df_path']
|
||||
df_html = df_dict['df_html']
|
||||
context = {'df_html': df_html}
|
||||
template = 'hr_import_validation.html'
|
||||
template = 'hr_module_import_validation.html'
|
||||
return render(request, template, context)
|
||||
|
||||
if 'import_insert' in request.POST:
|
||||
@ -202,11 +211,11 @@ def new_plan_api(request):
|
||||
report_location = create_planning_operation_report(log, user)
|
||||
print(user)
|
||||
user_obj = Employee.objects.get(pk=user)
|
||||
plan_creation_log = PlanCreationLog(username=user_obj, report_location=report_location)
|
||||
plan_creation_log.save()
|
||||
# plan_creation_log = PlanCreationLog(username=user_obj, report_location=report_location)
|
||||
# plan_creation_log.save()
|
||||
return JsonResponse(log)
|
||||
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def manage_schedule(request):
|
||||
template = 'hr_module_show_schedule.html'
|
||||
return render(request, template)
|
||||
|
BIN
import_reports/admin_2021-01-04T23:08:43.146410.xlsx
Normal file
BIN
import_reports/admin_2021-01-04T23:08:43.146410.xlsx
Normal file
Binary file not shown.
@ -1,3 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
@ -1,5 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ManagerModuleConfig(AppConfig):
|
||||
name = 'manager_module'
|
@ -1,3 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
@ -1,3 +0,0 @@
|
||||
from django.test import TestCase
|
||||
|
||||
# Create your tests here.
|
@ -1,3 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
@ -13,4 +13,15 @@ html, body {
|
||||
background-color: whitesmoke;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar_item {
|
||||
float: right;
|
||||
height: 35px;
|
||||
width: auto;
|
||||
display: block;
|
||||
vertical-align:middle;
|
||||
text-align:center;
|
||||
margin-top: 15px;
|
||||
margin-right: 15px;
|
||||
}
|
||||
|
@ -12,6 +12,17 @@
|
||||
<body>
|
||||
|
||||
<div class="navbar">
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
<div class="navbar_item">
|
||||
<a href="{% url 'hr_module:logout' %}">Log out</a>
|
||||
</div>
|
||||
<div class="navbar_item">You are logged in as: {{ user }} </div>
|
||||
|
||||
{% else %}
|
||||
|
||||
{% endif %}
|
||||
|
||||
</div>
|
||||
<div class="main_container">
|
||||
|
||||
|
Binary file not shown.
Binary file not shown.
@ -27,6 +27,7 @@ SECRET_KEY = 'tx#+u3u-r1$n_4r(!6vvcb@1f5!z21^74w(zesiz$&59&72$kq'
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = ['192.168.101.128',
|
||||
'192.168.101.129',
|
||||
'127.0.0.1',]
|
||||
|
||||
|
||||
@ -34,6 +35,7 @@ ALLOWED_HOSTS = ['192.168.101.128',
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'hr_module.apps.HrModuleConfig',
|
||||
'employee_module.apps.EmployeeModuleConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -132,4 +134,7 @@ STATICFILES_DIRS = [
|
||||
|
||||
|
||||
TMP_FILE_STORAGE = os.path.join(BASE_DIR, 'temp/')
|
||||
IMPORT_REPORT_STORAGE = os.path.join(BASE_DIR, 'import_reports/')
|
||||
IMPORT_REPORT_STORAGE = os.path.join(BASE_DIR, 'import_reports/')
|
||||
|
||||
LOGOUT_REDIRECT_URL = '/hr_module/login'
|
||||
LOGIN_REDIRECT_URL = '/hr_module/home'
|
@ -19,4 +19,5 @@ from django.urls import path, include
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('hr_module/', include('hr_module.urls')),
|
||||
path('employee_module/', include('employee_module.urls')),
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user