def normalizePeriodStartStop(period, dt): """ Returns the start/stop time for a period ensuring it stays within the given month. """ start = TimeAgent.utc2est(period.start) if start.month != dt.month: start = datetime(dt.year, dt.month, 1, 0, 0, 0) stop = TimeAgent.utc2est(period.end()) if stop.month != dt.month: _, day = calendar.monthrange(dt.year, dt.month) stop = datetime(dt.year, dt.month, day, 23, 59, 59) return start, stop
def test_summary(self): # setup a period for a month before lastMonth = self.start - timedelta(days = 31) lastMonthEst = TimeAgent.utc2est(lastMonth) pa = Period_Accounting(scheduled = self.dur) pa.save() p = Period( session = self.s , start = lastMonth , duration = self.dur , state = Period_State.get_state("S") , accounting = pa ) p.save() # get - sets up the form response = self.get('/schedule/summary') self.failUnlessEqual(response.status_code, 200) startStr = datetime.strftime(lastMonthEst, "%H:%M") self.assertTrue(startStr in response.content) self.assertTrue("mikes awesome project" in response.content) # post - they've requested something # first, the schedule summary report # default to last month response = self.post('/schedule/summary', {'summary' : 'schedule'}) self.failUnlessEqual(response.status_code, 200) self.assertTrue(startStr in response.content) self.assertTrue("mikes awesome project" in response.content) # now do an earlier month, and our period should not show up response = self.post('/schedule/summary' , {'summary' : 'schedule' , 'month' : 'December' , 'year' : '2000'} ) self.failUnlessEqual(response.status_code, 200) self.assertTrue(startStr not in response.content) self.assertTrue("mikes awesome project" not in response.content) # okay, now test the project summary report pcode = self.s.project.pcode response = self.post('/schedule/summary' , {'summary' : 'project' , 'project' : pcode} ) self.failUnlessEqual(response.status_code, 200) self.assertTrue("GBT Project Summary for" in response.content) self.assertTrue(pcode in response.content) self.assertTrue(str(self.dur) in response.content) # make sure we can handle all projects response = self.post('/schedule/summary' , {'summary' : 'project' , 'project' : None} ) self.failUnlessEqual(response.status_code, 200) self.assertTrue("GBT Project Summary for" in response.content) self.assertTrue(pcode in response.content) self.assertTrue(str(self.dur) in response.content)
def getSessionTable(self, periods): table = "Start (ET) | UT | LST | (hr) | T | S | PI | Rx | Session\n" table += "--------------------------------------------------------------------------------------\n" for p in periods: if p.session.project.pcode == "Maintenance": pi = "" else: pi = p.session.project.principal_investigator().last_name[:9] if p.session.project.principal_investigator() else "Unknown" table += "%s | %s | %s | %5s | %s | %s | %-9s | %-9s | %s\n" % ( TimeAgent.utc2est(p.start).strftime('%b %d %H:%M') # start (ET) , p.start.strftime('%b %d %H:%M') # start (UT) , TimeAgent.dt2tlst(p.start).strftime('%H:%M') # LST , "%2.2f" % p.duration # dur (Hrs) , p.session.session_type.type[0].upper() # sess type , p.state.abbreviation # state , pi , p.session.receiver_list_simple()[:9] , p.session.name ) return table
def summary(request, *args, **kws): """ Serves up a page that allows Operations to run reconcilation reports. There are two basic reports - schedule and project. Even though it is specifically for Operations, any logged in user may view it. """ now = datetime.now() psummary = [] if request.method == 'POST': summary = request.POST.get('summary', 'schedule') project = project_search(request.POST.get('project', '')) if isinstance(project, list) and len(project) == 1: project = project[0].pcode else: project = '' month = request.POST.get('month', None) year = request.POST.get('year', None) year = int(year) if year else None if month and year: start = datetime(int(year) , [m for m in calendar.month_name].index(month) , 1) else: # Default to this month start = datetime(now.year, now.month, 1) month = calendar.month_name[start.month] year = start.year else: # Default to this month summary = 'schedule' project = '' start = datetime(now.year, now.month, 1) month = calendar.month_name[start.month] year = start.year end = datetime(start.year , start.month , calendar.monthrange(start.year, start.month)[1]) + \ timedelta(days = 1) # View is in ET, database is in UTC. Only use scheduled periods. periods = Period.in_time_range(TimeAgent.est2utc(start) , TimeAgent.est2utc(end)) if project: periods = [p for p in periods if p.isScheduled() and p.session.project.pcode == project] # Handle either schedule or project summaries. if summary == "schedule": schedule = get_gbt_schedule_events(start, end, "ET", True) url = 'users/schedule_summary.html' projects = [] receivers = {} days = {} hours = {} summary = {} else: url = 'users/project_summary.html' projects = list(set([p.session.project for p in periods])) projects.sort(lambda x, y: cmp(x.pcode, y.pcode)) receivers = {} for p in periods: rxs = receivers.get(p.session.project.pcode, []) rxs.extend([r.abbreviation for r in p.receivers.all()]) receivers[p.session.project.pcode] = rxs schedule = {} days = dict([(p.pcode, []) for p in projects]) hours = dict([(p.pcode, 0) for p in projects]) summary = dict([(c, 0) for c in Sesshun.getCategories()]) for p in periods: pstart = TimeAgent.utc2est(p.start) pend = TimeAgent.utc2est(p.end()) # Find the days this period ran within the month. day = pstart.day if pstart >= start else pend.day days[p.session.project.pcode].append(str(day)) if day != pend.day: # For multi-day periods days[p.session.project.pcode].append(str(pend.day)) # Find the duration of this period within the month. duration = min(pend, end) - max(pstart, start) hrs = duration.seconds / 3600. + duration.days * 24. hours[p.session.project.pcode] += hrs # Tally hours for various categories important to Operations. summary[p.session.getCategory()] += hrs # If just for one project, create a more detailed summary. if project: psummary.append((pstart, hrs, p.receiver_list)) return render_to_response( url , {'calendar' : schedule , 'projects' : [(p , sorted(list(set(receivers[p.pcode]))) , sorted(list(set(days[p.pcode])) , lambda x, y: cmp(int(x), int(y))) , hours[p.pcode]) for p in projects] , 'start' : start , 'months' : calendar.month_name , 'month' : month , 'years' : [y for y in xrange(2009, now.year + 2, 1)] , 'year' : year , 'summary' : [(t, summary[t]) for t in sorted(summary)] , 'project' : project , 'psummary' : psummary , 'is_logged_in': request.user.is_authenticated()})
def utc2est(self, dt, frmt): return TimeAgent.utc2est(dt).strftime(frmt)
def test_nsfReport(self): # Periods look like (UTC, EST subtract 5): # 1 One: 2010-01-01 00:00:00 for 2.00 Hrs # 3 Two: 2010-01-01 02:00:00 for 3.00 Hrs # 2 One: 2010-01-01 05:00:00 for 1.00 Hrs - this one start in Jan, EST # 4 Two: 2010-01-01 06:00:00 for 2.00 Hrs decStart = datetime(2009,12, 1, 0) janStart = datetime(2010, 1, 1, 0) ps = Period.objects.all().order_by('start') ps = list(ps) # what are the periods that lie in Dec (EST)? filterd = filterPeriodsByDate(decStart) self.assertEquals([1,3], [p.id for p in filterd]) # what are the periods that lie in Jan (EST)? filterd = filterPeriodsByDate(janStart) self.assertEquals([2,4], [p.id for p in filterd]) pids = [1,2,4] dts = [decStart, janStart, janStart] for pid, dt in zip(pids, dts): p = Period.objects.get(id = pid) start, stop = normalizePeriodStartStop(p, dt) self.assertEquals(start, TimeAgent.utc2est(p.start)) self.assertEquals(stop, TimeAgent.utc2est(p.end())) # Period 3 is a special case p = Period.objects.get(id = 3) start, stop = normalizePeriodStartStop(p, decStart) self.assertEquals(start, TimeAgent.utc2est(p.start)) self.assertEquals(stop, datetime(2009, 12, 31, 23, 59, 59)) self.assertAlmostEquals(5.000, getTime(ps[:2], decStart), 2) self.assertAlmostEquals(3.000, getTime(ps[2:], janStart), 2) # tail of Q1 dt = decStart fps = filterPeriodsByDate(dt) self.assertAlmostEquals(5.000, getScheduledTime(fps, dt), 2) self.assertEquals(0.0, getDowntime(fps, dt)) self.assertEquals(0.0, getMaintenance(fps, dt)) self.assertEquals(0.0, getTesting(fps, dt)) # Start of Q2! dt = janStart fps = filterPeriodsByDate(dt) self.assertAlmostEquals(3.000, getScheduledTime(fps, dt), 2) self.assertEquals(0.5, getDowntime(fps, dt)) self.assertEquals(0.0, getMaintenance(fps, dt)) self.assertEquals(0.0, getTesting(fps, dt)) argv = ["program", "1", "2010"] quarters = { 1: [10, 11, 12] , 2: [1, 2, 3] , 3: [4, 5, 6] , 4: [7, 8, 9] } quarter = int(argv[1]) fiscal_year = int(argv[2]) months = quarters[quarter] year = fiscal_year if quarter != 1 else fiscal_year - 1 nsfReport('Q%dFY%d' % (quarter, fiscal_year) , [datetime(year, m, 1) for m in months], year) # can we handle 24 hour periods? dur = 24.0 scheduled = Period_State.get_state("S") pa = Period_Accounting(scheduled = dur) pa.save() p = Period(session = self.s1 , start = datetime(2010, 1, 1, 8) , duration = dur , state = scheduled , accounting = pa ) p.save() L = (Receiver.get_rcvr('L')) pg = Period_Receiver(period = p, receiver = L) pg.save() start, stop = normalizePeriodStartStop(p, janStart) self.assertEquals(start, TimeAgent.utc2est(p.start)) self.assertEquals(stop, TimeAgent.utc2est(p.end())) dt = janStart fps = filterPeriodsByDate(dt) self.assertAlmostEquals(27.000, getScheduledTime(fps, dt), 2) self.assertEquals(0.5, getDowntime(fps, dt)) self.assertEquals(0.0, getMaintenance(fps, dt)) self.assertEquals(0.0, getTesting(fps, dt))