예제 #1
0
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(),
            }
예제 #2
0
    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,
                }
예제 #3
0
 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
예제 #4
0
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
예제 #5
0
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),
            }
예제 #6
0
    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,
                }
예제 #7
0
 def format_web(self, value):
     if isinstance(value, datetime.timedelta):
         return timedelta_as_human_str(value)
     return value
예제 #8
0
    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,
                }