def set_data(self, employee_fullname, d, correction): self.year = d.year self.month = d.month self.info.setText( _("Correction for {} on {}").format(employee_fullname, date_to_my(d, True))) self.correction_time_widget.setText(str(correction))
def refresh_action(self): # Reimplements parent method ! self.remote_indicators_service.clear_caches() mainlog.debug("Refreshing {}".format(self.month_chooser.base_date)) # begin, end = month_period_as_date(self.month_chooser.base_date) begin, end = month_before(self.month_chooser.base_date, self.MONTHS_PERIOD - 1), self.month_chooser.base_date progress = make_progress(_("Collecting data..."), sum([len(x) - 1 for x in self.indicators])) mainlog.debug("Indicator run = {}".format( self._indicators_run(self.indicators))) for ind in self._indicators_run(self.indicators): ind._gather_data(begin, end) progress.setValue(progress.value() + 1) ind.repaint() for sf in self._sub_frames: if sf.original_title(): sf.set_title(sf.original_title().replace( "%MONTH%", date_to_my(self.month_chooser.base_date, full=True)))
def print_monthly_report(dao, month_date): strip_style = ParagraphStyle(name="regular", fontName='Helvetica-Bold', fontSize=16, spaceAfter=0, spaceBefore=0) s = ParagraphStyle(name="regular", fontName='Courrier', fontSize=7) order_style = ParagraphStyle(name="regular", fontName='Helvetica-Bold', fontSize=14, spaceAfter=6, spaceBefore=12) small = ParagraphStyle(name="regular", fontName='Helvetica', fontSize=8) small_right = ParagraphStyle(name="regular", fontName='Helvetica', fontSize=8, alignment=TA_RIGHT) client = ParagraphStyle(name="regular", fontName='Helvetica-Bold', fontSize=9) right_align = ParagraphStyle(name="right_align", fontName='Courier', fontSize=8, alignment=TA_RIGHT) right_align_bold = ParagraphStyle(name="right_align", fontName='Courier-Bold', fontSize=8, alignment=TA_RIGHT) complete_document = [] spacer = platypus.Spacer(1, 50) ts_begin = _first_moment_of_month(month_date) ts_end = _last_moment_of_month(month_date) # mainlog.debug("Turnover from {} to {} ({})".format(ts_begin, ts_end, month_date)) # data_ops = [[crlf_to_br(h) for h in [_('Ord.'),_('Description'),_('Hours'),_('Qties'),_('Sell\nprice'),_('To bill\nthis month'),_('Encours')]]] data_ops = [[ _('Ord.'), _('Description'), _('Hours'), _('Qties'), _('Sell\nprice'), _('To bill\nthis month'), _('Encours') ]] ts = platypus.TableStyle([('FONT', (0, 0), (-1, -1), 'Courier', 8)]) last_order_id = None total_sell_price = 0 total_encours = 0 total_to_facture = 0 sub_total_sell_price = 0 sub_total_encours = 0 sub_total_h_done = sub_total_h_planned = 0 sub_total_to_facture = 0 row = 1 first_row = True row_in_order = 0 mainlog.debug("dao.order_dao.order_parts_for_monthly_report(month_date):") for part_data in dao.order_dao.order_parts_for_monthly_report(month_date): if last_order_id != part_data.order_id: last_order_id = part_data.order_id if not first_row and row_in_order >= 2: # Display sums only if there is more than one row # for the order (if only one row, then showing a # sum doesn't add any information to the user) ts.add('LINEABOVE', (5, row), (-1, row), 0.5, colors.black) ts.add('LINEABOVE', (2, row), (2, row), 0.5, colors.black) data_ops.append([ '', '', Paragraph( '{} / {}'.format(duration_to_s(sub_total_h_done), duration_to_s(sub_total_h_planned)), small_right), '', '', # Paragraph(amount_to_short_s(sub_total_sell_price) or "0,00" ,right_align), Paragraph( amount_to_short_s(sub_total_to_facture) or "0,00", right_align_bold), Paragraph( amount_to_short_s(sub_total_encours) or "0,00", right_align) ]) row += 1 sub_total_sell_price = 0 sub_total_encours = 0 sub_total_h_done = sub_total_h_planned = 0 sub_total_to_facture = 0 row_in_order = 0 ts.add('LINEABOVE', (0, row), (-1, row), 0.5, colors.black) data_ops.append([ '', Paragraph(part_data.customer_name, client), '', '', '', '', '' ]) row += 1 facture_explain = "" q_out_this_month = part_data.part_qty_out - part_data.q_out_last_month # Only give an explanation if all the qty were not done # together if part_data.q_out_last_month > 0 and q_out_this_month > 0 and q_out_this_month < part_data.qty: facture_explain = "({}) ".format(q_out_this_month) if part_data.total_estimated_time > 0: qty_work = "{} / {}".format( duration_to_s(part_data.part_worked_hours) or "0,00", duration_to_s(part_data.total_estimated_time)) else: qty_work = "-" if part_data.qty > 0: qty_str = "{} / {}".format(part_data.part_qty_out, part_data.qty) else: qty_str = "-" data_ops.append([ Paragraph(part_data.human_identifier, small), Paragraph(part_data.description, small), Paragraph(qty_work, small_right), Paragraph(qty_str, small_right), Paragraph(amount_to_short_s(part_data.total_sell_price), right_align), Paragraph( facture_explain + amount_to_short_s(part_data.bill_this_month), right_align_bold), Paragraph(amount_to_short_s(part_data.encours), right_align) ]) # if part_data.bill_this_month or True: # print("{} {} {}".format(part_data.human_identifier, part_data.part_qty_out, amount_to_short_s(part_data.bill_this_month))) row_in_order += 1 row += 1 sub_total_sell_price += total_sell_price sub_total_to_facture += part_data.bill_this_month sub_total_encours += part_data.encours sub_total_h_done += part_data.part_worked_hours or 0 sub_total_h_planned += part_data.total_estimated_time or 0 total_to_facture += part_data.bill_this_month total_encours += part_data.encours first_row = False data_ops.append([ '', '', '', '', '', # Removed total_sell_price because it is misleading Paragraph(amount_to_short_s(total_to_facture), right_align_bold), Paragraph(amount_to_short_s(total_encours), right_align) ]) ts.add('LINEABOVE', (0, len(data_ops) - 1), (-1, len(data_ops) - 1), 1, colors.black) ts.add('FONT', (0, 0), (-1, 0), 'Helvetica-Bold', 9) ts.add('LINEBELOW', (0, 0), (-1, 0), 1, colors.black) t = platypus.Table(data_ops, repeatRows=1, colWidths=[ 1.50 * cm, 6 * cm, 2.5 * cm, 1.75 * cm, 2.25 * cm, 2.25 * cm ]) t.setStyle(ts) t.hAlign = "LEFT" complete_document.append(t) complete_document.append(platypus.Spacer(0, 10)) filename = make_pdf_filename("MonthlyOverview_") ladderDoc = basic_PDF(filename) ladderDoc.subject = _("Monthly financial report") ladderDoc.title = date_to_my(month_date, True) ladderDoc.build(complete_document, canvasmaker=NumberedCanvas) open_pdf(filename) return True
def refresh_action(self): global dao # mainlog.debug("refresh action started") self.hours_per_pers_subframe.set_title(date_to_my( self.base_date, True)) chrono.chrono_start() all_events_in_month = people_admin_service.events_for_month( self.base_date) employee_with_events = [ event.employee_id for event in all_events_in_month ] # mainlog.debug(all_events_in_month) self.all_events_in_year = people_admin_service.events_for_year( self.base_date.year) self.all_presences = all_presences = dao.employee_dao.presence_overview_for_month( self.base_date) all_correction_times = dict() for s in dao.month_time_synthesis_dao.load_all_synthesis( self.base_date.year, self.base_date.month): all_correction_times[s.employee_id] = s.correction_time special_activities = dao.special_activity_dao.find_on_month( self.base_date) employees = list( filter( lambda e: e.is_active or e.employee_id in all_presences or e. employee_id in all_correction_times or e.employee_id in special_activities or e.employee_id in employee_with_events, dao.employee_dao.list_overview())) self.employees = employees chrono.chrono_click() day_max = calendar.monthrange(self.base_date.year, self.base_date.month)[1] t_start = datetime(self.base_date.year, self.base_date.month, 1) t_end = datetime(self.base_date.year, self.base_date.month, day_max, 23, 59, 59, 999999) self._table_model.setRowCount(len(employees)) self._table_model.setColumnCount(1 + day_max + 3) headers = QStandardItemModel(1, 1 + day_max + 3) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(day_max): headers.setHeaderData(i + 1, Qt.Orientation.Horizontal, "{}".format(i + 1)) headers.setHeaderData(day_max + 1, Qt.Orientation.Horizontal, _("Correction")) headers.setHeaderData(day_max + 2, Qt.Orientation.Horizontal, _("Total")) headers.setHeaderData(day_max + 3, Qt.Orientation.Horizontal, _("Days off")) self.headers_view.setModel( headers) # qt's doc : The view does *not* take ownership self.header_model = headers self.headers_view.setModel( self.header_model) # qt's doc : The view does *not* take ownership # Compute all mondays indices monday = 0 if t_start.weekday() > 0: monday = 7 - t_start.weekday() all_mondays = [] while monday < day_max: all_mondays.append(monday) monday += 7 today = date.today() # mainlog.debug("Running on employees") for row in range(self._table_model.rowCount()): # Clear the line for col in range(0, 32): ndx = self._table_model.index(row, col) self._table_model.setData(ndx, None, Qt.BackgroundRole) self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData(ndx, None, Qt.DisplayRole) self._table_model.setData(ndx, None, Qt.UserRole) self._table_model.setData(ndx, None, Qt.UserRole + 1) # else: # self._table_model.setData(ndx,None,Qt.BackgroundRole) # else: # self._table_model.setData(ndx,None,Qt.DisplayRole) # self._table_model.setData(ndx,None,Qt.BackgroundRole) # Mark mondays for col in all_mondays: # col + 1 to account for the employee column self._table_model.setData( self._table_model.index(row, col + 1), QBrush(QColor(230, 230, 255)), Qt.BackgroundRole) # Mark today if today.month == self.base_date.month and today.year == self.base_date.year: self._table_model.setData( self._table_model.index(row, today.day), QBrush(QColor(255, 255, 128)), Qt.BackgroundRole) row = 0 for employee in employees: # employees are sorted self._table_model.setData(self._table_model.index(row, 0), employee.fullname, Qt.DisplayRole) # FIXME Use a delegate self._table_model.setData(self._table_model.index(row, 0), employee.employee_id, Qt.UserRole) # FIXME Use a delegate correction = 0 if employee.employee_id in all_correction_times: correction = all_correction_times[employee.employee_id] self._table_model.setData( self._table_model.index(row, day_max + 1), duration_to_hm(correction, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 1), None, Qt.DisplayRole) presence = 0 if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: import functools presence = functools.reduce( lambda acc, s: acc + s, all_presences[employee.employee_id], 0) presence += correction if presence != 0: self._table_model.setData(ndx, QBrush(Qt.GlobalColor.black), Qt.TextColorRole) self._table_model.setData( self._table_model.index(row, day_max + 2), duration_to_hm(presence, short_unit=True), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 2), None, Qt.DisplayRole) if employee.employee_id in all_presences and len( all_presences[employee.employee_id]) > 0: for b in range(len(all_presences[employee.employee_id])): ndx = self._table_model.index(row, b + 1) p = all_presences[employee.employee_id][b] if p > 0: self._table_model.setData( ndx, duration_to_hm(p, short_unit=True), Qt.DisplayRole) self._table_model.setData(ndx, p, Qt.UserRole) if p >= 4 and p <= 8: # Regular work load self._table_model.setData( ndx, QBrush(QColor(192, 255, 192)), Qt.BackgroundRole) elif p > 8 or (p < 4 and p > 0): # Problematic work load self._table_model.setData( ndx, QBrush(QColor(255, 192, 192)), Qt.BackgroundRole) if employee.employee_id in special_activities: sa_of_employee = special_activities[employee.employee_id] for sa in sa_of_employee: start = max(t_start, sa.start_time) end = min(t_end, sa.end_time) for i in range(start.day, end.day + 1): ndx = self._table_model.index(row, i) self._table_model.setData(ndx, QBrush(QColor(255, 128, 0)), Qt.BackgroundRole) # self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight | Qt.AlignVCenter,Qt.TextAlignmentRole) row += 1 # Display day events employee_id_to_row = dict() # little accelerator for row in range(len(employees)): employee_id_to_row[employees[row].employee_id] = row # Compute days off totals and show them self.day_event_totals = dict([(e.employee_id, dict()) for e in employees]) for day_event in all_events_in_month: # mainlog.debug("employee_id = {}".format(day_event.employee_id)) # if day_event.employee_id not in self.day_event_totals: # mainlog.debug(self.day_event_totals) t = self.day_event_totals[day_event.employee_id] if day_event.event_type not in t: t[day_event.event_type] = day_event.duration else: t[day_event.event_type] += day_event.duration for employee in employees: # employees are sorted t = self.day_event_totals[employee.employee_id] mainlog.debug(t) total_off = sum(t.values()) mainlog.debug(total_off) row = employee_id_to_row[employee.employee_id] mainlog.debug(row) if total_off: self._table_model.setData( self._table_model.index(row, day_max + 3), nice_round(total_off), Qt.DisplayRole) else: self._table_model.setData( self._table_model.index(row, day_max + 3), None, Qt.DisplayRole) # Show days off for day_event in all_events_in_month: row = employee_id_to_row[day_event.employee_id] col = day_event.date.day fg = bg = None if day_event.event_type in self.DAY_EVENT_PALETTE: fg, bg = self.DAY_EVENT_PALETTE[day_event.event_type] else: fg, bg = Qt.GlobalColor.red, Qt.GlobalColor.gray ndx = self._table_model.index(row, col) self._table_model.setData(ndx, day_event.day_event_id, Qt.UserRole + 1) # The problem here is to nicely blend the fact # that you can have a day event mixed with actual work # the very same day. Here's a poor man solution. active_time = self._table_model.data(ndx, Qt.UserRole) if not active_time: self._table_model.setData( ndx, DayEventType.short_code(day_event.event_type), Qt.DisplayRole) self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) else: self._table_model.setData(ndx, QBrush(fg), Qt.TextColorRole) self._table_model.setData(ndx, QBrush(bg), Qt.BackgroundRole) self._table_model.setData( ndx, duration_to_hm(active_time, short_unit=True) + DayEventType.short_code(day_event.event_type), Qt.DisplayRole) chrono.chrono_click() #for i in range(len(all_mondays)): self.table_view.resizeColumnsToContents() # mainlog.debug("Reset selection") ndx = self.table_view.currentIndex() self.table_view.selectionModel().clear() # self.table_view.selectionModel().clearSelection() # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(), ndx.column()), QItemSelectionModel.Select) self.cell_entered(self.table_view.currentIndex())
def refresh_action(self): global dao self.title_box.set_title(_("Time Records Overview - {}").format(date_to_my(self.base_date,True))) self.employees = dao.employee_dao.all() day_max = calendar.monthrange(self.base_date.year,self.base_date.month)[1] t_start = datetime(self.base_date.year,self.base_date.month,1) t_end = datetime(self.base_date.year,self.base_date.month,day_max,23,59,59,999999) self._table_model.setRowCount( len(self.employees)) self._table_model.setColumnCount( 1+day_max) headers = QStandardItemModel(1, 1+day_max) headers.setHeaderData(0, Qt.Orientation.Horizontal, _("Employee")) for i in range(day_max): headers.setHeaderData(i+1, Qt.Orientation.Horizontal, "{}".format(i+1)) self.headers_view.setModel(headers) # qt's doc : The view does *not* take ownership self.header_model = headers row = 0 for employee in self.employees: # mainlog.debug(u"refresh action employee {}".format(employee)) self._table_model.setData(self._table_model.index(row,0),employee.fullname,Qt.DisplayRole) # FIXME Use a delegate self._table_model.setData(self._table_model.index(row,0),employee,Qt.UserRole) # FIXME Use a delegate tracks = session().query(TimeTrack).filter(and_(TimeTrack.employee_id == employee.employee_id, TimeTrack.start_time >= t_start,TimeTrack.start_time <= t_end)).all() # One bucket per day buckets = [0] * day_max for t in tracks: mainlog.debug("Bucket {}".format(t)) buckets[t.start_time.day - 1] += t.duration for b in range(len(buckets)): if buckets[b] != 0: self._table_model.setData(self._table_model.index(row,b+1),duration_to_s(buckets[b]),Qt.DisplayRole) else: self._table_model.setData(self._table_model.index(row,b+1),None,Qt.DisplayRole) if buckets[b] >= 0: # Clear the background self._table_model.setData(self._table_model.index(row,b+1),None,Qt.BackgroundRole) else: self._table_model.setData(self._table_model.index(row,b+1),QBrush(QColor(255,128,128)),Qt.TextColorRole) self._table_model.setData(self._table_model.index(row,b+1),Qt.AlignRight,Qt.TextAlignmentRole) row += 1 # Compute all mondays indices monday = 0 if t_start.weekday() > 0: monday = 7 - t_start.weekday() all_mondays = [] while monday < day_max: all_mondays.append(monday) monday += 7 today = date.today() for row in range(len(self.employees)): # Mark mondays for col in all_mondays: # col + 1 to account for the employee column self._table_model.setData(self._table_model.index(row,col + 1),QBrush(QColor(230,230,255)),Qt.BackgroundRole) # Mark today if today.month == self.base_date.month and today.year == self.base_date.year: self._table_model.setData(self._table_model.index(row,today.day),QBrush(QColor(255,255,128)),Qt.BackgroundRole) #for i in range(len(all_mondays)): self.table_view.resizeColumnsToContents() # mainlog.debug("Reset selection") ndx = self.table_view.currentIndex() self.table_view.selectionModel().clear() # self.table_view.selectionModel().clearSelection() # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) # self.table_view.selectionModel().select( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select) self.table_view.selectionModel().setCurrentIndex( self.table_view.model().index(ndx.row(),ndx.column()), QItemSelectionModel.Select)