Example #1
0
 def test_mission_timesheet(self):
     self.client.login(username=TEST_USERNAME, password=TEST_PASSWORD)
     current_month = date.today().replace(day=1)
     next_month = nextMonth(current_month)
     previous_month = previousMonth(current_month)
     lead = Lead.objects.get(id=1)
     c1 = Consultant.objects.get(id=1)
     c2 = Consultant.objects.get(id=2)
     mission = Mission(lead=lead, subsidiary_id=1, billing_mode="TIME_SPENT", nature="PROD", probability=100)
     mission.save()
     response = self.client.get(urlresolvers.reverse("staffing.views.mission_timesheet", args=[mission.id,]), follow=True, HTTP_X_REQUESTED_WITH="XMLHttpRequest")
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.context["margin"], 0)
     self.assertEqual(response.context["objective_margin_total"], 0)
     self.assertEqual(response.context["forecasted_unused"], 0)
     self.assertEqual(response.context["current_unused"], 0)
     self.assertEqual(response.context["avg_daily_rate"], 0)
     # Add some forecast
     Staffing(mission=mission, staffing_date=current_month, consultant=c1, charge=15).save()
     Staffing(mission=mission, staffing_date=current_month, consultant=c2, charge=10).save()
     Staffing(mission=mission, staffing_date=next_month, consultant=c1, charge=8).save()
     Staffing(mission=mission, staffing_date=next_month, consultant=c2, charge=6).save()
     # Add some timesheet - we fake with all charge on the first day
     Timesheet(mission=mission, working_date=previous_month, consultant=c1, charge=8).save()
     Timesheet(mission=mission, working_date=previous_month, consultant=c2, charge=5).save()
     Timesheet(mission=mission, working_date=current_month, consultant=c1, charge=11).save()
     Timesheet(mission=mission, working_date=current_month, consultant=c2, charge=9).save()
     # Define objective rates for consultants
     RateObjective(consultant=c1, start_date=previous_month, daily_rate=700).save()
     RateObjective(consultant=c2, start_date=previous_month, daily_rate=1050).save()
     # Add financial conditions for this mission
     FinancialCondition(consultant=c1, mission=mission, daily_rate=800).save()
     FinancialCondition(consultant=c2, mission=mission, daily_rate=1100).save()
     # Define mission price
     mission.price = 50
     mission.save()
     # Let's test if computation are rights
     response = self.client.get(urlresolvers.reverse("staffing.views.mission_timesheet", args=[mission.id,]), follow=True, HTTP_X_REQUESTED_WITH="XMLHttpRequest")
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.context["margin"], 0)  # That's because we are in fixed price
     self.assertEqual(response.context["objective_margin_total"], 2600)
     self.assertEqual(response.context["forecasted_unused"], 2.1)
     self.assertEqual(response.context["current_unused"], 19.4)
     # Switch to fixed price mission
     mission.billing_mode = "FIXED_PRICE"
     mission.save()
     response = self.client.get(urlresolvers.reverse("staffing.views.mission_timesheet", args=[mission.id,]), follow=True, HTTP_X_REQUESTED_WITH="XMLHttpRequest")
     self.assertEqual(response.status_code, 200)
     self.assertEqual(response.context["margin"], 2.1)
     self.assertEqual(response.context["objective_margin_total"], 2600)
     self.assertEqual(response.context["forecasted_unused"], 0)  # Unused is margin in fixes price :-)
     self.assertEqual(response.context["current_unused"], 0)  # idem
     # Check mission data main table
     data = response.context["mission_data"]
     self.assertListEqual(data[0], [c2, [5, 9, 14, 15.4], [1, 6, 7, 7.7], [21, 23.1]])
     self.assertListEqual(data[1], [c1, [8, 11, 19, 15.2], [4, 8, 12, 9.6], [31, 24.8]])
     self.assertListEqual(data[2], [None, [13, 20, 33, 30.6], [5, 14, 19, 17.3], [52, 47.9],
                                    [11.9, 18.7], [4.3, 13],
                                    [915.4, 935, 927.3], [860, 928.6, 910.5]])
Example #2
0
def compute_automatic_staffing(mission, mode, duration, user=None):
    """Compute staffing for a given mission. Mode can be after (current staffing) for replace (erase and create)"""
    now = datetime.now().replace(microsecond=0)  # Remove useless microsecond
    current_month = date.today().replace(day=1)
    start_date = current_month
    total = 0

    if not mission.consultants():
        # no consultant, no staffing. Come on.
        return

    if mode=="replace":
        mission.staffing_set.all().delete()
        cache.delete("Mission.forecasted_work%s" % mission.id)
        cache.delete("Mission.done_work%s" % mission.id)
        if mission.lead:
            start_date = max(current_month, mission.lead.start_date.replace(day=1))
    else:
        max_staffing = Staffing.objects.filter(mission=mission).aggregate(Max("staffing_date"))["staffing_date__max"]
        if max_staffing:
            start_date = max(current_month, nextMonth(max_staffing))

    if mission.start_date:
        start_date = max(start_date, mission.start_date)

    margin = mission.remaining(mode="target")
    rates = mission.consultant_rates()
    rates_sum = sum([i[0] for i in rates.values()])
    days = margin*1000 / rates_sum / duration
    days = max(floor(days * 4) / 4, 0.25)

    for consultant in rates.keys():
        month = start_date
        for i in range(duration):
            if total > margin*1000:
                break
            if mission.end_date and month > mission.end_date:
                break
            s = Staffing(mission=mission, consultant=consultant, charge=days, staffing_date=month, update_date = now)
            if user:
                s.last_user = str(user)
            s.save()
            total += days * rates[consultant][0]

            month = nextMonth(month)
Example #3
0
def solver_apply_forecast(solver, staffing, consultants, missions,
                          staffing_dates, user):
    """Apply solver solution to staffing forecast"""
    now = datetime.now().replace(microsecond=0)  # Remove useless microsecond
    for mission in missions:
        mission_id = mission.mission_id()
        # Remove previous staffing for this mission after first month
        Staffing.objects.filter(
            mission=mission, staffing_date__gte=staffing_dates[0][0]).delete()
        # Create new staffing according to solver solution
        for consultant in consultants:
            for month in staffing_dates:
                charge = solver.Value(
                    staffing[consultant.trigramme][mission_id][month[1]])
                if charge > 0:
                    s = Staffing(mission=mission,
                                 consultant=consultant,
                                 staffing_date=month[0],
                                 charge=charge,
                                 update_date=now,
                                 last_user=str(user))
                    s.save()
Example #4
0
def compute_automatic_staffing(mission, mode, duration, user=None):
    """Compute staffing for a given mission. Mode can be after (current staffing) for replace (erase and create)"""
    now = datetime.now().replace(microsecond=0)  # Remove useless microsecond
    current_month = date.today().replace(day=1)
    start_date = current_month
    total = 0

    if mode=="replace":
        mission.staffing_set.all().delete()
        cache.delete("Mission.forecasted_work%s" % mission.id)
        cache.delete("Mission.done_work%s" % mission.id)
        if mission.lead:
            start_date = max(current_month, mission.lead.start_date.replace(day=1))
    else:
        max_staffing = Staffing.objects.filter(mission=mission).aggregate(Max("staffing_date"))["staffing_date__max"]
        if max_staffing:
            start_date = max(current_month, nextMonth(max_staffing))

    margin = mission.margin(mode="target")
    rates = mission.consultant_rates()
    rates_sum = sum([i[0] for i in rates.values()])
    days = margin*1000 / rates_sum / duration
    days = max(floor(days * 4) / 4, 0.25)

    for consultant in rates.keys():
        month = start_date
        for i in range(duration):
            if total > margin*1000:
                break
            s = Staffing(mission=mission, consultant=consultant, charge=days, staffing_date=month, update_date = now)
            if user:
                s.last_user = str(user)
            s.save()
            total += days * rates[consultant][0]

            month = nextMonth(month)