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

Last change on this file since 13346 was 13346, checked in by Henrik Bettermann, 9 years ago

Remove beds_reserved attribute from hostels. Hostels do no longer
contain information about reserved bed spaces.

Use default values for list attributes. Otherwise the hostel manage page cannot be opened after import of hostels.

  • Property svn:keywords set to Id
File size: 10.4 KB
Line 
1## $Id: hostel.py 13346 2015-10-26 08:57:30Z 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 zope.component.interfaces import IFactory
25from datetime import datetime
26from waeup.kofa.utils.helpers import attrs_to_fields
27from waeup.kofa.hostels.vocabularies import NOT_OCCUPIED
28from waeup.kofa.hostels.interfaces import IHostel, IBed
29from waeup.kofa.students.interfaces import IBedTicket
30from waeup.kofa.interfaces import IKofaUtils
31from waeup.kofa.interfaces import MessageFactory as _
32from waeup.kofa.utils.helpers import now
33
34class Hostel(grok.Container):
35    """This is a hostel.
36    """
37    grok.implements(IHostel)
38    grok.provides(IHostel)
39
40    @property
41    def bed_statistics(self):
42        total = len(self.keys())
43        booked = 0
44        for value in self.values():
45            if value.owner != NOT_OCCUPIED:
46                booked += 1
47        return {'booked':booked, 'total':total}
48
49    def clearHostel(self):
50        """Remove all beds
51        """
52        keys = [i for i in self.keys()] # create deep copy
53        for bed in keys:
54            del self[bed]
55        return
56
57    def addBed(self, bed):
58        """Add a bed.
59        """
60        if not IBed.providedBy(bed):
61            raise TypeError(
62                'Hostels contain only IBed instances')
63        self[bed.bed_id] = bed
64        return
65
66    def updateBeds(self):
67        """Fill hostel with beds or update beds.
68        """
69        added_counter = 0
70        modified_counter = 0
71        removed_counter = 0
72        modified_beds = u''
73
74        # Remove all empty beds. Occupied beds remain in hostel!
75        keys = list(self.keys()) # create list copy
76        for key in keys:
77            if self[key].owner == NOT_OCCUPIED:
78                del self[key]
79                self._p_changed = True
80                removed_counter += 1
81            else:
82                self[key].bed_number = 9999
83        remaining = len(keys) - removed_counter
84
85        blocks_for_female = getattr(self,'blocks_for_female',[])
86        blocks_for_male = getattr(self,'blocks_for_male',[])
87        beds_for_fresh = getattr(self,'beds_for_fresh',[])
88        beds_for_pre = getattr(self,'beds_for_pre',[])
89        beds_for_returning = getattr(self,'beds_for_returning',[])
90        beds_for_final = getattr(self,'beds_for_final',[])
91        beds_for_all = getattr(self,'beds_for_all',[])
92        all_blocks = blocks_for_female + blocks_for_male
93        all_beds = (beds_for_pre + beds_for_fresh +
94            beds_for_returning + beds_for_final + beds_for_all)
95        for block in all_blocks:
96            sex = 'male'
97            if block in blocks_for_female:
98                sex = 'female'
99            for floor in range(1,int(self.floors_per_block)+1):
100                for room in range(1,int(self.rooms_per_floor)+1):
101                    for bed in all_beds:
102                        room_nr = floor*100 + room
103                        bt = 'all'
104                        if bed in beds_for_fresh:
105                            bt = 'fr'
106                        elif bed in beds_for_pre:
107                            bt = 'pr'
108                        elif bed in beds_for_final:
109                            bt = 'fi'
110                        elif bed in beds_for_returning:
111                            bt = 're'
112                        bt = u'%s_%s_%s' % (self.special_handling,sex,bt)
113                        uid = u'%s_%s_%d_%s' % (
114                            self.hostel_id,block,room_nr,bed)
115                        if uid in self:
116                            bed = self[uid]
117                            # Renumber remaining bed
118                            bed.bed_number = len(self) + 1 - remaining
119                            remaining -= 1
120                            if bed.bed_type != bt:
121                                bed.bed_type = bt
122                                modified_counter += 1
123                                modified_beds += '%s, ' % uid
124                                notify(grok.ObjectModifiedEvent(bed))
125                        else:
126                            bed = Bed()
127                            bed.bed_id = uid
128                            bed.bed_type = bt
129                            bed.bed_number = len(self) + 1 - remaining
130                            bed.owner = NOT_OCCUPIED
131                            self.addBed(bed)
132                            added_counter +=1
133        return removed_counter, added_counter, modified_counter, modified_beds
134
135    def writeLogMessage(self, view, message):
136        ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
137        self.__parent__.logger.info(
138            '%s - %s - %s' % (ob_class, self.__name__, message))
139        return
140
141Hostel = attrs_to_fields(Hostel)
142
143class Bed(grok.Container):
144    """This is a bed.
145    """
146    grok.implements(IBed)
147    grok.provides(IBed)
148
149    @property
150    def coordinates(self):
151        """Determine the coordinates from the bed_id.
152        """
153        return self.bed_id.split('_')
154
155    # The following property attributes are only needed
156    # for the exporter to ease evaluation with Excel.
157
158    @property
159    def hall(self):
160        return self.coordinates[0]
161
162    @property
163    def block(self):
164        return self.coordinates[1]
165
166    @property
167    def room(self):
168        return self.coordinates[2]
169
170    @property
171    def bed(self):
172        return self.coordinates[3]
173
174    @property
175    def special_handling(self):
176        return self.bed_type.split('_')[0]
177
178    @property
179    def sex(self):
180        return self.bed_type.split('_')[1]
181
182    @property
183    def bt(self):
184        return self.bed_type.split('_')[2]
185
186
187    def bookBed(self, student_id):
188        if self.owner == NOT_OCCUPIED:
189            self.owner = student_id
190            notify(grok.ObjectModifiedEvent(self))
191            return None
192        else:
193            return self.owner
194
195    def switchReservation(self):
196        """Reserves or unreserve bed respectively.
197        """
198        sh, sex, bt = self.bed_type.split('_')
199        hostel_id, block, room_nr, bed = self.coordinates
200        hostel = self.__parent__
201        beds_for_fresh = getattr(hostel,'beds_for_fresh',[])
202        beds_for_pre = getattr(hostel,'beds_for_pre',[])
203        beds_for_returning = getattr(hostel,'beds_for_returning',[])
204        beds_for_final = getattr(hostel,'beds_for_final',[])
205        bed_string = u'%s_%s_%s' % (block, room_nr, bed)
206        if bt == 'reserved':
207            bt = 'all'
208            if bed in beds_for_fresh:
209                bt = 'fr'
210            elif bed in beds_for_pre:
211                bt = 'pr'
212            elif bed in beds_for_final:
213                bt = 'fi'
214            elif bed in beds_for_returning:
215                bt = 're'
216            bt = u'%s_%s_%s' % (sh, sex, bt)
217            message = _(u'unreserved')
218        else:
219            bt = u'%s_%s_reserved' % (sh, sex)
220            message = _(u'reserved')
221        self.bed_type = bt
222        notify(grok.ObjectModifiedEvent(self))
223        return message
224
225    def releaseBed(self):
226        if self.owner == NOT_OCCUPIED:
227            return
228        old_owner = self.owner
229        self.owner = NOT_OCCUPIED
230        notify(grok.ObjectModifiedEvent(self))
231        accommodation_session = grok.getSite()[
232            'hostels'].accommodation_session
233        try:
234            bedticket = grok.getSite()['students'][old_owner][
235                          'accommodation'][str(accommodation_session)]
236        except KeyError:
237            return '%s without bed ticket' % old_owner
238        bedticket.bed = None
239        tz = getUtility(IKofaUtils).tzinfo
240        timestamp = now(tz).strftime("%Y-%m-%d %H:%M:%S %Z")
241        bedticket.bed_coordinates = u'-- booking cancelled on %s --' % (
242            timestamp,)
243        return old_owner
244
245    def releaseBedIfMaintenanceNotPaid(self, n=7):
246        if self.owner == NOT_OCCUPIED:
247            return
248        accommodation_session = grok.getSite()[
249            'hostels'].accommodation_session
250        try:
251            bedticket = grok.getSite()['students'][self.owner][
252                          'accommodation'][str(accommodation_session)]
253        except KeyError:
254            return
255        if bedticket.maint_payment_made:
256            return
257        jetzt = datetime.utcnow()
258        days_ago = getattr(jetzt - bedticket.booking_date, 'days')
259        if days_ago > n:
260            old_owner = self.owner
261            self.owner = NOT_OCCUPIED
262            notify(grok.ObjectModifiedEvent(self))
263            bedticket.bed = None
264            tz = getUtility(IKofaUtils).tzinfo
265            timestamp = now(tz).strftime("%Y-%m-%d %H:%M:%S %Z")
266            bedticket.bed_coordinates = u'-- booking expired (%s) --' % (
267                timestamp,)
268            return old_owner
269        return
270
271    def writeLogMessage(self, view, message):
272        ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
273        self.__parent__.__parent__.logger.info(
274            '%s - %s - %s' % (ob_class, self.__name__, message))
275        return
276
277Bed = attrs_to_fields(Bed)
278
279class HostelFactory(grok.GlobalUtility):
280    """A factory for hostels.
281
282    We need this factory for the hostel processor.
283    """
284    grok.implements(IFactory)
285    grok.name(u'waeup.Hostel')
286    title = u"Create a new hostel.",
287    description = u"This factory instantiates new hostel instances."
288
289    def __call__(self, *args, **kw):
290        return Hostel()
291
292    def getInterfaces(self):
293        return implementedBy(Hostel)
294
295
296@grok.subscribe(IBedTicket, grok.IObjectRemovedEvent)
297def handle_bedticket_removed(bedticket, event):
298    """If a bed ticket is deleted, we make sure that also the owner attribute
299    of the bed is cleared (set to NOT_OCCUPIED).
300    """
301    if bedticket.bed != None:
302        bedticket.bed.owner = NOT_OCCUPIED
303        notify(grok.ObjectModifiedEvent(bedticket.bed))
304
Note: See TracBrowser for help on using the repository browser.