示例#1
0
    def test_ActualHours(self):
        """
        """
        task = self.portal.project.iteration.story.task
        booking = task.booking
        ann = IActualHours(booking)
        self.assertEqual(ann.actual_time, 3.25)

        task.invokeFactory('Booking', id='booking2', hours=0, minutes=0)
        ann = IActualHours(task.booking2)
        self.assertEqual(ann.actual_time, 0.0)

        task.invokeFactory('Booking', id='booking3', hours=0, minutes=45)
        ann = IActualHours(task.booking3)
        self.assertEqual(ann.actual_time, 0.75)

        # The following two have a weird number of minutes, but if
        # they pass, that is fine.
        task.invokeFactory('Booking', id='booking4', hours=4, minutes=60)
        ann = IActualHours(task.booking4)
        self.assertEqual(ann.actual_time, 5.0)

        task.invokeFactory('Booking', id='booking5', hours=4, minutes=75)
        ann = IActualHours(task.booking5)
        self.assertEqual(ann.actual_time, 5.25)
示例#2
0
    def recalculate_actual(self, action, data):
        """Recalculate the actual hours.

        Can be used in case the totals are wrong for some reason.
        """
        context = aq_inner(self.context)
        cat = getToolByName(context, 'portal_catalog')
        for portal_type in ('Booking', 'Task', 'PoiTask',
                            'Story', 'Iteration'):
            brains = cat(portal_type=portal_type)
            for brain in brains:
                obj = brain.getObject()
                anno = IActualHours(obj)
                anno.recalc()
    def recalculate_actual(self, action, data):
        """Recalculate the actual hours.

        Can be used in case the totals are wrong for some reason.
        """
        context = aq_inner(self.context)
        cat = getToolByName(context, 'portal_catalog')
        for portal_type in ('Booking', 'Task', 'PoiTask',
                            'Story', 'Iteration'):
            brains = cat(portal_type=portal_type)
            for brain in brains:
                obj = brain.getObject()
                anno = IActualHours(obj)
                anno.recalc()
    def main(self):
        """Get a dict with info from this Booking.
        """
        context = aq_inner(self.context)
        anno = IActualHours(context, None)
        if anno is not None:
            actual = anno.actual_time
        else:
            # What the???
            actual = -99.0
        ploneview = context.restrictedTraverse('@@plone')

        # Webintelligenttext for the description
        desc = context.Description()
        pt = getToolByName(context, 'portal_transforms')
        desc = pt('web_intelligent_plain_text_to_html', desc)

        returnvalue = dict(
            title=context.title_or_id(),
            description=desc,
            actual=formatTime(actual),
            booking_date=ploneview.toLocalizedTime(context.getBookingDate()),
            billable=context.getBillable(),
            creator=context.Creator(),
            # base_view of a booking gets redirected to the task view,
            # which we do not want here.
            url=context.absolute_url() + '/base_edit',
        )
        return returnvalue
示例#5
0
 def assertAnnotationGeneralBrainHoursEquality(self, obj, value,
                                               portal_type):
     ann = IActualHours(obj)
     self.assertEqual(ann.actual_time, value)
     catalog = self.portal.portal_catalog
     brains = catalog(portal_type=portal_type,
                      path='/'.join(obj.getPhysicalPath()))
     self.assertEqual(brains[0]['actual_time'], value)
示例#6
0
 def actual_budget_left(self):
     context = self.context
     project = aq_parent(aq_inner(self.context))
     hours_left = project.getBudgetHours()
     if not hours_left:
         return None
     contentfilter = dict(portal_type='Iteration')
     iteration_brains = project.getFolderContents(contentfilter)
     for brain in iteration_brains:
         iteration = brain.getObject()
         hours_left -= IActualHours(brain.getObject()).actual_time
     return hours_left
示例#7
0
    def main(self):
        """Get a dict with info from this Context.
        """
        context = aq_inner(self.context)
        anno = IActualHours(context, None)
        if anno is not None:
            actual = anno.actual_time
        else:
            # Should not happen (tm).
            actual = -99.0
        est = IEstimate(context, None)
        if est is not None:
            estimate = est.estimate
        else:
            # Should not happen (tm).
            estimate = -99.0

        # Size estimate.  We may want to do this smarter.
        filter = dict(portal_type='Story')
        items = context.getFolderContents(filter)
        size_estimate = sum([
            item.size_estimate for item in items
            if item.size_estimate is not None
        ])

        review_state = self.workflow.getInfoFor(context, 'review_state')
        if review_state in ['completed', 'invoiced', 'own-account']:
            budget_left = None
        else:
            budget_left = self.actual_budget_left()
        if budget_left is not None:
            budget_left = formatTime(budget_left)
        ploneview = context.restrictedTraverse('@@plone')
        if hasattr(context, 'getManHours'):
            manhours = context.getManHours()
        else:
            manhours = None
        returnvalue = dict(
            title=context.Title(),
            description=context.Description(),
            man_hours=manhours,
            start_date=ploneview.toLocalizedTime(context.getStartDate()),
            end_date=ploneview.toLocalizedTime(context.getEndDate()),
            estimate=formatTime(estimate),
            size_estimate=size_estimate,
            actual=formatTime(actual),
            difference=formatTime(estimate - actual),
            review_state=review_state,
            budget_left=budget_left,
        )
        return returnvalue
 def __init__(self, context, request):
     super(ChartView, self).__init__(context, request)
     self.table = []
     self.total_iterations = 0
     self.project = aq_inner(self.context).getProject()
     for it in self.get_iterations_generator():
         self.total_iterations += 1
         estim_total = int(self.get_total_estimate_iteration(it) + 0.5)
         estim_total_adapt = int((IEstimate(it).estimate / 8.0) + 0.5)
         work_total = int((IActualHours(it).actual_time / 8.0) + 0.5)
         self.table.append({
             'label': it.title_or_id(),
             'estimate_stories': estim_total,
             'estimate_tasks': estim_total_adapt,
             'worked': work_total
         })
 def totals(self):
     """Get a dict with totals for this Story.
     """
     context = aq_inner(self.context)
     anno = IActualHours(context, None)
     if anno is not None:
         actual = anno.actual_time
     else:
         # Should not happen (tm).
         actual = -99.0
     est = IEstimate(context, None)
     if est is not None:
         estimate = est.estimate
     else:
         # Should not happen (tm).
         estimate = -99.0
     totals = dict(
         estimate=formatTime(estimate),
         actual=formatTime(actual),
         difference=formatTime(estimate - actual),
     )
     return totals
示例#10
0
    def main(self):
        """Get a dict with info from this Task.
        """
        context = aq_inner(self.context)
        anno = IActualHours(context, None)
        if anno is not None:
            actual = anno.actual_time
        else:
            # Should not happen (tm).
            actual = -99.0
        est = IEstimate(context, None)
        if est is not None:
            estimate = est.estimate
        else:
            # Should not happen (tm).
            estimate = -99.0
        pas_member = queryMultiAdapter((context, self.request),
                                       name='pas_member')
        if pas_member is None:
            # Plone 3, Poi 1.2
            nice_namer = context.poi_niceName
        else:
            # Plone 4
            nice_namer = lambda x: pas_member.info(x).get('name_or_id')

        # Get info for previous and next links.  We only want tasks
        # here, not for example images.
        story = aq_parent(context)
        tasks = story.getFolderContents()
        num_tasks = len(tasks)
        pos = story.getObjectPosition(context.id)
        next = None
        next_pos = pos + 1
        while next_pos < num_tasks:
            if tasks[next_pos].portal_type in ('Task', 'PoiTask'):
                next = tasks[next_pos]
                break
            next_pos += 1
        prev = None
        prev_pos = pos - 1
        while prev_pos >= 0:
            if tasks[prev_pos].portal_type in ('Task', 'PoiTask'):
                prev = tasks[prev_pos]
                break
            prev_pos -= 1

        returnvalue = dict(
            title=context.Title(),
            description=context.Description(),
            cooked_body=context.CookedBody(),
            estimate=formatTime(estimate),
            actual=formatTime(actual),
            difference=formatTime(estimate - actual),
            review_state=self.workflow.getInfoFor(context, 'review_state'),
            assignees=[{
                'niceName': nice_namer(x),
                'username': x,
                'active': True
            } for x in context.getAssignees()],
            prev=prev,
            next=next,
        )
        return returnvalue