Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    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)))
Ejemplo n.º 3
0
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
Ejemplo n.º 4
0
    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())
Ejemplo n.º 5
0
    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)