|
@@ -0,0 +1,156 @@
|
|
|
|
+import xlsxwriter
|
|
|
|
+from xlsxwriter.utility import xl_range
|
|
|
|
+from datetime import datetime, timedelta
|
|
|
|
+
|
|
|
|
+class xlsx_creator():
|
|
|
|
+ style_header = {
|
|
|
|
+ 'bold': True,
|
|
|
|
+ 'border': 1,
|
|
|
|
+ 'align': 'center',
|
|
|
|
+ 'valign': 'vcenter'
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ def __init__(self, DATA, path='/tmp/'):
|
|
|
|
+ self.FileName= F"employee-attendance-{str(datetime.now())}.xlsx"
|
|
|
|
+ self.path = path+self.FileName
|
|
|
|
+ self.DATA = DATA
|
|
|
|
+ self.workbook = xlsxwriter.Workbook(self.path)
|
|
|
|
+ self.worksheet = self.workbook.add_worksheet()
|
|
|
|
+
|
|
|
|
+ def cook_xlsx(self):
|
|
|
|
+ self.create_header()
|
|
|
|
+ self.create_diff_date_and_hours()
|
|
|
|
+ self.create_sub_head()
|
|
|
|
+ self.create_body_data()
|
|
|
|
+ self.workbook.close()
|
|
|
|
+ return self.path
|
|
|
|
+
|
|
|
|
+ def create_header(self):
|
|
|
|
+ self.worksheet.set_row(0, 70)
|
|
|
|
+ style_header = self.workbook.add_format(self.style_header)
|
|
|
|
+ style_header.set_text_wrap()
|
|
|
|
+
|
|
|
|
+ colum = 0
|
|
|
|
+
|
|
|
|
+ for data in self.DATA:
|
|
|
|
+ text_header = F"{data['FIO']} \n посещаемость с {data['STARTDATE']}г. по {data['ENDDATE']}г."
|
|
|
|
+ self.worksheet.merge_range(self.get_column_range(0, colum, 0, colum+4), text_header, style_header)
|
|
|
|
+ colum += 6
|
|
|
|
+
|
|
|
|
+ def convert_str_to_datetime(self, date_string):
|
|
|
|
+ (h,m,s) = date_string.split(':')
|
|
|
|
+ return timedelta(hours=int(h), minutes=int(m), seconds=int(s))
|
|
|
|
+
|
|
|
|
+ def get_count_work_hours(self, DateAttendance):
|
|
|
|
+ count_work_hours = timedelta()
|
|
|
|
+ for x in DateAttendance:
|
|
|
|
+ count_work_hours += self.convert_str_to_datetime(self.return_correct_value(x["diffTime"]))
|
|
|
|
+
|
|
|
|
+ hours, remainder = divmod(count_work_hours.total_seconds(), 3600)
|
|
|
|
+ minutes, seconds = divmod(remainder, 60)
|
|
|
|
+ print(count_work_hours)
|
|
|
|
+ return F"{int(hours)}:{int(minutes)}:{int(seconds)}"
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def create_diff_date_and_hours(self):
|
|
|
|
+ style_body = self.workbook.add_format({
|
|
|
|
+ 'border': 1,
|
|
|
|
+ 'align': 'center',
|
|
|
|
+ })
|
|
|
|
+ style_header = self.workbook.add_format(self.style_header)
|
|
|
|
+ col_work_day_text = "Количество рабочих дней"
|
|
|
|
+ col_calendar_day = "Количество календарных дней"
|
|
|
|
+ col_work_hours = "Количество рабочих часов"
|
|
|
|
+ column = 0
|
|
|
|
+
|
|
|
|
+ for data in self.DATA:
|
|
|
|
+ self.worksheet.merge_range(self.get_column_range(1, column, 1, column+3),
|
|
|
|
+ col_work_day_text, style_header)
|
|
|
|
+ self.worksheet.write(1, column+4, len(data['DateAttendance']), style_body)
|
|
|
|
+
|
|
|
|
+ self.worksheet.merge_range(self.get_column_range(2, column, 2, column+3),
|
|
|
|
+ col_calendar_day, style_header)
|
|
|
|
+ self.worksheet.write(2, column+4, len(data['EmptyDatesAttendance']+data['DateAttendance']), style_body)
|
|
|
|
+
|
|
|
|
+ self.worksheet.merge_range(self.get_column_range(3, column, 3, column+3),
|
|
|
|
+ col_work_hours, style_header)
|
|
|
|
+ self.worksheet.write(3, column+4, self.get_count_work_hours(data['DateAttendance']), style_body)
|
|
|
|
+ column += 6
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def create_sub_head(self):
|
|
|
|
+ colum = 0
|
|
|
|
+ style_header = self.workbook.add_format(self.style_header)
|
|
|
|
+ style_header.set_text_wrap()
|
|
|
|
+ self.worksheet.set_row(4, 30)
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for data in self.DATA:
|
|
|
|
+ self.worksheet.write(4, colum, 'Д/н', style_header)
|
|
|
|
+ self.worksheet.write(4, colum+1, 'Дата', style_header)
|
|
|
|
+ self.worksheet.write(4, colum+2, 'Вход', style_header)
|
|
|
|
+ self.worksheet.write(4, colum+3, 'Выход', style_header)
|
|
|
|
+
|
|
|
|
+ self.worksheet.set_column(4, colum+4, 15)
|
|
|
|
+ self.worksheet.write(4, colum+4, 'Время пребывания', style_header)
|
|
|
|
+ colum += 6
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ def get_column_range(self, srow, scolumn, erow, ecolumn):
|
|
|
|
+ return xl_range(srow, scolumn, erow, ecolumn)
|
|
|
|
+
|
|
|
|
+ def sort_attendance(self, arr):
|
|
|
|
+ return sorted(arr, key=lambda x : datetime.strptime(self.return_correct_value(x['date']), '%d.%m.%Y'))
|
|
|
|
+
|
|
|
|
+ def is_bold_diff_time(self, val, s, b):
|
|
|
|
+ val = self.return_correct_value(val)
|
|
|
|
+
|
|
|
|
+ if len(val) > 0:
|
|
|
|
+ if int(val.split(':')[0]) > 7:
|
|
|
|
+ return b
|
|
|
|
+ return s
|
|
|
|
+
|
|
|
|
+ def is_bold_entrance(self, val, s, b):
|
|
|
|
+ val = self.return_correct_value(val)
|
|
|
|
+
|
|
|
|
+ if len(val) > 0:
|
|
|
|
+ hours = val.split(':')[0]
|
|
|
|
+ if int(hours) >= 9 and int(hours) <= 18:
|
|
|
|
+ return b
|
|
|
|
+ return s
|
|
|
|
+
|
|
|
|
+ def create_body_data(self):
|
|
|
|
+ colum = 0
|
|
|
|
+ style_body = self.workbook.add_format({
|
|
|
|
+ 'border': 1,
|
|
|
|
+ 'align': 'center',
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ style_body_with_bold = self.workbook.add_format({
|
|
|
|
+ 'border': 1,
|
|
|
|
+ 'align': 'center',
|
|
|
|
+ 'bold': True
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ for data in self.DATA:
|
|
|
|
+ body_data = (data['EmptyDatesAttendance']+data['DateAttendance'])
|
|
|
|
+ row = 5
|
|
|
|
+ for attendance in self.sort_attendance(body_data):
|
|
|
|
+ self.worksheet.write(row, colum, self.return_correct_value(attendance['wd']), style_body_with_bold)
|
|
|
|
+ self.worksheet.write(row, colum+1, self.return_correct_value(attendance['date']), style_body)
|
|
|
|
+
|
|
|
|
+ body_entrance_style = self.is_bold_entrance(attendance['entrance'], style_body, style_body_with_bold)
|
|
|
|
+ self.worksheet.write(row, colum+2, self.return_correct_value(attendance['entrance']), body_entrance_style)
|
|
|
|
+
|
|
|
|
+ self.worksheet.write(row, colum+3, self.return_correct_value(attendance['exit']), style_body)
|
|
|
|
+
|
|
|
|
+ body_diff_time = self.is_bold_diff_time(attendance['diffTime'], style_body, style_body_with_bold)
|
|
|
|
+ self.worksheet.write(row, colum+4, self.return_correct_value(attendance['diffTime']), body_diff_time)
|
|
|
|
+ row += 1
|
|
|
|
+ colum += 6
|
|
|
|
+
|
|
|
|
+ def return_correct_value(self, val):
|
|
|
|
+ if type(val).__name__ == 'list':
|
|
|
|
+ return val[0]
|
|
|
|
+ else:
|
|
|
|
+ return val
|