diff --git a/db.sqlite3 b/db.sqlite3 index 2e11d5f..ff12e82 100644 Binary files a/db.sqlite3 and b/db.sqlite3 differ diff --git a/hr_module/__pycache__/models.cpython-38.pyc b/hr_module/__pycache__/models.cpython-38.pyc index a4fbf57..d4c67c6 100644 Binary files a/hr_module/__pycache__/models.cpython-38.pyc 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 dca41ab..6c9d8da 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 8b4bd8c..962df7d 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/handling_functions/__pycache__/data_import_functions.cpython-38.pyc b/hr_module/handling_functions/__pycache__/data_import_functions.cpython-38.pyc index a2f44a4..0370321 100644 Binary files a/hr_module/handling_functions/__pycache__/data_import_functions.cpython-38.pyc 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 index 8bd7682..48e4d8c 100644 Binary files a/hr_module/handling_functions/__pycache__/monthly_planning_functions.cpython-38.pyc and b/hr_module/handling_functions/__pycache__/monthly_planning_functions.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 c25aa08..381d54e 100644 --- a/hr_module/handling_functions/data_import_functions.py +++ b/hr_module/handling_functions/data_import_functions.py @@ -4,7 +4,7 @@ from django.conf import settings import datetime from sqlalchemy import create_engine -def create_connection(db_file): +def create_connection(db_file, type=1): """ create a database connection to the SQLite database specified by the db_file :param db_file: database file @@ -13,11 +13,13 @@ def create_connection(db_file): conn = None try: path = 'sqlite:///' + str(db_file) - engine = create_engine(path) - conn = engine.connect() + if type == 1: + return create_engine(path) + else: + return create_engine(path).connect() except Exception as e: print(e) - return conn + return None diff --git a/hr_module/handling_functions/monthly_planning_functions.py b/hr_module/handling_functions/monthly_planning_functions.py index 47ad7f1..6e4a21a 100644 --- a/hr_module/handling_functions/monthly_planning_functions.py +++ b/hr_module/handling_functions/monthly_planning_functions.py @@ -1,8 +1,8 @@ -from sqlalchemy.orm import sessionmaker -from sqlalchemy import create_engine + from django.conf import settings -from ..models import Employee, TimeModel, Plan +import pandas as pd +from ..models import Employee, Plan import datetime @@ -31,8 +31,7 @@ def insert_into_plan(user, start_date, end_date, start_time, daily_hours, activi 6: timemodel['sun']} days = (end_date - start_date).days - overlaps = [] - inserted = [] + 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) @@ -45,20 +44,21 @@ def insert_into_plan(user, start_date, end_date, start_time, daily_hours, activi end_time=end_time, activity_type=activity_type) plan.save() - inserted.append({'username': username.pk, + log.append({'username': username.pk, 'date': date_to_add, 'begin_time': start_time, 'end_time': end_time, - 'activity_type': activity_type}) + 'activity_type': activity_type, + 'status': 'imported'}) else: - overlaps.append({'username': username.pk, + log.append({'username': username.pk, 'date': date_to_add, 'begin_time': start_time, 'end_time': end_time, - 'activity_type': activity_type}) - return {'overlaps': overlaps, - 'inserted': inserted} + 'activity_type': activity_type, + 'status': 'failed due to conflicting overlap'}) + return log def check_conflicting_records(username, date, start_time, end_time): @@ -74,4 +74,12 @@ def check_conflicting_records(username, date, start_time, end_time): else: return False else: - return False \ No newline at end of file + return False + + +def create_planning_operation_report(dict_, current_user): + df = pd.DataFrame(dict_) + filename = current_user + '_' + datetime.datetime.now().isoformat() + '.xlsx' + path_temp = settings.IMPORT_REPORT_STORAGE + filename + df.to_excel(path_temp, index=False) + return filename \ No newline at end of file diff --git a/hr_module/migrations/0001_initial.py b/hr_module/migrations/0001_initial.py new file mode 100644 index 0000000..0ff6aca --- /dev/null +++ b/hr_module/migrations/0001_initial.py @@ -0,0 +1,76 @@ +# Generated by Django 3.1.3 on 2020-12-22 19:18 + +from django.db import migrations, models +import django.db.models.deletion + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('auth', '0012_alter_user_first_name_max_length'), + ] + + operations = [ + migrations.CreateModel( + name='Employee', + fields=[ + ('username', models.OneToOneField(db_column='username', on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='auth.user', to_field='username')), + ('department', models.CharField(max_length=200)), + ('manager_username', models.CharField(max_length=200)), + ('manager_flag', models.BooleanField()), + ], + ), + migrations.CreateModel( + name='TimeModel', + fields=[ + ('time_model_id', models.IntegerField(primary_key=True, serialize=False)), + ('daily_hours', models.DecimalField(decimal_places=2, max_digits=4)), + ('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()), + ], + ), + migrations.CreateModel( + name='TimeLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('begin_time', models.TimeField()), + ('end_time', models.TimeField()), + ('activity_type', models.CharField(max_length=100)), + ('username', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hr_module.employee')), + ], + ), + migrations.CreateModel( + name='PlanCreationLog', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('report_location', models.CharField(max_length=500)), + ('creation_date', models.DateTimeField(auto_now_add=True)), + ('username', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hr_module.employee')), + ], + ), + migrations.CreateModel( + name='Plan', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('date', models.DateField()), + ('begin_time', models.TimeField()), + ('end_time', models.TimeField()), + ('activity_type', models.CharField(max_length=100)), + ('username', models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hr_module.employee')), + ], + ), + migrations.AddField( + model_name='employee', + name='time_model', + field=models.ForeignKey(on_delete=django.db.models.deletion.PROTECT, to='hr_module.timemodel'), + ), + ] diff --git a/hr_module/migrations/__init__.py b/hr_module/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/hr_module/migrations/__pycache__/0001_initial.cpython-38.pyc b/hr_module/migrations/__pycache__/0001_initial.cpython-38.pyc new file mode 100644 index 0000000..17f22ed Binary files /dev/null and b/hr_module/migrations/__pycache__/0001_initial.cpython-38.pyc differ diff --git a/hr_module/migrations/__pycache__/__init__.cpython-38.pyc b/hr_module/migrations/__pycache__/__init__.cpython-38.pyc new file mode 100644 index 0000000..c4179f5 Binary files /dev/null and b/hr_module/migrations/__pycache__/__init__.cpython-38.pyc differ diff --git a/hr_module/models.py b/hr_module/models.py index 6cbf201..8102f71 100644 --- a/hr_module/models.py +++ b/hr_module/models.py @@ -48,3 +48,9 @@ class TimeLog(models.Model): begin_time = models.TimeField() end_time = models.TimeField() activity_type = models.CharField(max_length=100) + + +class PlanCreationLog(models.Model): + username = models.ForeignKey(Employee, on_delete=models.PROTECT) + report_location = models.CharField(max_length=500) + creation_date = models.DateTimeField(auto_now_add=True) \ No newline at end of file diff --git a/hr_module/static/css/calendar.css b/hr_module/static/css/calendar.css new file mode 100644 index 0000000..5fa4054 --- /dev/null +++ b/hr_module/static/css/calendar.css @@ -0,0 +1,110 @@ + +html, body { + font-family: sans-serif; +} + +table, th, td { + text-align: center; + border-collapse: collapse; + border-width: thin; + font-weight: lighter; + +} + +th { + background-color: darkred; + color: white; + border: solid 1px white; + border-width: thin; +} + +#calendar_container { + height: 257px; +} + +#months_block { + float: left; +} + +.month_container { + float: left; + margin: 10px; +} + +.calendar_button:hover { + background-color: white; + cursor: pointer; +} + +.calendar_button { + float: left; + margin-top: 10px; + margin-bottom: 10px; + height: 271px; + width: 30px; + background-color: lightgray; + display: flex; + align-items: center; + justify-content: center; +} + +#date_selector { + clear: both; + display: flex; + align-items: center; + justify-content: center; +} + +#year_selector, #month_selector { + margin-right: 5px; + margin-left: 5px; + height: 25px; + +} + +#button_load_selected_months{ + height: 25px; + margin-left: 5px; + width: 50px; +} + +.days_of_month { + font-size: 15px; + width: 32px; + height: 32px; + margin: auto; + vertical-align:middle; + display: table-cell; +} + +.days_of_month_current { + background-color: #ab9898; + color: white; +} + +.days_of_month_not_current { + background-color: #dbd7d7; + color: white; +} + +.days_of_month_today{ + background-color: darkred; +} + +.month_header { + font-size: 15px; + height: 28px; + margin: auto; + vertical-align:middle; + display: table-cell; +} + +.weekday_header { + font-size: 15px; + height: 32px; + text-transform: capitalize; + display: flex; + justify-content: center; + align-items: center; + +} \ No newline at end of file diff --git a/hr_module/static/css/calendar_local.css b/hr_module/static/css/calendar_local.css new file mode 100644 index 0000000..6c91be9 --- /dev/null +++ b/hr_module/static/css/calendar_local.css @@ -0,0 +1,5 @@ + + +.days_of_month_work { + background-color: darkslateblue; +} \ No newline at end of file diff --git a/hr_module/static/js/calendar.js b/hr_module/static/js/calendar.js new file mode 100644 index 0000000..7998a28 --- /dev/null +++ b/hr_module/static/js/calendar.js @@ -0,0 +1,264 @@ + +const monthsStrings = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'] +var today = new Date() + +function addCalendar(parent, monthsAhead = 1, currentMonth = new Date().getMonth() + 1, currentYear= new Date().getFullYear()){ + parent.innerHTML = '' + + var calendar = renderCalendarFor(currentYear, currentMonth, monthsAhead, 1) + + var container = document.createElement('div') + container.id = 'calendar_container' + + var buttonBack = createButton('calendar_button_back', 'calendar_button', '<') + buttonBack.addEventListener('click', function(){ + if (currentMonth == 1){ + currentMonth = 11 + currentYear = currentYear - 1 + } + addCalendar(parent, monthsAhead, currentMonth - 1, currentYear) + }) + container.appendChild(buttonBack) + container.appendChild(calendar) + + var buttonForward = createButton('calendar_button_forwards', 'calendar_button', '>') + buttonForward.addEventListener('click', function(){ + if (currentMonth == 12){ + currentMonth = 0 + currentYear = currentYear + 1 + } + addCalendar(parent, monthsAhead, currentMonth + 1, currentYear) + }) + + container.appendChild(buttonForward) + container.appendChild(createDateSelection()) + + parent.appendChild(container) + + var buttonGoToDate = document.getElementById('button_load_selected_months') + buttonGoToDate.addEventListener('click', function(){ + var currentYear = parseInt(document.getElementById('year_selector').value) + var currentMonth = parseInt(document.getElementById('month_selector').value) + addCalendar(parent, monthsAhead, currentMonth + 1, currentYear) + }) + + formatContainerSize() + +} + + +function formatContainerSize(){ + + var container = document.getElementById('calendar_container') + + var monthsBlock = document.getElementById('months_block') + var calendarButton = document.getElementById('calendar_button_back') + var dateSelector = document.getElementById('date_selector') + + var widthMonths = monthsBlock.offsetWidth + var heightMonths = monthsBlock.offsetHeight + var heightDateSelector = dateSelector.offsetHeight + var widthCalendarButton = calendarButton.offsetWidth * 2 + + var widthTotal = widthMonths + widthCalendarButton + var heightTotal = heightMonths + heightDateSelector + + container.setAttribute('style','height:' + heightTotal +'px; width:' + widthTotal + 'px'); + +} + + +function createDateSelection(){ + + var container = document.createElement('div') + container.id = 'date_selector' + + var goButton = document.createElement('button') + goButton.innerText = 'Go' + goButton.id = 'button_load_selected_months' + + var label = document.createElement('label') + label.setAttribute('for', 'years') + label.innerText = 'Go to: ' + + var selectYear = document.createElement('select') + selectYear.name='years' + selectYear.id = 'year_selector' + + spanBegin = 1990 + spanEnd = 2030 + yearsSpan = spanEnd - spanBegin + for (var i = 0; i < yearsSpan; i++){ + var option = document.createElement('option') + option.value = spanBegin + i + option.innerText = option.value + selectYear.appendChild(option) + } + selectYear.value = today.getFullYear() + + var selectMonth = document.createElement('select') + selectMonth.name='months' + selectMonth.id = 'month_selector' + for (var i = 0; i < 12; i++){ + var option = document.createElement('option') + option.value = i; + option.innerText = monthsStrings[i] + selectMonth.appendChild(option) + } + + selectMonth.value = today.getMonth() + + container.appendChild(label) + container.appendChild(selectYear) + container.appendChild(selectMonth) + container.appendChild(goButton) + return container +} + + +function createButton(id, className, innerText){ + var button = document.createElement('div') + button.id = id + button.className = className + button.innerText = innerText + return button +} + +function renderCalendarFor(year, month, nMonths, weekStart){ + var parent = document.createElement('div') + parent.id = 'months_block' + + var monthToCreate = month - 1 + for (var i = 0; i < nMonths; i++){ + monthToCreate = monthToCreate + 1 + if (monthToCreate == 13){ + monthToCreate = 1; + year = year + 1; + console.log(monthToCreate) + } + + var monthContainer = document.createElement('div') + monthContainer.className = 'month_container' + + monthContainer.appendChild(renderMonth(year, monthToCreate, weekStart)) + parent.appendChild(monthContainer) + } + return parent +} + + +function renderMonth(year, month, weekStart = 0, daysOfWeekNumeric){ + var daysOfWeek = ['sun', 'mon', 'tue', 'wed', 'thu', 'fri', 'sat'] + var daysOfWeekNumeric = [0, 1, 2, 3, 4, 5, 6] + for (var i = 0; i < weekStart; i++){ + daysOfWeek.push(daysOfWeek.shift()) + daysOfWeekNumeric.push(daysOfWeekNumeric.shift()) + } + + var table = document.createElement('table') + var monthString = monthsStrings[month - 1] + createHeaders(table, year, monthString, daysOfWeek) + createDates(table, year, month, daysOfWeekNumeric) + + return table +} + + +function createHeaders(table, year, month, daysOfWeek){ + let monthHeaderRow = document.createElement('tr') + let monthHeader = document.createElement('th') + monthHeader.innerText = month + ' ' + year + monthHeader.className = "month_header" + monthHeader.colSpan = 7 + monthHeaderRow.appendChild(monthHeader) + table.appendChild(monthHeaderRow) + + let header = document.createElement('tr') + for (var i = 0; i < daysOfWeek.length; i++){ + var headerDay = document.createElement('th') + var headerText = document.createElement('div') + headerText.innerText = daysOfWeek[i] + headerText.className = 'weekday_header' + headerDay.appendChild(headerText) + header.appendChild(headerDay) + table.appendChild(header) + } +} + +function createDates(table, year, month, daysOfWeekNumeric){ + var weekEnd = daysOfWeekNumeric[daysOfWeekNumeric.length - 1] + + var daysOfMonth = daysArray(year, month, daysOfWeekNumeric) + var row = document.createElement('tr') + for (var i = 0; i < daysOfMonth.length; i++){ + var date = daysOfMonth[i] + var dayNr = date.getDate() + var cell = document.createElement('td') + var dateString = new Date(date.getTime() - (date.getTimezoneOffset() * 60000 )) + .toISOString() + .split("T")[0]; + + var dateContainer = document.createElement('div') + dateContainer.innerText = dayNr + dateContainer.className = 'days_of_month' + dateContainer.id = 'date_' + dateString + + if (month - 1 == date.getMonth()){ + dateContainer.classList.add('days_of_month_current') + today.setHours(0, 0, 0, 0) + if(today.getTime()==date.getTime()){ + dateContainer.classList.add('days_of_month_today') + } + } else { + dateContainer.classList.add('days_of_month_not_current') + } + + + dateContainer.setAttribute('date', dateString) + + cell.appendChild(dateContainer) + + row.appendChild(cell) + + + if (date.getDay() == weekEnd) { + table.appendChild(row) + var row = document.createElement('tr') + + } + + } + table.appendChild(row) +} + +function daysArray(year, month, daysOfWeekNumeric) { + month = month - 1 + + var arr = [] + var daysInCurrentMonth = daysInMonth(year, month + 1) + + var firstDayOfMonth = new Date(year, month, 1).getDay() + var blankDaysStart = daysOfWeekNumeric.indexOf(firstDayOfMonth) * -1 + + for (var i = blankDaysStart + 1; i < 1; i++){ + var date = new Date(year, month, i) + arr.push(date) + } + + for (var i = 1; i < daysInCurrentMonth + 1; i++){ + var date = new Date(year, month, i) + arr.push(date) + } + + var daysToFill = arr.length + for (var i = 1; i < 42 - daysToFill + 1; i++){ + var date = new Date(year, month + 1, i) + arr.push(date) + } + + return arr +} + +function daysInMonth (year, month) { + return new Date(year, month, 0).getDate(); +} \ 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 9c126b2..6f07153 100644 --- a/hr_module/static/js/hr_module_schedule.js +++ b/hr_module/static/js/hr_module_schedule.js @@ -43,7 +43,7 @@ function appendFoundFilterOptions(data){ for (var i = 0; i < data.length; i++) { var caption = data[i]['caption']; - var value = data[i]['value']; + var value = data[i]['column_value']; console.log(caption) console.log(value) @@ -228,7 +228,7 @@ function postPlanToDb(){ json }), }).then((response) => { - return true; + return response; }).then((data) => { console.log(data); }); @@ -250,4 +250,17 @@ function getCookie(name) { } } return cookieValue; +} + + +function showPopup(){ + document.getElementById("popup_content").addEventListener("click", function(e) { + e.stopPropagation(); + }); + let popup = document.getElementById("login_popup"); + if (window.getComputedStyle(popup).getPropertyValue('display') === 'none'){ + popup.style.display ='flex'; + } else { + popup.style.display ='none'; + } } \ No newline at end of file diff --git a/hr_module/static/js/hr_module_show_schedule.js b/hr_module/static/js/hr_module_show_schedule.js new file mode 100644 index 0000000..9c61d5e --- /dev/null +++ b/hr_module/static/js/hr_module_show_schedule.js @@ -0,0 +1,89 @@ +const csrftoken = getCookie('csrftoken'); + +var parent = document.getElementById('calendar_box') +document.onload = addCalendar(parent, 3) + +document.getElementById('load_schedule_button').addEventListener('click', function(){ + fetchDays() +}) +document.getElementById('calendar_button_back').addEventListener('click', function(){ + fetchDays() +}) +document.getElementById('calendar_button_forwards').addEventListener('click', function(){ + fetchDays() +}) +document.getElementById('button_load_selected_months').addEventListener('click', function(){ + fetchDays() +}) + + +function fetchDays(){ + var host = 'http://' + window.location.host; + var fetch_url = host + '/hr_module/show_employee_plan_api' + + var range = searchedDateRange() + var startDate = range['min'] + var endDate = range['max'] + var username = document.getElementById('username_input').value + + fetch(fetch_url, + { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'X-CSRFToken': csrftoken + }, + body: JSON.stringify({ + "username": username, + "start_date": startDate, + "end_date" : endDate + }), + }).then((response) => { + return response.json(); + }).then((data) => { + console.log(data); + adjustCalendar(data); + }); +} + +function adjustCalendar(data){ + + for (var i = 0; i < data.length; i++){ + var processedDate = data[i]['date'] + var processedActivityType = data[i]['activity_type'] + var nodeToChange = document.getElementById('date_' + processedDate) + nodeToChange.classList.add('days_of_month_' + processedActivityType) + } +} + + +function searchedDateRange(){ + var dates = document.getElementsByClassName('days_of_month_current') + + var datesArray = [] + for (var i = 0; i < dates.length; i++){ + var dateAttr = new Date(dates[i].getAttribute('date')) + datesArray.push(dateAttr) + } + var minDate = new Date(Math.min.apply(null, datesArray)) + var maxDate = new Date(Math.max.apply(null, datesArray)) + var out = {'min' : minDate, + 'max': maxDate} + return out +} + +function getCookie(name) { + let cookieValue = null; + if (document.cookie && document.cookie !== '') { + let cookies = document.cookie.split(';'); + for (let i = 0; i < cookies.length; i++) { + let cookie = cookies[i].trim(); + + if (cookie.substring(0, name.length + 1) === (name + '=')) { + cookieValue = decodeURIComponent(cookie.substring(name.length + 1)); + break; + } + } + } + return cookieValue; +} diff --git a/hr_module/templates/hr_module_import_success.html b/hr_module/templates/hr_module_import_success.html new file mode 100644 index 0000000..1bd052b --- /dev/null +++ b/hr_module/templates/hr_module_import_success.html @@ -0,0 +1,11 @@ +{% extends 'hr_module_base.html' %} + +{% load static %} + +{% block action_panel %} + +
Data has been imported successfully +
+ + +{% endblock %} diff --git a/hr_module/templates/hr_import_validation.html b/hr_module/templates/hr_module_import_validation.html similarity index 100% rename from hr_module/templates/hr_import_validation.html rename to hr_module/templates/hr_module_import_validation.html diff --git a/hr_module/templates/hr_module_schedule.html b/hr_module/templates/hr_module_schedule.html index 695dd2b..0193a7a 100644 --- a/hr_module/templates/hr_module_schedule.html +++ b/hr_module/templates/hr_module_schedule.html @@ -52,6 +52,10 @@ + s + {% endblock %} diff --git a/hr_module/templates/hr_module_show_schedule.html b/hr_module/templates/hr_module_show_schedule.html new file mode 100644 index 0000000..aa16875 --- /dev/null +++ b/hr_module/templates/hr_module_show_schedule.html @@ -0,0 +1,20 @@ +{% extends 'hr_module_base.html' %} + +{% load static %} + +{% block action_panel %} + + + +
+ + + +
+
+ + + + + +{% endblock %} diff --git a/hr_module/urls.py b/hr_module/urls.py index c3c69c3..c3edbd7 100644 --- a/hr_module/urls.py +++ b/hr_module/urls.py @@ -5,10 +5,11 @@ from . import views app_name = 'hr_module' urlpatterns = [ - path('', views.index, name='index'), + path('create_schedule', views.create_schedule, name='schedule'), 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'), - + path('new_plan_api', views.new_plan_api, name='new_plan_api'), + path('show_schedule', views.show_employee_plan, name='employee_schedule'), + path('show_employee_plan_api', views.show_employee_plan_api, name='show_employee_plan_api') ] \ No newline at end of file diff --git a/hr_module/views.py b/hr_module/views.py index 71485f4..0e9258c 100644 --- a/hr_module/views.py +++ b/hr_module/views.py @@ -1,18 +1,18 @@ 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 -from hr_module.handling_functions.monthly_planning_functions import insert_into_plan +from hr_module.handling_functions.monthly_planning_functions import insert_into_plan, create_planning_operation_report import pandas as pd import json -from .models import Employee -from django.core import serializers +from .models import Employee, PlanCreationLog, Plan from django.http import HttpResponse, JsonResponse, Http404 from django.db import connection +import datetime + # Create your views here. -def index(request): +def create_schedule(request): template_name = 'hr_module_schedule.html' - return render(request, template_name) @@ -35,17 +35,19 @@ def hr_import(request): df = pd.read_csv(request.session['df_path']) insert_excel(df) del request.session['df_path'] - return redirect('import_data') + template = 'hr_module_import_success.html' + return render(request, template) 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'): + 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') + template = 'hr_module_import_success.html' + return render(request, template) else: columns_user = ['first_name', @@ -89,15 +91,16 @@ def search_users_api(request): if searched_field == 'department': - cursor.execute('select department as caption, department as value from hr_module_employee ' + cursor.execute('select department as caption, department as column_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 ' + cursor.execute('select auth.first_name || %s || auth.last_name as caption, empl.manager_username as column_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 ' + cursor.execute('select auth.first_name || %s || auth.last_name as caption, empl.username as column_value from hr_module_employee empl ' 'inner join auth_user auth on empl.username = auth.username ', [' ',] ) @@ -148,11 +151,43 @@ def load_employees_api(request): return JsonResponse(response, safe=False) -def plan_api(request): +def new_plan_api(request): if request.method == 'POST': + user = request.user.username body = json.loads(request.body)['json'] + log = [] for item in body: insert_result = insert_into_plan(item['username'], item['date_start'], item['date_end'], item['start_time'], item['daily_hours'], item['activity_type'], item['timemodel_pattern']) - print(insert_result) - response = '' - return JsonResponse(response, safe=False) + log = log + insert_result + + report_location = create_planning_operation_report(log, user) + print(user) + user_obj = Employee.objects.get(pk=user) + plan_creation_log = PlanCreationLog(username=user_obj, report_location=report_location) + plan_creation_log.save() + return JsonResponse(log) + + +def show_employee_plan(request): + template = 'hr_module_show_schedule.html' + return render(request, template) + + +def show_employee_plan_api(request): + + if request.method == 'POST': + body = json.loads(request.body) + username = body['username'] + start_date = body['start_date'].split('T')[0] + end_date = body['end_date'].split('T')[0] + + start_date = datetime.datetime.strptime(start_date, '%Y-%m-%d') + end_date = datetime.datetime.strptime(end_date, '%Y-%m-%d') + + print(username, start_date, end_date) + + user_obj = Employee.objects.get(pk=username) + + query_result = Plan.objects.filter(username=user_obj, date__range= [start_date, end_date]) + response = list(query_result.values()) + return JsonResponse(response, safe=False) \ No newline at end of file diff --git a/import_reports/admin_2020-12-22T19:08:15.299016.xlsx b/import_reports/admin_2020-12-22T19:08:15.299016.xlsx new file mode 100644 index 0000000..f59185d Binary files /dev/null and b/import_reports/admin_2020-12-22T19:08:15.299016.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:09:05.123287.xlsx b/import_reports/admin_2020-12-22T19:09:05.123287.xlsx new file mode 100644 index 0000000..915716e Binary files /dev/null and b/import_reports/admin_2020-12-22T19:09:05.123287.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:09:28.658828.xlsx b/import_reports/admin_2020-12-22T19:09:28.658828.xlsx new file mode 100644 index 0000000..00b2b6e Binary files /dev/null and b/import_reports/admin_2020-12-22T19:09:28.658828.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:11:49.978261.xlsx b/import_reports/admin_2020-12-22T19:11:49.978261.xlsx new file mode 100644 index 0000000..ac7c445 Binary files /dev/null and b/import_reports/admin_2020-12-22T19:11:49.978261.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:13:02.417671.xlsx b/import_reports/admin_2020-12-22T19:13:02.417671.xlsx new file mode 100644 index 0000000..2519c59 Binary files /dev/null and b/import_reports/admin_2020-12-22T19:13:02.417671.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:14:59.952208.xlsx b/import_reports/admin_2020-12-22T19:14:59.952208.xlsx new file mode 100644 index 0000000..b97ced7 Binary files /dev/null and b/import_reports/admin_2020-12-22T19:14:59.952208.xlsx differ diff --git a/import_reports/admin_2020-12-22T19:17:30.188295.xlsx b/import_reports/admin_2020-12-22T19:17:30.188295.xlsx new file mode 100644 index 0000000..dcb852b Binary files /dev/null and b/import_reports/admin_2020-12-22T19:17:30.188295.xlsx differ diff --git a/import_reports/admin_2020-12-26T16:46:57.200845.xlsx b/import_reports/admin_2020-12-26T16:46:57.200845.xlsx new file mode 100644 index 0000000..51a4de5 Binary files /dev/null and b/import_reports/admin_2020-12-26T16:46:57.200845.xlsx differ diff --git a/import_reports/admin_2020-12-26T16:48:14.407064.xlsx b/import_reports/admin_2020-12-26T16:48:14.407064.xlsx new file mode 100644 index 0000000..d54ecaa Binary files /dev/null and b/import_reports/admin_2020-12-26T16:48:14.407064.xlsx differ diff --git a/import_reports/admin_2020-12-26T16:49:58.769368.xlsx b/import_reports/admin_2020-12-26T16:49:58.769368.xlsx new file mode 100644 index 0000000..fbd7a3b Binary files /dev/null and b/import_reports/admin_2020-12-26T16:49:58.769368.xlsx differ diff --git a/temp/admin2020-12-22T18:09:47.063879.xlsx b/temp/admin2020-12-22T18:09:47.063879.xlsx new file mode 100644 index 0000000..ff2e96f Binary files /dev/null and b/temp/admin2020-12-22T18:09:47.063879.xlsx differ diff --git a/temp/import_file.csv b/temp/import_file.csv index f85f523..4b86890 100644 --- a/temp/import_file.csv +++ b/temp/import_file.csv @@ -1,6 +1,6 @@ ,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,Janina,Kowalska,kowalskaja,kowalskaja@company.com,0,1,0,test department,test department0,1,0 +2,Tadeusz,Tadeuszowicz,tadeuszowiczta,tadeuszowiczta@company.com,0,1,0,dfdfdv,dfdfdv0,1,0 +3,Aleksander,Lukaszenko,lukaszenkoal,lukaszenkoal@company.com,0,1,0,fsdfgfg,hitlerad,1,0 +4,Adolf,Hitler,hitlerad,hitlerad@company.com,0,1,0,fg,hitlerad,1,0 diff --git a/timefall/__pycache__/settings.cpython-38.pyc b/timefall/__pycache__/settings.cpython-38.pyc index f2bc508..c9307bf 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 225e1d9..01422e0 100644 --- a/timefall/settings.py +++ b/timefall/settings.py @@ -131,4 +131,5 @@ STATICFILES_DIRS = [ ] -TMP_FILE_STORAGE = os.path.join(BASE_DIR, 'temp/') \ No newline at end of file +TMP_FILE_STORAGE = os.path.join(BASE_DIR, 'temp/') +IMPORT_REPORT_STORAGE = os.path.join(BASE_DIR, 'import_reports/') \ No newline at end of file