source: main/waeup.kofa/trunk/src/waeup/kofa/hostels/hostel.py @ 9030

Last change on this file since 9030 was 8685, checked in by Henrik Bettermann, 13 years ago

Add hostel allocation start end end date attributes to hostels.

Move hostel allocation parameters from configuration to hostels. AccommodationOfficer? must be able to edit these parameters.

  • Property svn:keywords set to Id
File size: 9.0 KB
Line 
1## $Id: hostel.py 8685 2012-06-12 07:17:01Z henrik $
2##
3## Copyright (C) 2011 Uli Fouquet & Henrik Bettermann
4## This program is free software; you can redistribute it and/or modify
5## it under the terms of the GNU General Public License as published by
6## the Free Software Foundation; either version 2 of the License, or
7## (at your option) any later version.
8##
9## This program is distributed in the hope that it will be useful,
10## but WITHOUT ANY WARRANTY; without even the implied warranty of
11## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12## GNU General Public License for more details.
13##
14## You should have received a copy of the GNU General Public License
15## along with this program; if not, write to the Free Software
16## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17##
18"""
19These are the hostels.
20"""
21import grok
22from zope.event import notify
23from zope.component import getUtility
24from datetime import datetime
25from waeup.kofa.utils.helpers import attrs_to_fields
26from waeup.kofa.hostels.vocabularies import NOT_OCCUPIED
27from waeup.kofa.hostels.interfaces import IHostel, IBed, IBedAllocateStudent
28from waeup.kofa.students.interfaces import IBedTicket
29from waeup.kofa.interfaces import IKofaUtils
30from waeup.kofa.interfaces import MessageFactory as _
31from waeup.kofa.utils.helpers import now
32
33class Hostel(grok.Container):
34    """This is a hostel.
35    """
36    grok.implements(IHostel)
37    grok.provides(IHostel)
38
39    def loggerInfo(self, ob_class, comment=None):
40        target = self.__name__
41        return grok.getSite()['hostels'].logger_info(ob_class,target,comment)
42
43    def addBed(self, bed):
44        """Add a bed.
45        """
46        if not IBed.providedBy(bed):
47            raise TypeError(
48                'Hostels contain only IBed instances')
49        self[bed.bed_id] = bed
50        return
51
52    def updateBeds(self):
53        """Fill hostel with beds or update beds.
54        """
55        added_counter = 0
56        modified_counter = 0
57        removed_counter = 0
58        modified_beds = u''
59
60        # Remove all empty beds. Occupied beds remain in hostel!
61        keys = list(self.keys()) # create list copy
62        for key in keys:
63            if self[key].owner == NOT_OCCUPIED:
64                del self[key]
65                self._p_changed = True
66                removed_counter += 1
67            else:
68                self[key].bed_number = 9999
69        remaining = len(keys) - removed_counter
70
71        blocks_for_female = getattr(self,'blocks_for_female',[])
72        blocks_for_male = getattr(self,'blocks_for_male',[])
73        beds_for_fresh = getattr(self,'beds_for_fresh',[])
74        beds_for_pre = getattr(self,'beds_for_pre',[])
75        beds_for_returning = getattr(self,'beds_for_returning',[])
76        beds_for_final = getattr(self,'beds_for_final',[])
77        beds_for_all = getattr(self,'beds_for_all',[])
78        beds_reserved = getattr(self,'beds_reserved',[])
79        all_blocks = blocks_for_female + blocks_for_male
80        all_beds = (beds_for_pre + beds_for_fresh +
81            beds_for_returning + beds_for_final + beds_for_all)
82        for block in all_blocks:
83            sex = 'male'
84            if block in blocks_for_female:
85                sex = 'female'
86            for floor in range(1,int(self.floors_per_block)+1):
87                for room in range(1,int(self.rooms_per_floor)+1):
88                    for bed in all_beds:
89                        room_nr = floor*100 + room
90                        bt = 'all'
91                        if '%s_%s_%s' % (block,room_nr,bed) in beds_reserved:
92                            bt = "reserved"
93                        elif bed in beds_for_fresh:
94                            bt = 'fr'
95                        elif bed in beds_for_pre:
96                            bt = 'pr'
97                        elif bed in beds_for_final:
98                            bt = 'fi'
99                        elif bed in beds_for_returning:
100                            bt = 're'
101                        bt = u'%s_%s_%s' % (self.special_handling,sex,bt)
102                        uid = u'%s_%s_%d_%s' % (self.hostel_id,block,room_nr,bed)
103                        if self.has_key(uid):
104                            bed = self[uid]
105                            # Renumber remaining beds
106                            bed.bed_number = len(self) + 1 - remaining
107                            remaining -= 1
108                            if bed.bed_type != bt:
109                                bed.bed_type = bt
110                                modified_counter += 1
111                                modified_beds += '%s ' % uid
112                        else:
113                            bed = Bed()
114                            bed.bed_id = uid
115                            bed.bed_type = bt
116                            bed.bed_number = len(self) + 1 - remaining
117                            bed.owner = NOT_OCCUPIED
118                            self.addBed(bed)
119                            added_counter +=1
120        return removed_counter, added_counter, modified_counter, modified_beds
121
122Hostel = attrs_to_fields(Hostel)
123
124class Bed(grok.Container):
125    """This is a bed.
126    """
127    grok.implements(IBed, IBedAllocateStudent)
128    grok.provides(IBed)
129
130    def getBedCoordinates(self):
131        """Determine the coordinates from the bed_id.
132        """
133        return self.bed_id.split('_')
134
135    def bookBed(self, student_id):
136        if self.owner == NOT_OCCUPIED:
137            self.owner = student_id
138            notify(grok.ObjectModifiedEvent(self))
139            return None
140        else:
141            return self.owner
142
143    def switchReservation(self):
144        """Reserves or unreserve bed respectively.
145        """
146        sh, sex, bt = self.bed_type.split('_')
147        hostel_id, block, room_nr, bed = self.getBedCoordinates()
148        hostel = self.__parent__
149        beds_for_fresh = getattr(hostel,'beds_for_fresh',[])
150        beds_for_pre = getattr(hostel,'beds_for_pre',[])
151        beds_for_returning = getattr(hostel,'beds_for_returning',[])
152        beds_for_final = getattr(hostel,'beds_for_final',[])
153        bed_string = u'%s_%s_%s' % (block, room_nr, bed)
154        if bt == 'reserved':
155            bt = 'all'
156            if bed in beds_for_fresh:
157                bt = 'fr'
158            elif bed in beds_for_pre:
159                bt = 'pr'
160            elif bed in beds_for_final:
161                bt = 'fi'
162            elif bed in beds_for_returning:
163                bt = 're'
164            bt = u'%s_%s_%s' % (sh, sex, bt)
165
166            # Comment of Martijn:
167            # If you have a non-Persistent subobject (like a list) and
168            # you change it, you need to manually flag the persistence
169            # machinery on the object that its subobject changed, with
170            # _p_changed. This is only necessary if some of the
171            # objects are not sublclasses of Persistent. For common
172            # built-in collections in Python such as list and
173            # dictionary there are replacements (PersistentList,
174            # PersistentMapping), and more advanced building blocks
175            # for indexes (BTrees), that don't have this issue.
176            #hostel._p_changed = True
177
178            # Henrik: Unfortunately, this doesn't work in our case.
179            # After restarting the portal,
180            # added or removed list items are gone. The only way to ensure
181            # persistance is to reassign the list attribute.
182            br = hostel.beds_reserved
183            br.remove(bed_string)
184            hostel.beds_reserved = br
185            message = _(u'unreserved')
186        else:
187            bt = u'%s_%s_reserved' % (sh, sex)
188            # See comment above
189            br = hostel.beds_reserved
190            br.append(bed_string)
191            hostel.beds_reserved = br
192            message = _(u'reserved')
193        self.bed_type = bt
194        return message
195
196    def releaseBed(self):
197        if self.owner == NOT_OCCUPIED:
198            return
199        else:
200            old_owner = self.owner
201            self.owner = NOT_OCCUPIED
202            notify(grok.ObjectModifiedEvent(self))
203            accommodation_session = grok.getSite()[
204                'hostels'].accommodation_session
205            try:
206                bedticket = grok.getSite()['students'][old_owner][
207                              'accommodation'][str(accommodation_session)]
208            except KeyError:
209                return '%s without bed ticket' % old_owner
210            bedticket.bed = None
211            tz = getUtility(IKofaUtils).tzinfo
212            timestamp = now(tz).strftime("%Y-%m-%d %H:%M:%S %Z")
213            bedticket.bed_coordinates = u'-- booking cancelled on %s --' % (
214                timestamp,)
215            return old_owner
216
217    def loggerInfo(self, ob_class, comment=None):
218        target = self.__name__
219        return grok.getSite()['hostels'].logger_info(ob_class,target,comment)
220
221Bed = attrs_to_fields(Bed)
222
223@grok.subscribe(IBedTicket, grok.IObjectRemovedEvent)
224def handle_bedticket_removed(bedticket, event):
225    """If a bed ticket is deleted, we make sure that also the owner attribute
226    of the bed is cleared (set to NOT_OCCUPIED).
227    """
228    if bedticket.bed != None:
229        bedticket.bed.owner = NOT_OCCUPIED
230        notify(grok.ObjectModifiedEvent(bedticket.bed))
Note: See TracBrowser for help on using the repository browser.