removed sqlite from git

This commit is contained in:
muahahahh 2021-01-16 23:56:16 +01:00
parent 3f26366eda
commit 2d6ccc1462
37 changed files with 197 additions and 158 deletions

3
.gitignore vendored
View File

@ -2,4 +2,5 @@
venv/
venv
media
media/
media/
db.sqlite3

View File

@ -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

View File

@ -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',
}
}

View File

@ -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,

View File

@ -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,
{

View File

@ -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'),
]

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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_)

View File

@ -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',
}
}

View File

@ -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 = ''

View File

@ -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']

View File

@ -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
}

View File

@ -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']

View File

@ -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++){

View File

@ -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,

View File

@ -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,

View File

@ -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++) {

View File

@ -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>

View File

@ -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>

View File

@ -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'),
]

View File

@ -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_)

View File

@ -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/')

View File

@ -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'),
]