==============
Emergency Days
==============

Set up
------

    >>> from schooltool.testing import setup as sbsetup
    >>> sbsetup.setUpCalendaring()
    >>> sbsetup.setUpApplicationPreferences()

    >>> from schooltool.term.interfaces import ITermContainer
    >>> from schooltool.term.term import getTermContainer
    >>> from zope.component import provideAdapter
    >>> from zope.interface import Interface
    >>> provideAdapter(getTermContainer, [Interface], ITermContainer)

    >>> from schooltool.schoolyear.schoolyear import getSchoolYearContainer
    >>> provideAdapter(getSchoolYearContainer)


First of all, we need an app object:

    >>> app = sbsetup.setUpSchoolToolSite()
    >>> from schooltool.timetable.schema import TimetableSchemaContainer
    >>> schemas = TimetableSchemaContainer()
    >>> from zope.component import provideAdapter
    >>> from schooltool.timetable.interfaces import ITimetableSchemaContainer
    >>> provideAdapter(lambda x: schemas, adapts=[Interface], provides=ITimetableSchemaContainer)
    >>> from zope.location.location import locate
    >>> locate(schemas, app, 'ttschemas')

We will need a schoolyear with a term:

    >>> import datetime

    >>> from schooltool.schoolyear.schoolyear import SchoolYear
    >>> from schooltool.schoolyear.interfaces import ISchoolYearContainer
    >>> sy = SchoolYear("2005",
    ...                 datetime.date(2005, 1, 1),
    ...                 datetime.date(2005, 12, 31))
    >>> ISchoolYearContainer(app)['2005'] = sy

    >>> from schooltool.term.term import Term
    >>> term = Term('2005 summer',
    ...             datetime.date(2005, 6, 1),
    ...             datetime.date(2005, 8, 31))
    >>> from schooltool.term.interfaces import ITermContainer
    >>> ITermContainer(app)["2005-summer"] = term
    >>> term.addWeekdays(0, 1, 2, 3, 4, 5)

We have a timetable schema to put the view on:

    >>> from schooltool.timetable.browser import SpecialDayView
    >>> ttschema = createSchema(['Day 1', 'Day 2'],
    ...                         ['First',
    ...                          'Second',
    ...                          'Third',
    ...                          'Fourth'],
    ...                         ['First',
    ...                          'Second',
    ...                          'Third',
    ...                          'Fourth'])
    >>> schemas['usual'] = ttschema
    >>> ttschema1 = createSchema(['Day 1', 'Day 2', 'Day 3'],
    ...                          ['First', 'Second', 'Third', 'Fourth'],
    ...                          ['First', 'Second', 'Third', 'Fourth'],
    ...                          ['First', 'Second', 'Third', 'Fourth'])
    >>> schemas['unusual'] = ttschema1

The schemas have a model attribute:

    >>> from schooltool.timetable.model import SequentialDaysTimetableModel
    >>> default = createDayTemplate([(9, 0, 45),
    ...                              (10, 0, 45),
    ...                              (11, 0, 45),
    ...                              (12, 0, 45)])
    >>> ttschema.model = SequentialDaysTimetableModel(['Day 1', 'Day 2'],
    ...                                               {None: default})
    >>> ttschema1.model = SequentialDaysTimetableModel(
    ...     ['Day 1', 'Day 2', 'Day 3'],
    ...     {None: default})

Now we can create the view:

    >>> from zope.publisher.browser import TestRequest
    >>> request = TestRequest()
    >>> from schooltool.term.browser.emergency import EmergencyDayView
    >>> view = EmergencyDayView(term, request)
    >>> print view()
    <BLANKLINE>
    ...
    <p>
    This form allows you to mark a date as an emergency non-schoolday and
    add a replacement day to the term.
    </p>
    ...
      <div class="row">
        <label for="date">Date</label>
        <input type="text" name="date" id="date" />
      </div>
    <BLANKLINE>
      <div class="controls">
        <input type="submit" class="button-ok" name="CHOOSE"
               value="Proceed" />
        <input type="submit" class="button-cancel" name="CANCEL"
               value="Cancel" />
      </div>
    ...

When we enter the emergency date, we get to choose the replacement day:

    >>> request = TestRequest(form={'date': '2005-07-07'})
    >>> view = EmergencyDayView(term, request)
    >>> view.update()
    >>> view.date
    datetime.date(2005, 7, 7)

The view now can offer a choice of replacements after this day.  These will be
all non-schooldays in the term and 3 days after the term:

    >>> view.replacements()
    [datetime.date(2005, 7, 10),
     datetime.date(2005, 7, 17),
     datetime.date(2005, 7, 24),
     datetime.date(2005, 7, 31),
     datetime.date(2005, 8, 7),
     datetime.date(2005, 8, 14),
     datetime.date(2005, 8, 21),
     datetime.date(2005, 8, 28),
     datetime.date(2005, 9, 1),
     datetime.date(2005, 9, 2),
     datetime.date(2005, 9, 3)]


The page presented next contains a selection of these dates:

    >>> print view()
    <BLANKLINE>
    ...
      <input type="hidden" name="date" value="2005-07-07" />
    ...
      <div class="row">
        <label for="replacement">Replacement</label>
        <select id="replacement" name="replacement">
          <option>2005-07-10</option>
          <option>2005-07-17</option>
          <option>2005-07-24</option>
          <option>2005-07-31</option>
          <option>2005-08-07</option>
          <option>2005-08-14</option>
          <option>2005-08-21</option>
          <option>2005-08-28</option>
          <option>2005-09-01</option>
          <option>2005-09-02</option>
          <option>2005-09-03</option>
        </select>
      </div>
      ...

The original day ids of the emergency day were:

     >>> def getDayId(date, ttschema):
     ...     return ttschema.model._periodsInDay(term, ttschema, date)[0]
     >>> getDayId(datetime.date(2005, 7, 7), ttschema)
     'Day 2'
     >>> getDayId(datetime.date(2005, 7, 7), ttschema1)
     'Day 2'

The ids of some other days before and after the planned replacement day:

     >>> getDayId(datetime.date(2005, 7, 8), ttschema)
     'Day 1'
     >>> getDayId(datetime.date(2005, 7, 11), ttschema)
     'Day 1'

     >>> getDayId(datetime.date(2005, 7, 8), ttschema1)
     'Day 3'
     >>> getDayId(datetime.date(2005, 7, 11), ttschema1)
     'Day 2'

If the user selects a replacement day and calls the view, several things
happen:

    >>> request = TestRequest(form={'date': '2005-07-07',
    ...                             'replacement': '2005-07-10'})
    >>> view = EmergencyDayView(term, request)
    >>> result = view()
    >>> view.date
    datetime.date(2005, 7, 7)
    >>> view.replacement
    datetime.date(2005, 7, 10)

The user gets redirected:

    >>> request.response.getStatus()
    302
    >>> request.response.getHeader('location')
    'http://127.0.0.1/schooltool.schoolyear/2005/2005-summer'

The replacement day gets added to the calendar, and the emergency day gets an
empty day template:

    >>> term.isSchoolday(datetime.date(2005, 7, 10))
    True
    >>> term.isSchoolday(datetime.date(2005, 7, 7))
    True
    >>> ttschema.model.periodsInDay(term, ttschema,
    ...                             datetime.date(2005, 7, 7))
    []
    >>> ttschema1.model.periodsInDay(term, ttschema1,
    ...                              datetime.date(2005, 7, 7))
    []

The day id of the replacement day is the same as that of the emergency day:

     >>> getDayId(datetime.date(2005, 7, 7), ttschema)
     'Day 2'
     >>> getDayId(datetime.date(2005, 7, 7), ttschema1)
     'Day 2'

Day ids of the days before and after the replacement day are unchanged:

     >>> getDayId(datetime.date(2005, 7, 8), ttschema)
     'Day 1'
     >>> getDayId(datetime.date(2005, 7, 11), ttschema)
     'Day 1'

     >>> getDayId(datetime.date(2005, 7, 8), ttschema1)
     'Day 3'
     >>> getDayId(datetime.date(2005, 7, 11), ttschema1)
     'Day 2'

All day events get posted to the schoolwide calendar on both days, notifying
of the shift:

    >>> from schooltool.app.app import getSchoolToolApplication
    >>> from schooltool.app.interfaces import ISchoolToolCalendar
    >>> cal = ISchoolToolCalendar(getSchoolToolApplication())
    >>> events = list(cal)
    >>> events.sort()
    >>> for event in events:
    ...     print event.dtstart
    ...     print event.title
    2005-07-07 00:00:00+00:00
    School cancelled due to emergency. Replacement day 2005-07-10.
    2005-07-10 00:00:00+00:00
    Replacement day for emergency day 2005-07-07.

When the replacement day is outside the term, the end date of the term gets
adjusted:

    >>> request = TestRequest(form={'date': '2005-07-08',
    ...                             'replacement': '2005-09-03'})
    >>> view = EmergencyDayView(term, request)
    >>> result = view()
    >>> getDayId(datetime.date(2005, 9, 3), ttschema)
    'Day 1'
    >>> getDayId(datetime.date(2005, 9, 3), ttschema1)
    'Day 3'
    >>> term.last
    datetime.date(2005, 9, 3)

The days that might have been implicitly added to the term (might have been a
weekend) are not marked as schooldays:

    >>> term.isSchoolday(datetime.date(2005, 9, 1))
    False
    >>> term.isSchoolday(datetime.date(2005, 9, 2))
    False
    >>> term.isSchoolday(datetime.date(2005, 9, 3))
    True


Cancel
------

If the cancel button is pressed, nothing is changed, and the user is
redirected:

    >>> request = TestRequest(form={'date': '2005-07-09',
    ...                             'replacement': '2005-09-04',
    ...                             'CANCEL': 'Cancel'})
    >>> view = EmergencyDayView(term, request)
    >>> result = view()
    >>> ttschema.model.periodsInDay(term, ttschema,
    ...                             datetime.date(2005, 7, 9))
    [('First', datetime.time(9, 0), datetime.timedelta(0, 2700)),
    ('Second', datetime.time(10, 0), datetime.timedelta(0, 2700)),
    ('Third', datetime.time(11, 0), datetime.timedelta(0, 2700)),
    ('Fourth', datetime.time(12, 0), datetime.timedelta(0, 2700))]

    >>> term.last
    datetime.date(2005, 9, 3)

    >>> request.response.getStatus()
    302
    >>> request.response.getHeader('location')
    'http://127.0.0.1/schooltool.schoolyear/2005/2005-summer'


Errors
------

If date is invalid, the user sees a nice error:

    >>> request = TestRequest(form={'date': '2007-09-05'})
    >>> view = EmergencyDayView(term, request)
    >>> print view()
    <BLANKLINE>
    ...
    <div class="error">The date you entered is invalid.
       Please use the YYYY-MM-DD format.</div>
    ...


If the date is not in term, the user sees the appropriate message:

    >>> request = TestRequest(form={'date': '1999-12-31'})
    >>> view = EmergencyDayView(term, request)
    >>> print view()
    <BLANKLINE>
    ...
    <div class="error">The date you entered does not belong
    to this term.</div>
    ...

If the date is not a schoolday, we tell that:

    >>> request = TestRequest(form={'date': '2005-07-17'})
    >>> view = EmergencyDayView(term, request)
    >>> print view()
    <BLANKLINE>
    ...
    <div class="error">The date you entered is not a schoolday.</div>
    ...

If replacement is invalid, the user gets to enter it again:

    >>> request = TestRequest(form={'date': '2005-07-19',
    ...                             'replacement': 'whatever'})
    >>> view = EmergencyDayView(term, request)
    >>> print view()
    <BLANKLINE>
    ...
    <div class="error">The replacement date you entered is invalid.</div>
    ...
