def latest_entries(context, request): """ Returns an HTML fragment with tables of the latest time entries """ qry = DBSession.query(TimeEntry) current_user = request.environ.get('repoze.who.identity')['user'] qry = qry.filter(TimeEntry.author_id==current_user.id) qry = qry.order_by(sa.desc(TimeEntry.date), sa.desc(TimeEntry.start), sa.desc(TimeEntry.creation_date)) time_entries_today = qry.filter(TimeEntry.date==datetime.date.today()).all() today_total = timedelta_as_human_str(sum([a.hours for a in time_entries_today], datetime.timedelta())) latest_limit = 20 time_entries_latest = qry.limit(latest_limit) return { 'context': context, 'request': request, 'time_entries_today': time_entries_today, 'today_total': today_total, 'time_entries_latest': time_entries_latest, 'time_entries_latest_limit': latest_limit, 'report_my_from_date': datetime.date.today() - datetime.timedelta(days=6), 'today': datetime.date.today(), }
def __call__(self): schema = self.MyEntriesSchema(validator=validate_period).clone()\ .bind(yesterday=yesterday(), today=datetime.date.today()) limit = 1000 projects = qry_active_projects().all() form = PorInlineForm(schema, formid='my_entries', method='GET', buttons=[ SearchButton(title=u'Search'), ]) form['project_id'].widget.values = [('', '')] + sorted([(str(p.id), ' / '.join([p.customer.name, p.name])) for p in projects], key=lambda x: x[1].lower()) result_table = '' controls = self.request.GET.items() try: appstruct = form.validate(controls) except ValidationFailure as e: return { 'form': e.render(), 'saved_query_form': render_saved_query_form(self.request), 'result_table': None } current_uid = self.request.authenticated_user.id entries_by_date, entries_count = self.search(author_id=current_uid, limit=limit, **appstruct) highlight = functools.partial(webhelpers.html.tools.highlight, phrase=appstruct['searchtext']) delta0 = datetime.timedelta() delta_tot = sum([sum((e.hours for e in x[1]), delta0) for x in entries_by_date], delta0) human_tot = timedelta_as_human_str(delta_tot) days_tot = timedelta_as_work_days(delta_tot) result_table = render('por.dashboard:reports/templates/my_entries_results.pt', { 'entries_by_date': entries_by_date, 'entries_count': entries_count, 'highlight': highlight, 'human_tot': human_tot, 'days_tot': days_tot, 'datetime': datetime, 'ticket_url': ticket_url, 'timedelta_as_human_str': timedelta_as_human_str, }, request=self.request) return { 'form': form.render(appstruct=appstruct), 'saved_query_form': render_saved_query_form(self.request), 'result_table': result_table, }
def custom_json(self): schema = self.CustomSchema(validator=validate_period).clone() form = PorInlineForm(schema) controls = self.request.GET.items() appstruct = form.validate(controls) detail = self.search(render_links=False, **appstruct) result = [] for row in detail['rows']: row['hours'] = timedelta_as_human_str(row['hours']) del row['description'] result.append(row) return result
def time_parse(text, maximum=None, minimum=None): """ Returns a timedelta object, given a string like HH:MM, HH or :MM """ if not text: return None m = re.match('^([0-1]?[0-9]|2[0-4]):([0-5][0-9])$', text) if not m: raise ValueError(u'Cannot parse time (must be HH:MM)') hh, mm = m.groups() hh = int(hh) mm = int(mm) ret = datetime.timedelta(seconds=hh*60*60+mm*60) if maximum and ret > maximum: raise ValueError(u'Time value too big (must be <= %s)' % timedelta_as_human_str(maximum)) if minimum and ret < minimum: raise ValueError(u'Time value too small (must be >= %s)' % timedelta_as_human_str(minimum)) return ret
def time_entry_total_duration(request, date): try: date = datetime.datetime.strptime(date, '%Y-%m-%d') except ValueError: return { 'status': False, 'message': 'bad date format', } qry = DBSession.query(TimeEntry).filter(TimeEntry.date==date) qry = qry.filter(TimeEntry.author_id==request.authenticated_user.id) duration = sum((te.hours for te in qry), datetime.timedelta(0)) # we can return past timeentry descriptions here return { 'status': True, 'duration': timedelta_as_human_str(duration), }
def custom_xls(self): schema = self.CustomSchema(validator=validate_period).clone() form = PorInlineForm(schema) controls = self.request.GET.items() appstruct = form.validate(controls) detail = self.search(render_links=False, **appstruct) columns = detail['columns'] rows = [ [ self.format_xls(row[col_key]) for col_key, col_title in columns ] + [timedelta_as_human_str(row['hours'])] for row in detail['rows'] ] return { 'header': [col_title for col_key, col_title in columns] + ['Ore'], 'rows': rows, }
def format_web(self, value): if isinstance(value, datetime.timedelta): return timedelta_as_human_str(value) return value
def __call__(self): schema = self.CustomSchema(validator=validate_period).clone() projects = self.request.filter_viewables(qry_active_projects()) # select customers that have some active project customers = self.request.filter_viewables(sorted(set(p.customer for p in projects), key=unicodelower)) users = DBSession.query(User).order_by(User.fullname) users = filter_users_with_timeentries(users) customer_requests = self.request.filter_viewables(DBSession.query(CustomerRequest).order_by(CustomerRequest.name)) form = PorInlineForm(schema, formid='report-customer', method='GET', buttons=[ SearchButton(title=u'Search'), ]) workflow = get_workflow(TimeEntry(), 'TimeEntry') all_wf_states = [ (state, workflow._state_data[state]['title'] or state) for state in workflow._state_order ] form['workflow_states'].widget.values = all_wf_states # XXX the following validator is broken form['workflow_states'].validator = colander.OneOf([str(ws[0]) for ws in all_wf_states]) form['customer_id'].widget.values = [('', '')] + [(str(c.id), c.name) for c in customers] # don't validate as it might be an archived customer form['project_id'].widget.values = [('', '')] + [(str(p.id), p.name) for p in projects] # don't validate as it might be an archived project form['users'].widget.values = [(str(u.id), u.fullname) for u in users] # XXX the following validator is broken form['users'].validator = colander.OneOf([str(u.id) for u in users]) form['customer_requests'].widget.values = [(str(c.id), c.name) for c in customer_requests] # XXX the following validator is broken form['customer_requests'].validator = colander.OneOf([str(c.id) for c in customer_requests]) controls = self.request.GET.items() if not controls: # the form is empty return { 'form': form.render(), 'saved_query_form': render_saved_query_form(self.request), 'qs':'', 'result_table': None } try: appstruct = form.validate(controls) except ValidationFailure as e: return { 'form': e.render(), 'saved_query_form': render_saved_query_form(self.request), 'qs':'', 'result_table': None } detail = self.search(render_links=True, **appstruct) result_table = None if detail['rows']: base_link = self.request.path_url.rsplit('/', 1)[0] xls_link = ''.join([base_link, '/', 'custom_xls', '?', self.request.query_string]) json_link = ''.join([base_link, '/', 'custom_json', '?', self.request.query_string]) delta0 = datetime.timedelta() delta_tot = sum((row['hours'] for row in detail['rows']), delta0) human_tot = timedelta_as_human_str(delta_tot) result_table = render('por.dashboard:reports/templates/custom_results.pt', { 'rows': detail['rows'], 'columns': detail['columns'], 'xls_link': xls_link, 'json_link': json_link, 'format_web': self.format_web, 'human_tot': human_tot, }, request=self.request) return { 'form': form.render(appstruct=appstruct), 'saved_query_form': render_saved_query_form(self.request), 'qs': self.request.query_string, 'result_table': result_table, }