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()
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()
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))