Esempio n. 1
0
    def accept(self):
        """overridden accept method
        """
        # get the info
        task = self.tasks_comboBox.currentTask()
        resource = self.get_current_resource()

        # war the user if the resource is not the logged_in_user
        if resource != self.logged_in_user:
            msg_box = QtWidgets.QMessageBox(self)
            msg_box.setWindowTitle('Baskasi Adina TimeLog Giriyorsun')
            msg_box.setText('Baskasi adina TimeLog giriyorsun???')
            accept_button = msg_box.addButton('Sorumlulugu Kabul Ediyorum',
                                              QtWidgets.QMessageBox.AcceptRole)
            cancel_button = msg_box.addButton('Cancel',
                                              QtWidgets.QMessageBox.RejectRole)
            msg_box.setDefaultButton(cancel_button)
            msg_box.exec_()
            clicked_button = msg_box.clickedButton()
            if clicked_button == cancel_button:
                return

        description = self.description_plainTextEdit.toPlainText()
        revision_cause_text = \
            self.revision_type_comboBox.currentText().replace(' ', '_')

        is_complete = self.set_as_complete_radioButton.isChecked()
        submit_to_final_review = \
            self.submit_for_final_review_radioButton.isChecked()

        # get the revision Types
        from stalker import Type
        revision_type = Type.query\
            .filter(Type.target_entity_type == 'Note')\
            .filter(Type.name == revision_cause_text)\
            .first()

        date = self.calendarWidget.selectedDate()
        start = self.start_timeEdit.time()
        end = self.end_timeEdit.time()

        # construct proper datetime.DateTime instances
        import datetime
        start_date = datetime.datetime(date.year(), date.month(), date.day(),
                                       start.hour(), start.minute())
        end_date = datetime.datetime(date.year(), date.month(), date.day(),
                                     end.hour(), end.minute())

        today_midnight = datetime.datetime.now().replace(hour=23,
                                                         minute=59,
                                                         second=59,
                                                         microsecond=999)

        # raise an error if the user is trying to enter a TimeLog to the future
        if start_date > today_midnight or end_date > today_midnight:
            QtWidgets.QMessageBox.critical(
                self,
                'Error',
                'Gelecege TimeLog giremezsiniz!!!',
            )
            return

        # convert them to utc
        from anima.utils import local_to_utc
        utc_start_date = local_to_utc(start_date)
        utc_end_date = local_to_utc(end_date)

        # create a TimeLog
        # print('Task          : %s' % task.name)
        # print('Resource      : %s' % resource.name)
        # print('utc_start_date: %s' % utc_start_date)
        # print('utc_end_date  : %s' % utc_end_date)

        # now if we are not using extra time just create the TimeLog
        from stalker import db, TimeLog
        from stalker.exceptions import OverBookedError
        utc_now = local_to_utc(datetime.datetime.now())

        if not self.timelog:
            try:
                new_time_log = TimeLog(task=task,
                                       resource=resource,
                                       start=utc_start_date,
                                       end=utc_end_date,
                                       description=description,
                                       date_created=utc_now)
            except OverBookedError:
                # inform the user that it can not do that
                QtWidgets.QMessageBox.critical(
                    self, 'Error', 'O saatte baska time log var!!!')
                return

            from sqlalchemy.exc import IntegrityError
            try:
                db.DBSession.add(new_time_log)
                db.DBSession.commit()
                self.timelog_created = True
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self, 'Error', 'Database hatasi!!!'
                    '<br>'
                    '%s' % e)
                db.DBSession.rollback()
                return
        else:
            # just update the date values
            self.timelog.start = utc_start_date
            self.timelog.end = utc_end_date
            self.timelog.date_updated = utc_now
            db.DBSession.add(self.timelog)
            db.DBSession.commit()

        if self.no_time_left:
            # we have no time left so automatically extend the task
            from stalker import Task
            schedule_timing, schedule_unit = \
                task.least_meaningful_time_unit(
                    task.total_logged_seconds
                )

            if schedule_timing != 0:
                task.schedule_timing = schedule_timing
                task.schedule_unit = schedule_unit

            # also create a Note
            from stalker import Note
            new_note = Note(
                content='Extending timing of the task <b>%s h %s min.</b>' %
                (self.extended_hours, self.extended_minutes),
                type=revision_type,
                created_by=self.logged_in_user,
                date_created=local_to_utc(datetime.datetime.now()))
            db.DBSession.add(new_note)
            task.notes.append(new_note)

            try:
                db.DBSession.commit()
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self, 'Error', 'Database hatasi!!!'
                    '<br>'
                    '%s' % e)
                db.DBSession.rollback()
                return

        if is_complete:
            # set the status to complete
            from stalker import Type, Status
            status_cmpl = Status.query.filter(Status.code == 'CMPL').first()

            forced_status_type = \
                Type.query.filter(Type.name == 'Forced Status').first()

            # also create a Note
            from stalker import Note
            new_note = Note(
                content='%s has changed this task status to Completed' %
                resource.name,
                type=forced_status_type,
                created_by=self.logged_in_user,
                date_created=local_to_utc(datetime.datetime.now()))
            db.DBSession.add(new_note)
            task.notes.append(new_note)
            task.status = status_cmpl
            db.DBSession.commit()

            task.update_parent_statuses()
            db.DBSession.commit()

        elif submit_to_final_review:
            # clip the Task timing to current time logs
            from stalker import Task
            schedule_timing, schedule_unit = \
                task.least_meaningful_time_unit(
                    task.total_logged_seconds
                )

            task.schedule_timing = schedule_timing
            task.schedule_unit = schedule_unit
            db.DBSession.add(task)

            try:
                db.DBSession.commit()
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self, 'Error', 'Database hatasi!!!'
                    '<br>'
                    '%s' % e)
                db.DBSession.rollback()
                return

            # request a review
            reviews = task.request_review()
            utc_now = local_to_utc(datetime.datetime.now())
            for review in reviews:
                review.created_by = review.updated_by = self.logged_in_user
                review.date_created = utc_now
                review.date_updated = utc_now
            db.DBSession.add_all(reviews)

            # and create a Note for the Task
            request_review_note_type = \
                Type.query\
                    .filter(Type.target_entity_type == 'Note')\
                    .filter(Type.name == 'Request Review')\
                    .first()

            from stalker import Note
            request_review_note = Note(type=request_review_note_type,
                                       created_by=self.logged_in_user,
                                       date_created=local_to_utc(
                                           datetime.datetime.now()))
            db.DBSession.add(request_review_note)
            db.DBSession.add(task)
            task.notes.append(request_review_note)

            try:
                db.DBSession.commit()
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self, 'Error', 'Database hatasi!!!'
                    '<br>'
                    '%s' % e)
                db.DBSession.rollback()
                return

        # if nothing bad happens close the dialog
        super(MainDialog, self).accept()
Esempio n. 2
0
    def accept(self):
        """overridden accept method
        """
        # get the info
        task = self.tasks_combo_box.currentTask()
        resource = self.get_current_resource()

        # war the user if the resource is not the logged_in_user
        if resource != self.logged_in_user:
            msg_box = QtWidgets.QMessageBox(self)
            msg_box.setWindowTitle(
                'Entering TimeLog On Behalf of Somebody Else'
            )
            msg_box.setText(
                "You're entering a TimeLog on behalf of somebody else???"
            )
            accept_button = msg_box.addButton(
                'Accept the responsibility',
                QtWidgets.QMessageBox.AcceptRole
            )
            cancel_button = msg_box.addButton(
                'Cancel',
                QtWidgets.QMessageBox.RejectRole
            )
            msg_box.setDefaultButton(cancel_button)
            msg_box.exec_()
            clicked_button = msg_box.clickedButton()
            msg_box.deleteLater()
            if clicked_button == cancel_button:
                return

        description = self.description_plain_text_edit.toPlainText()
        revision_cause_text = \
            self.revision_type_combo_box.currentText().replace(' ', '_')

        is_complete = self.set_as_complete_radio_button.isChecked()
        submit_to_final_review = \
            self.submit_for_final_review_radio_button.isChecked()

        # get the revision Types
        from stalker import Type
        revision_type = Type.query\
            .filter(Type.target_entity_type == 'Note')\
            .filter(Type.name == revision_cause_text)\
            .first()

        date = self.calendar_widget.selectedDate()
        start = self.start_time_edit.time()
        end = self.end_time_edit.time()

        # construct proper datetime.DateTime instances
        import datetime
        start_date = datetime.datetime(
            date.year(), date.month(), date.day(),
            start.hour(), start.minute()
        )
        end_date = datetime.datetime(
            date.year(), date.month(), date.day(),
            end.hour(), end.minute()
        )

        today_midnight = datetime.datetime.now().replace(
            hour=23, minute=59, second=59, microsecond=999
        )

        # raise an error if the user is trying to enter a TimeLog to the future
        if start_date > today_midnight or end_date > today_midnight:
            QtWidgets.QMessageBox.critical(
                self,
                'Error',
                'Gelecege TimeLog giremezsiniz!!!',
            )
            return

        # convert them to utc
        from anima.utils import local_to_utc
        utc_start_date = local_to_utc(start_date)
        utc_end_date = local_to_utc(end_date)

        # create a TimeLog
        # print('Task          : %s' % task.name)
        # print('Resource      : %s' % resource.name)
        # print('utc_start_date: %s' % utc_start_date)
        # print('utc_end_date  : %s' % utc_end_date)

        # now if we are not using extra time just create the TimeLog
        from stalker import TimeLog
        from stalker.db.session import DBSession
        from stalker.exceptions import (OverBookedError,
                                        DependencyViolationError)
        utc_now = local_to_utc(datetime.datetime.now())

        # TODO: Remove this in a later version
        import stalker
        from distutils.version import LooseVersion
        if LooseVersion(stalker.__version__) >= LooseVersion('0.2.18'):
            # inject timezone info
            import pytz
            utc_start_date = utc_start_date.replace(tzinfo=pytz.utc)
            utc_end_date = utc_end_date.replace(tzinfo=pytz.utc)
            utc_now = utc_now.replace(tzinfo=pytz.utc)

        from sqlalchemy.exc import IntegrityError
        if not self.timelog:
            try:
                new_time_log = TimeLog(
                    task=task,
                    resource=resource,
                    start=utc_start_date,
                    end=utc_end_date,
                    description=description,
                    date_created=utc_now
                )
            except (OverBookedError, DependencyViolationError) as e:
                # inform the user that it can not do that
                QtWidgets.QMessageBox.critical(
                    self,
                    'Error',
                    '%s' % e
                )
                DBSession.rollback()
                return

            try:
                DBSession.add(new_time_log)
                DBSession.commit()
                self.timelog_created = True
            except IntegrityError as e:
                DBSession.rollback()
                QtWidgets.QMessageBox.critical(
                    self,
                    'Error',
                    'Database Error!!!'
                    '<br>'
                    '%s' % e
                )
                return
        else:
            # just update the date values
            self.timelog.start = utc_start_date
            self.timelog.end = utc_end_date
            self.timelog.date_updated = utc_now
            DBSession.add(self.timelog)
            DBSession.commit()

        if self.no_time_left:
            # we have no time left so automatically extend the task
            from stalker import Task
            schedule_timing, schedule_unit = \
                task.least_meaningful_time_unit(
                    task.total_logged_seconds
                )

            if schedule_timing != 0:
                task.schedule_timing = schedule_timing
                task.schedule_unit = schedule_unit

            # also create a Note
            from stalker import Note
            new_note = Note(
                content='Extending timing of the task <b>%s h %s min.</b>' % (
                    self.extended_hours,
                    self.extended_minutes
                ),
                type=revision_type,
                created_by=self.logged_in_user,
                date_created=utc_now
            )
            DBSession.add(new_note)
            task.notes.append(new_note)

            try:
                DBSession.commit()
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self,
                    'Error',
                    'Database Error!!!'
                    '<br>'
                    '%s' % e
                )
                DBSession.rollback()
                return

        if is_complete:
            # set the status to complete
            from stalker import Type, Status
            status_cmpl = Status.query.filter(Status.code == 'CMPL').first()

            forced_status_type = \
                Type.query.filter(Type.name == 'Forced Status').first()

            # also create a Note
            from stalker import Note
            new_note = Note(
                content='%s has changed this task status to Completed' %
                        resource.name,
                type=forced_status_type,
                created_by=self.logged_in_user,
                date_created=utc_now
            )
            DBSession.add(new_note)
            task.notes.append(new_note)
            task.status = status_cmpl
            DBSession.commit()

        elif submit_to_final_review:
            # clip the Task timing to current time logs
            from stalker import Task
            schedule_timing, schedule_unit = \
                task.least_meaningful_time_unit(
                    task.total_logged_seconds
                )

            task.schedule_timing = schedule_timing
            task.schedule_unit = schedule_unit
            DBSession.add(task)

            try:
                DBSession.commit()
            except IntegrityError as e:
                QtWidgets.QMessageBox.critical(
                    self,
                    'Error',
                    'Database Error!!!'
                    '<br>'
                    '%s' % e
                )
                DBSession.rollback()
                return

            # request a review
            reviews = task.request_review()
            for review in reviews:
                review.created_by = review.updated_by = self.logged_in_user
                review.date_created = utc_now
                review.date_updated = utc_now
            DBSession.add_all(reviews)

            # and create a Note for the Task
            request_review_note_type = \
                Type.query\
                    .filter(Type.target_entity_type == 'Note')\
                    .filter(Type.name == 'Request Review')\
                    .first()

            from stalker import Note
            request_review_note = Note(
                type=request_review_note_type,
                created_by=self.logged_in_user,
                date_created=utc_now
            )
            DBSession.add(request_review_note)
            DBSession.add(task)
            task.notes.append(request_review_note)

            try:
                DBSession.commit()
            except IntegrityError as e:
                DBSession.rollback()
                QtWidgets.QMessageBox.critical(
                    self,
                    'Error',
                    'Database Error!!!'
                    '<br>'
                    '%s' % e
                )
                return

        # Fix statuses
        from anima import utils
        utils.fix_task_statuses(task)
        try:
            DBSession.commit()
        except IntegrityError as e:
            DBSession.rollback()
            QtWidgets.QMessageBox.critical(
                self,
                'Error',
                'Database Error!!!'
                '<br>'
                '%s' % e
            )
            return

        # if nothing bad happens close the dialog
        super(MainDialog, self).accept()
Esempio n. 3
0
    def fill_calendar_with_time_logs(self):
        """fill the calendar with daily time log info
        """
        resource_id = self.get_current_resource_id()
        # do not update if the calendar is showing the same user
        if self.calendar_widget.resource_id == resource_id or resource_id == -1:
            return

        tool_tip_text_format = u'{start:%H:%M} - {end:%H:%M} | {task_name}'

        # import time
        # start = time.time()
        # get all the TimeLogs grouped daily
        sql = """-- TOP DOWN SEARCH --
select
    "TimeLogs".start::date as date,
    array_agg(task_rec_data.full_path) as task_name,
    array_agg("TimeLogs".start) as start,
    array_agg("TimeLogs".end) as end,
    sum(extract(epoch from ("TimeLogs".end - "TimeLogs".start)))

from "TimeLogs"

join (
    with recursive recursive_task(id, parent_id, path_names) as (
        select
        task.id,
        task.project_id,
        -- task.project_id::text as path,
        ("Projects".code || '') as path_names
        from "Tasks" as task
        join "Projects" on task.project_id = "Projects".id
        where task.parent_id is NULL
    union all
        select
        task.id,
        task.parent_id,
        -- (parent.path || '|' || task.parent_id:: text) as path,
        (parent.path_names || ' | ' || "Parent_SimpleEntities".name) as path_names
        from "Tasks" as task
        inner join recursive_task as parent on task.parent_id = parent.id
        inner join "SimpleEntities" as "Parent_SimpleEntities" on parent.id = "Parent_SimpleEntities".id
    ) select
        recursive_task.id,
        "SimpleEntities".name || ' (' || recursive_task.path_names || ')' as full_path
    from recursive_task
    join "SimpleEntities" on recursive_task.id = "SimpleEntities".id
) as task_rec_data on "TimeLogs".task_id = task_rec_data.id

-- getting all the data is as fast as getting one, so get all the TimeLogs of this user
where "TimeLogs".resource_id = :resource_id
group by cast("TimeLogs".start as date)
order by cast("TimeLogs".start as date)
        """
        from sqlalchemy import text
        from stalker.db.session import DBSession
        result = DBSession.connection().execute(
            text(sql),
            resource_id=resource_id
        ).fetchall()
        # end = time.time()
        # print('getting data from sql: %0.3f sec' % (end - start))

        # TODO: Remove this in a later version
        from anima.utils import utc_to_local
        time_shifter = utc_to_local
        from distutils.version import LooseVersion
        import stalker
        if LooseVersion(stalker.__version__) >= LooseVersion('0.2.18'):
            def time_shifter(x):
                return x

        last_end_date = None
        for r in result:
            calendar_day = r[0]
            year = calendar_day.year
            month = calendar_day.month
            day = calendar_day.day
            daily_logged_seconds = r[4]
            daily_logged_hours = daily_logged_seconds // 3600
            daily_logged_minutes = \
                (daily_logged_seconds - daily_logged_hours * 3600) // 60

            tool_tip_text_data = [
                u'Total: %i h %i min logged' %
                (daily_logged_hours, daily_logged_minutes)
                if daily_logged_hours
                else u'Total: %i min logged' % daily_logged_minutes
            ]

            for task_name, start, end in sorted(zip(r[1], r[2], r[3]), key=lambda x: x[1]):
                time_log_tool_tip_text = tool_tip_text_format.format(
                    start=time_shifter(start),
                    end=time_shifter(end),
                    task_name=task_name
                )
                tool_tip_text_data.append(time_log_tool_tip_text)
                # store the last_end_date
                last_end_date = end

            merged_tool_tip = u'\n'.join(tool_tip_text_data)

            date_format = QtGui.QTextCharFormat()
            bg_brush = QtGui.QBrush()
            bg_brush.setColor(
                QtGui.QColor(0, 255.0 / 86400.0 * daily_logged_seconds, 0)
            )

            date_format.setBackground(bg_brush)
            date_format.setToolTip(merged_tool_tip)

            date = QtCore.QDate(year, month, day)

            self.calendar_widget.setDateTextFormat(date, date_format)

        # set the start time in the UI to the last_end_date's time value
        # so the UI will automatically be set to the start of the next
        # available slot
        import pytz
        import datetime
        from anima.utils import local_to_utc
        utc_now = local_to_utc(datetime.datetime.now())
        utc_now = utc_now.replace(tzinfo=pytz.utc)
        start_of_today = datetime.datetime(utc_now.year, utc_now.month, utc_now.day, tzinfo=utc_now.tzinfo)
        if last_end_date and last_end_date > start_of_today:
            from anima import TIMING_RESOLUTION
            last_end_time = QtCore.QTime(last_end_date.hour, last_end_date.minute)
            self.start_time_edit.setTime(last_end_time)
            self.end_time_edit.setTime(last_end_time.addSecs(TIMING_RESOLUTION * 60))