Changeset 7068


Ignore:
Timestamp:
10 Nov 2011, 18:56:18 (13 years ago)
Author:
Henrik Bettermann
Message:

Much more logic for bed allocation, bed release.

Implement student relocation.

Location:
main/waeup.sirp/trunk/src/waeup/sirp
Files:
13 edited

Legend:

Unmodified
Added
Removed
  • main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser.py

    r7063 r7068  
    650650        story.append(Spacer(1, 24))
    651651
    652         data = []
     652
    653653        # insert passport photograph
    654654        img = getUtility(IExtFileStore).getFileByContext(self.context)
     
    656656            img = open(os.path.join(IMAGE_PATH, 'placeholder_m.jpg'), 'rb')
    657657        doc_img = Image(img.name, width=4*cm, height=3*cm, kind='bound')
    658         data.append(['', doc_img])
     658        story.append(doc_img)
     659        story.append(Spacer(1, 18))
    659660
    660661        # render widget fields
     662        data = []
    661663        self.setUpWidgets()
    662664        for widget in self.widgets:
  • main/waeup.sirp/trunk/src/waeup/sirp/applicants/browser_templates/form_display.pt

    r7063 r7068  
    1313<table class="zebra">
    1414  <tbody>
    15     <tr><td></td>
     15    <tr>
    1616    <td><img src="" tal:attributes="src view/passport_url" /></td>
    1717    </tr>
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser.py

    r7042 r7068  
    3535from waeup.sirp.authentication import get_principal_role_manager
    3636from waeup.sirp.hostels.container import HostelsContainer
    37 from waeup.sirp.hostels.hostel import Hostel, NOT_OCCUPIED
    38 from waeup.sirp.hostels.interfaces import IHostelsContainer, IHostel
     37from waeup.sirp.hostels.vocabularies import NOT_OCCUPIED
     38from waeup.sirp.hostels.hostel import Hostel
     39from waeup.sirp.hostels.interfaces import (
     40    IHostelsContainer, IHostel, IBed, IBedAllocateStudent)
    3941
    4042def write_log_message(view, message):
     
    8688    def title(self):
    8789        return self.context.hostel_name
     90
     91class BedBreadcrumb(Breadcrumb):
     92    """A breadcrumb for the hostel container.
     93    """
     94    grok.context(IBed)
     95
     96    def title(self):
     97        co = self.context.getBedCoordinates()
     98        return 'Block %s, Room %s, Bed %s' % (co[1], co[2], co[3])
    8899
    89100class HostelsContainerPage(WAeUPDisplayFormPage):
     
    277288        released = []
    278289        for bed_id in child_id:
    279             try:
    280                 message = self.context[bed_id].releaseBed()
    281                 released.append('%s (%s)' % (bed_id,message))
    282             except:
    283                 self.flash('Could not release %s: %s: %s' % (
    284                         id, sys.exc_info()[0], sys.exc_info()[1]))
    285                 self.redirect(self.url(self.context, '@@manage')+'#tab-2')
    286                 return
     290            message = self.context[bed_id].releaseBed()
     291            released.append('%s (%s)' % (bed_id,message))
    287292        if len(released):
    288293            message = ', '.join(released)
     
    291296            self.redirect(self.url(self.context, '@@manage')+'#tab-2')
    292297        return
     298
     299class BedManageFormPage(WAeUPEditFormPage):
     300    """ View to edit bed data
     301    """
     302    grok.context(IBedAllocateStudent)
     303    grok.name('index')
     304    grok.require('waeup.manageHostels')
     305    form_fields = grok.AutoFields(IBedAllocateStudent).omit(
     306        'bed_id').omit('bed_number').omit('bed_type')
     307    label = 'Allocate student'
     308    pnav = 5
     309
     310    @property
     311    def title(self):
     312        co = self.context.getBedCoordinates()
     313        return '%s, Block %s, Room %s, Bed %s' % (
     314            self.context.__parent__.hostel_name, co[1], co[2], co[3])
     315
     316    @grok.action('Save')
     317    def save(self, **data):
     318        msave(self, **data)
     319        self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab-2')
     320        return
     321
     322    def update(self):
     323        if self.context.owner != NOT_OCCUPIED:
     324            # Don't use this form for exchanging students.
     325            # Beds must be released first before they can be allocated to
     326            # other students.
     327            self.redirect(self.url(self.context.__parent__, '@@manage')+'#tab-2')
     328        return
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/browser_templates/hostelmanagepage.pt

    r7012 r7068  
    8888              <span tal:content="value/owner">Owner</span>
    8989            </a>
     90            <a tal:condition="python: value.owner == view.not_occupied"
     91               tal:attributes="href python: view.url(value)">
     92            [allocate student]
     93            </a>
    9094          </td>
    9195        </tr>
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/catalog.py

    r7006 r7068  
    2121    bed_type = index.Field(attribute='bed_type')
    2222    owner = index.Field(attribute='owner')
    23 
    24 class BedQueryResultItem(object):
    25     grok.implements(IQueryResultItem)
    26 
    27     title = u'Bed Query Item'
    28     description = u'Some bed found in a search'
    29 
    30     def __init__(self, context, view):
    31         self.context = context
    32         self.url = view.url(context)
    33         self.bed_id = context.bed_id
    34         self.bed_type = context.bed_type
    35         self.bed_number = context.bed_number
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/hostel.py

    r7058 r7068  
    2222from grok import index
    2323from waeup.sirp.utils.helpers import attrs_to_fields
    24 from waeup.sirp.hostels.interfaces import IHostel, IBed
     24from waeup.sirp.hostels.vocabularies import NOT_OCCUPIED
     25from waeup.sirp.hostels.interfaces import IHostel, IBed, IBedAllocateStudent
    2526from waeup.sirp.students.interfaces import IBedTicket
    26 
    27 NOT_OCCUPIED = u'not occupied'
    2827
    2928class Hostel(grok.Container):
     
    121120    """This is a bed.
    122121    """
    123     grok.implements(IBed)
     122    grok.implements(IBed, IBedAllocateStudent)
    124123    grok.provides(IBed)
    125124
     
    208207    of the bed is cleared (set to NOT_OCCUPIED).
    209208    """
    210     allocated_bed = bedticket.bed
    211     allocated_bed.owner = NOT_OCCUPIED
    212     notify(grok.ObjectModifiedEvent(allocated_bed))
     209    if bedticket.bed != None:
     210        bedticket.bed.owner = NOT_OCCUPIED
     211        notify(grok.ObjectModifiedEvent(bedticket.bed))
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/interfaces.py

    r6996 r7068  
    55from waeup.sirp.interfaces import IWAeUPObject
    66from waeup.sirp.hostels.vocabularies import (
    7     bed_letters, blocks, special_handling)
     7    bed_letters, blocks, special_handling, StudentSource)
    88
    99class IHostelsContainer(IWAeUPObject):
     
    172172        default = u'',
    173173        )
     174
     175
     176
     177class IBedAllocateStudent(IBed):
     178    """A representation of beds for allocation form only.
     179
     180    """
     181
     182    owner = schema.Choice(
     183        title = u'Owner (Student)',
     184        source = StudentSource(),
     185        default = None,
     186        required = True,
     187        )
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/tests.py

    r7045 r7068  
    108108        self.student['studycourse'].current_session = 2004
    109109        self.student['studycourse'].entry_session = 2004
     110        # The students_catalog must be informed that the
     111        # session attribute has changed
     112        notify(grok.ObjectModifiedEvent(self.student))
    110113
    111114        # Set accommodation_session
     
    125128
    126129        self.container_path = 'http://localhost/app/hostels'
     130        self.student_path = 'http://localhost/app/students/%s' % self.student_id
    127131        self.manage_container_path = self.container_path + '/@@manage'
    128132        self.add_hostel_path = self.container_path + '/addhostel'
     
    269273        self.browser.open(self.container_path + '/hall-1/manage')
    270274        ctrl = self.browser.getControl(name='val_id')
     275        self.browser.getControl("Release selected beds", index=0).click()
     276        self.assertMatches("...No item selected...", self.browser.contents)
     277        ctrl = self.browser.getControl(name='val_id')
    271278        ctrl.getControl(value='hall-1_A_101_D').selected = True
    272279        self.browser.getControl("Release selected beds", index=0).click()
     
    276283        self.assertMatches(bedticket.bed_coordinates,
    277284          u' -- booking cancelled on <YYYY-MM-DD hh:mm:ss> --')
     285        # Managers can manually allocate studenst after cancellation
     286        self.browser.open(self.container_path + '/hall-1/hall-1_A_101_A')
     287        self.browser.getControl(name="form.owner").value = [self.student_id]
     288        self.browser.getControl("Save").click()
     289        self.assertMatches("...Form has been saved...", self.browser.contents)
    278290        # Remove entire hostel
    279291        self.browser.open(self.manage_container_path)
  • main/waeup.sirp/trunk/src/waeup/sirp/hostels/vocabularies.py

    r6973 r7068  
    11"""Vocabularies and sources for the accommodation section.
    22"""
     3from  grok import getSite
     4from zope.component import getUtility
     5from zope.catalog.interfaces import ICatalog
     6from zc.sourcefactory.contextual import BasicContextualSourceFactory
    37from zc.sourcefactory.basic import BasicSourceFactory
    48from waeup.sirp.interfaces import SimpleWAeUPVocabulary
    59
     10NOT_OCCUPIED = u'not occupied'
     11
     12class StudentSource(BasicContextualSourceFactory):
     13    """A students source delivers all students in accommodation session.
     14    """
     15
     16    def acco_students(self, context):
     17        catalog = getUtility(ICatalog, name='students_catalog')
     18        accommodation_session = getSite()['configuration'].accommodation_session
     19        students = catalog.searchResults(current_session=(
     20            accommodation_session,accommodation_session))
     21        try:
     22            existing_students = [
     23                context.__parent__[key].owner
     24                for key in context.__parent__.keys()]
     25        except AttributeError:
     26            return {NOT_OCCUPIED:NOT_OCCUPIED}
     27        students = [student for student in students
     28                      if not student.student_id in existing_students]
     29        students = sorted(list(students),
     30                          key=lambda value: value.student_id)
     31        return dict([(student.student_id,student.fullname) for student in students])
     32
     33    def getValues(self, context):
     34        return self.acco_students(context).keys()
     35
     36    def getToken(self, context, value):
     37        return value
     38
     39    def getTitle(self, context, value):
     40        return "%s - %s" % (value, self.acco_students(context)[value])
    641
    742bed_letters = SimpleWAeUPVocabulary(
  • main/waeup.sirp/trunk/src/waeup/sirp/students/browser.py

    r7061 r7068  
    186186                self.flash('Empty search string.')
    187187            return
     188        if self.searchtype == 'current_session':
     189            self.searchterm = int(self.searchterm)
    188190        self.hitlist = search(query=self.searchterm,
    189191            searchtype=self.searchtype, view=self)
     
    11781180        deleted = []
    11791181        for id in child_id:
    1180             try:
    1181                 del self.context[id]
    1182                 deleted.append(id)
    1183             except:
    1184                 self.flash('Could not delete %s: %s: %s' % (
    1185                         id, sys.exc_info()[0], sys.exc_info()[1]))
     1182            del self.context[id]
     1183            deleted.append(id)
    11861184        if len(deleted):
    11871185            self.flash('Successfully removed: %s' % ', '.join(deleted))
     
    12951293        coordinates = bed.getBedCoordinates()[1:]
    12961294        block, room_nr, bed_nr = coordinates
    1297         bedticket.bed_coordinates = '%s, Block %s, Room %s, Bed %s' % (
    1298             hall_title, block, room_nr, bed_nr)
     1295        bedticket.bed_coordinates = '%s, Block %s, Room %s, Bed %s (%s)' % (
     1296            hall_title, block, room_nr, bed_nr, bed.bed_type)
    12991297        key = str(acc_details['booking_session'])
    13001298        self.context[key] = bedticket
     
    13811379        student = self.context.getStudent()
    13821380        acc_details  = self.getAccommodationDetails(student)
     1381        if self.context.bed != None and \
     1382              'reserved' in self.context.bed.bed_type:
     1383            self.flash("Students in reserved beds can't be relocated.")
     1384            self.redirect(self.url(self.context))
     1385            return
    13831386        if acc_details['bt'] == self.context.bed_type and \
     1387                self.context.bed != None and \
    13841388                self.context.bed.bed_type == self.context.bed_type:
    1385             self.flash("Bed category hasn't changed. Student can't be relocated.")
    1386             return
    1387         # Search a bed and exit if no bed is found
     1389            self.flash("Student can't be relocated.")
     1390            self.redirect(self.url(self.context))
     1391            return
     1392        # Search a bed
    13881393        cat = queryUtility(ICatalog, name='beds_catalog', default=None)
    13891394        entries = cat.searchResults(
    1390             bed_type=(acc_details['bt'],acc_details['bt']))
    1391         available_beds = [
    1392             entry for entry in entries if entry.owner == NOT_OCCUPIED]
    1393         if not available_beds:
    1394             self.flash('There is no free bed in your category %s.'
    1395                         % acc_details['bt'])
    1396             return
    1397         #entries = cat.searchResults(
    1398         #    owner=(student.student_id,student.student_id))
    1399         # Rlease old bed
    1400         try:
    1401             allocated_bed = self.context.bed
    1402             allocated_bed.owner = NOT_OCCUPIED
    1403             notify(grok.ObjectModifiedEvent(allocated_bed))
    1404         except AttributeError:
    1405             # Cannot happen but anyway...
    1406             pass
     1395            owner=(student.student_id,student.student_id))
     1396        if len(entries) and self.context.bed == None:
     1397            # If booking has been cancelled but other bed space has been
     1398            # manually allocated after cancellation use this bed
     1399            new_bed = [entry for entry in entries][0]
     1400        else:
     1401            # Search for other available beds
     1402            entries = cat.searchResults(
     1403                bed_type=(acc_details['bt'],acc_details['bt']))
     1404            available_beds = [
     1405                entry for entry in entries if entry.owner == NOT_OCCUPIED]
     1406            if available_beds:
     1407                new_bed = self.selectBed(available_beds)
     1408                new_bed.bookBed(student.student_id)
     1409            else:
     1410                self.flash('There is no free bed in your category %s.'
     1411                            % acc_details['bt'])
     1412                self.redirect(self.url(self.context))
     1413                return
     1414        # Rlease old bed if exists
     1415        if self.context.bed != None:
     1416            self.context.bed.owner = NOT_OCCUPIED
     1417            notify(grok.ObjectModifiedEvent(self.context.bed))
    14071418        # Alocate new bed
    14081419        self.context.bed_type = acc_details['bt']
    1409         bed = self.selectBed(available_beds)
    1410         bed.bookBed(student.student_id)
    1411         self.context.bed = bed
    1412         hall_title = bed.__parent__.hostel_name
    1413         coordinates = bed.getBedCoordinates()[1:]
     1420        self.context.bed = new_bed
     1421        hall_title = new_bed.__parent__.hostel_name
     1422        coordinates = new_bed.getBedCoordinates()[1:]
    14141423        block, room_nr, bed_nr = coordinates
    1415         self.context.bed_coordinates = '%s, Block %s, Room %s, Bed %s' % (
    1416             hall_title, block, room_nr, bed_nr)
    1417         self.flash('Student relocated and new bed booked: %s'
    1418             % self.context.bed_coordinates)
     1424        self.context.bed_coordinates = '%s, Block %s, Room %s, Bed %s (%s)' % (
     1425            hall_title, block, room_nr, bed_nr, new_bed.bed_type)
     1426        self.flash('Student relocated: %s' % self.context.bed_coordinates)
    14191427        self.redirect(self.url(self.context))
    14201428        return
    14211429
    14221430    def render(self):
    1423         self.redirect(self.url(self.context, '@@index'))
     1431        #self.redirect(self.url(self.context, '@@index'))
    14241432        return
    14251433
  • main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/containermanagepage.pt

    r6820 r7068  
    1010    <option value="student_id">with id</option>
    1111    <option value="fullname">with name</option>
     12    <option value="current_session">in session</option>
    1213  </select>
    1314
  • main/waeup.sirp/trunk/src/waeup/sirp/students/browser_templates/containerpage.pt

    r6818 r7068  
    1212    <option value="reg_number">with registration number</option>
    1313    <option value="matric_number">with matriculation number</option>
     14    <option value="current_session">in session</option>
    1415  </select>
    1516
  • main/waeup.sirp/trunk/src/waeup/sirp/students/tests/test_browser.py

    r7061 r7068  
    961961        self.browser.getLink("Relocate student").click()
    962962        self.assertMatches(
    963             "...Bed category hasn't changed...", self.browser.contents)
     963            "...Student can't be relocated...", self.browser.contents)
    964964        self.student.sex = u'f'
    965965        self.browser.getLink("Relocate student").click()
     
    977977        # Managers can relocate students if the bed's bed_type has changed
    978978        bed1.bed_type = u'regular_female_fr'
    979         bed2.bed_type = u'regular_male_reserved'
     979        bed2.bed_type = u'regular_male_fr'
    980980        notify(grok.ObjectModifiedEvent(bed1))
    981981        notify(grok.ObjectModifiedEvent(bed2))
    982982        self.browser.getLink("Relocate student").click()
    983983        self.assertMatches(
    984             "...Student relocated and new bed booked...", self.browser.contents)
     984            "...Student relocated...", self.browser.contents)
    985985        self.assertMatches(
    986986            "... Hall 1, Block A, Room 101, Bed A...", self.browser.contents)
    987987        self.assertMatches(bed1.owner, self.student_id)
    988988        self.assertMatches(bed2.owner, NOT_OCCUPIED)
    989         # Managers can delete bed tickets
     989        # Managers can't relocate students if bed is reserved
     990        self.student.sex = u'm'
     991        bed1.bed_type = u'regular_female_reserved'
     992        notify(grok.ObjectModifiedEvent(bed1))
     993        self.browser.getLink("Relocate student").click()
     994        self.assertMatches(
     995            "...Students in reserved beds can't be relocated...",
     996            self.browser.contents)
     997        # Managers can relocate students if booking has been cancelled but
     998        # other bed space has been manually allocated after cancellation
     999        old_owner = bed1.releaseBed()
     1000        self.assertMatches(old_owner, self.student_id)
     1001        bed2.owner = self.student_id
     1002        self.browser.open(self.acco_student_path + '/2004')
     1003        self.assertMatches(
     1004            "...booking cancelled...", self.browser.contents)
     1005        self.browser.getLink("Relocate student").click()
     1006        # We didn't informed the catalog therefore the new owner is not found
     1007        self.assertMatches(
     1008            "...There is no free bed in your category regular_male_fr...",
     1009            self.browser.contents)
     1010        # Now we fire the event properly
     1011        notify(grok.ObjectModifiedEvent(bed2))
     1012        self.browser.getLink("Relocate student").click()
     1013        self.assertMatches(
     1014            "...Student relocated...", self.browser.contents)
     1015        self.assertMatches(
     1016            "... Hall 1, Block A, Room 101, Bed B...", self.browser.contents)
     1017          # Managers can delete bed tickets
    9901018        self.browser.open(self.acco_student_path)
    9911019        ctrl = self.browser.getControl(name='val_id')
Note: See TracChangeset for help on using the changeset viewer.