removed sqlite from git
This commit is contained in:
parent
3f26366eda
commit
2d6ccc1462
3
.gitignore
vendored
3
.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
venv/
|
||||
venv
|
||||
media
|
||||
media/
|
||||
media/
|
||||
db.sqlite3
|
19
README.md
19
README.md
@ -0,0 +1,19 @@
|
||||
|
||||
# Timefall - time tracking app
|
||||
This application is designed for schedule creating and time tracking activities within the enterprise.
|
||||
Application consists of two parts:
|
||||
1. HR Module - module for HR administration employees and managers.
|
||||
The module has the following functionality:
|
||||
1. Creating of schedule
|
||||
2. Showing and editing existing schedule records
|
||||
3. Showing and editing employees logged time
|
||||
4. Changing employee data
|
||||
5. Creating new employees via frontend or importing from excel
|
||||
6. Exporting reports in excel format via frontend
|
||||
|
||||
2. Employee module - module for employees.
|
||||
The module has the following functionality:
|
||||
1. Logging in start and end of work
|
||||
2. Showing existing schedule records
|
||||
3. Showing existing logged time
|
||||
4. Showing employee data
|
Binary file not shown.
@ -1,13 +1,13 @@
|
||||
|
||||
const urls = {
|
||||
'show_schedule': {
|
||||
'show': '/employee_module/show_employee_plan_api',
|
||||
'show-schedule': {
|
||||
'show': '/employee-module/show-employee-plan-api',
|
||||
'update': '/employee_module/update_plan_api'
|
||||
}
|
||||
,
|
||||
'show_timelog': {
|
||||
'show': '/employee_module/show_employee_timelog_api',
|
||||
'update': '/employee_module/update_timelog_api',
|
||||
'show-timelog': {
|
||||
'show': '/employee-module/show-employee-timelog-api',
|
||||
'update': '/employee-module/update-timelog-api',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ searchEmployeeButton.addEventListener('click', function(){
|
||||
|
||||
function fetchSearchEmployeeData() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/change_employee_data_api'
|
||||
var fetch_url = host + '/hr-module/change-employee-data-api'
|
||||
var username = document.getElementById('username_input').value
|
||||
|
||||
fetch(fetch_url,
|
||||
|
@ -6,7 +6,7 @@ window.addEventListener('load', function(){
|
||||
|
||||
function fetchSearchEmployeeData() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/employee_module/show_employee_data_api'
|
||||
var fetch_url = host + '/employee-module/show-employee-data-api'
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
|
@ -7,12 +7,12 @@ app_name = 'employee_module'
|
||||
|
||||
urlpatterns = [
|
||||
path('home', views.homepage, name='homepage'),
|
||||
path('time_tracking', views.time_tracking, name='time_tracking'),
|
||||
path('show_schedule', views.show_schedule, name='show_schedule'),
|
||||
path('show_timelog', views.show_timelog, name='show_timelog'),
|
||||
path('show_employee_plan_api', views.show_employee_plan_api, name='show_employee_plan_api'),
|
||||
path('show_employee_timelog_api', views.show_employee_timelog_api, name='show_employee_timelog_api'),
|
||||
path('show_employee_data', views.show_employee_data, name='show_employee_data'),
|
||||
path('show_employee_data_api', views.show_employee_data_api, name='show_employee_data_api'),
|
||||
path('time-tracking', views.time_tracking, name='time_tracking'),
|
||||
path('show-schedule', views.show_schedule, name='show_schedule'),
|
||||
path('show-timelog', views.show_timelog, name='show_timelog'),
|
||||
path('show-employee-plan-api', views.show_employee_plan_api, name='show_employee_plan_api'),
|
||||
path('show-employee-timelog-api', views.show_employee_timelog_api, name='show_employee_timelog_api'),
|
||||
path('show-employee-data', views.show_employee_data, name='show_employee_data'),
|
||||
path('show-employee-data-api', views.show_employee_data_api, name='show_employee_data_api'),
|
||||
|
||||
]
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -10,10 +10,10 @@ class NewUserForm(forms.Form):
|
||||
last_name = forms.CharField(max_length=200)
|
||||
username = forms.CharField(max_length=200)
|
||||
email = forms.EmailField(max_length=200)
|
||||
is_staff = forms.BooleanField()
|
||||
is_active = forms.BooleanField()
|
||||
is_superuser = forms.BooleanField()
|
||||
is_staff = forms.BooleanField(required=False)
|
||||
is_active = forms.BooleanField(required=False)
|
||||
is_superuser = forms.BooleanField(required=False)
|
||||
department = forms.CharField(max_length=200)
|
||||
manager_username = forms.CharField(max_length=200)
|
||||
time_model_id = forms.IntegerField()
|
||||
manager_flag = forms.BooleanField()
|
||||
manager_flag = forms.BooleanField(required=False)
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
hr_module/handling_functions/__pycache__/util.cpython-38.pyc
Normal file
BIN
hr_module/handling_functions/__pycache__/util.cpython-38.pyc
Normal file
Binary file not shown.
@ -6,12 +6,11 @@ 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
|
||||
''''' 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:
|
||||
@ -25,18 +24,28 @@ def create_connection(db_file, type=1):
|
||||
|
||||
|
||||
def read_and_parse_excel(file):
|
||||
'''function to read exce, save it as a csv file and return html representation of table
|
||||
:param file - path to the excel file which is to be read
|
||||
:return returns dictionary with the dataframe in html format and path to the saved file
|
||||
'''
|
||||
df = pd.read_excel(file)
|
||||
path_temp = settings.TMP_FILE_STORAGE + file.name.split('.')[0] + '.csv'
|
||||
print(path_temp)
|
||||
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):
|
||||
'''void function, inserting pandas dataframe into the database
|
||||
:param df - dataframe which is to be inserted into the database
|
||||
'''
|
||||
conn = create_connection(settings.DATABASES['default']['NAME'])
|
||||
df['date_joined'] = datetime.date.today()
|
||||
#hashing of default 'start' password
|
||||
df['password'] = make_password('start')
|
||||
|
||||
#taking the columns we have to insert into auth_user table
|
||||
df_to_user_model = df[['username',
|
||||
'first_name',
|
||||
'last_name',
|
||||
@ -47,16 +56,19 @@ def insert_excel(df):
|
||||
'is_superuser',
|
||||
'password']]
|
||||
|
||||
#insert
|
||||
df_to_user_model.to_sql(name='auth_user',
|
||||
con=conn,
|
||||
if_exists='append', index=False)
|
||||
|
||||
# taking the columns we have to insert into hr_module_employee table
|
||||
df_to_employee = df[['username',
|
||||
'department',
|
||||
'manager_username',
|
||||
'time_model_id',
|
||||
'manager_flag']]
|
||||
|
||||
#insert
|
||||
df_to_employee.to_sql(name='hr_module_employee',
|
||||
con=conn,
|
||||
if_exists='append', index=False)
|
||||
if_exists='append', index=False)
|
||||
|
||||
|
@ -7,83 +7,32 @@ import datetime
|
||||
|
||||
|
||||
def time_timedelta(time, timedelta):
|
||||
'''addition of timedelta hours to datetime.time object
|
||||
:param: time - datetime.time instance
|
||||
:param timedelta - integer, hours to add
|
||||
:return datetime.time object
|
||||
'''
|
||||
start = datetime.datetime(2020, 1, 1, time.hour, time.minute)
|
||||
end = start + timedelta
|
||||
return end.time()
|
||||
|
||||
def timediff_hours(time_start, time_end):
|
||||
'''calculating time difference between end and start time in minutes
|
||||
:param time_start - time start
|
||||
:param time_end - time end
|
||||
:return timedelta in hours
|
||||
'''
|
||||
start = datetime.datetime(2020, 1, 1, time_start.hour, time_start.minute, time_start.second)
|
||||
end = datetime.datetime(2020, 1, 1, time_end.hour, time_end.minute, time_end.second)
|
||||
timedelta = (end - start).seconds/3600
|
||||
return timedelta
|
||||
|
||||
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):
|
||||
'''function creating and saving xlsx report from dictionary
|
||||
:param dict_: dictionary, from which pandas dataframe will be generated
|
||||
:param current_user
|
||||
:return saved file name
|
||||
'''
|
||||
df = pd.DataFrame(dict_)
|
||||
filename = current_user + '_' + datetime.datetime.now().isoformat() + '.xlsx'
|
||||
path_temp = settings.IMPORT_REPORT_STORAGE + filename
|
||||
|
@ -1,8 +1,25 @@
|
||||
|
||||
import datetime
|
||||
|
||||
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()
|
||||
]
|
||||
]
|
||||
|
||||
|
||||
def months_list(start_date, end_date):
|
||||
'''function, returning list of months between dates, including months of both dates'''
|
||||
start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d').date()
|
||||
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d').date()
|
||||
tmp = end_date
|
||||
list_ = []
|
||||
while tmp >= start_date:
|
||||
list_.append(tmp.strftime('%Y-%m'))
|
||||
tmp = tmp.replace(day=1) - datetime.timedelta(days=1)
|
||||
start_date_str = start_date.strftime('%Y-%m')
|
||||
if not start_date_str in list_:
|
||||
list_.append(start_date_str)
|
||||
return tuple(list_)
|
@ -1,13 +1,13 @@
|
||||
|
||||
const urls = {
|
||||
'show_schedule': {
|
||||
'show': '/hr_module/show_employee_plan_api',
|
||||
'update': '/hr_module/update_plan_api'
|
||||
'show-schedule': {
|
||||
'show': '/hr-module/show-employee-plan-api',
|
||||
'update': '/hr-module/update-plan-api'
|
||||
}
|
||||
,
|
||||
'show_timelog': {
|
||||
'show': '/hr_module/show_employee_timelog_api',
|
||||
'update': '/hr_module/update_timelog_api',
|
||||
'show-timelog': {
|
||||
'show': '/hr-module/show-employee-timelog-api',
|
||||
'update': '/hr-module/update-timelog-api',
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ import { fetchDays } from './calendar_ajax_hr_module_requests.js'
|
||||
|
||||
window.addEventListener('load', renderWhole)
|
||||
|
||||
//render calendar and add event listeners
|
||||
function renderWhole(){
|
||||
var parent = document.getElementById('calendar_box')
|
||||
parent.innerHTML = ''
|
||||
|
@ -4,7 +4,9 @@ import {detailedRecordsMainBlock, formatTableSize} from "./calendar_to_table.js"
|
||||
import { urls } from './calendar_ajax_hr_module_config.js'
|
||||
|
||||
function fetchDays(){
|
||||
//function, fetching records from either schedule or timelog tables, depending on a current host
|
||||
var host = 'http://' + window.location.host;
|
||||
//url is imported from config file and compared against current location
|
||||
var fetch_url = host + urls[window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1)]['show']
|
||||
var range = searchedDateRange()
|
||||
var startDate = range['min']
|
||||
@ -43,6 +45,7 @@ function fetchDays(){
|
||||
|
||||
|
||||
function updateCheckedRecords(recordsArray, action){
|
||||
//submitting data with checked records to the database
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + urls[window.location.pathname.substring(window.location.pathname.lastIndexOf('/') + 1)]['update']
|
||||
|
||||
|
@ -49,6 +49,7 @@ function formatCalendarSize(){
|
||||
}
|
||||
|
||||
function cleanCalendarClasses(){
|
||||
//reset calendar classes to the initial state
|
||||
var classesToKeep = ['days_of_month', 'days_of_month_current', 'days_of_month_today']
|
||||
var days = document.getElementsByClassName('days_of_month_current')
|
||||
for (var i = 0; i < days.length; i++){
|
||||
@ -63,6 +64,7 @@ function cleanCalendarClasses(){
|
||||
}
|
||||
|
||||
function addClassToWorkingDays(data){
|
||||
//adding class to the calendar cell, indicating that employee has a record in schedule
|
||||
cleanCalendarClasses()
|
||||
for (var i = 0; i < data.length; i++){
|
||||
var processedDate = data[i]['date']
|
||||
@ -73,6 +75,7 @@ function addClassToWorkingDays(data){
|
||||
}
|
||||
|
||||
function searchedDateRange(){
|
||||
//function, returning earliest and latest visible day of the active months from the calendar
|
||||
var dates = document.getElementsByClassName('days_of_month_current')
|
||||
var datesArray = []
|
||||
for (var i = 0; i < dates.length; i++){
|
||||
@ -83,7 +86,6 @@ function searchedDateRange(){
|
||||
var maxDate = new Date(Math.max.apply(null, datesArray))
|
||||
var out = {'min' : minDate,
|
||||
'max': maxDate}
|
||||
console.log(out)
|
||||
return out
|
||||
}
|
||||
|
||||
|
@ -1,24 +1,25 @@
|
||||
|
||||
import { updateCheckedRecords } from './calendar_ajax_hr_module_requests.js'
|
||||
|
||||
function detailedRecordsMainBlock(data){
|
||||
var container = document.createElement('div')
|
||||
//this file contains functions, used to crate table, containing employee schedule
|
||||
|
||||
function detailedRecordsMainBlock(data){
|
||||
//add control buttons and table body
|
||||
var container = document.createElement('div')
|
||||
var buttonsContainer = document.createElement('div')
|
||||
buttonsContainer.id = 'buttons_container'
|
||||
|
||||
buttonsContainer.appendChild(addButton('Edit', 'edit', eventListenerEdit))
|
||||
buttonsContainer.appendChild(addButton('Save', 'save', eventListenerUpdate))
|
||||
buttonsContainer.appendChild(addButton('Delete', 'delete', eventListenerUpdate))
|
||||
buttonsContainer.appendChild(addButton('Cancel', 'cancel'))
|
||||
buttonsContainer.appendChild(addButton('Select all/none', 'checkbox_select', eventListenerSelectAll))
|
||||
|
||||
container.appendChild(buttonsContainer)
|
||||
container.appendChild(detailedCalendarRecordsTable(data))
|
||||
return container
|
||||
}
|
||||
|
||||
function addButton(innText, name, eventListener=null){
|
||||
//add single button
|
||||
var button = document.createElement('button')
|
||||
button.innerHTML = innText
|
||||
button.name = name
|
||||
@ -32,6 +33,7 @@ function addButton(innText, name, eventListener=null){
|
||||
|
||||
|
||||
function detailedCalendarRecordsTable(data){
|
||||
//create table from separate elements
|
||||
var table = createDetailedHeaders()
|
||||
for (var i = 0; i < data.length; i++){
|
||||
var index = data[i]['id']
|
||||
@ -60,6 +62,7 @@ function detailedCalendarRecordsTable(data){
|
||||
}
|
||||
|
||||
function eventListenerSelectAll(){
|
||||
//function that checks or unchecks all checkboxes
|
||||
var elements = document.getElementsByTagName('input')
|
||||
for (var i = 0; i < elements.length; i++){
|
||||
if (elements[i].type == 'checkbox' && elements[i].checked == true){
|
||||
@ -71,17 +74,20 @@ function eventListenerSelectAll(){
|
||||
}
|
||||
|
||||
function eventListenerEdit(){
|
||||
//function, added to Edit button
|
||||
unhideCheckboxes()
|
||||
unlockRecordsForEditing()
|
||||
}
|
||||
|
||||
function eventListenerUpdate(e){
|
||||
//function, added to Update button
|
||||
var action = e.target.name
|
||||
var data = getCheckedRecords()
|
||||
updateCheckedRecords(data, action)
|
||||
}
|
||||
|
||||
function appendCell(tableRow, tag, tagName, tagText, cellIndex){
|
||||
//appending cell
|
||||
var cell = tableRow.insertCell(cellIndex)
|
||||
var textInput = document.createElement(tag)
|
||||
textInput.innerText = tagText
|
||||
@ -91,6 +97,7 @@ function appendCell(tableRow, tag, tagName, tagText, cellIndex){
|
||||
}
|
||||
|
||||
function unhideCheckboxes(){
|
||||
//function, unhiding checkboxes
|
||||
var checkboxes = document.getElementsByClassName('copy_over_checkbox_cell')
|
||||
for (var i = 0; i < checkboxes.length; i++){
|
||||
checkboxes[i].style.display = 'initial'
|
||||
@ -101,6 +108,7 @@ function unhideCheckboxes(){
|
||||
}
|
||||
|
||||
function unlockRecordsForEditing(){
|
||||
//function, switching div elements to input
|
||||
var rows = document.getElementsByClassName('database_row')
|
||||
for (var j = 0; j < rows.length; j++) {
|
||||
var children = rows[j].getElementsByTagName('div')
|
||||
@ -121,6 +129,7 @@ function unlockRecordsForEditing(){
|
||||
|
||||
|
||||
function getCheckedRecords(){
|
||||
//getting list of records where checkbox is checked
|
||||
var checkboxes = document.getElementsByClassName('copy_over_checkbox_cell')
|
||||
var outputArray = []
|
||||
for (var i = 0; i < checkboxes.length; i++) {
|
||||
@ -147,6 +156,7 @@ function getCheckedRecords(){
|
||||
}
|
||||
|
||||
function formatTableSize(){
|
||||
//adjusting table formats
|
||||
var calendar = document.getElementById('calendar_container')
|
||||
var tableDiv = document.getElementById('list_container')
|
||||
var width = calendar.offsetWidth
|
||||
@ -154,6 +164,7 @@ function formatTableSize(){
|
||||
}
|
||||
|
||||
function createDetailedHeaders(){
|
||||
//creating table with header row
|
||||
var table = document.createElement('table')
|
||||
let headerRow = document.createElement('tr')
|
||||
let columns = ['Date', 'Start time', 'End time', 'Activity type', 'Copy over']
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
window.addEventListener('load', function(){
|
||||
//add class name to currently open sidebar link for css
|
||||
var sidebarItems = document.getElementById('sidebar').getElementsByTagName('a')
|
||||
var pathName = window.location.pathname
|
||||
for (var i = 0; i < sidebarItems.length; i++){
|
||||
|
@ -7,7 +7,7 @@ searchEmployeeButton.addEventListener('click', function(){
|
||||
|
||||
function fetchSearchEmployeeData() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/change_employee_data_api'
|
||||
var fetch_url = host + '/hr-module/change-employee-data-api'
|
||||
var username = document.getElementById('username_input').value
|
||||
|
||||
fetch(fetch_url,
|
||||
|
@ -1,7 +1,10 @@
|
||||
|
||||
import { csrftoken } from '../../../static/js/csrf_token.js'
|
||||
|
||||
//adding event listeners on load
|
||||
window.addEventListener('load', function (){
|
||||
|
||||
//filling datalist with choices for default searched field (Person)
|
||||
fetchSearchOptions()
|
||||
|
||||
var filterType = document.getElementById('schedule_filter_category')
|
||||
@ -15,9 +18,9 @@ window.addEventListener('load', function (){
|
||||
})
|
||||
|
||||
function fetchSearchOptions() {
|
||||
//function, loading list of choices for datalist
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/search_api'
|
||||
|
||||
var fetch_url = host + '/hr-module/search-api'
|
||||
var searched_field = document.getElementById('schedule_filter_category').value
|
||||
var searched_string = document.getElementById('searched_string').value
|
||||
|
||||
@ -41,6 +44,7 @@ function fetchSearchOptions() {
|
||||
|
||||
|
||||
function appendFoundFilterOptions(data){
|
||||
//appending html elements to datalist
|
||||
var parent = document.getElementById('schedule_filter_search');
|
||||
parent.innerHTML = '';
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
@ -59,8 +63,9 @@ function appendFoundFilterOptions(data){
|
||||
}
|
||||
|
||||
function fetchEmployees() {
|
||||
//function to fetch list of found employees
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/loademployees'
|
||||
var fetch_url = host + '/hr-module/loademployees'
|
||||
|
||||
var searched_field = document.getElementById('schedule_filter_category').value
|
||||
var searched_string = document.getElementById('searched_string').value
|
||||
@ -85,6 +90,7 @@ function fetchEmployees() {
|
||||
}
|
||||
|
||||
function appendFoundEmployees(data){
|
||||
//function to append found employees to the container
|
||||
var parentTable = document.getElementById('scheduling_list');
|
||||
parent.innerHTML = '';
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
@ -117,6 +123,7 @@ function appendFoundEmployees(data){
|
||||
}
|
||||
|
||||
function addDeleteButton(username){
|
||||
//adding delete button to every single row of found employees
|
||||
var cell = document.createElement('td')
|
||||
var submit = document.createElement('button')
|
||||
submit.innerHTML = 'Delete'
|
||||
@ -127,6 +134,7 @@ function addDeleteButton(username){
|
||||
}
|
||||
|
||||
function addActivityType(){
|
||||
//adding dropdown with activity type
|
||||
var cell = document.createElement('td')
|
||||
var options = {'work': 'Work',
|
||||
'vacation': 'Vacation',
|
||||
@ -147,12 +155,14 @@ function addActivityType(){
|
||||
}
|
||||
|
||||
function addCell(row, innerhtml, index){
|
||||
//adding cell to a table
|
||||
var cell = row.insertCell(index);
|
||||
cell.innerHTML = innerhtml;
|
||||
return cell
|
||||
}
|
||||
|
||||
function workingDays(parent, data){
|
||||
//creating cell with checkboxes checked for working days
|
||||
var days = ['mon',
|
||||
'tue',
|
||||
'wed',
|
||||
@ -183,12 +193,14 @@ function workingDays(parent, data){
|
||||
}
|
||||
|
||||
function deleteRow(username){
|
||||
//function, deleting the row of the mployee
|
||||
console.log(username)
|
||||
var row = document.getElementById('employee_row_' + username)
|
||||
row.outerHTML = ''
|
||||
}
|
||||
|
||||
function addDeleteEventListener(){
|
||||
//adding delete button event listener and calling deleteRow
|
||||
var buttons = document.getElementsByClassName('delete_button')
|
||||
for (let i = 0; i < buttons.length; i++){
|
||||
buttons[i].addEventListener('click', function (){
|
||||
@ -198,13 +210,14 @@ function addDeleteEventListener(){
|
||||
}
|
||||
|
||||
function buildPlanJson(){
|
||||
//craete json to be submitted to the api to create new plan
|
||||
var listJsons = []
|
||||
var employees = document.getElementsByClassName('employee_row')
|
||||
var lowerBoundary = document.getElementById('planning_lower_boundary').value
|
||||
var upperBoundary = document.getElementById('planning_upper_boundary').value
|
||||
for (var i = 0; i < employees.length; i++) {
|
||||
var planJson = {}
|
||||
var row = employees[0]
|
||||
var row = employees[i]
|
||||
var username = row.getAttribute('data-username')
|
||||
var startTime = row.getElementsByClassName('schedule_time_input')[0].value
|
||||
var activityType = row.getElementsByClassName('activity_type')[0].value
|
||||
@ -228,8 +241,9 @@ function buildPlanJson(){
|
||||
}
|
||||
|
||||
function postPlanToDb(){
|
||||
//submitting the data to the database
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/new_plan_api'
|
||||
var fetch_url = host + '/hr-module/new-plan-api'
|
||||
var json = buildPlanJson()
|
||||
|
||||
fetch(fetch_url,
|
||||
|
@ -2,21 +2,19 @@
|
||||
import { csrftoken } from '../../../static/js/csrf_token.js'
|
||||
|
||||
window.addEventListener('load', function (){
|
||||
//fetch search options for default searched category(Person)
|
||||
fetchSearchOptions()
|
||||
|
||||
var filterType = document.getElementById('schedule_filter_category')
|
||||
filterType.addEventListener('change', fetchSearchOptions)
|
||||
|
||||
var fetchEmployeesButton = document.getElementById('load_employees');
|
||||
fetchEmployeesButton.addEventListener('click', fetchEmployees);
|
||||
|
||||
var submitToDb = document.getElementById('run_planning');
|
||||
submitToDb.addEventListener('click', postPlanToDb);
|
||||
})
|
||||
|
||||
function fetchSearchOptions() {
|
||||
//function, loading list of choices for datalist
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/search_api'
|
||||
var fetch_url = host + '/hr-module/search-api'
|
||||
|
||||
var searched_field = document.getElementById('schedule_filter_category').value
|
||||
var searched_string = document.getElementById('searched_string').value
|
||||
@ -41,6 +39,7 @@ function fetchSearchOptions() {
|
||||
|
||||
|
||||
function appendFoundFilterOptions(data){
|
||||
//appending html elements to datalist
|
||||
var parent = document.getElementById('schedule_filter_search');
|
||||
parent.innerHTML = '';
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
|
@ -39,7 +39,7 @@
|
||||
</a>
|
||||
|
||||
<a href="{% url 'hr_module:change_employee_data' %}">
|
||||
<div class="sidebar_item" >Manage employee data
|
||||
<div class="sidebar_item" >Show employee data
|
||||
</div>
|
||||
</a>
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
<div class="import_text">
|
||||
Add employee manually
|
||||
</div>
|
||||
<form method="post">
|
||||
<form method="post" autocomplete="off">
|
||||
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.first_name.id_for_label }}">First Name:</label>
|
||||
|
@ -9,18 +9,18 @@ urlpatterns = [
|
||||
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'),
|
||||
path('search-api', views.search_users_api, name='search_users_api'),
|
||||
path('loademployees', views.load_employees_api, name='load_employees'),
|
||||
path('new_plan_api', views.new_plan_api, name='new_plan_api'),
|
||||
path('show_schedule', views.manage_schedule, name='manage_schedule'),
|
||||
path('show_employee_plan_api', views.show_employee_plan_api, name='show_employee_plan_api'),
|
||||
path('update_plan_api', views.update_plan_api, name='update_plan_api'),
|
||||
path('show_timelog', views.manage_timelog, name='manage_timelog'),
|
||||
path('show_employee_timelog_api', views.show_employee_timelog_api, name='show_employee_timelog_api'),
|
||||
path('update_timelog_api', views.update_timelog_api, name='update_timelog_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'),
|
||||
path('plan_creation_log', views.plan_creation_log, name='plan_creation_log'),
|
||||
path('new-plan-api', views.new_plan_api, name='new_plan_api'),
|
||||
path('show-schedule', views.manage_schedule, name='manage_schedule'),
|
||||
path('show-employee-plan-api', views.show_employee_plan_api, name='show_employee_plan_api'),
|
||||
path('update-plan-api', views.update_plan_api, name='update_plan_api'),
|
||||
path('show-timelog', views.manage_timelog, name='manage_timelog'),
|
||||
path('show-employee-timelog-api', views.show_employee_timelog_api, name='show_employee_timelog_api'),
|
||||
path('update-timelog-api', views.update_timelog_api, name='update_timelog_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'),
|
||||
path('plan-creation-log', views.plan_creation_log, name='plan_creation_log'),
|
||||
path('export', views.export, name='export'),
|
||||
|
||||
]
|
@ -1,27 +1,28 @@
|
||||
from django.shortcuts import render, redirect
|
||||
from django.shortcuts import render
|
||||
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.misc import dictfetchall
|
||||
from hr_module.handling_functions.insert_to_plan import UpdatePlan
|
||||
from hr_module.handling_functions.monthly_planning_functions import create_planning_operation_report
|
||||
from hr_module.sql_queries import export_queries
|
||||
import pandas as pd
|
||||
import json
|
||||
from .models import Employee, PlanCreationLog, Plan, TimeLog
|
||||
from django.contrib.auth.models import User
|
||||
from django.http import HttpResponse, JsonResponse, HttpResponseRedirect
|
||||
from django.db import connection
|
||||
import datetime
|
||||
from django.urls import reverse, reverse_lazy
|
||||
from django.conf import settings
|
||||
from .forms import UploadFileForm, NewUserForm
|
||||
from .models import Employee, PlanCreationLog, Plan, TimeLog
|
||||
from hr_module.handling_functions.data_import_functions import read_and_parse_excel, insert_excel
|
||||
from hr_module.handling_functions.util import dictfetchall, months_list
|
||||
from hr_module.handling_functions.insert_to_plan_class import UpdatePlan
|
||||
from hr_module.handling_functions.monthly_planning_functions import create_planning_operation_report
|
||||
from hr_module.sql_queries import export_queries
|
||||
import datetime
|
||||
import csv
|
||||
import pandas as pd
|
||||
import json
|
||||
|
||||
|
||||
login_url = reverse_lazy('login')
|
||||
# Create your views here.
|
||||
@login_required(login_url=login_url)
|
||||
def create_schedule(request):
|
||||
'''rendering base html for schedule creating'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -32,6 +33,7 @@ def create_schedule(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def homepage(request):
|
||||
'''rendering homepage'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -42,6 +44,7 @@ def homepage(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def change_employee_data(request):
|
||||
'''rendering base html for data change'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -51,6 +54,7 @@ def change_employee_data(request):
|
||||
|
||||
|
||||
def change_employee_data_api(request):
|
||||
'''api for data changing'''
|
||||
if request.method == 'POST':
|
||||
if request.user.is_authenticated:
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
@ -93,10 +97,12 @@ def change_employee_data_api(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def create_employees(request):
|
||||
'''view for creating new employees'''
|
||||
if not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('hr_module:homepage'))
|
||||
|
||||
if request.method == 'POST':
|
||||
'''preview inserted file'''
|
||||
if 'import_preview' in request.POST:
|
||||
fileform = UploadFileForm(request.POST, request.FILES)
|
||||
if fileform.is_valid():
|
||||
@ -109,6 +115,7 @@ def create_employees(request):
|
||||
template = 'hr_module_import_validation.html'
|
||||
return render(request, template, context)
|
||||
|
||||
'''processing insert from excel'''
|
||||
if 'import_insert' in request.POST:
|
||||
df = pd.read_csv(request.session['df_path'])
|
||||
insert_excel(df)
|
||||
@ -116,17 +123,21 @@ def create_employees(request):
|
||||
template = 'hr_module_import_success.html'
|
||||
return render(request, template)
|
||||
|
||||
|
||||
'''importing single employee from form'''
|
||||
if 'import_single' in request.POST:
|
||||
df_dict = {k: v[0] for k, v in dict(request.POST).items()}
|
||||
for i in ('csrfmiddlewaretoken', 'import_single'):
|
||||
df_dict.pop(i, None)
|
||||
for i in ('is_superuser', 'is_staff', 'is_active', 'manager_flag'):
|
||||
if i not in df_dict.keys():
|
||||
df_dict[i] = False
|
||||
df = pd.DataFrame(df_dict, index=[0])
|
||||
insert_excel(df)
|
||||
template = 'hr_module_import_success.html'
|
||||
return render(request, template)
|
||||
|
||||
else:
|
||||
'''column names to be displayed on the frontend as mandatory'''
|
||||
columns_user = ['first_name',
|
||||
'last_name',
|
||||
'username',
|
||||
@ -151,10 +162,10 @@ def create_employees(request):
|
||||
|
||||
|
||||
def search_users_api(request):
|
||||
'''api view, loading search options into select field on the frontend'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
searched_field = body['searched_field']
|
||||
searched_string = body['searched_string']
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
||||
@ -177,6 +188,7 @@ def search_users_api(request):
|
||||
|
||||
|
||||
def load_employees_api(request):
|
||||
'''api view, loading employee details for schedule creating'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
searched_field = body['searched_field']
|
||||
@ -196,9 +208,9 @@ def load_employees_api(request):
|
||||
cursor.execute('select auth.first_name || %s || auth.last_name as name, auth.username as username, '
|
||||
'empl.manager_username as manager_name, tm.daily_hours, '
|
||||
'tm.mon, tm.tue, tm.wed, tm.thu, tm.fri, tm.sat, tm.fri '
|
||||
'from hr_module_employee empl inner join auth_user auth on auth.username = empl.manager_username '
|
||||
'inner join hr_module_timemodel tm on empl.time_model_id = tm.time_model_id '
|
||||
'where manager_username = %s', [' ', searched_string])
|
||||
'from hr_module_employee empl inner join auth_user auth on auth.username = empl.username '
|
||||
'inner join hr_module_timemodel tm on empl.time_model_id = tm.time_model_id '
|
||||
'where empl.manager_username = %s', [' ', searched_string])
|
||||
|
||||
elif searched_field == 'username':
|
||||
cursor.execute('select auth.first_name || %s || auth.last_name as name, auth.username as username, '
|
||||
@ -210,10 +222,12 @@ def load_employees_api(request):
|
||||
'where empl.username = %s ', [' ', searched_string])
|
||||
|
||||
response = dictfetchall(cursor)
|
||||
print(response, searched_field)
|
||||
return JsonResponse(response, safe=False)
|
||||
|
||||
|
||||
def new_plan_api(request):
|
||||
'''api view, inserting new schedule records into the database'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)['json']
|
||||
log = []
|
||||
@ -230,6 +244,7 @@ def new_plan_api(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def manage_schedule(request):
|
||||
'''rendering base html for changing schedule'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -239,6 +254,7 @@ def manage_schedule(request):
|
||||
|
||||
|
||||
def show_employee_plan_api(request):
|
||||
'''api view to select employee records from the DB and return as json'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
username = body['username']
|
||||
@ -256,6 +272,7 @@ def show_employee_plan_api(request):
|
||||
|
||||
|
||||
def update_plan_api(request):
|
||||
'''update schedule records plan'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
if body['action'] == 'delete':
|
||||
@ -279,6 +296,7 @@ def update_plan_api(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def manage_timelog(request):
|
||||
'''render base html view for showing timelog'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -287,6 +305,7 @@ def manage_timelog(request):
|
||||
return render(request, template)
|
||||
|
||||
def show_employee_timelog_api(request):
|
||||
'''api to load employee timelog'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
username = body['username']
|
||||
@ -304,6 +323,7 @@ def show_employee_timelog_api(request):
|
||||
|
||||
|
||||
def update_timelog_api(request):
|
||||
'''api to update emplotee timelog'''
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
if body['action'] == 'delete':
|
||||
@ -327,6 +347,7 @@ def update_timelog_api(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def plan_creation_log(request):
|
||||
'''view to display schedule creating logs'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
session_user_manager_flag = session_user.employee.manager_flag
|
||||
if not session_user_manager_flag and not request.user.is_superuser:
|
||||
@ -346,6 +367,7 @@ def plan_creation_log(request):
|
||||
|
||||
@login_required(login_url=login_url)
|
||||
def export(request):
|
||||
'''view to download xlsx as exported report'''
|
||||
session_user = User.objects.select_related('employee').get(username=request.user.username)
|
||||
if not session_user.employee.manager_flag and not request.user.is_superuser:
|
||||
return HttpResponseRedirect(reverse('employee_module:homepage'))
|
||||
@ -376,15 +398,3 @@ def export(request):
|
||||
return render(request, template)
|
||||
|
||||
|
||||
def months_list(start_date, end_date):
|
||||
start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d').date()
|
||||
end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d').date()
|
||||
tmp = end_date
|
||||
list_ = []
|
||||
while tmp >= start_date:
|
||||
list_.append(tmp.strftime('%Y-%m'))
|
||||
tmp = tmp.replace(day=1) - datetime.timedelta(days=1)
|
||||
start_date_str = start_date.strftime('%Y-%m')
|
||||
if not start_date_str in list_:
|
||||
list_.append(start_date_str)
|
||||
return tuple(list_)
|
Binary file not shown.
Binary file not shown.
@ -145,5 +145,5 @@ LOGIN_REDIRECT_URL = reverse_lazy('hr_module:homepage')
|
||||
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
|
||||
MEDIA_URL = '/media/'
|
||||
|
||||
TMP_FILE_STORAGE = os.path.join(MEDIA_ROOT, 'temp/')
|
||||
TMP_FILE_STORAGE = os.path.join(MEDIA_ROOT, 'tmp/')
|
||||
IMPORT_REPORT_STORAGE = os.path.join(MEDIA_ROOT, 'import_reports/')
|
||||
|
@ -21,12 +21,12 @@ from django.contrib.auth import views as auth_views
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls),
|
||||
path('hr_module/', include('hr_module.urls')),
|
||||
path('employee_module/', include('employee_module.urls')),
|
||||
path('hr-module/', include('hr_module.urls')),
|
||||
path('employee-module/', include('employee_module.urls')),
|
||||
|
||||
path('login', auth_views.LoginView.as_view(template_name='login.html'), name='login'),
|
||||
path('logout', auth_views.LogoutView.as_view(), name='logout'),
|
||||
path('change_password', auth_views.PasswordChangeView.as_view(template_name='change_password.html'),
|
||||
path('change-password', auth_views.PasswordChangeView.as_view(template_name='change_password.html'),
|
||||
name='change_password'),
|
||||
]
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user