1 # -*- coding: utf-8 -*-
4 ## This file is part of Indico.
5 ## Copyright (C) 2002 - 2012 European Organization for Nuclear Research (CERN).
7 ## Indico is free software; you can redistribute it and/or
8 ## modify it under the terms of the GNU General Public License as
9 ## published by the Free Software Foundation; either version 3 of the
10 ## License, or (at your option) any later version.
12 ## Indico is distributed in the hope that it will be useful, but
13 ## WITHOUT ANY WARRANTY; without even the implied warranty of
14 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ## General Public License for more details.
17 ## You should have received a copy of the GNU General Public License
18 ## along with Indico;if not, see <http://www.gnu.org/licenses/>.
19 from MaKaC
.conference
import ConferenceHolder
22 Part of Room Booking Module (rb_)
25 from MaKaC
.plugins
.RoomBooking
.common
import rb_check_user_access
26 from MaKaC
.rb_tools
import Impersistant
, checkPresence
, iterdays
27 from MaKaC
.rb_location
import Location
, RoomGUID
, CrossLocationQueries
28 from MaKaC
.user
import Avatar
, AvatarHolder
29 from MaKaC
.accessControl
import AccessWrapper
30 from MaKaC
.errors
import MaKaCError
31 from datetime
import datetime
, timedelta
33 from zope
.interface
import implements
36 class RoomBase( object ):
38 Generic room, Data Access Layer independant.
39 Represents physical room suitable for meetings and/or conferences.
44 Do NOT insert object into database in the constructor.
48 self
._locationName
= None
52 Inserts room into database
58 Updates room in database
64 Removes room from database
68 def notifyAboutResponsibility( self
):
70 FINAL (not intented to be overriden)
71 Notifies (e-mails) previous and new responsible about
72 responsibility change. Called after creating/updating the room.
76 # Query ------------------------------------------------------------------
79 def getRooms( *args
, **kwargs
):
81 Returns list of rooms meeting specified conditions.
83 It is 'query by example'. You specify conditions by creating
84 the object and passing it to the method.
86 All arguments are optional:
88 roomID - just a shortcut. Will return ONE room (not a list) or None.
89 roomName - just a shortcut. Will return ONE room (not a list) or None.
90 roomExample - example RoomBase object.
91 reservationExample - example ReservationBase object. Represents reservation period.
92 available - Bool, true if room must be available, false if must be booked, None if do not care
93 freeText - str, room will be found if this string will be found anywhere in the object
94 i.e. in equipment list, comments, responsible etc.
95 minCapacity - Bool, defaults to False. If True, then rooms of capacity >= will be found.
96 Otherwise capacity it looks for rooms with capacity within 20% range.
97 allFast - Bool, defaults to False. If True, ALL active rooms will be returned
98 in ultra fast way, REGARDLESS of all other options.
100 customAtts - for rooms with custom attributes.
101 rooms with no .customAtts attributes will be filtered out if this parameter is present
102 The customAtts attribute should be a list of dictionaries with the attributes "name", "allowEmpty", "filter".
103 "name" -> the name of the custom attribute
104 "allowEmpty" -> if we allow the custom attribute to be empty or not (empty = "" or string with only whitespaces)
105 "filter" -> a function to which we will pass the value of the custom attribute and has to return True or False.
106 If there is more than 1 dictionary in the list, it will be like doing an AND of the conditions they represent.
112 rooms = RoomBase.getRooms()
114 # 2. Get all rooms with capacity about 30
115 r = Factory.newRoom()
117 rooms = RoomBase.getRooms( roomExample = r )
119 # 3. Get all rooms reserved on the New Year 2007,
120 # which have capacity about 30, are at Meyrin site and have 'jean' in comments.
122 r = Factory.newRoom()
126 p = ReservationBase()
127 p.startDT = datetime.datetime( 2007, 01, 01 )
128 p.endDT = datetime.datetime( 2007, 01, 01 )
129 p.repeatability = None
131 rooms = RoomBase.getRooms( roomExample = r, reservationExample = p, available = False )
133 # 4. Get all rooms containing "sex" in their attributes
135 rooms = RoomBase.getRooms( freeText = 'sex' )
137 # 5. Get room 'AT AMPHITHEATRE'
139 oneRoom = RoomBase.getRooms( roomName = 'AT AMPHITHEATRE' )
141 #6. Get rooms with a H.323 IP defined
142 rooms = RoomBase.getRooms ( customAtts = [{"name":'H323 IP', "allowEmpty":False,
143 "filter": (lambda ip: validIP(ip))}])
145 # Simply redirect to the plugin
146 from MaKaC
.rb_factory
import Factory
147 return Factory
.newRoom().getRooms( **kwargs
)
149 def getReservations( self
, resvExample
= None, archival
= None ):
151 FINAL (not intented to be overriden)
152 Returns reservations of this room, meeting specified criteria.
153 Look ReservationBase.getReservations for details.
155 # Simply redirect to the plugin
156 from MaKaC
.rb_factory
import Factory
157 from MaKaC
.rb_reservation
import ReservationBase
159 return ReservationBase
.getReservations( resvExample
= resvExample
, rooms
= [self
], archival
= archival
)
161 def getLiveReservations( self
, resvExample
= None ):
163 FINAL (not intented to be overriden)
164 Returns valid, non archival reservations of this room,
165 meeting specified criteria. Look ReservationBase.getReservations for details.
167 from MaKaC
.rb_factory
import Factory
168 from MaKaC
.rb_reservation
import ReservationBase
170 if resvExample
== None:
171 resvExample
= Factory
.newReservation()
172 resvExample
.isCancelled
= False
173 resvExample
.isRejected
= False
175 return ReservationBase
.getReservations( resvExample
= resvExample
,
176 rooms
= [self
], archival
= False )
178 def isAvailable( self
, potentialReservation
):
180 FINAL (not intented to be overriden)
181 Checks whether the room is available for the potentialReservation.
182 potentialReservation is of type ReservationBase. It specifies the period.
184 from MaKaC
.rb_reservation
import ReservationBase
185 if potentialReservation
.getCollisions( boolResult
= True ):
189 def getResponsible( self
):
191 FINAL (not intented to be overriden)
192 Returns responsible person (Avatar object).
194 avatar
= AvatarHolder().getById( self
.responsibleId
)#match( { 'id': self.responsibleId } )[0]
198 # Statistical ------------------------------------------------------------
201 def getNumberOfRooms( **kwargs
):
203 FINAL (not intented to be overriden)
204 Returns total number of rooms in database.
206 name
= kwargs
.get( 'location', Location
.getDefaultLocation().friendlyName
)
207 location
= Location
.parse(name
)
208 return location
.factory
.newRoom().getNumberOfRooms(location
=name
)
211 def getNumberOfActiveRooms( **kwargs
):
213 FINAL (not intented to be overriden)
214 Returns number of rooms that are active (not logicaly deleted).
216 name
= kwargs
.get( 'location', Location
.getDefaultLocation().friendlyName
)
217 location
= Location
.parse(name
)
218 return location
.factory
.newRoom().getNumberOfActiveRooms(location
=name
)
221 def getNumberOfReservableRooms( **kwargs
):
223 FINAL (not intented to be overriden)
224 Returns number of rooms which can be reserved.
226 name
= kwargs
.get( 'location', Location
.getDefaultLocation().friendlyName
)
227 location
= Location
.parse(name
)
228 return location
.factory
.newRoom().getNumberOfReservableRooms(location
=name
)
231 def getTotalSurfaceAndCapacity( **kwargs
):
233 FINAL (not intented to be overriden)
234 Returns (total_surface, total_capacity) of all Active rooms.
236 name
= kwargs
.get( 'location', Location
.getDefaultLocation().friendlyName
)
237 location
= Location
.parse(name
)
238 roomEx
= location
.factory
.newRoom()
239 roomEx
.isActive
= True
240 roomEx
.isReservable
= True
241 rooms
= CrossLocationQueries
.getRooms( roomExample
= roomEx
, location
= name
)
242 totalSurface
, totalCapacity
= 0, 0
245 totalSurface
+= r
.surfaceArea
247 totalCapacity
+= r
.capacity
248 return ( totalSurface
, totalCapacity
)
251 def getAverageOccupation( **kwargs
):
253 FINAL (not intented to be overriden)
254 Returns float <0, 1> representing how often - on the avarage -
255 the rooms are booked during the working hours. (1 == all the time, 0 == never).
258 name
= kwargs
.get( 'location', Location
.getDefaultLocation().friendlyName
)
260 # Get active, publically reservable rooms
261 from MaKaC
.rb_factory
import Factory
262 roomEx
= Factory
.newRoom()
263 roomEx
.isActive
= True
264 roomEx
.isReservable
= True
266 rooms
= CrossLocationQueries
.getRooms( roomExample
= roomEx
, location
= name
)
268 # Find collisions with last month period
269 from MaKaC
.rb_reservation
import ReservationBase
, RepeatabilityEnum
270 resvEx
= ReservationBase()
272 resvEx
.endDT
= datetime( now
.year
, now
.month
, now
.day
, 17, 30 )
273 resvEx
.startDT
= resvEx
.endDT
- timedelta( 30, 9 * 3600 ) # - 30 days and 9 hours
274 resvEx
.repeatability
= RepeatabilityEnum
.daily
275 collisions
= resvEx
.getCollisions( rooms
= rooms
)
279 for day
in iterdays( resvEx
.startDT
, resvEx
.endDT
):
280 if day
.weekday() in [5,6]: # Skip Saturday and Sunday
283 # if c.startDT is CERN Holiday: continue
284 totalWorkingDays
+= 1
286 booked
= timedelta( 0 )
288 if c
.startDT
.weekday() in [5,6]: # Skip Saturday and Sunday
290 # if c.startDT is CERN Holiday: continue
291 booked
= booked
+ ( c
.endDT
- c
.startDT
)
292 totalBookableTime
= totalWorkingDays
* 9 * len( rooms
) # Hours
293 bookedTime
= booked
.days
* 24 + 1.0 * booked
.seconds
/ 3600 # Hours
294 if totalBookableTime
> 0:
295 return bookedTime
/ totalBookableTime
297 return 0 # Error (no rooms in db)
300 def getMyAverageOccupation( self
, period
="pastmonth" ):
302 FINAL (not intented to be overriden)
303 Returns float <0, 1> representing how often - on the avarage -
304 the room is booked during the working hours. (1 == all the time, 0 == never).
306 # Find collisions with last month period
307 from MaKaC
.rb_reservation
import ReservationBase
, RepeatabilityEnum
308 resvEx
= ReservationBase()
310 if period
== "pastmonth":
311 resvEx
.endDT
= datetime( now
.year
, now
.month
, now
.day
, 17, 30 )
312 resvEx
.startDT
= resvEx
.endDT
- timedelta( 30, 9 * 3600 ) # - 30 days and 9 hours
313 elif period
== "thisyear":
314 resvEx
.endDT
= datetime( now
.year
, now
.month
, now
.day
, 17, 30 )
315 resvEx
.startDT
= datetime( now
.year
, 1, 1, 0, 0 )
316 resvEx
.repeatability
= RepeatabilityEnum
.daily
317 collisions
= resvEx
.getCollisions( rooms
= [self
] )
321 for day
in iterdays( resvEx
.startDT
, resvEx
.endDT
):
322 if day
.weekday() in [5,6]: # Skip Saturday and Sunday
325 # if c.startDT is CERN Holiday: continue
326 totalWorkingDays
+= 1
328 booked
= timedelta( 0 )
330 if c
.startDT
.weekday() in [5,6]: # Skip Saturday and Sunday
332 # if c.startDT is CERN Holiday: continue
333 booked
= booked
+ ( c
.endDT
- c
.startDT
)
334 totalBookableTime
= totalWorkingDays
* 9 # Hours
335 bookedTime
= booked
.days
* 24 + 1.0 * booked
.seconds
/ 3600 # Hours
336 if totalBookableTime
> 0:
337 return bookedTime
/ totalBookableTime
342 # Equipment ------------------------------------------------------------
344 def setEquipment( self
, eq
):
346 Sets (replaces) the equipment list with the new one.
347 It may be list ['eq1', 'eq2', ...] or str 'eq1`eq2`eq3`...'
349 if isinstance( eq
, list ):
350 self
._equipment
= '`'.join( eq
)
352 elif isinstance( eq
, str ):
355 raise MaKaCError('Invalid equipment list')
357 def getEquipment( self
):
359 Returns the room's equipment list.
361 return self
._equipment
.split( '`' )
363 def insertEquipment( self
, equipmentName
):
364 """ Adds new equipment to the room. """
365 if len( self
._equipment
) > 0:
366 self
._equipment
+= '`'
367 self
._equipment
+= equipmentName
369 def removeEquipment( self
, equipmentName
):
370 """ Removes equipment from the room. """
371 e
= self
.getEquipment()
372 e
.remove( equipmentName
)
373 self
.setEquipment( e
)
375 def hasEquipment( self
, equipmentName
):
376 return equipmentName
in self
._equipment
378 def isCloseToBuilding( self
, buildingNr
):
379 """ Returns true if room is close to the specified building """
380 raise NotImplementedError('Not implemented')
382 def belongsTo( self
, user
):
383 """ Returns true if current CrbsUser is responsible for this room """
384 raise NotImplementedError('Not implemented')
386 # "System" ---------------------------------------------------------------
388 def checkIntegrity( self
):
390 FINAL (not intented to be overriden)
392 - all required attributes has values
393 - values are of correct type
394 - semantic coherence (i.e. star date <= end date)
400 # check presence and types of arguments
401 # =====================================================
402 if self
.id != None: # Only for existing objects
403 checkPresence( self
, errors
, 'id', int )
404 checkPresence( self
, errors
, '_locationName', str )
405 # check semantic integrity
406 # =====================================================
411 # Photos -----------------------------------------------------------------
413 # NOTE: In general, URL generation should be in urlHandlers.
414 # This exception is because we want to allow other room booking systems
415 # to override room photos.
417 def getPhotoURL( self
):
418 # Used to send photos via Python script
419 #from MaKaC.webinterface.urlHandlers import UHSendRoomPhoto
420 #return UHSendRoomPhoto.getURL( self.photoId, small = False )
421 from MaKaC
.webinterface
.urlHandlers
import UHRoomPhoto
422 return UHRoomPhoto
.getURL( self
.photoId
)
424 def getSmallPhotoURL( self
):
425 # Used to send photos via Python script
426 #from MaKaC.webinterface.urlHandlers import UHSendRoomPhoto
427 #return UHSendRoomPhoto.getURL( self.photoId, small = True )
428 from MaKaC
.webinterface
.urlHandlers
import UHRoomPhotoSmall
429 return UHRoomPhotoSmall
.getURL( self
.photoId
)
431 def savePhoto( self
, photoPath
):
433 Saves room's photo on the server.
437 def saveSmallPhoto( self
, photoPath
):
439 Saves room's small photo on the server.
443 # Indico architecture ----------------------------------------------------
447 def getLocator( self
):
449 FINAL (not intented to be overriden)
450 Returns a globaly unique identification encapsulated in a Locator object
452 owner
= self
.getOwner()
454 loc
= owner
.getLocator()
456 from MaKaC
.common
.Locators
import Locator
458 loc
["roomLocation"] = self
.locationName
459 loc
["roomID"] = self
.id
462 def setOwner( self
, owner
):
464 FINAL (not intented to be overriden)
466 oryg
= self
._p
_changed
469 self
.__owner
= owner
.getId()#Impersistant( owner )
470 self
._p
_changed
= oryg
472 def getOwner( self
):
474 FINAL (not intented to be overriden)
475 Owner in terms of "parent", i.e. conference
477 ####---FIXING THE USE OF IMPERSISTANT CLASS-----
478 if isinstance(self
.__owner
, Impersistant
):
479 o
= self
.__owner
.getObject()
481 self
.__owner
=o
.getId()
484 ####---ENDO OF FIXING THE USE OF IMPERSISTANT CLASS-----
485 ch
= ConferenceHolder()
486 if self
.__owner
and self
.__owner
in ch
._getIdx
():
487 return ch
.getById(self
.__owner
)
491 def isProtected( self
):
493 FINAL (not intented to be overriden)
494 The one must be logged in to do anything in RB module.
498 def canView( self
, accessWrapper
):
500 FINAL (not intented to be overriden)
501 Room details are public - anyone can view.
505 def canBook(self
, user
):
507 FINAL (not intented to be overriden)
508 Reservable rooms which does not require pre-booking can be booked by anyone.
509 Other rooms - only by their responsibles.
512 # if the user has no access to the RB module, let's end it here
513 if not rb_check_user_access(user
):
516 if self
.isActive
and self
.isReservable
and not self
.resvsNeedConfirmation
:
517 simbaList
= self
.customAtts
.get('Booking Simba List')
518 if simbaList
and simbaList
!= "Error: unknown mailing list" and simbaList
!= "":
519 if user
.isMemberOfSimbaList(simbaList
):
526 if (self
.isOwnedBy( user
) and self
.isActive
) \
531 def canPrebook(self
, user
):
533 FINAL (not intented to be overriden)
534 Reservable rooms can be pre-booked by anyone.
535 Other rooms - only by their responsibles.
538 # if the user has no access to the RB module, let's end it here
539 if not rb_check_user_access(user
):
542 if self
.isActive
and self
.isReservable
:
543 simbaList
= self
.customAtts
.get('Booking Simba List')
544 if simbaList
and simbaList
!= "Error: unknown mailing list" and simbaList
!= "":
545 if user
.isMemberOfSimbaList(simbaList
):
551 if (self
.isOwnedBy( user
) and self
.isActive
) \
556 def canModify( self
, accessWrapper
):
558 FINAL (not intented to be overriden)
559 Only admin can modify rooms.
561 if accessWrapper
== None:
563 if isinstance( accessWrapper
, AccessWrapper
):
564 if accessWrapper
.getUser():
565 return accessWrapper
.getUser().isRBAdmin()
568 elif isinstance( accessWrapper
, Avatar
):
569 return accessWrapper
.isRBAdmin()
571 raise MaKaCError('canModify requires either AccessWrapper or Avatar object')
573 def canDelete( self
, user
):
574 return self
.canModify( user
)
576 def isOwnedBy( self
, user
):
578 Returns True if user is responsible for this room. False otherwise.
580 if not self
.responsibleId
:
582 if self
.responsibleId
== user
.id:
585 if user
in self
._v
_isOwnedBy
.keys():
586 return self
._v
_isOwnedBy
[user
]
588 self
._v
_isOwnedBy
= {}
589 if self
.customAtts
.get( 'Simba List' ):
590 list = self
.customAtts
.get( 'Simba List' )
591 if list != "Error: unknown mailing list" and list != "":
592 if user
.isMemberOfSimbaList( list ):
593 self
._v
_isOwnedBy
[user
] = True
595 self
._v
_isOwnedBy
[user
] = False
598 def getLocationName( self
):
599 if self
.__class
__.__name
__ == 'RoomBase':
600 return Location
.getDefaultLocation().friendlyName
601 #raise 'This method is purely virtual. Call it only on derived objects.'
602 return self
.getLocationName() # Subclass
604 def setLocationName( self
, locationName
):
605 if self
.__class
__.__name
__ == 'RoomBase':
606 raise MaKaCError('This method is purely virtual. Call it only on derived objects.')
607 return self
.setLocationName( locationName
) # Subclass
609 def getAccessKey( self
): return ""
611 def getFullName( self
):
613 if self
.building
!= None and self
.floor
!= None and self
.building
!= None:
614 s
= str( self
.building
) + '-' + str( self
.floor
) + '-' + str( self
.roomNr
)
617 if self
._name
!= None and len( self
._name
.strip() ) > 0:
618 name
+= " - %s" % self
._name
621 # ==== Private ===================================================
624 _equipment
= '' # str, 'eq1`eq2`eq3' - list of room's equipment, joined by '`'
626 def _getGuid( self
):
627 if self
.id == None or self
.locationName
== None:
629 if Location
.parse( self
.locationName
):
630 return RoomGUID( Location
.parse( self
.locationName
), self
.id )
633 def _getName( self
):
634 if self
._name
!= None and len( self
._name
.strip() ) > 0:
636 if self
.building
!= None and self
.floor
!= None and self
.building
!= None:
637 s
= str( self
.building
) + '-' + str( self
.floor
) + '-' + str( self
.roomNr
)
643 def _setName( self
, s
):
644 # Try to parse the name
648 parts
= s
.split( '-' )
649 if len( parts
) == 3:
651 self
.building
= int( parts
[0] )
652 self
.floor
= parts
[1]
653 self
.roomNr
= parts
[2]
657 # Parsing failed, that means it is real name
660 # CERN specific; don't bother
661 def _getNeedsAVCSetup( self
):
662 eq
= self
.getEquipment()
663 if not self
.locationName
or not eq
:
665 return 'Video conference' in ' '.join( eq
)
667 # CERN specific; don't bother
668 def hasWebcastRecording( self
):
669 eq
= self
.getEquipment()
670 if not self
.locationName
or not eq
:
672 return 'Webcast/Recording' in ' '.join( eq
)
674 def _eval_str( self
, s
):
679 ix
= s
.find( "#{", ixPrv
)
682 ret
+= s
[ixPrv
:ix
] # verbatim
683 ixPrv
= s
.index( "}", ix
+ 2 ) + 1
684 ret
+= str( eval( s
[ix
+2:ixPrv
-1] ) )
685 ret
+= s
[ixPrv
:len(s
)]
689 def _getVerboseEquipment( self
):
691 eqList
= self
.getEquipment()
694 if len( eqList
) > 0: s
= s
[0:len(s
)-2] # Cut off last ','
697 def _getPhotoId( self
):
699 Feel free to override this in your inherited class.
701 return self
._doGetPhotoId
()
703 def _setPhotoId( self
, value
):
704 self
._photoId
= value
706 def _doGetPhotoId( self
):
707 if '_photoId' in dir( self
): return self
._photoId
714 isActive: #{self.isActive}
718 building: #{self.building}
720 roomNr: #{self.roomNr}
721 isReservable: #{self.isReservable}
722 rNeedConfirmation: #{self.resvsNeedConfirmation}
723 startNotification: #{self.resvStartNotification}
724 endNotification: #{self.resvEndNotification}
725 startNotificationBefore: #{self.resvStartNotificationBefore}
726 notificationToResponsible: #{self.resvNotificationToResponsible}
727 notificationAssistance: #{self.resvNotificationAssistance}
730 capacity: #{self.capacity}
731 surfaceArea: #{self.surfaceArea}
732 division: #{self.division}
733 photoId: #{self.photoId}
734 externalId: #{self.externalId}
736 telephone: #{self.telephone}
737 whereIsKey: #{self.whereIsKey}
738 comments: #{self.comments}
739 responsibleId: #{self.responsibleId}
742 s
+= self
.verboseEquipment
+ "\n"
745 def __cmp__( self
, other
):
746 if self
.__class
__.__name
__ == 'NoneType' and other
.__class
__.__name
__ == 'NoneType':
748 if self
.__class
__.__name
__ == 'NoneType':
749 return cmp( None, 1 )
750 if other
.__class
__.__name
__ == 'NoneType':
751 return cmp( 1, None )
753 if self
.id != None and other
.id != None:
754 if self
.id == other
.id:
757 c
= cmp( self
.locationName
, other
.locationName
)
759 c
= cmp( self
.building
, other
.building
)
761 c
= cmp( self
.floor
, other
.floor
)
763 c
= cmp( self
.roomNr
, other
.roomNr
)
765 c
= cmp( self
.name
, other
.name
)
769 # ==== Properties ===================================================
771 # DO NOT set default values here, since query-by-example will change!!!
773 id = None # int - artificial ID; initialy value from oracle db
774 locationName
= property( getLocationName
, setLocationName
) # location (plugin) name
775 guid
= property( _getGuid
) # RoomGUID
776 isActive
= None # bool - whether the room is active (not logicaly removed) [STSCRBOK]
777 resvsNeedConfirmation
= None # bool - whether reservations for this room must be confirmed by responsible
779 building
= None # int, positive
780 floor
= None # str, alphanumeric
782 latitude
= None # str
783 longitude
= None # str
785 name
= property( _getName
, _setName
) # str - room name
787 capacity
= None # int, positive
788 site
= None # str - global room localisation, i.e. city
789 division
= None # str, TODO
790 isReservable
= None # bool - whether the room is reservable
791 photoId
= property( _getPhotoId
, _setPhotoId
) # str - room picture id
792 externalId
= None # str - custom external room id, i.e. for locating on the map
794 resvStartNotification
= False # bool - whether to send notifications on booking start
795 resvStartNotificationBefore
= None # bool - whether to send notifications on booking start
796 resvEndNotification
= False # bool - whether to send notifications on booking end
797 resvNotificationToResponsible
= False # bool - whether to send notifications to the room responsible, too
798 resvNotificationAssistance
= False # bool - whether to send notifications on assistance
800 telephone
= None # str
801 surfaceArea
= None # int, positive - in meters^2
802 whereIsKey
= None # str, typically telephone number
803 comments
= None # str
804 responsibleId
= None # str, responsible person id (avatar.id)
805 maxAdvanceDays
= 0 # maximum number of days a booking can be done in advance
807 #customAtts = {} # Must behave like name-value dictionary of
808 # custom attributes. Must be put in derived classes.
810 verboseEquipment
= property( _getVerboseEquipment
)
811 needsAVCSetup
= property( _getNeedsAVCSetup
)
813 # ============================================================================
814 # ================================== TEST ====================================
815 # ============================================================================
818 from MaKaC
.rb_factory
import Factory
821 def getReservations():
822 from MaKaC
.rb_factory
import Factory
823 from datetime
import datetime
825 dalManager
= Factory
.getDALManager()
828 amphitheatre
= RoomBase
.getRooms( roomName
= 'IT AMPHITHEATRE' )
829 print "All reservations for IT AMPHITHEATRE: %d" % len( amphitheatre
.getReservations() )
831 resvEx
= Factory
.newReservation()
832 resvEx
.startDT
= datetime( 2006, 9, 23, 0 )
833 resvEx
.endDT
= datetime( 2006, 9, 30, 23, 59 )
834 reservations
= amphitheatre
.getLiveReservations( resvExample
= resvEx
)
836 dalManager
.disconnect()
839 if __name__
== '__main__':
840 Test
.getReservations()