Test bookings
=============

We want to test some browser views for Bookings.  We need some test
requests.

    >>> from zope.publisher.browser import TestRequest
    >>> from Products.eXtremeManagement.tests.base import reset_request
    >>> request = TestRequest()

At first there is one Booking but it is not in this month so we do not
see it.

    >>> self.login('test_user_1_')
    >>> catalog = self.portal.portal_catalog
    >>> from Products.eXtremeManagement.browser.bookings import BookingsDetailedView
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    0

Let's add a Booking as someone else.  That person should by default
only see his own Bookings.

    >>> self.login('employee')
    >>> task = self.portal.project.iteration.story.task
    >>> task.invokeFactory('Booking', id='booking-emp', hours=2)
    'booking-emp'
    >>> reset_request(task)
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    1
    >>> bookview.bookinglist[0]['booking_hours']
    '2:00'
    >>> bookview.total
    '2:00'
    >>> len(catalog(portal_type='Booking'))
    2

Adding another one should update the total actual hours

    >>> task.invokeFactory('Booking', id='booking-emp-2', hours=3, minutes=30)
    'booking-emp-2'
    >>> reset_request(task)
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    2
    >>> bookview.total
    '5:30'

No bookings have been done in January 2007.

    >>> request = TestRequest(form={'year': 2007, 'month': 1})
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> bookview.bookinglist
    []
    >>> bookview.total
    '0:00'

Let us add one in that month.

    >>> from DateTime import DateTime
    >>> jan1 = DateTime('2007-01-01')
    >>> task.invokeFactory('Booking', id='emp-jan1', hours=1, bookingDate=jan1)
    'emp-jan1'
    >>> reset_request(task)

Since I have learned a few things about requests lately, let us check
it in three ways.

We first check it by adding some keyword arguments.

    >>> request = TestRequest()
    >>> bookview = BookingsDetailedView(self.portal, request, year=2007, month=1)
    >>> len(bookview.bookinglist)
    1
    >>> bookview.bookinglist[0]['booking_date'] in ('Jan 01, 2007', '2007-01-01')
    True

Then we check it by adding a dictionary

    >>> request = TestRequest()
    >>> options = dict(year=2007, month=1)
    >>> bookview = BookingsDetailedView(self.portal, request, **options)
    >>> len(bookview.bookinglist)
    1
    >>> bookview.bookinglist[0]['booking_date'] in ('Jan 01, 2007', '2007-01-01')
    True

And then we check it by adjusting the request, to show that the result
is the same.

    >>> request = TestRequest(form={'year': 2007, 'month': 1})
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    1
    >>> bookview.bookinglist[0]['booking_date'] in ('Jan 01, 2007', '2007-01-01')
    True

Now, a booking on the first of the month might inadvertently be listed
in the previous month as well.  Let's make sure we do not make that
mistake.

    >>> request = TestRequest(form={'year': 2006, 'month': 12})
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> bookview.bookinglist
    []


Daylight Savings Time can be annoying.  Bookings at Monday March 27
2006 can end up in overviews on Monday *and* Sunday.

    >>> request = TestRequest(form={'year': 2006, 'month': 3})
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    0
    >>> monday_after_dst = DateTime('2006-03-27')
    >>> task.invokeFactory('Booking', id='emp-mad06', hours=2, bookingDate=monday_after_dst)
    'emp-mad06'
    >>> reset_request(task)
    >>> request = TestRequest(form={'year': 2006, 'month': 3})
    >>> bookview = BookingsDetailedView(self.portal, request)
    >>> len(bookview.bookinglist)
    1

And in practice we noticed that it can apparantely also go wrong when
going from summer to winter time.  So we add a few bookings around
that time too.

In 2006 DST kicked in during the night of Saturday 28 October and
Sunday 29 October, at least in The Netherlands.

    >>> dummy = task.invokeFactory('Booking', id='emp-okt1', hours=1,
    ...                                 bookingDate=DateTime('2006-10-01'))
    >>> dummy = task.invokeFactory('Booking', id='emp-okt28', hours=2,
    ...                                 bookingDate=DateTime('2006-10-28'))
    >>> dummy = task.invokeFactory('Booking', id='emp-okt29', hours=3,
    ...                                 bookingDate=DateTime('2006-10-29'))
    >>> dummy = task.invokeFactory('Booking', id='emp-okt30', hours=4,
    ...                                 bookingDate=DateTime('2006-10-30'))
    >>> dummy = task.invokeFactory('Booking', id='emp-okt31', hours=5,
    ...                                 bookingDate=DateTime('2006-10-31'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov1', hours=6,
    ...                                bookingDate=DateTime('2006-11-01'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov6', hours=8,
    ...                                 bookingDate=DateTime('2006-11-06'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov7', hours=8,
    ...                                 bookingDate=DateTime('2006-11-07'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov8', hours=8,
    ...                                 bookingDate=DateTime('2006-11-08'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov9', hours=8,
    ...                                 bookingDate=DateTime('2006-11-09'))
    >>> dummy = task.invokeFactory('Booking', id='emp-nov10', hours=8,
    ...                                 bookingDate=DateTime('2006-11-10'))
    >>> reset_request(task)
    >>> len(BookingsDetailedView(self.portal, TestRequest(form={'year': 2006,
    ...                                           'month': 10})).bookinglist)
    5
    >>> len(BookingsDetailedView(self.portal, TestRequest(form={'year': 2006,
    ...                                           'month': 11})).bookinglist)
    6

This does not show any errors though.  Which reminds us to test the
WeekBookingOverview and DayBookingOverview.  These can suffers from
DST bugs too if we are not careful.

First let's test some days.

    >>> from Products.eXtremeManagement.browser.bookings import DayBookingOverview
    >>> dayview = DayBookingOverview(self.portal, TestRequest())
    >>> dayview.total(date=DateTime(2006, 10, 27))
    '0:00'
    >>> dayview.total(date=DateTime(2006, 10, 28))
    '2:00'
    >>> dayview.total(date=DateTime(2006, 10, 29))
    '3:00'
    >>> dayview.total(date=DateTime(2006, 10, 30))
    '4:00'

Now we test the week view for oktober and november.

    >>> from Products.eXtremeManagement.browser.bookings import WeekBookingOverview
    >>> okt = WeekBookingOverview(self.portal, TestRequest(form={'year': 2006,
    ...                                                    'month': 10}))
    >>> nov =  WeekBookingOverview(self.portal, TestRequest(form={'year': 2006,
    ...                                                     'month': 11}))

Does it give the right totals for each week (and the correct amount of
weeks)?  Note that the week totals show the totals for that week
regardless of whether each day falls in the month that you are looking
at: it is helpful for an employee to know how many hours he has worked
in this week.

    >>> [week['week_total'] for week in okt.bookinglist]
    ['1:00', '0:00', '0:00', '0:00', '5:00', '15:00']
    >>> [week['week_number'] for week in okt.bookinglist]
    [39, 40, 41, 42, 43, 44]
    >>> [week['week_total'] for week in nov.bookinglist]
    ['15:00', '40:00', '0:00', '0:00', '0:00']

How about the billable percentge?  Note that billable percentage for
one day is the billable time for that day time in a percentage of the
norm of 8 hours.  So it does not matter how much you worked that day,
as we just assume that any time you did not book was unbillable.

    >>> [week['perc_billable'] for week in okt.bookinglist]
    ['12.5 %', '0.0 %', '0.0 %', '0.0 %', '31.2 %', '62.5 %']
    >>> [week['perc_billable'] for week in nov.bookinglist]
    ['62.5 %', '100.0 %', '0.0 %', '0.0 %', '0.0 %']

Does it give the totals (and other info) per month correctly?

    >>> from pprint import pprint
    >>> pprint(okt.main())
    {'month': 10,
     'perc_billable': '37.5 %',
     'raw_total': 15.0,
     'total': '15:00',
     'year': 2006}
    >>> pprint(nov.main())
    {'month': 11,
     'perc_billable': '95.8 %',
     'raw_total': 46.0,
     'total': '46:00',
     'year': 2006}

When the week total is below 40 hours the entry should be highligted. In
November we added exactly 40 hours in week 45.
   >>> week45 = nov.bookinglist[1]
   >>> week45['week_number']
   45
   >>> week45['week_total']
   '40:00'
   >>> week45['total_style']
   'good'

Let's look at week 43 in oktober, at the end of which the DST kicks in.

    >>> week43 = okt.bookinglist[4]
    >>> str(week43['week_start'])  # Returns unicode in Plone 4
    'Oct 23, 2006'
    >>> week43['week_number']
    43
    >>> week43['week_total']
    '5:00'
    >>> week43['total_style']
    'not-enough'
    >>> week43['days'][0]
    {'style': 'greyed', 'total': None, 'day_of_week': 'Monday'}
    >>> week43['days'][5]
    {'style': 'good', 'total': '2:00', 'day_of_week': 'Saturday'}
    >>> week43['days'][6]
    {'style': 'good', 'total': '3:00', 'day_of_week': 'Sunday'}
    >>> week43['total_style']
    'not-enough'

Let's also look at week 5.

    >>> okt.bookinglist[5]['days'][0]
    {'style': 'good', 'total': '4:00', 'day_of_week': 'Monday'}
    >>> okt.bookinglist[5]['days'][1]
    {'style': 'good', 'total': '5:00', 'day_of_week': 'Tuesday'}
    >>> okt.bookinglist[5]['days'][2]
    {'style': 'greyed', 'total': '6:00', 'day_of_week': 'Wednesday'}
    >>> okt.bookinglist[5]['days'][3]
    {'style': 'greyed', 'total': None, 'day_of_week': 'Thursday'}

At the beginning of the year things can go wrong, so test that too.

    >>> jan1 = DateTime('2002-01-01')
    >>> task.invokeFactory('Booking', id='jan102', hours=1, bookingDate=jan1)
    'jan102'
    >>> reset_request(task)
    >>> view = WeekBookingOverview(self.portal, TestRequest(form={'year': 2002, 'month': 1}))
    >>> [week['week_total'] for week in view.bookinglist]
    ['1:00', '0:00', '0:00', '0:00', '0:00']


There is a big overview that shows a table for the past year with for
every month for every employee the billable percentage.  These
percentages should be the same as what we got in the month overviews.

    >>> from Products.eXtremeManagement.browser.employees import EmployeesView
    >>> empview = EmployeesView(self.portal, TestRequest(), year=2006)
    >>> items = empview.items()
    >>> percentages = [item['monthly_percentages'] for item in items if \
    ...                item['name'] == 'employee'][0]
    >>> len(percentages)
    12
    >>> october = percentages[9]
    >>> october['url']
    'http://nohost/plone/booking_month?memberid=employee&month=10&year=2006'
    >>> okt.main()['perc_billable'] == october['percentage']
    True
    >>> november = percentages[10]
    >>> november['url']
    'http://nohost/plone/booking_month?memberid=employee&month=11&year=2006'
    >>> nov.main()['perc_billable'] == november['percentage']
    True
