more ajax
This commit is contained in:
parent
8da99758f2
commit
2c516b24e8
@ -22,6 +22,7 @@
|
||||
<option name="TEMPLATE_FOLDERS">
|
||||
<list>
|
||||
<option value="$MODULE_DIR$/templates" />
|
||||
<option value="$MODULE_DIR$/hr_module/templates" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
|
BIN
__pycache__/manage.cpython-38.pyc
Normal file
BIN
__pycache__/manage.cpython-38.pyc
Normal file
Binary file not shown.
BIN
db.sqlite3
BIN
db.sqlite3
Binary file not shown.
BIN
hr_module/__pycache__/admin.cpython-38.pyc
Normal file
BIN
hr_module/__pycache__/admin.cpython-38.pyc
Normal file
Binary file not shown.
BIN
hr_module/__pycache__/apps.cpython-38.pyc
Normal file
BIN
hr_module/__pycache__/apps.cpython-38.pyc
Normal file
Binary file not shown.
BIN
hr_module/__pycache__/forms.cpython-38.pyc
Normal file
BIN
hr_module/__pycache__/forms.cpython-38.pyc
Normal file
Binary file not shown.
BIN
hr_module/__pycache__/models.cpython-38.pyc
Normal file
BIN
hr_module/__pycache__/models.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,3 +1,9 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
from .models import Employee, TimeModel, Plan, TimeLog
|
||||
|
||||
admin.site.register(Employee)
|
||||
admin.site.register(TimeModel)
|
||||
admin.site.register(Plan)
|
||||
admin.site.register(TimeLog)
|
||||
|
@ -0,0 +1,19 @@
|
||||
from django import forms
|
||||
from django.conf import settings
|
||||
|
||||
class UploadFileForm(forms.Form):
|
||||
file = forms.FileField(widget=forms.ClearableFileInput(attrs={'id': 'import_filepicker'}))
|
||||
|
||||
|
||||
class NewUserForm(forms.Form):
|
||||
first_name = forms.CharField(max_length=200)
|
||||
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()
|
||||
department = forms.CharField(max_length=200)
|
||||
manager_username = forms.CharField(max_length=200)
|
||||
time_model_id = forms.IntegerField()
|
||||
manager_flag = forms.BooleanField()
|
BIN
hr_module/handling_functions/__pycache__/__init__.cpython-38.pyc
Normal file
BIN
hr_module/handling_functions/__pycache__/__init__.cpython-38.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,9 +1,8 @@
|
||||
|
||||
import pandas as pd
|
||||
import sqlite3
|
||||
from django.conf import settings
|
||||
import datetime
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
def create_connection(db_file):
|
||||
""" create a database connection to the SQLite database
|
||||
@ -13,8 +12,10 @@ def create_connection(db_file):
|
||||
"""
|
||||
conn = None
|
||||
try:
|
||||
conn = sqlite3.connect(db_file)
|
||||
except Error as e:
|
||||
path = 'sqlite:///' + str(db_file)
|
||||
engine = create_engine(path)
|
||||
conn = engine.connect()
|
||||
except Exception as e:
|
||||
print(e)
|
||||
return conn
|
||||
|
||||
@ -28,36 +29,8 @@ def read_and_parse_excel(file):
|
||||
return {'df_html': html, 'df_path': path_temp}
|
||||
|
||||
|
||||
def load_existing_users():
|
||||
conn = create_connection(settings.DATABASES['default']['NAME'])
|
||||
cur = conn.cursor()
|
||||
cur.execute('select username from auth_user')
|
||||
usernames = [user[0] for user in cur.fetchall()]
|
||||
return usernames
|
||||
|
||||
|
||||
def generate_username(first_name, last_name, usernames):
|
||||
username = first_name + last_name[:1]
|
||||
i = 1
|
||||
while username + str(i) in usernames:
|
||||
i += 1
|
||||
|
||||
username = username + str(i)
|
||||
return username.lower()
|
||||
|
||||
|
||||
def insert_excel(df):
|
||||
conn = create_connection(settings.DATABASES['default']['NAME'])
|
||||
|
||||
usernames = load_existing_users()
|
||||
print(usernames)
|
||||
for i in range(len(df)):
|
||||
row = df.iloc[i]
|
||||
username = generate_username(row['first_name'], row['last_name'], usernames)
|
||||
df.at[i, 'username'] = username
|
||||
usernames.append(username)
|
||||
|
||||
|
||||
df['date_joined'] = datetime.date.today()
|
||||
df['password'] = 'start'
|
||||
|
||||
|
@ -0,0 +1,46 @@
|
||||
|
||||
from sqlalchemy.orm import sessionmaker
|
||||
from sqlalchemy import create_engine
|
||||
from django.conf import settings
|
||||
from ..models import Employee, TimeModel, 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 main(user, start_date, end_date, start_time, 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')
|
||||
|
||||
username = Employee.objects.get(username=user)
|
||||
|
||||
daily_hours = int(timemodel.daily_hours * 60)
|
||||
time_end = 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
|
||||
for day in range(days):
|
||||
date_to_add = start_date + datetime.timedelta(days=day)
|
||||
if timemodel_pattern[date_to_add.weekday()]:
|
||||
print(start_time, time_end)
|
||||
plan = Plan(username=username,
|
||||
date=date_to_add,
|
||||
begin_time=start_time,
|
||||
end_time=time_end,
|
||||
activity_type=activity_type)
|
||||
plan.save()
|
||||
|
||||
|
||||
|
@ -0,0 +1,47 @@
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import Column, Integer, String, Boolean, Date, Numeric, Time
|
||||
|
||||
|
||||
Base = declarative_base()
|
||||
|
||||
class Employee(Base):
|
||||
__tablename__ = 'hr_module_employee'
|
||||
|
||||
username = Column(String, primary_key=True)
|
||||
department = Column(String)
|
||||
manager_username = Column(String)
|
||||
time_model_id = Column(Integer)
|
||||
manager_flag = Column(Boolean)
|
||||
|
||||
class TimeModel(Base):
|
||||
__tablename__ = 'hr_module_timemodel'
|
||||
|
||||
time_model_id = Column(Integer, primary_key=True)
|
||||
daily_hours = Column(Numeric)
|
||||
weekly_days = Column(Integer)
|
||||
mon = Column(Boolean)
|
||||
tue = Column(Boolean)
|
||||
wed = Column(Boolean)
|
||||
thu = Column(Boolean)
|
||||
fri = Column(Boolean)
|
||||
sat = Column(Boolean)
|
||||
sun = Column(Boolean)
|
||||
|
||||
class Plan(Base):
|
||||
__tablename__ = 'hr_module_plan'
|
||||
username = Column(String, primary_key=True)
|
||||
date = Column(Date)
|
||||
begin_time = Column(Time)
|
||||
end_time = Column(Time)
|
||||
activity_type = Column(String)
|
||||
|
||||
class TimeLog(Base):
|
||||
__tablename__ = 'hr_module_timelog'
|
||||
username = Column(String, primary_key=True)
|
||||
date = Column(Date)
|
||||
begin_time = Column(Time)
|
||||
end_time = Column(Time)
|
||||
activity_type = Column(String)
|
||||
|
||||
|
||||
|
@ -1,17 +1,50 @@
|
||||
from django.db import models
|
||||
from django.contrib.auth.models import User
|
||||
|
||||
ACTIVITY_TYPES = [('work', 'Work'),
|
||||
('vacation', 'Vacation'),
|
||||
('sickness', 'Sickness'),
|
||||
('parental_leave', 'Parental leave'),
|
||||
]
|
||||
|
||||
|
||||
# Create your models here.
|
||||
class Employee(models.Model):
|
||||
person_id = models.IntegerField(blank=False,
|
||||
null=False,
|
||||
unique=True)
|
||||
first_name = models.CharField(max_length=200,
|
||||
null=False,
|
||||
blank=False)
|
||||
last_name = models.CharField(max_length=200,
|
||||
null=False,
|
||||
blank=False)
|
||||
username = models.OneToOneField(User, on_delete=models.CASCADE,
|
||||
to_field='username',
|
||||
db_column="username",
|
||||
primary_key=True)
|
||||
department = models.CharField(max_length=200,
|
||||
null=False,
|
||||
blank=False)
|
||||
manager_id = models.IntegerField()
|
||||
manager_username = models.CharField(max_length=200)
|
||||
time_model = models.ForeignKey('TimeModel', on_delete=models.PROTECT)
|
||||
manager_flag = models.BooleanField()
|
||||
|
||||
|
||||
class TimeModel(models.Model):
|
||||
time_model_id = models.IntegerField(primary_key=True)
|
||||
daily_hours = models.DecimalField(max_digits=4, decimal_places=2)
|
||||
weekly_days = models.IntegerField()
|
||||
mon = models.BooleanField()
|
||||
tue = models.BooleanField()
|
||||
wed = models.BooleanField()
|
||||
thu = models.BooleanField()
|
||||
fri = models.BooleanField()
|
||||
sat = models.BooleanField()
|
||||
sun = models.BooleanField()
|
||||
|
||||
class Plan(models.Model):
|
||||
username = models.ForeignKey(Employee, on_delete=models.PROTECT)
|
||||
date = models.DateField()
|
||||
begin_time = models.TimeField()
|
||||
end_time = models.TimeField()
|
||||
activity_type = models.CharField(max_length=100)
|
||||
|
||||
|
||||
class TimeLog(models.Model):
|
||||
username = models.ForeignKey(Employee, on_delete=models.PROTECT)
|
||||
date = models.DateField()
|
||||
begin_time = models.TimeField()
|
||||
end_time = models.TimeField()
|
||||
activity_type = models.CharField(max_length=100)
|
||||
|
@ -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 {
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
95
hr_module/static/css/hr_module_import.css
vendored
95
hr_module/static/css/hr_module_import.css
vendored
@ -0,0 +1,95 @@
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
@ -0,0 +1,244 @@
|
||||
const csrftoken = getCookie('csrftoken');
|
||||
|
||||
var searchInput = document.getElementById('searched_string');
|
||||
searchInput.addEventListener("click", fetchSearchOptions);
|
||||
|
||||
var fetchEmployeesButton = document.getElementById('load_employees');
|
||||
fetchEmployeesButton.addEventListener('click', fetchEmployees);
|
||||
|
||||
var submitToDb = document.getElementById('run_planning');
|
||||
submitToDb.addEventListener('click', postPlanToDb);
|
||||
|
||||
function fetchSearchOptions() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/search'
|
||||
|
||||
var searched_field = document.getElementById('schedule_filter_category').value
|
||||
var searched_string = document.getElementById('searched_string').value
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"searched_field": searched_field,
|
||||
"searched_string": searched_string
|
||||
}),
|
||||
}).then((response) => {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
appendFoundFilterOptions(data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function appendFoundFilterOptions(data){
|
||||
console.log(data)
|
||||
var parent = document.getElementById('schedule_filter_search');
|
||||
parent.innerHTML = '';
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
|
||||
var caption = data[i]['caption'];
|
||||
var value = data[i]['value'];
|
||||
console.log(caption)
|
||||
console.log(value)
|
||||
|
||||
innerHTML = '<option value="' + value + '">' + caption + '</option>'
|
||||
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.innerHTML = innerHTML;
|
||||
var htmlNode = wrapper.firstChild;
|
||||
|
||||
parent.appendChild(htmlNode);
|
||||
}
|
||||
}
|
||||
|
||||
function fetchEmployees() {
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/loeademployees'
|
||||
|
||||
var searched_field = document.getElementById('schedule_filter_category').value
|
||||
var searched_string = document.getElementById('searched_string').value
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
"searched_field": searched_field,
|
||||
"searched_string": searched_string
|
||||
}),
|
||||
}).then((response) => {
|
||||
return response.json();
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
appendFoundEmployees(data);
|
||||
});
|
||||
}
|
||||
|
||||
function appendFoundEmployees(data){
|
||||
console.log(data)
|
||||
var parentTable = document.getElementById('scheduling_list');
|
||||
parent.innerHTML = '';
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
|
||||
var name = data[i]['name'];
|
||||
var username = data[i]['username'];
|
||||
var manager_name = data[i]['manager_name'];
|
||||
var daily_hours = data[i]['daily_hours'];
|
||||
|
||||
|
||||
var newRow = parentTable.insertRow(-1)
|
||||
newRow.className = 'employee_row'
|
||||
newRow.id = 'employee_row_' + username
|
||||
newRow.setAttribute('data-username', username)
|
||||
addCell(newRow, username, 0)
|
||||
addCell(newRow, name, 1)
|
||||
addCell(newRow, manager_name, 2)
|
||||
addCell(newRow, daily_hours, 3)
|
||||
var cellDays = addCell(newRow, '', 4)
|
||||
workingDays(cellDays, data[i])
|
||||
|
||||
addCell(newRow, addActivityType(), 5)
|
||||
|
||||
addCell(newRow,'<td><input type="time" class="schedule_time_input"></td>', 6)
|
||||
var cellButton = addCell(newRow, addDeleteButton(username),7)
|
||||
cellButton.firstChild.addEventListener('click', function(){
|
||||
deleteRow(username)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
function addDeleteButton(username){
|
||||
var cell = document.createElement('td')
|
||||
var submit = document.createElement('button')
|
||||
submit.innerHTML = 'Delete'
|
||||
cell.appendChild(submit)
|
||||
return cell.outerHTML
|
||||
}
|
||||
|
||||
function addActivityType(){
|
||||
var cell = document.createElement('td')
|
||||
var options = {'work': 'Work',
|
||||
'vacation': 'Vacation',
|
||||
'sickness': 'Sickness',
|
||||
'parental_leave': 'Parental leave'}
|
||||
var select = document.createElement('select')
|
||||
select.id = 'activity_type'
|
||||
|
||||
for (const [key, value] of Object.entries(options)) {
|
||||
var option = document.createElement('option');
|
||||
option.value = key;
|
||||
option.text = value;
|
||||
select.appendChild(option)
|
||||
}
|
||||
|
||||
cell.appendChild(select)
|
||||
return cell.outerHTML
|
||||
}
|
||||
|
||||
function addCell(row, innerhtml, index){
|
||||
var cell = row.insertCell(index);
|
||||
cell.innerHTML = innerhtml;
|
||||
return cell
|
||||
}
|
||||
|
||||
function workingDays(parent, data){
|
||||
var days = ['mon',
|
||||
'tue',
|
||||
'wed',
|
||||
'thu',
|
||||
'fri',
|
||||
'sat',
|
||||
'sun',]
|
||||
days.forEach(function (item) {
|
||||
if (data[item] === true) {
|
||||
var tag = '<label for="' + item + '">'+ item + '</label><input class="working_days" type="checkbox" id="' + item + '" value="' + item + '" checked>'
|
||||
|
||||
} else {
|
||||
var tag = '<label for="' + item + '">'+ item + '</label><input class="working_days" type="checkbox" id="' + item + '" value="' + item + '" >'
|
||||
}
|
||||
var wrapper = document.createElement('div');
|
||||
wrapper.className = 'day_of_week_checkbox'
|
||||
wrapper.innerHTML = tag;
|
||||
parent.appendChild(wrapper)
|
||||
});
|
||||
}
|
||||
|
||||
function deleteRow(username){
|
||||
var row = document.getElementById('employee_row_' + username)
|
||||
row.outerHTML = ''
|
||||
}
|
||||
|
||||
function buildPlanJson(){
|
||||
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 = {}
|
||||
row = employees[0]
|
||||
var username = row.getAttribute('data-username')
|
||||
var startTime = row.getElementsByClassName('schedule_time_input')[0].value
|
||||
var days = row.getElementsByClassName('working_days')
|
||||
var daysOfWeek = {}
|
||||
for (var k = 0; k < days.length; k++){
|
||||
day = days[k]
|
||||
daysOfWeek[day.value] = day.checked
|
||||
}
|
||||
planJson['username'] = username
|
||||
planJson['start_time'] = startTime
|
||||
planJson['timemodel_pattern'] = daysOfWeek
|
||||
planJson['date_start'] = lowerBoundary
|
||||
planJson['date_end'] = upperBoundary
|
||||
listJsons.push(planJson)
|
||||
}
|
||||
return listJsons
|
||||
}
|
||||
|
||||
function postPlanToDb(){
|
||||
var host = 'http://' + window.location.host;
|
||||
var fetch_url = host + '/hr_module/plan_api'
|
||||
var json = buildPlanJson()
|
||||
|
||||
fetch(fetch_url,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': csrftoken
|
||||
},
|
||||
body: JSON.stringify({
|
||||
json
|
||||
}),
|
||||
}).then((response) => {
|
||||
return true;
|
||||
}).then((data) => {
|
||||
console.log(data);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
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;
|
||||
}
|
@ -1,10 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
{% extends 'hr_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
<link rel="stylesheet" href="{% static '/css/hr_import_validation.css' %}">
|
||||
<div class="import_instructions">The following data will be imported:
|
||||
</div>
|
||||
<div class="import_table">
|
||||
{{ df_html|safe }}
|
||||
</div>
|
||||
<form method="post" enctype="multipart/form-data" >
|
||||
{% csrf_token %}
|
||||
<input type="submit" value="Confirm import" name="import_insert">
|
||||
</form>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -1,10 +1,32 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block stylesheet_hr_module_base %}
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_base.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
|
||||
|
||||
{% block core_content %}
|
||||
|
||||
<div class="sidebar">
|
||||
<div class="sidebar_item">Create schedule
|
||||
</div>
|
||||
|
||||
<div class="sidebar_item">Manage Employees
|
||||
</div>
|
||||
|
||||
<div class="sidebar_item">Import Data
|
||||
</div>
|
||||
|
||||
<div class="sidebar_item">Export Data
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="hr_module_main_container">
|
||||
{% block action_panel %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
@ -1,10 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
{% extends 'hr_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_import.css' %}">
|
||||
<div class="import_container">
|
||||
<div class="import_text">
|
||||
Add employee manually
|
||||
</div>
|
||||
<form method="post">
|
||||
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.first_name.id_for_label }}">First Name:</label>
|
||||
{{ userform.first_name }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.last_name.id_for_label }}">Last Name:</label>
|
||||
{{ userform.last_name }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.username.id_for_label }}">Username:</label>
|
||||
{{ userform.username }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.email.id_for_label }}">Email:</label>
|
||||
{{ userform.email }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.is_staff.id_for_label }}">Is Staff:</label>
|
||||
{{ userform.is_staff }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.is_active.id_for_label }}">Is Active:</label>
|
||||
{{ userform.is_active }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.is_superuser.id_for_label }}">Is Superser:</label>
|
||||
{{ userform.is_superuser }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.manager_flag.id_for_label }}">Is Manager:</label>
|
||||
{{ userform.manager_flag }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.department.id_for_label }}">Department:</label>
|
||||
{{ userform.department }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.manager_username.id_for_label }}">Manager's username:</label>
|
||||
{{ userform.manager_username }}
|
||||
</div>
|
||||
<div class="form_element">
|
||||
<label for="{{ userform.time_model_id.id_for_label }}">Time model id:</label>
|
||||
{{ userform.time_model_id }}
|
||||
</div>
|
||||
{% csrf_token %}
|
||||
<input class="import_execute" type="submit" value="Submit" name="import_single">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
<div class="separator">
|
||||
<div class="separatorline"></div>
|
||||
<div class="wordwrapper">
|
||||
<div class="word">or</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="import_container">
|
||||
<div class="import_text">
|
||||
Import employees from Excel file
|
||||
</div>
|
||||
<table>
|
||||
<tr>
|
||||
<th>Column name</th>
|
||||
<th>Data type</th>
|
||||
</tr>
|
||||
{% for item in columns %}
|
||||
<tr>
|
||||
<td>{{ item }}</td>
|
||||
|
||||
</tr>
|
||||
{% endfor %}
|
||||
</table>
|
||||
<form method="post" enctype="multipart/form-data" >
|
||||
{% csrf_token %}
|
||||
<div class="import_input">
|
||||
{{ fileform.file }}
|
||||
</div>
|
||||
<input class="import_execute" type="submit" value="Preview" name="import_preview">
|
||||
</form>
|
||||
</div>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -1,10 +1,57 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
</body>
|
||||
</html>
|
||||
{% extends 'hr_module_base.html' %}
|
||||
|
||||
{% load static %}
|
||||
|
||||
{% block action_panel %}
|
||||
<link rel="stylesheet" href="{% static '/css/hr_module_schedule.css' %}">
|
||||
|
||||
<div class="scheduleSearchRow">
|
||||
<div class="search_element">Select filter type:
|
||||
<select name="category" id="schedule_filter_category">
|
||||
<option value="username">Person</option>
|
||||
<option value="manager">Manager</option>
|
||||
<option value="department">Department</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="search_element">
|
||||
<input list="schedule_filter_search" id="searched_string">
|
||||
<datalist id="schedule_filter_search">
|
||||
</datalist>
|
||||
</div>
|
||||
<div class="search_element">
|
||||
<button type="button" id="load_employees">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<table style="width:100%" id="scheduling_list">
|
||||
<tr>
|
||||
<th>Username</th>
|
||||
<th>Name</th>
|
||||
<th>Name of the Manager</th>
|
||||
<th>Daily working hours</th>
|
||||
<th>Default schedule</th>
|
||||
<th>Activity type</th>
|
||||
<th>Start time</th>
|
||||
<th></th>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<div class="date_select_row">
|
||||
<div class="search_element">
|
||||
<input type="date" id="planning_lower_boundary">
|
||||
</div>
|
||||
|
||||
<div class="search_element">
|
||||
<input type="date" id="planning_upper_boundary">
|
||||
</div>
|
||||
|
||||
<div class="search_element">
|
||||
<button type="button" id="run_planning">Create plan</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script src="{% static '/js/hr_module_schedule.js' %}"></script>
|
||||
|
||||
{% endblock %}
|
||||
|
@ -2,6 +2,13 @@
|
||||
from django.urls import path
|
||||
from . import views
|
||||
|
||||
app_name = 'hr_module'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.index, name='index'),
|
||||
path('import_data', views.hr_import, name='import_data'),
|
||||
path('search', views.search_users_api, name='search_users_api'),
|
||||
path('loeademployees', views.load_employees_api, name='load_employees'),
|
||||
path('plan_api', views.plan_api, name='plan_api'),
|
||||
|
||||
]
|
@ -1,6 +1,147 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import render, redirect
|
||||
from .forms import UploadFileForm, NewUserForm
|
||||
from hr_module.handling_functions.data_import_functions import read_and_parse_excel, insert_excel
|
||||
import pandas as pd
|
||||
import json
|
||||
from .models import Employee
|
||||
from django.core import serializers
|
||||
from django.http import HttpResponse, JsonResponse, Http404
|
||||
from django.db import connection
|
||||
|
||||
# Create your views here.
|
||||
def index(request):
|
||||
return HttpResponse("Hello, world. You're at the app index.")
|
||||
template_name = 'hr_module_schedule.html'
|
||||
|
||||
return render(request, template_name)
|
||||
|
||||
|
||||
def hr_import(request):
|
||||
if request.method == 'POST':
|
||||
if 'import_preview' in request.POST:
|
||||
fileform = UploadFileForm(request.POST, request.FILES)
|
||||
print(fileform.is_valid())
|
||||
if fileform.is_valid():
|
||||
uploaded_file = request.FILES['file']
|
||||
df_dict = read_and_parse_excel(uploaded_file)
|
||||
|
||||
request.session['df_path'] = df_dict['df_path']
|
||||
df_html = df_dict['df_html']
|
||||
context = {'df_html': df_html}
|
||||
template = 'hr_import_validation.html'
|
||||
return render(request, template, context)
|
||||
|
||||
if 'import_insert' in request.POST:
|
||||
df = pd.read_csv(request.session['df_path'])
|
||||
insert_excel(df)
|
||||
del request.session['df_path']
|
||||
return redirect('import_data')
|
||||
|
||||
|
||||
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)
|
||||
df = pd.DataFrame(df_dict, index=[0])
|
||||
insert_excel(df)
|
||||
print('done')
|
||||
return redirect('import_data')
|
||||
|
||||
else:
|
||||
columns_user = ['first_name',
|
||||
'last_name',
|
||||
'username',
|
||||
'email',
|
||||
'is_staff',
|
||||
'is_active',
|
||||
'is_superuser']
|
||||
columns_empl = ['department',
|
||||
'manager_username',
|
||||
'time_model_id',
|
||||
'manager_flag']
|
||||
columns = columns_user + columns_empl
|
||||
|
||||
fileform = UploadFileForm()
|
||||
userform = NewUserForm()
|
||||
context = {'userform': userform,
|
||||
'columns': columns,
|
||||
'fileform': fileform
|
||||
}
|
||||
template = 'hr_module_import.html'
|
||||
return render(request, template, context)
|
||||
|
||||
|
||||
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 search_users_api(request):
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
searched_field = body['searched_field']
|
||||
searched_string = body['searched_string']
|
||||
print(searched_field, searched_string)
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
||||
if searched_field == 'department':
|
||||
cursor.execute('select department as caption, department as value from hr_module_employee '
|
||||
'group by department')
|
||||
elif searched_field == 'manager':
|
||||
cursor.execute('select auth.first_name || %s || auth.last_name as caption, empl.manager_username as value '
|
||||
'from hr_module_employee empl inner join auth_user auth on auth.username = empl.manager_username '
|
||||
'group by auth.first_name || %s || auth.last_name, empl.manager_username', [' ', ' ']
|
||||
)
|
||||
elif searched_field == 'username':
|
||||
cursor.execute('select auth.first_name || %s || auth.last_name as caption, empl.username as value from hr_module_employee empl '
|
||||
'inner join auth_user auth on empl.username = auth.username ', [' ',]
|
||||
)
|
||||
|
||||
response = dictfetchall(cursor)
|
||||
print(response)
|
||||
return JsonResponse(response, safe=False)
|
||||
|
||||
|
||||
def load_employees_api(request):
|
||||
if request.method == 'POST':
|
||||
body = json.loads(request.body)
|
||||
searched_field = body['searched_field']
|
||||
searched_string = body['searched_string']
|
||||
print(searched_field, searched_string)
|
||||
cursor = connection.cursor()
|
||||
|
||||
|
||||
if searched_field == 'department':
|
||||
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 department = %s', [' ', searched_string])
|
||||
elif searched_field == 'manager':
|
||||
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])
|
||||
|
||||
elif searched_field == 'username':
|
||||
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.sun '
|
||||
'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 auth.username = %s ', [' ', searched_string])
|
||||
|
||||
response = dictfetchall(cursor)
|
||||
print(response)
|
||||
return JsonResponse(response, safe=False)
|
||||
|
||||
|
||||
def plan_api(request):
|
||||
|
||||
print(json.loads(request.body))
|
@ -1,8 +1,16 @@
|
||||
|
||||
|
||||
.top-bar {
|
||||
height: 150;
|
||||
background: #C0C0C0;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
html, body {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
font-family: sans-serif;
|
||||
}
|
||||
.navbar {
|
||||
height: 50px;
|
||||
background-color: #D3D3D3;
|
||||
width: 100%;
|
||||
}
|
||||
.main_container {
|
||||
background-color: whitesmoke;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
@ -1,23 +1,6 @@
|
||||
,first_name,last_name,email,is_staff,is_active,is_superuser,department,manager_username,time_model_id,manager_flag
|
||||
0,test,test2,testtest2@fff.com,False,True,False,test department,93099,10,0
|
||||
1,test,sf,testsf@fff.com,False,True,False,test department,123555,5,0
|
||||
2,test,fsdc,testfsdc@fff.com,False,True,False,dfdfdv,58347,14,0
|
||||
3,test,sdvcds,testsdvcds@fff.com,False,True,False,fsdfgfg,21411,11,0
|
||||
4,test,vsd,testvsd@fff.com,False,True,False,fg,100670,14,0
|
||||
5,gf,ddsf,gfddsf@fff.com,False,True,False,fsdfgfg,56776,1,1
|
||||
6,fg,bg,fgbg@fff.com,False,True,False,fg,1012,7,1
|
||||
7,gf,gb,gfgb@fff.com,False,True,False,fsdfgfg,24615,6,1
|
||||
8,fg,gb,fggb@fff.com,False,True,False,dfgdfgffgs,131029,10,1
|
||||
9,fg,gf,fggf@fff.com,False,True,False,fsdfgfg,150186,6,1
|
||||
10,gf,bfg,gfbfg@fff.com,False,True,False,sfgdfsgdfg,127720,7,0
|
||||
11,dfg,bvdf,dfgbvdf@fff.com,False,True,False,test department,21584,13,1
|
||||
12,fg,test2,fgtest2@fff.com,False,True,False,test department,106721,6,0
|
||||
13,first_name,bfg,first_namebfg@fff.com,False,True,False,test department,151398,10,0
|
||||
14,dfg,test2,dfgtest2@fff.com,False,True,False,test department,18196,1,0
|
||||
15,gf,gbb,gfgbb@fff.com,False,True,False,fsdfgfg,23266,11,0
|
||||
16,dfg,fd,dfgfd@fff.com,False,True,False,fsdfgfg,109517,15,0
|
||||
17,gf,bsdgbdf,gfbsdgbdf@fff.com,False,True,False,fsdfgfg,56302,13,1
|
||||
18,gf,fd,gffd@fff.com,False,True,False,fsdfgfg,149169,11,1
|
||||
19,dfg,gdf,dfggdf@fff.com,False,True,False,fsdfgfg,83458,3,0
|
||||
20,dfg,gb,dfggb@fff.com,False,True,False,fsdfgfg,12670,6,0
|
||||
21,test,test2,testtest2@fff.com,False,True,False,test department,49135,3,1
|
||||
,first_name,last_name,username,email,is_staff,is_active,is_superuser,department,manager_username,time_model_id,manager_flag
|
||||
0,Jan,Kowalski,kowalskija,kowalskija@company.com,0,1,0,test department,hitlerad,1,0
|
||||
1,Janina,Kowalska,kowalskaja,kowalskaja@company.com,0,1,0,test department,hitlerad,2,0
|
||||
2,Tadeusz,Tadeuszowicz,tadeuszowiczta,tadeuszowiczta@company.com,0,1,0,dfdfdv,hitlerad,3,0
|
||||
3,Aleksander,Lukaszenko,lukaszenkoal,lukaszenkoal@company.com,0,1,0,fsdfgfg,hitlerad,4,0
|
||||
4,Adolf,Hitler,hitlerad,hitlerad@company.com,0,1,0,fg,hitlerad,5,0
|
||||
|
|
@ -1,10 +1,24 @@
|
||||
{% load static %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>$Title$</title>
|
||||
<title>Title</title>
|
||||
<link rel="stylesheet" href="{% static '/css/base.css' %}">
|
||||
{% block stylesheet_hr_module_base %}
|
||||
{% endblock %}
|
||||
</head>
|
||||
<body>
|
||||
$END$
|
||||
|
||||
<div class="navbar">
|
||||
</div>
|
||||
<div class="main_container">
|
||||
|
||||
{% block core_content %}
|
||||
{% endblock %}
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
Binary file not shown.
@ -11,6 +11,7 @@ https://docs.djangoproject.com/en/3.1/ref/settings/
|
||||
"""
|
||||
|
||||
from pathlib import Path
|
||||
import os
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||
@ -25,12 +26,14 @@ SECRET_KEY = 'tx#+u3u-r1$n_4r(!6vvcb@1f5!z21^74w(zesiz$&59&72$kq'
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
ALLOWED_HOSTS = []
|
||||
ALLOWED_HOSTS = ['192.168.101.128',
|
||||
'127.0.0.1',]
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
INSTALLED_APPS = [
|
||||
'hr_module.apps.HrModuleConfig',
|
||||
'django.contrib.admin',
|
||||
'django.contrib.auth',
|
||||
'django.contrib.contenttypes',
|
||||
@ -54,7 +57,8 @@ ROOT_URLCONF = 'timefall.urls'
|
||||
TEMPLATES = [
|
||||
{
|
||||
'BACKEND': 'django.template.backends.django.DjangoTemplates',
|
||||
'DIRS': [BASE_DIR / 'templates']
|
||||
'DIRS': [BASE_DIR / 'templates',
|
||||
BASE_DIR / 'hr_module/templates']
|
||||
,
|
||||
'APP_DIRS': True,
|
||||
'OPTIONS': {
|
||||
@ -78,6 +82,7 @@ DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': BASE_DIR / 'db.sqlite3',
|
||||
'STRING': 'sqlite:///' + str(BASE_DIR / 'db.sqlite3')
|
||||
}
|
||||
}
|
||||
|
||||
@ -119,3 +124,11 @@ USE_TZ = True
|
||||
# https://docs.djangoproject.com/en/3.1/howto/static-files/
|
||||
|
||||
STATIC_URL = '/static/'
|
||||
|
||||
STATICFILES_DIRS = [
|
||||
os.path.join(BASE_DIR, 'static'),
|
||||
|
||||
]
|
||||
|
||||
|
||||
TMP_FILE_STORAGE = os.path.join(BASE_DIR, 'temp/')
|
Loading…
Reference in New Issue
Block a user