diff --git a/tailbone/views/master.py b/tailbone/views/master.py index e57a6104..5534a966 100644 --- a/tailbone/views/master.py +++ b/tailbone/views/master.py @@ -2145,8 +2145,8 @@ class MasterView(View): os.remove(path) response.content_length = len(response.body) - response.content_type = b'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - response.content_disposition = b'attachment; filename={}.xlsx'.format(self.get_grid_key()) + response.content_type = str('application/vnd.openxmlformats-officedocument.spreadsheetml.sheet') + response.content_disposition = str('attachment; filename={}.xlsx').format(self.get_grid_key()) return response def get_xlsx_fields(self): diff --git a/tailbone/views/shifts/core.py b/tailbone/views/shifts/core.py index 9e439cfa..45574426 100644 --- a/tailbone/views/shifts/core.py +++ b/tailbone/views/shifts/core.py @@ -93,6 +93,7 @@ class WorkedShiftsView(MasterView): """ model_class = model.WorkedShift url_prefix = '/shifts/worked' + results_downloadable_xlsx = True has_versions = True grid_columns = [ @@ -125,6 +126,10 @@ class WorkedShiftsView(MasterView): # TODO: these sorters should be automatic once we fix the schema g.sorters['start_time'] = g.make_sorter(model.WorkedShift.punch_in) g.sorters['end_time'] = g.make_sorter(model.WorkedShift.punch_out) + # TODO: same goes for these renderers + g.set_type('start_time', 'datetime') + g.set_type('end_time', 'datetime') + # (but we'll still have to set this) g.set_sort_defaults('start_time', 'desc') g.set_renderer('length', render_shift_length) @@ -157,6 +162,29 @@ class WorkedShiftsView(MasterView): url = self.request.route_url('employees.view', uuid=employee.uuid) return tags.link_to(text, url) + def get_xlsx_fields(self): + fields = super(WorkedShiftsView, self).get_xlsx_fields() + + # add employee name + i = fields.index('employee_uuid') + fields.insert(i + 1, 'employee_name') + + return fields + + def get_xlsx_row(self, shift, fields): + row = super(WorkedShiftsView, self).get_xlsx_row(shift, fields) + + # add custom fields + row['employee_name'] = shift.employee.person.display_name + + # localize start and end times (Excel requires time with no zone) + if shift.punch_in: + row['punch_in'] = localtime(self.rattail_config, shift.punch_in, from_utc=True, tzinfo=False) + if shift.punch_out: + row['punch_out'] = localtime(self.rattail_config, shift.punch_out, from_utc=True, tzinfo=False) + + return row + def includeme(config): ScheduledShiftsView.defaults(config)