diff --git a/.idea/timefall.iml b/.idea/timefall.iml
index 6dd7f5e..04c03b9 100644
--- a/.idea/timefall.iml
+++ b/.idea/timefall.iml
@@ -22,6 +22,7 @@
diff --git a/__pycache__/manage.cpython-38.pyc b/__pycache__/manage.cpython-38.pyc
new file mode 100644
index 0000000..2ea454f
Binary files /dev/null and b/__pycache__/manage.cpython-38.pyc differ
diff --git a/db.sqlite3 b/db.sqlite3
index d1deb82..f92fe53 100644
Binary files a/db.sqlite3 and b/db.sqlite3 differ
diff --git a/hr_module/__pycache__/admin.cpython-38.pyc b/hr_module/__pycache__/admin.cpython-38.pyc
new file mode 100644
index 0000000..43bb924
Binary files /dev/null and b/hr_module/__pycache__/admin.cpython-38.pyc differ
diff --git a/hr_module/__pycache__/apps.cpython-38.pyc b/hr_module/__pycache__/apps.cpython-38.pyc
new file mode 100644
index 0000000..a00467e
Binary files /dev/null and b/hr_module/__pycache__/apps.cpython-38.pyc differ
diff --git a/hr_module/__pycache__/forms.cpython-38.pyc b/hr_module/__pycache__/forms.cpython-38.pyc
new file mode 100644
index 0000000..03e027d
Binary files /dev/null and b/hr_module/__pycache__/forms.cpython-38.pyc differ
diff --git a/hr_module/__pycache__/models.cpython-38.pyc b/hr_module/__pycache__/models.cpython-38.pyc
new file mode 100644
index 0000000..a4fbf57
Binary files /dev/null and b/hr_module/__pycache__/models.cpython-38.pyc differ
diff --git a/hr_module/__pycache__/urls.cpython-38.pyc b/hr_module/__pycache__/urls.cpython-38.pyc
index 8e583b3..dca41ab 100644
Binary files a/hr_module/__pycache__/urls.cpython-38.pyc and b/hr_module/__pycache__/urls.cpython-38.pyc differ
diff --git a/hr_module/__pycache__/views.cpython-38.pyc b/hr_module/__pycache__/views.cpython-38.pyc
index 192a0e9..8ef351b 100644
Binary files a/hr_module/__pycache__/views.cpython-38.pyc and b/hr_module/__pycache__/views.cpython-38.pyc differ
diff --git a/hr_module/admin.py b/hr_module/admin.py
index 8c38f3f..e7dde83 100644
--- a/hr_module/admin.py
+++ b/hr_module/admin.py
@@ -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)
diff --git a/hr_module/forms.py b/hr_module/forms.py
index e69de29..bd15122 100644
--- a/hr_module/forms.py
+++ b/hr_module/forms.py
@@ -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()
\ No newline at end of file
diff --git a/hr_module/handling_functions/__pycache__/__init__.cpython-38.pyc b/hr_module/handling_functions/__pycache__/__init__.cpython-38.pyc
new file mode 100644
index 0000000..d4e91f0
Binary files /dev/null and b/hr_module/handling_functions/__pycache__/__init__.cpython-38.pyc differ
diff --git a/hr_module/handling_functions/__pycache__/data_import_functions.cpython-38.pyc b/hr_module/handling_functions/__pycache__/data_import_functions.cpython-38.pyc
new file mode 100644
index 0000000..a2f44a4
Binary files /dev/null and b/hr_module/handling_functions/__pycache__/data_import_functions.cpython-38.pyc differ
diff --git a/hr_module/handling_functions/__pycache__/monthly_planning_functions.cpython-38.pyc b/hr_module/handling_functions/__pycache__/monthly_planning_functions.cpython-38.pyc
new file mode 100644
index 0000000..02aa54e
Binary files /dev/null and b/hr_module/handling_functions/__pycache__/monthly_planning_functions.cpython-38.pyc differ
diff --git a/hr_module/handling_functions/__pycache__/sqlalchemy_tables.cpython-38.pyc b/hr_module/handling_functions/__pycache__/sqlalchemy_tables.cpython-38.pyc
new file mode 100644
index 0000000..40fd9ca
Binary files /dev/null and b/hr_module/handling_functions/__pycache__/sqlalchemy_tables.cpython-38.pyc differ
diff --git a/hr_module/handling_functions/data_import_functions.py b/hr_module/handling_functions/data_import_functions.py
index 5a9a3d1..c25aa08 100644
--- a/hr_module/handling_functions/data_import_functions.py
+++ b/hr_module/handling_functions/data_import_functions.py
@@ -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'
diff --git a/hr_module/handling_functions/monthly_planning_functions.py b/hr_module/handling_functions/monthly_planning_functions.py
index e69de29..7f29482 100644
--- a/hr_module/handling_functions/monthly_planning_functions.py
+++ b/hr_module/handling_functions/monthly_planning_functions.py
@@ -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()
+
+
+
diff --git a/hr_module/handling_functions/sqlalchemy_tables.py b/hr_module/handling_functions/sqlalchemy_tables.py
index e69de29..843efa4 100644
--- a/hr_module/handling_functions/sqlalchemy_tables.py
+++ b/hr_module/handling_functions/sqlalchemy_tables.py
@@ -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)
+
+
+
diff --git a/hr_module/models.py b/hr_module/models.py
index dc15f5b..6cbf201 100644
--- a/hr_module/models.py
+++ b/hr_module/models.py
@@ -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()
\ No newline at end of file
+ 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)
diff --git a/hr_module/static/css/hr_import_validation.css b/hr_module/static/css/hr_import_validation.css
index e69de29..821f485 100644
--- a/hr_module/static/css/hr_import_validation.css
+++ b/hr_module/static/css/hr_import_validation.css
@@ -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 {
+
+}
\ No newline at end of file
diff --git a/hr_module/static/css/hr_module_base.css b/hr_module/static/css/hr_module_base.css
index e69de29..a0c144f 100644
--- a/hr_module/static/css/hr_module_base.css
+++ b/hr_module/static/css/hr_module_base.css
@@ -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;
+}
+
diff --git a/hr_module/static/css/hr_module_import.css b/hr_module/static/css/hr_module_import.css
index e69de29..89a94db 100644
--- a/hr_module/static/css/hr_module_import.css
+++ b/hr_module/static/css/hr_module_import.css
@@ -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;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/hr_module/static/css/hr_module_schedule.css b/hr_module/static/css/hr_module_schedule.css
index e69de29..e3cecf1 100644
--- a/hr_module/static/css/hr_module_schedule.css
+++ b/hr_module/static/css/hr_module_schedule.css
@@ -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;
+}
\ No newline at end of file
diff --git a/hr_module/static/js/hr_module_schedule.js b/hr_module/static/js/hr_module_schedule.js
index e69de29..7efff7f 100644
--- a/hr_module/static/js/hr_module_schedule.js
+++ b/hr_module/static/js/hr_module_schedule.js
@@ -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 = '' + caption + ''
+
+ 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,'
| ', 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 = ''
+
+ } else {
+ var tag = ''
+ }
+ 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;
+}
\ No newline at end of file
diff --git a/hr_module/templates/hr_import_validation.html b/hr_module/templates/hr_import_validation.html
index 4bdcfcb..2117b41 100644
--- a/hr_module/templates/hr_import_validation.html
+++ b/hr_module/templates/hr_import_validation.html
@@ -1,10 +1,17 @@
-
-
-
-
- $Title$
-
-
-$END$
-
-
\ No newline at end of file
+{% extends 'hr_module_base.html' %}
+
+{% load static %}
+
+{% block action_panel %}
+
+ The following data will be imported:
+
+
+ {{ df_html|safe }}
+
+
+
+{% endblock %}
diff --git a/hr_module/templates/hr_module_base.html b/hr_module/templates/hr_module_base.html
index 4bdcfcb..24716d6 100644
--- a/hr_module/templates/hr_module_base.html
+++ b/hr_module/templates/hr_module_base.html
@@ -1,10 +1,32 @@
-
-
-
-
- $Title$
-
-
-$END$
-
-
\ No newline at end of file
+{% extends 'base.html' %}
+{% load static %}
+
+{% block stylesheet_hr_module_base %}
+
+{% endblock %}
+
+
+
+{% block core_content %}
+
+
+
+
+{% block action_panel %}
+{% endblock %}
+
+
+{% endblock %}
\ No newline at end of file
diff --git a/hr_module/templates/hr_module_import.html b/hr_module/templates/hr_module_import.html
index 4bdcfcb..7ffb83c 100644
--- a/hr_module/templates/hr_module_import.html
+++ b/hr_module/templates/hr_module_import.html
@@ -1,10 +1,94 @@
-
-
-
-
- $Title$
-
-
-$END$
-
-
\ No newline at end of file
+{% extends 'hr_module_base.html' %}
+
+{% load static %}
+
+{% block action_panel %}
+
+
+
+ Add employee manually
+
+
+
+
+
+
+
+
+ Import employees from Excel file
+
+
+
+ Column name |
+ Data type |
+
+ {% for item in columns %}
+
+ {{ item }} |
+
+
+ {% endfor %}
+
+
+
+
+{% endblock %}
diff --git a/hr_module/templates/hr_module_schedule.html b/hr_module/templates/hr_module_schedule.html
index 4bdcfcb..695dd2b 100644
--- a/hr_module/templates/hr_module_schedule.html
+++ b/hr_module/templates/hr_module_schedule.html
@@ -1,10 +1,57 @@
-
-
-
-
- $Title$
-
-
-$END$
-
-
\ No newline at end of file
+{% extends 'hr_module_base.html' %}
+
+{% load static %}
+
+{% block action_panel %}
+
+
+
+
Select filter type:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Username |
+ Name |
+ Name of the Manager |
+ Daily working hours |
+ Default schedule |
+ Activity type |
+ Start time |
+ |
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/hr_module/urls.py b/hr_module/urls.py
index 91f65b2..c3c69c3 100644
--- a/hr_module/urls.py
+++ b/hr_module/urls.py
@@ -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'),
+
]
\ No newline at end of file
diff --git a/hr_module/views.py b/hr_module/views.py
index a189121..38f8eac 100644
--- a/hr_module/views.py
+++ b/hr_module/views.py
@@ -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.")
\ No newline at end of file
+ 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))
\ No newline at end of file
diff --git a/static/css/base.css b/static/css/base.css
index b248c23..14408a9 100644
--- a/static/css/base.css
+++ b/static/css/base.css
@@ -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%;
}
\ No newline at end of file
diff --git a/temp/import_file.csv b/temp/import_file.csv
index eebff6f..f85f523 100644
--- a/temp/import_file.csv
+++ b/temp/import_file.csv
@@ -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
diff --git a/templates/base.html b/templates/base.html
index 4bdcfcb..8976638 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -1,10 +1,24 @@
+{% load static %}
+
-
- $Title$
+
+ Title
+
+ {% block stylesheet_hr_module_base %}
+ {% endblock %}
-$END$
+
+
+
+
+
+ {% block core_content %}
+ {% endblock %}
+
+
+
\ No newline at end of file
diff --git a/timefall/__pycache__/settings.cpython-38.pyc b/timefall/__pycache__/settings.cpython-38.pyc
index 9ce795e..f2bc508 100644
Binary files a/timefall/__pycache__/settings.cpython-38.pyc and b/timefall/__pycache__/settings.cpython-38.pyc differ
diff --git a/timefall/settings.py b/timefall/settings.py
index 9dec448..225e1d9 100644
--- a/timefall/settings.py
+++ b/timefall/settings.py
@@ -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/')
\ No newline at end of file