]> git.parisson.com Git - mezzo.git/commitdiff
[Timesheet] : export timesheet with leaved days
authorEmilie Zawadzki <zawadzki@ircam.fr>
Tue, 17 Jan 2017 18:59:48 +0000 (19:59 +0100)
committerEmilie Zawadzki <zawadzki@ircam.fr>
Tue, 17 Jan 2017 18:59:48 +0000 (19:59 +0100)
app/organization/network/admin.py
app/organization/network/api.py
app/organization/network/management/commands/export-ircam-timesheet-xls.py
app/organization/network/management/commands/import-ircam-project.py
app/organization/network/management/commands/import-ircam-timesheet-xls.py
app/organization/network/utils.py
app/organization/network/views.py

index 39c89dd4b215ee283919bc9b76c04e6e4d92e3f9..7d8311123590de6c94ae248b8a62aebd4b9e3d64 100644 (file)
@@ -21,6 +21,7 @@
 
 from django.contrib import admin
 from django import forms
+from django.http import HttpResponse
 from copy import deepcopy
 from dal import autocomplete
 from dal_select2_queryset_sequence.views import Select2QuerySetSequenceView
@@ -32,7 +33,7 @@ from organization.pages.models import *
 from organization.core.admin import *
 from organization.pages.admin import PageImageInline, PageBlockInline, PagePlaylistInline, DynamicContentPageInline, PageRelatedTitleAdmin
 from organization.shop.models import PageProductList
-from django.http import HttpResponse
+from organization.network.utils import TimesheetXLS
 
 class OrganizationAdminInline(StackedDynamicInlineAdmin):
 
@@ -274,8 +275,6 @@ class TrainingTopicAdmin(BaseTranslationModelAdmin):
     model = TrainingTopic
 
 
-
-
 class PersonActivityTimeSheetAdmin(BaseTranslationOrderedModelAdmin):
     model = PersonActivityTimeSheet
     search_fields = ['year','activity__person__last_name', "project__title"]
index 268b5c8b11b336e0be6c1e83e15ac4705801e72f..af2773c4a17ff9259f79fe471df8856d6e99fa0b 100644 (file)
@@ -22,7 +22,7 @@ def figgo_request(method):
 def get_active_persons():
     r_p_active = figgo_request('api/users?fields=id,lastname,firstname')
     r_p_active = r_p_active.json()
-    return r_p_active['data']
+    return r_p_active['data'] if 'data' in r_p_active else {}
 
 
 def get_inactive_persons():
@@ -30,13 +30,14 @@ def get_inactive_persons():
     yesterday = yesterday.isoformat()
     r_p_inactive = figgo_request('api/users?dtContractEnd=until,'+yesterday+',null&fields=id,lastname,firstname')
     r_p_inactive = r_p_inactive.json()
-    return r_p_inactive['data']
+    return r_p_inactive['data'] if 'data' in r_p_inactive else {}
 
 
 def get_leave_periods(date_from, date_to, person_external_id):
     leave_periods = figgo_request('api/leaves?date=between,'+str(date_from)+','+str(date_to)+'&fields=owner.name,owner.login,owner.mail,owner.matricule,duration,name,date,status,leaveScope&owner.id='+str(person_external_id))
     leave_periods = leave_periods.json()
-    return leave_periods['data']
+
+    return leave_periods['data'] if 'data' in leave_periods else {}
 
 
 def get_leave_days(date_from, date_to, person_external_id):
index 44231eff7c980375b2878ac8db60da94551be557..93a813aa8d133b0d10c2521fbbe9a23336dd3770 100644 (file)
@@ -91,6 +91,7 @@ class IrcamTimeSheet(object):
     def set_work_package(self, person_activity_timesheet):
         """ set contract id of the project """
 
+
 class Command(BaseCommand):
     help = """Import Person data from IRCAM's legacy XLS management file.
               python manage.py import-ircam-timesheet-xls -s /srv/backup/TemplateInputTimeSheet2015-16.xlsx
@@ -146,6 +147,7 @@ class Command(BaseCommand):
                     # get month
                     month = int(sheet.cell_value(xls.first_month_row, col_index))
                     self.logger.info('Processing', 'year : ' + str(curr_year) + " | month : " + str(month))
+
                     # calculate the current date
                     curr_date = datetime.date(curr_year, month, 1)
 
index 7440834405d9cb44f8912c94e3d01247ac24b6ab..1ca335110ae651ad69c2caf611aa75ddd18eed5d 100644 (file)
@@ -94,6 +94,7 @@ class IrcamXLS:
 class IrcamProjects(object):
 
     def __init__(self, project_name):
+        print("project", project_name)
         project, is_created = Project.objects.get_or_create(title=project_name)
         self.project = project
         self.is_created = is_created
index 50394f3cb21a74d51f9e90661bc13d000cf69cf0..3efed67f084338532c2c91d1511229b9614c3731 100644 (file)
@@ -118,7 +118,7 @@ class IrcamTimeSheet(object):
 
 class Command(BaseCommand):
     help = """Import Person data from IRCAM's legacy XLS management file.
-              python manage.py import-ircam-timesheet-xls -s /srv/backup/TemplateInputTimeSheet2015-16.xlsx
+              python manage.py import-ircam-timesheet-xls -s /srv/backup/time_sheet_2015_V3_H2020.xls
     """
 
     option_list = BaseCommand.option_list + (
@@ -155,10 +155,8 @@ class Command(BaseCommand):
             for person in persons:
                 period_str = sheet.cell_value(xls.period_row, xls.period_col)
                 periods = findall(r'\d{1,2}/\d{1,2}/\d{4}', period_str)
-                print("periods", periods, person, period_str)
                 date_from = dateutil.parser.parse(periods[0])
                 date_to = dateutil.parser.parse(periods[1])
-                print("date_from", type(date_from), "date_to", type(date_to))
                 curr_range_date = datetimerange.DateTimeRange(date_from, date_to)
                 curr_year = date_to.year
 
@@ -213,7 +211,6 @@ class Command(BaseCommand):
                             # processing projects
                             if end_project_list_row == 0:
                                 # check if project exists
-                                print("project_id_str", project_id_str, project_row_index, xls.first_project_col - 1)
                                 project, is_created = Project.objects.get_or_create(external_id=str(project_id_str))
                                 if is_created:
                                     project.title = sheet.cell_value(project_row_index, xls.first_project_col)
@@ -233,19 +230,16 @@ class Command(BaseCommand):
 
                         # processing work package
                         work_package_row_index = project_row_index + 1
-                        print("WK", sheet.cell_value(work_package_row_index, xls.first_project_col))
                         while sheet.cell_value(work_package_row_index, xls.first_project_col) != "Date entrĂ©e":
 
                             # get project
                             project_external_id = int(sheet.cell_value(work_package_row_index, xls.first_project_col - 1))
-                            print("project_external_id", project_external_id)
                             project = Project.objects.get(external_id=str(project_external_id))
 
                             # check if project exists
                             if project:
 
                                 # list all work package
-                                print(work_package_row_index, col_index)
                                 wk_p_str = sheet.cell_value(work_package_row_index, col_index)
                                 if wk_p_str :
                                     self.logger.info('Processing', 'work packages : ' + str(wk_p_str) + " | project" + project.external_id + " - " + project.title)
@@ -255,7 +249,6 @@ class Command(BaseCommand):
                                     elif isinstance(wk_p_str, float):
                                         i, d = divmod(wk_p_str, 1)
                                         wk_p_list = (int(i), int(d))
-                                        print("wk_p_list", wk_p_list, wk_p_str)
                                     # link work packages to timesheet
                                     for wk_p_num in wk_p_list:
                                         wk_p_num = str(wk_p_num)
@@ -288,3 +281,4 @@ class Command(BaseCommand):
                             pat.save()
 
                 self.logger.info('Processing', '_________________________ Number of record : ' + str(processing_counter) + ' _________________________')
+                print("Person : " + person.title + " | Number of record : " + str(processing_counter))
index 7b7eb32bcbdebc09177bfa5fc6adcef84c94385d..f2e0ef00b71fbab9d260da4481fc102c93cfc4ff 100644 (file)
@@ -2,11 +2,12 @@
 import pandas as pd
 import csv
 from django.http import HttpResponse
-from xlwt import Workbook
+from xlwt import *
 import calendar
 from organization.network.api import *
 import datetime
-
+from collections import defaultdict, OrderedDict
+from pprint import pprint
 
 
 def get_nb_half_days_by_period(date_from, date_to):
@@ -45,22 +46,23 @@ def get_nb_half_days_by_period(date_from, date_to):
 
 def get_nb_half_days_by_period_per_month(date_from, date_to):
     day_list = pd.date_range(date_from, date_to).tolist()
-    day_dict = {
-      "monday_am": 0,
-      "monday_pm": 0,
-      "tuesday_am": 0,
-      "tuesday_pm": 0,
-      "wednesday_am": 0,
-      "wednesday_pm": 0,
-      "thursday_am": 0,
-      "thursday_pm": 0,
-      "friday_am": 0,
-      "friday_pm": 0,
-    }
 
     md_dict = {}
     for i in range(1,13):
-        md_dict[i] = day_dict
+        md_dict[i] = {
+          "monday_am": 0,
+          "monday_pm": 0,
+          "tuesday_am": 0,
+          "tuesday_pm": 0,
+          "wednesday_am": 0,
+          "wednesday_pm": 0,
+          "thursday_am": 0,
+          "thursday_pm": 0,
+          "friday_am": 0,
+          "friday_pm": 0,
+        }
+
+    # for each day of the period
     for day in day_list :
         if day.dayofweek == 0:
             md_dict[day.month]['monday_am'] += 1
@@ -77,16 +79,23 @@ def get_nb_half_days_by_period_per_month(date_from, date_to):
         if day.dayofweek == 4:
             md_dict[day.month]['friday_am'] += 1
             md_dict[day.month]['friday_pm'] += 1
+
     return md_dict
 
 
+class TimesheetXLS2(object):
+
+    def __init__(self, timesheets):
+        self.timesheets = timesheets.order_by('activity','project', 'year', 'month')
+
 
 class TimesheetXLS(object):
 
+    t_dict = OrderedDict()
     first_month_row = 5
     first_month_col = 4
     last_month_col = first_month_col + 13
-    project_margin_row = 6
+    project_margin_row = 4
     project_first_row = 6
     project_first_col = 0
     percent_margin = 1
@@ -97,11 +106,14 @@ class TimesheetXLS(object):
     hours_label = "Productive hours worked on project"
     hours_label_row = 8
     hours_label_col = 0
+    wk_margin = 3
     wk_label = "Workpackages to which the person has contributed"
     wk_label_row = 9
     wk_label_col = 0
+    accounting_margin = 4
     accounting_label = "Date of accounting by person working on the action"
     accounting_label_col = 0
+    validation_margin = 5
     validation_label_row = 0
     validation_label = "Date of validation by the superior"
     validation_label_col = 0
@@ -117,13 +129,20 @@ class TimesheetXLS(object):
     grant_row = 1
     type_personal_col = 2
     type_personal_row = 3
-    work_package_margin = 3
-    accounting_margin = 3
-    validation_margin = 4
+
 
     def __init__(self, timesheets):
-        self.timesheets = timesheets.order_by('activity','project', 'month')
+        self.timesheets = timesheets.order_by('activity','project', 'year', 'month')
         self.book = Workbook()
+        self.grey_pattern = Pattern()
+        self.grey_pattern.pattern = Pattern.SOLID_PATTERN
+        self.grey_pattern.pattern_fore_colour = Style.colour_map['gray25']
+        self.header_style = XFStyle()
+        self.header_style.pattern = self.grey_pattern
+        self.date_style = XFStyle()
+        self.date_style.num_format_str = 'M/D/YY'
+
+
 
     def init_layout(self, sheet, year):
         sheet.write(self.title_row, self.title_col, "TIME RECORDING FOR A HORIZON 2020 ACTION")
@@ -134,93 +153,123 @@ class TimesheetXLS(object):
         sheet.write(self.type_personal_row, self.type_personal_col, "Type of personnel :")
         row = sheet.row(self.first_month_row)
         for i in range(self.first_month_col, self.last_month_col):
-            row.write(i, calendar.month_name[i - self.first_month_col] +"-"+ str(year % 100))
-
-    def export(self):
-        curr_project = ''
-        project_row_index = self.project_first_row
-        percent_label_row_index = self.percent_label_row
-        hours_label_row_index = self.hours_label_row
-        wk_label_row_index = self.wk_label_row
+            row.write(i, calendar.month_name[i - self.first_month_col] +"-"+ str(year % 100), self.header_style)
 
+    def format(self):
+        self.t_dict = OrderedDict()
         for timesheet in self.timesheets:
-            print("TIME SHEET", timesheet.id)
-            try :
-                self.sheet = self.book.add_sheet(timesheet.activity.person.slug)
-                self.init_layout(self.sheet, timesheet.year)
-
-                # calculate nb of worked hours
+            person_slug = timesheet.activity.person.slug
+            # if new person
+            if not person_slug in self.t_dict:
+                self.t_dict[person_slug] = {}
+                # caculate for each person leaved days in year
                 date_from = datetime.date(timesheet.year, 1, 1)
                 date_to = datetime.date(timesheet.year, 12, 31)
                 nb_half_days = get_nb_half_days_by_period_per_month(date_from, date_to)
                 leave_days = get_leave_days_per_month(date_from, date_to, timesheet.activity.person.external_id)
-                # substract none worked half days
-                # print(nb_half_days)
-                # print("****************************")
-                # print(leave_days)
-                # print("****************************")
+                worked_hours_by_month = {"test" : "1"}
+                # for each month
                 for m_key, m_val in nb_half_days.items():
-                    if m_key in leave_days :
-                        for nhd_k, nhd_v in m_val.items():
-                            if nhd_k in leave_days[m_key]:
-                                print(m_key, nhd_k, leave_days[m_key][nhd_k], nb_half_days[m_key][nhd_k])
-                                nb_half_days[m_key][nhd_k] = nhd_v - leave_days[m_key][nhd_k]
-                                print(m_key, nhd_k, nb_half_days[m_key][nhd_k])
-                print(nb_half_days)
-            except:
-                pass
-
-            if curr_project == '':
-                curr_project = timesheet.project
-            elif curr_project != timesheet.project:
-                curr_project = timesheet.project
-                project_row_index += self.project_margin_row
-                percent_label_row_index += self.project_margin_row
-                hours_label_row_index += self.project_margin_row
-                wk_label_row_index += self.project_margin_row
-
-            # percent
-            self.sheet.write(project_row_index + self.percent_margin, timesheet.month + self.first_month_col, timesheet.percentage)
-
-
-
-            # multiplying by nb of theoretical worked hours
-            #
-            # theo_worked_hours =
-            # timesheet.activity.monday_am =
-
-            # multiplying by percent
-
-            # work packages
-            work_packages = [str(wk.number) for wk in timesheet.work_packages.all()]
-            work_packages = ",".join(work_packages)
-            self.sheet.write(project_row_index + self.work_package_margin, timesheet.month + self.first_month_col, work_packages)
-
-            try :
-                self.sheet.write(project_row_index, self.project_first_col, timesheet.project.__str__())
-                self.sheet.write(project_row_index, self.project_first_col + 1, timesheet.project.external_id)
-                self.sheet.write(percent_label_row_index, self.percent_label_col, self.percent_label)
-                self.sheet.write(hours_label_row_index, self.hours_label_col, self.hours_label)
-                self.sheet.write(wk_label_row_index, self.wk_label_col, self.wk_label)
-            except:
-                pass
-
-            # check were is the lower cell
-            if wk_label_row_index > self.validation_label_row:
-                self.validation_label_row = wk_label_row_index
-            elif wk_label_row_index == self.validation_label_row:
-                try :
-                    # accounting date
-                    self.sheet.write(self.validation_label_row + 1, timesheet.month + self.first_month_col, timesheet.accounting)
-
-                    # validation date
-                    self.sheet.write(self.validation_label_row + 2, timesheet.month + self.first_month_col, timesheet.validation)
-                except:
-                    pass
+                    # for each week day
+                    for nhd_k, nhd_v in m_val.items():
+                        if not m_key in worked_hours_by_month:
+                            worked_hours_by_month[m_key] = 0
+                        half_day_nb_hours = getattr(timesheet.activity, nhd_k)
+                        if not half_day_nb_hours is None :
+                            # is the person has been present during current m_key month ?
+                            if m_key in leave_days :
+                                if nhd_k in leave_days[m_key]:
+                                    # is the person has been present during current half day nhd_d ?
+                                    worked_hours_by_month[m_key] += (nb_half_days[m_key][nhd_k] - leave_days[m_key][nhd_k]) * half_day_nb_hours
+                                else :
+                                    # if not, count theorical nb oh hours for this half day
+                                    worked_hours_by_month[m_key] += nb_half_days[m_key][nhd_k] * half_day_nb_hours
+                            # if not, count theorical nb of hours for whole month
+                            else :
+                                worked_hours_by_month[m_key] += nb_half_days[m_key][nhd_k] * half_day_nb_hours
+                        else :
+                            # missing data...
+                            worked_hours_by_month[m_key] = 0
+
+            # for each percent time worked on a project...
+            project_slug = timesheet.project.slug
+            if not project_slug in self.t_dict[person_slug]:
+                self.t_dict[person_slug][project_slug] = []
+            # ...calculate nb of worked hours proportionally
+            # the property 'worked_hours' does not exists in the model, it just calculated on the fly
+            timesheet.worked_hours = worked_hours_by_month[timesheet.month] * timesheet.percentage
+            self.t_dict[person_slug][project_slug].append(timesheet)
+        return self.t_dict
+
+
+    def export(self):
+        curr_project = ''
+        percent_label_row_index = self.percent_label_row
+        hours_label_row_index = self.hours_label_row
+        # for each person
+        for person_k, person_v in self.t_dict.items():
+            # for each project
+            project_row_last = (len(person_v) - 1) * self.project_margin_row + self.project_first_row
+            for project_k, project_v in person_v.items():
+                project_position = list(person_v.keys()).index(project_k)
+                project_row_index = self.project_margin_row * project_position + self.project_first_row
+                # for each timesheet
+                for timesheet in project_v:
+                    try :
+                        self.sheet = self.book.add_sheet(person_k)
+                        self.init_layout(self.sheet, timesheet.year)
+                    except:
+                        pass
+
+                    # project name
+                    try :
+                        self.sheet.write(project_row_index, self.project_first_col, timesheet.project.title, self.header_style)
+                    except:
+                        pass
+
+
+                    # percent
+                    try:
+                        self.sheet.write(project_row_index + self.percent_margin, timesheet.month + self.first_month_col, timesheet.percentage)
+                    except :
+                        pass
+
+                    # nb worked hours
+                    try:
+                        self.sheet.write(project_row_index + self.hours_margin, timesheet.month + self.first_month_col, timesheet.worked_hours)
+                    except :
+                        pass
+
+
+                    # work packages
+                    work_packages = [str(wk.number) for wk in timesheet.work_packages.all()]
+                    work_packages = ",".join(work_packages)
+                    try :
+                        self.sheet.write(project_row_index + self.wk_margin, timesheet.month + self.first_month_col, work_packages)
+                    except:
+                        pass
+
+                    try :
+                        self.sheet.write(project_row_index, self.project_first_col + 1, timesheet.project.external_id, self.header_style)
+                        self.sheet.write(project_row_index + self.percent_margin, self.percent_label_col, self.percent_label)
+                        self.sheet.write(project_row_index + self.hours_margin, self.hours_label_col, self.hours_label)
+                        self.sheet.write(project_row_index + self.wk_margin, self.wk_label_col, self.wk_label)
+                    except:
+                        pass
+
+                    try :
+                        # accounting date
+                        self.sheet.write(project_row_last + self.accounting_margin, timesheet.month + self.first_month_col, timesheet.accounting, self.date_style)
+
+                        # validation date
+                        self.sheet.write(project_row_last + self.validation_margin, timesheet.month + self.first_month_col, timesheet.validation, self.date_style)
+                    except:
+                        pass
 
 
 
     def write(self):
+        self.format()
         self.export()
         response = HttpResponse(content_type="application/vnd.ms-excel")
         response['Content-Disposition'] = 'attachment; filename=users.xls'
index 45e2e7e5b12907275a134ee688f79909201e8e7d..41cb3045687dcf8ff2c2133790fe6ddb4ac52d3a 100644 (file)
@@ -31,7 +31,7 @@ from organization.network.models import *
 from organization.core.views import *
 from datetime import date
 from organization.network.forms import *
-from organization.network.utils import TimesheetXLS
+from organization.network.utils import TimesheetXLS, TimesheetXLS2
 
 
 class PersonListView(ListView):
@@ -175,4 +175,5 @@ class PersonActivityTimeSheetExportView(TimesheetAbstractView, View):
     def get(self, *args, **kwargs):
         timesheets = PersonActivityTimeSheet.objects.filter(activity__person__slug__exact=kwargs['slug'], year=kwargs['year'])
         xls = TimesheetXLS(timesheets)
-        return xls.write()
+        response = xls.write()
+        return response