def time_entry_list(from_date, to_date, user, redmine): print("Fetching time entries from {} to {} for {}...".format( from_date, to_date, user)) print() # Get yesterday's time entries time_entries = redmine.time_entry.filter(user_id=user.id, from_date=from_date, to_date=to_date, sort='hours:desc') if time_entries: sum = 0 # Print scrum update template report = "Time entries:\n" for entry in time_entries: report += helpers.entry_bullet_point(entry) sum += entry.hours report += "\n" + str(sum) + " hours.\n" else: report = "No time entries.\n" print(report)
def update_entry(args, config, app_data): changed = False # Need to use cached time entry data because API doesn't support getting time entry data by ID cached_entry = app_data['clockify'].cache.get_cached_entry(args.id) if not cached_entry: print('Time entry does not exist or is not cached.') return # Establish entry hours cached_hours = app_data['clockify'].cache.iso_duration_to_hours(cached_entry['timeInterval']['duration']) updated_hours = cached_hours # Adjust hours, if necessary if args.hours and (helpers.contains_calculation(args.hours) or cached_hours != float(args.hours)): changed = True updated_hours = helpers.handle_hours_calculation_value(float(cached_hours), args.hours) print("Changing hours from {} to: {}".format(str(cached_hours), str(updated_hours))) updated_entry = app_data['clockify'].cache.generate_update_entry(args.id, comments=args.comments, date=args.date, hours=updated_hours) # Update description, if necessary if args.comments and args.comments != cached_entry['description']: changed = True print("Changing comments to: {}".format(args.comments)) # Append to description, if necesary if args.append: changed = True updated_entry['description'] += ' ' + args.append print("Appended to comments: {}".format(args.append)) # Update start date, if necessary if args.date: cached_date_local = app_data['clockify'].utc_iso_8601_string_to_local_datetime(cached_entry['timeInterval']['start']) update_date_local = app_data['clockify'].utc_iso_8601_string_to_local_datetime(updated_entry['start']) if cached_date_local.date() != update_date_local.date(): changed = True print("Changing date to {}".format(args.date)) if changed: # Perform update via API response = app_data['clockify'].update_entry(updated_entry, cached_entry) if response.status_code == 200: print(helpers.entry_bullet_point(app_data['clockify'], cached_entry)) print('Time entry updated.') else: response_data = response.json() print('Unexpected response status code: ' + str(response.status_code)) if 'message' in response_data: print('Message: ' + response_data['message']) else: print('No update as no change requested.')
def update_entry(args, config, app_data): if args.id: changed = False try: entry = app_data['redmine'].time_entry.get(args.id) if entry.user.id != app_data['user'].id: print("Entry was created by {}. Update skipped.".format( str(entry.user))) return except redminelib.exceptions.ResourceNotFoundError: print("Entry not found.") return print(helpers.entry_bullet_point(entry)) if args.comments and entry.comments != args.comments: changed = True entry.comments = args.comments print('Changing comments to: ' + args.comments) if args.hours and (args.hours[:1] == '+' or args.hours[:1] == '-' or entry.hours != float(args.hours)): changed = True original_hours = entry.hours if args.hours[:1] == '+': entry.hours += float(args.hours[1:]) elif args.hours[:1] == '-': entry.hours -= float(args.hours[1:]) else: entry.hours = float(args.hours) print('Changing hours from ' + str(original_hours) + ' to: ' + str(entry.hours)) if args.date: changed = True original_date = entry.spent_on entry.spent_on = helpers.handle_date_calculation_value(args.date) print('Changing activies from ' + str(original_date) + ' to ' + str(entry.spent_on)) # share code with new_entry? if args.activity: changed = True original_activity = str(entry.activity) entry.activity_id = app_data['activities'][args.activity] print('Changing activity from ' + original_activity + ' to ' + args.activity) if changed: entry.save() else: print("Specify a time entry ID using the --id option.")
def new_entry(args, config, app_data): if 'hours' not in args or not args.hours: print('Specifiy hours.') return entry = app_data['clockify'].create_entry(args.id, args.comments, args.hours, args.date) if 'message' in entry and 'code' in entry: print(entry['message']) return print(helpers.entry_bullet_point(entry)) print("Time entry created.")
def new_entry(args, config, app_data): if 'hours' not in args or not args.hours: print('Specifiy hours.') return # Check if ID indicates a task rather than project task_id = None project_id = app_data['clockify'].get_task_project_id(args.id) if project_id is None: project_id = args.id else: task_id = args.id entry = app_data['clockify'].create_entry(project_id, args.comments, args.hours, args.date, args.start, task=task_id) if 'message' in entry and 'code' in entry: print(entry['message']) return print(helpers.entry_bullet_point(app_data['clockify'], entry)) print("Time entry created.")
def new_entry(args, config, app_data): if args.id: # Warn user is issue isn't assigned or is assigned to another user issue = app_data['redmine'].issue.get(args.id) if not hasattr(issue, 'assigned_to'): print("*** Note: Issue is unassigned. ***\n") elif issue.assigned_to.id != app_data['user'].id: print("*** Note: Issue is not assigned to you. ***\n") entry = app_data['redmine'].time_entry.new() entry.issue_id = args.id entry.spent_on = date.today() if args.date: entry.spent_on = datetime.strptime( helpers.handle_date_calculation_value(args.date), '%Y-%m-%d').date() if args.comments: entry.comments = args.comments if args.hours: entry.hours = args.hours if not args.activity and 'default activity' in config: args.activity = helpers.resolve_activity_alias( config['default activity'], config['activities']) if args.activity: entry.activity_id = app_data['activities'][args.activity] entry.save() print(helpers.entry_bullet_point(entry)) print("Time entry created.") else: print("Specify an issue ID using the --id option.")
def update_entry(args, config, app_data): changed = False # Need to use cached time entry data because API doesn't support getting time entry data by ID cached_entry = helpers.get_cached_entry(args.id) if not cached_entry: print('Time entry does not exist or is not cached.') return # Change TimeEntrySummaryDto to work as UpdateTimeEntryRequest format (see Clockify API documentation) entry = {} entry['id'] = cached_entry['id'] entry['description'] = cached_entry['description'] entry['start'] = cached_entry['timeInterval']['start'] entry['end'] = cached_entry['timeInterval']['end'] entry['projectId'] = cached_entry['project']['id'] entry['billable'] = cached_entry['billable'] entry['tagIds'] = [] if 'task' in cached_entry and cached_entry['task']: entry['taskId'] = cached_entry['task']['id'] if 'tags' in cached_entry and cached_entry['tags']: for tag in cached_entry['tags']: entry['tagIds'].append(tag['id']) # Update description, if necessary if args.comments and args.comments != entry['description']: changed = True entry['description'] = args.comments cached_entry['description'] = args.comments print('Changing comments to: ' + args.comments) # Establish entry hours current_hours = helpers.iso_duration_to_hours( cached_entry['timeInterval']['duration']) if args.hours and (args.hours[:1] == '+' or args.hours[:1] == '-' or current_hours != float(args.hours)): changed = True original_hours = current_hours if args.hours[:1] == '+': current_hours += float(args.hours[1:]) elif args.hours[:1] == '-': current_hours -= float(args.hours[1:]) else: current_hours = float(args.hours) print('Changing hours from ' + str(original_hours) + ' to: ' + str(current_hours)) # Change UTC start date/time, if necessary if args.date: # Convert entry date to simple sting in local timezone original_date_localized = dateutil.parser.parse( entry['start']).astimezone(app_data['clockify'].tz) original_date = original_date_localized.strftime('%Y-%m-%d') if original_date != args.date: changed = True # Convert new date to UTC ISO 8601 entry['start'] = app_data[ 'clockify'].local_date_string_to_utc_iso_8601(args.date) cached_entry['timeInterval']['start'] = entry['start'] print('Changing activies from ' + original_date + ' to ' + args.date) # Convert UTC start/time to localized datetime and use it to calculate ISO 8601 end date/time start_datetime = dateutil.parser.parse(entry['start']) entry['end'] = app_data[ 'clockify'].add_hours_to_localized_datetime_and_convert_to_iso_8601( start_datetime, current_hours) cached_entry['timeInterval']['duration'] = isodate.duration_isoformat( dateutil.parser.parse(entry['end']) - dateutil.parser.parse(entry['start'])) cached_entry['timeInterval']['end'] = entry['end'] if changed: # Perform update via API response = app_data['clockify'].update_entry(entry) if response.status_code == 200: helpers.write_cache_entry(cached_entry) print(helpers.entry_bullet_point(cached_entry)) print('Time entry updated.') else: response_data = response.json() print('Unexpected response status code: ' + str(response.status_code)) if 'message' in response_data: print('Message: ' + response_data['message']) else: print('No update as no change requested.')