Ignore:
Timestamp:
16 Nov 2015, 09:05:30 (9 years ago)
Author:
Henrik Bettermann
Message:

Add option which allows students to select a desired hostel before booking accommodation.

Location:
main/waeup.kofa/trunk/src/waeup/kofa/students
Files:
7 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.kofa/trunk/src/waeup/kofa/students/accommodation.py

    r13455 r13457  
    133133                entry for entry in entries if entry.owner == NOT_OCCUPIED]
    134134            if available_beds:
    135                 new_bed = students_utils.selectBed(available_beds)
     135                new_bed = students_utils.selectBed(
     136                    available_beds, self.__parent__.desired_hostel)
     137                if new_bed is None:
     138                    return False, _(
     139                        'There is no free bed in your desired hostel.')
    136140                new_bed.bookBed(student.student_id)
    137141            else:
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser.py

    r13455 r13457  
    19281928    grok.template('accommodationmanagepage')
    19291929    pnav = 4
    1930     officers_only_actions = [_('Remove selected')]
     1930    with_hostel_selection = True
     1931
     1932    @property
     1933    def actionsgroup1(self):
     1934        if not self.with_hostel_selection:
     1935            return []
     1936        students_utils = getUtility(IStudentsUtils)
     1937        acc_details  = students_utils.getAccommodationDetails(self.context.student)
     1938        error_message = students_utils.checkAccommodationRequirements(
     1939            self.context.student, acc_details)
     1940        if error_message:
     1941            return []
     1942        return [_('Save')]
     1943
     1944    @property
     1945    def actionsgroup2(self):
     1946        if getattr(self.request.principal, 'user_type', None) == 'student':
     1947            return [_('Book accommodation')]
     1948        return [_('Book accommodation'), _('Remove selected')]
    19311949
    19321950    @property
     
    19341952        return _('${a}: Accommodation',
    19351953            mapping = {'a':self.context.__parent__.display_fullname})
     1954
     1955    def getHostels(self):
     1956        """Get a list of all stored hostels.
     1957        """
     1958        yield(dict(name=None, title='--', selected=''))
     1959        for val in grok.getSite()['hostels'].values():
     1960            selected = ''
     1961            if val.hostel_id == self.context.desired_hostel:
     1962                selected = 'selected'
     1963            yield(dict(name=val.hostel_id, title=val.hostel_name,
     1964                       selected=selected))
     1965
     1966    @action(_('Save'), style='primary')
     1967    def save(self):
     1968        hostel = self.request.form.get('hostel', None)
     1969        self.context.desired_hostel = hostel
     1970        self.flash(_('Your selection has been saved.'))
     1971        return
     1972
     1973    @jsaction(_('Book accommodation'), style='primary')
     1974    def bookAccommodation(self, **data):
     1975        self.redirect(self.url(self.context, 'add'))
     1976        return
    19361977
    19371978    @jsaction(_('Remove selected'))
     
    19622003        self.redirect(self.url(self.context))
    19632004        return
    1964 
    1965     @property
    1966     def selected_actions(self):
    1967         if getattr(self.request.principal, 'user_type', None) == 'student':
    1968             return [action for action in self.actions
    1969                     if not action.label in self.officers_only_actions]
    1970         return self.actions
    19712005
    19722006class BedTicketAddPage(KofaPage):
     
    20302064            if available_beds:
    20312065                students_utils = getUtility(IStudentsUtils)
    2032                 bed = students_utils.selectBed(available_beds)
     2066                bed = students_utils.selectBed(
     2067                    available_beds, self.context.desired_hostel)
     2068                if bed is None:
     2069                    self.flash(_(
     2070                        'There is no free bed in your desired hostel. '
     2071                        'Please try another hostel.'),
     2072                        type="warning")
     2073                    self.redirect(self.url(self.context))
     2074                    return
    20332075                # Safety belt for paranoids: Does this bed really exist
    20342076                # in portal?
     
    20452087                self.flash(_('There is no free bed in your category ${a}.',
    20462088                    mapping = {'a':acc_details['bt']}), type="warning")
     2089                self.redirect(self.url(self.context))
    20472090                return
    20482091        if self.with_ac:
  • main/waeup.kofa/trunk/src/waeup/kofa/students/browser_templates/accommodationmanagepage.pt

    r13455 r13457  
    11<form action="." tal:attributes="action request/URL" method="POST"
    22      i18n:domain="waeup.kofa" enctype="multipart/form-data">
     3
     4  <tal:desired_hostel condition="view/actionsgroup1">
     5    <br />
     6    <p i18n:translate="">
     7    Select and save the <strong>desired hostel</strong> before booking acommodation.
     8    Your choice cannot be changed afterwards.
     9    </p>
     10    <div class="form-inline">
     11      <br />
     12      <div class="form-group">
     13        <select class="form-control" id="hostel" name="hostel">
     14          <option tal:repeat="hostel view/getHostels"
     15                  tal:attributes="value hostel/name; selected hostel/selected">
     16          <span tal:replace="hostel/title">USERTITLE
     17          </span>
     18          </option>
     19        </select>
     20      </div>
     21      <div class="form-group">
     22        <span tal:repeat="action view/actions" tal:omit-tag="">
     23          <input tal:condition="python:action.label in view.actionsgroup1"
     24                 tal:replace="structure action/render"/>
     25        </span>
     26      </div>
     27    </div>
     28    <br />
     29  </tal:desired_hostel>
     30
     31  <h3 i18n:domain="waeup.kofa" i18n:translate="">Bookings</h3>
     32  <br />
    333
    434  <table class="kofa-data-table dataTableManage">
     
    2858  </table>
    2959
    30   <div tal:condition="view/availableActions">
    31     <span tal:repeat="action view/selected_actions"
    32           tal:omit-tag="">
    33       <input tal:replace="structure action/render"/>
    34     </span>
    35   </div>
     60  <span tal:repeat="action view/actions"
     61        tal:omit-tag="">
     62    <input tal:condition="python:action.label in view.actionsgroup2"
     63          tal:replace="structure action/render"/>
     64  </span>
     65
    3666</form>
  • main/waeup.kofa/trunk/src/waeup/kofa/students/interfaces.py

    r13345 r13457  
    251251    phone = PhoneNumber(
    252252        title = _(u'Phone'),
    253         description = u'',
    254253        required = False,
    255254        )
     
    697696    """
    698697
     698    desired_hostel = schema.TextLine(
     699        title = _(u'Desired Hostel'),
     700        required = False,
     701        )
     702
    699703    def addBedTicket(bedticket):
    700704        """Add a bed ticket object.
  • main/waeup.kofa/trunk/src/waeup/kofa/students/tests/test_browser.py

    r13455 r13457  
    12031203        # Managers can use HOS code and book a bed space with it
    12041204        self.browser.open(self.acco_path)
    1205         self.browser.getLink("Book accommodation").click()
     1205        self.browser.getControl("Book accommodation").click()
    12061206        self.assertMatches('...You are in the wrong...',
    12071207                           self.browser.contents)
     
    12101210        # are in accommodation session
    12111211        self.student['studycourse'].current_session = 2003
    1212         self.browser.getLink("Book accommodation").click()
     1212        self.browser.getControl("Book accommodation").click()
    12131213        self.assertMatches('...Your current session does not match...',
    12141214                           self.browser.contents)
    12151215        self.student['studycourse'].current_session = 2004
    12161216        # All requirements are met and ticket can be created
    1217         self.browser.getLink("Book accommodation").click()
     1217        self.browser.getControl("Book accommodation").click()
    12181218        self.assertMatches('...Activation Code:...',
    12191219                           self.browser.contents)
     
    12271227        self.assertTrue(bed1.owner == self.student_id)
    12281228        # BedTicketAddPage is now blocked
    1229         self.browser.getLink("Book accommodation").click()
     1229        self.browser.getControl("Book accommodation").click()
    12301230        self.assertMatches('...You already booked a bed space...',
    12311231            self.browser.contents)
     
    30083008
    30093009    def test_student_accommodation(self):
     3010        # Create a second hostel with one bed
     3011        hostel = Hostel()
     3012        hostel.hostel_id = u'hall-2'
     3013        hostel.hostel_name = u'Hall 2'
     3014        self.app['hostels'].addHostel(hostel)
     3015        bed = Bed()
     3016        bed.bed_id = u'hall-2_A_101_A'
     3017        bed.bed_number = 1
     3018        bed.owner = NOT_OCCUPIED
     3019        bed.bed_type = u'regular_female_fr'
     3020        self.app['hostels'][hostel.hostel_id].addBed(bed)
     3021
    30103022        self.browser.open(self.login_path)
    30113023        self.browser.getControl(name="form.login").value = self.student_id
     
    30323044        # ... but not if booking period has expired ...
    30333045        self.app['hostels'].enddate = datetime.now(pytz.utc)
    3034         self.browser.getLink("Book accommodation").click()
     3046        self.browser.getControl("Book accommodation").click()
    30353047        self.assertMatches('...Outside booking period: ...',
    30363048                           self.browser.contents)
     
    30383050        # ... or student data are incomplete ...
    30393051        self.student['studycourse'].current_level = None
    3040         self.browser.getLink("Book accommodation").click()
     3052        self.browser.getControl("Book accommodation").click()
    30413053        self.assertMatches('...Your data are incomplete...',
    30423054            self.browser.contents)
    30433055        self.student['studycourse'].current_level = 100
    30443056        # ... or student is not the an allowed state ...
    3045         self.browser.getLink("Book accommodation").click()
     3057        self.browser.getControl("Book accommodation").click()
    30463058        self.assertMatches('...You are in the wrong...',
    30473059                           self.browser.contents)
     3060        # Students can still not see the disired hostel selector.
     3061        self.assertFalse('desired hostel' in self.browser.contents)
    30483062        IWorkflowInfo(self.student).fireTransition('admit')
    3049         self.browser.getLink("Book accommodation").click()
     3063        # Students can now see the disired hostel selector.
     3064        self.browser.reload()
     3065        self.browser.open(self.acco_path)
     3066        self.assertTrue('desired hostel' in self.browser.contents)
     3067        self.browser.getControl(name="hostel").value = ['hall-2']
     3068        self.browser.getControl("Save").click()
     3069        self.assertTrue('selection has been saved' in self.browser.contents)
     3070        self.assertTrue('<option selected="selected" value="hall-2">'
     3071            in self.browser.contents)
     3072        self.browser.getControl("Book accommodation").click()
    30503073        self.assertMatches('...Activation Code:...',
    30513074                           self.browser.contents)
     
    30583081        # ... or ACs owned by somebody else.
    30593082        ac.owner = u'Anybody'
     3083        self.browser.getControl(name="ac_series").value = sfeseries
     3084        self.browser.getControl(name="ac_number").value = sfenumber
     3085        self.browser.getControl("Create bed ticket").click()
     3086        # Hostel 2 has only a bed for women.
     3087        self.assertTrue('There is no free bed in your desired hostel'
     3088            in self.browser.contents)
     3089        self.browser.getControl(name="hostel").value = ['hall-1']
     3090        self.browser.getControl("Save").click()
     3091        self.browser.getControl("Book accommodation").click()
     3092        # Student can't use faked ACs ...
    30603093        self.browser.getControl(name="ac_series").value = sfeseries
    30613094        self.browser.getControl(name="ac_number").value = sfenumber
     
    30753108        self.assertTrue(bed.owner == self.student_id)
    30763109        # BedTicketAddPage is now blocked.
    3077         self.browser.getLink("Book accommodation").click()
     3110        self.browser.getControl("Book accommodation").click()
    30783111        self.assertMatches('...You already booked a bed space...',
    30793112            self.browser.contents)
  • main/waeup.kofa/trunk/src/waeup/kofa/students/utils.py

    r13304 r13457  
    627627        return
    628628
    629     def selectBed(self, available_beds):
    630         """Select a bed from a list of available beds.
    631         In the base configuration we select the first bed found,
    632         but can also randomize the selection if we like.
    633         """
    634         return available_beds[0]
     629    def selectBed(self, available_beds, desired_hostel=None):
     630        """Select a bed from a filtered list of available beds.
     631        In the base configuration beds are sorted by the sort id
     632        of the hostel and the bed number. The first bed found in
     633        this sorted list is taken.
     634        """
     635        sorted_beds = sorted(available_beds,
     636                key=lambda bed: 1000 * bed.__parent__.sort_id + bed.bed_number)
     637        if desired_hostel:
     638            # Filter desired hostel beds
     639            filtered_beds = [bed for bed in sorted_beds
     640                             if bed.bed_id.startswith(desired_hostel)]
     641            if not filtered_beds:
     642                return
     643            return filtered_beds[0]
     644        return sorted_beds[0]
    635645
    636646    def _admissionText(self, student, portal_language):
  • main/waeup.kofa/trunk/src/waeup/kofa/students/viewlets.py

    r13129 r13457  
    501501        return self.view.url(self.view.context, self.target)
    502502
    503 class AddBedTicketActionButton(ManageActionButton):
    504     grok.order(1)
    505     grok.context(IStudentAccommodation)
    506     grok.view(AccommodationManageFormPage)
    507     grok.require('waeup.handleAccommodation')
    508     icon = 'actionicon_home.png'
    509     text = _('Book accommodation')
    510     target = 'add'
    511 
    512503class BedTicketSlipActionButton(ManageActionButton):
    513504    grok.order(1)
Note: See TracChangeset for help on using the changeset viewer.