source: main/waeup.kofa/trunk/src/waeup/kofa/hostels/browser.py @ 9106

Last change on this file since 9106 was 8685, checked in by Henrik Bettermann, 12 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: 12.2 KB
Line 
1## $Id: browser.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"""UI components for hostels and related components.
19"""
20import grok
21import sys
22from zope.i18n import translate
23from zope.component import getUtility
24from waeup.kofa.browser import (
25    KofaEditFormPage, KofaAddFormPage, KofaDisplayFormPage,
26    NullValidator)
27from waeup.kofa.browser.breadcrumbs import Breadcrumb
28from waeup.kofa.browser.resources import datepicker, datatable, tabs, warning
29from waeup.kofa.browser.layout import default_primary_nav_template
30from waeup.kofa.browser.pages import delSubobjects
31from waeup.kofa.browser.viewlets import (
32    ManageActionButton, PrimaryNavTab)
33from waeup.kofa.browser.layout import jsaction, action
34from waeup.kofa.interfaces import IKofaObject, IKofaUtils
35from waeup.kofa.interfaces import MessageFactory as _
36from waeup.kofa.hostels.vocabularies import NOT_OCCUPIED
37from waeup.kofa.hostels.hostel import Hostel
38from waeup.kofa.hostels.interfaces import (
39    IHostelsContainer, IHostel, IBed, IBedAllocateStudent)
40from waeup.kofa.widgets.datewidget import FriendlyDatetimeDisplayWidget
41
42def write_log_message(view, message):
43    ob_class = view.__implemented__.__name__.replace('waeup.kofa.','')
44    view.context.loggerInfo(ob_class, message)
45    return
46
47# Save function used for save methods in manager pages
48def msave(view, **data):
49    changed_fields = view.applyData(view.context, **data)
50    # Turn list of lists into single list
51    if changed_fields:
52        changed_fields = reduce(lambda x,y: x+y, changed_fields.values())
53    fields_string = ' + '.join(changed_fields)
54    view.context._p_changed = True
55    view.flash(_('Form has been saved.'))
56    if fields_string:
57        write_log_message(view, 'saved: % s' % fields_string)
58    return
59
60class HostelsTab(PrimaryNavTab):
61    """Hostels tab in primary navigation.
62    """
63
64    grok.context(IKofaObject)
65    grok.order(5)
66    grok.require('waeup.viewHostels')
67    template = default_primary_nav_template
68    pnav = 5
69    tab_title = _(u'Hostels')
70
71    @property
72    def link_target(self):
73        return self.view.application_url('hostels')
74
75class HostelsBreadcrumb(Breadcrumb):
76    """A breadcrumb for the hostels container.
77    """
78    grok.context(IHostelsContainer)
79    title = _(u'Hostels')
80
81class HostelBreadcrumb(Breadcrumb):
82    """A breadcrumb for the hostel container.
83    """
84    grok.context(IHostel)
85
86    def title(self):
87        return self.context.hostel_name
88
89class BedBreadcrumb(Breadcrumb):
90    """A breadcrumb for the hostel container.
91    """
92    grok.context(IBed)
93
94    def title(self):
95        co = self.context.getBedCoordinates()
96        return _('Block ${a}, Room ${b}, Bed ${c}',
97            mapping = {'a':co[1], 'b':co[2], 'c':co[3]})
98
99class HostelsContainerPage(KofaDisplayFormPage):
100    """The standard view for hostels containers.
101    """
102    grok.context(IHostelsContainer)
103    grok.name('index')
104    grok.require('waeup.viewHostels')
105    grok.template('containerpage')
106    label = _('Accommodation Section')
107    pnav = 5
108    form_fields = grok.AutoFields(IHostelsContainer)
109    form_fields[
110        'startdate'].custom_widget = FriendlyDatetimeDisplayWidget('le')
111    form_fields[
112        'enddate'].custom_widget = FriendlyDatetimeDisplayWidget('le')
113
114class HostelsContainerManageActionButton(ManageActionButton):
115    grok.order(1)
116    grok.context(IHostelsContainer)
117    grok.view(HostelsContainerPage)
118    grok.require('waeup.manageHostels')
119    text = _('Manage accommodation section')
120
121class HostelsContainerManagePage(KofaEditFormPage):
122    """The manage page for hostel containers.
123    """
124    grok.context(IHostelsContainer)
125    grok.name('manage')
126    grok.require('waeup.manageHostels')
127    grok.template('containermanagepage')
128    pnav = 5
129    label = _('Manage accommodation section')
130    form_fields = grok.AutoFields(IHostelsContainer)
131    taboneactions = [_('Save')]
132    tabtwoactions = [_('Add hostel'), _('Remove selected')]
133
134    def update(self):
135        tabs.need()
136        self.tab1 = self.tab2 = self.tab3 = self.tab4 = ''
137        qs = self.request.get('QUERY_STRING', '')
138        if not qs:
139            qs = 'tab1'
140        setattr(self, qs, 'active')
141        warning.need()
142        datatable.need()
143        return super(HostelsContainerManagePage, self).update()
144
145    # It's quite dangerous to remove entire hostels with its content (beds).
146    # Thus, this remove method should be combined with an archiving function.
147    @jsaction(_('Remove selected'))
148    def delHostels(self, **data):
149        form = self.request.form
150        if form.has_key('val_id'):
151            deleted = []
152            child_id = form['val_id']
153            if not isinstance(child_id, list):
154                child_id = [child_id]
155            for id in child_id:
156                deleted.append(id)
157            write_log_message(self, 'deleted: % s' % ', '.join(deleted))
158        delSubobjects(self, redirect='@@manage', tab='2')
159        return
160
161    @action(_('Add hostel'), validator=NullValidator)
162    def addSubunit(self, **data):
163        self.redirect(self.url(self.context, 'addhostel'))
164        return
165
166    @action(_('Save'), style='primary')
167    def save(self, **data):
168        self.applyData(self.context, **data)
169        self.flash(_('Settings have been saved.'))
170        return
171
172class HostelAddFormPage(KofaAddFormPage):
173    """Add-form to add a hostel.
174    """
175    grok.context(IHostelsContainer)
176    grok.require('waeup.manageHostels')
177    grok.name('addhostel')
178    #grok.template('hosteladdpage')
179    form_fields = grok.AutoFields(IHostel).omit('beds_reserved')
180    label = _('Add hostel')
181    pnav = 5
182
183    @action(_('Create hostel'))
184    def addHostel(self, **data):
185        hostel = Hostel()
186        self.applyData(hostel, **data)
187        hostel.hostel_id = data[
188            'hostel_name'].lower().replace(' ','-').replace('_','-')
189        try:
190            self.context.addHostel(hostel)
191        except KeyError:
192            self.flash(_('The hostel already exists.'))
193            return
194        self.flash(_('Hostel created.'))
195        write_log_message(self, 'added: % s' % data['hostel_name'])
196        self.redirect(self.url(self.context[hostel.hostel_id], 'index'))
197        return
198
199class HostelDisplayFormPage(KofaDisplayFormPage):
200    """ Page to display hostel data
201    """
202    grok.context(IHostel)
203    grok.name('index')
204    grok.require('waeup.viewHostels')
205    #grok.template('hostelpage')
206    pnav = 5
207
208    @property
209    def label(self):
210        return self.context.hostel_name
211
212class HostelManageActionButton(ManageActionButton):
213    grok.order(1)
214    grok.context(IHostel)
215    grok.view(HostelDisplayFormPage)
216    grok.require('waeup.manageHostels')
217    text = _('Manage')
218    target = 'manage'
219
220class HostelManageFormPage(KofaEditFormPage):
221    """ View to edit hostel data
222    """
223    grok.context(IHostel)
224    grok.name('manage')
225    grok.require('waeup.manageHostels')
226    form_fields = grok.AutoFields(IHostel).omit('hostel_id')
227    form_fields['beds_reserved'].for_display = True
228    grok.template('hostelmanagepage')
229    label = _('Manage hostel')
230    pnav = 5
231    taboneactions = [_('Save')]
232    tabtwoactions = [_('Update all beds'),
233        _('Switch reservation of selected beds'),
234        _('Release selected beds')]
235    not_occupied = NOT_OCCUPIED
236
237    @property
238    def students_url(self):
239        return self.url(grok.getSite(),'students')
240
241    def update(self):
242        datepicker.need() # Enable jQuery datepicker in date fields.
243        tabs.need()
244        datatable.need()
245        self.tab1 = self.tab2 = ''
246        qs = self.request.get('QUERY_STRING', '')
247        if not qs:
248            qs = 'tab1'
249        setattr(self, qs, 'active')
250        super(HostelManageFormPage, self).update()
251        return
252
253    @action(_('Save'))
254    def save(self, **data):
255        msave(self, **data)
256        return
257
258    @action(_('Update all beds'))
259    def updateBeds(self, **data):
260        removed, added, modified, modified_beds = self.context.updateBeds()
261        message = '%d empty beds removed, %d beds added, %d occupied beds modified (%s)' % (
262            removed, added, modified, modified_beds)
263        flash_message = _(
264            '${a} empty beds removed, ${b} beds added, '
265            + '${c} occupied beds modified (${d})',
266            mapping = {'a':removed, 'b':added, 'c':modified, 'd':modified_beds})
267        self.flash(flash_message)
268        write_log_message(self, message)
269        self.redirect(self.url(self.context, '@@manage')+'?tab2')
270        return
271
272    @action(_('Switch reservation of selected beds'))
273    def switchReservations(self, **data):
274        form = self.request.form
275        if form.has_key('val_id'):
276            child_id = form['val_id']
277        else:
278            self.flash(_('No item selected.'))
279            self.redirect(self.url(self.context, '@@manage')+'?tab2')
280            return
281        if not isinstance(child_id, list):
282            child_id = [child_id]
283        switched = [] # for log file
284        switched_translated = [] # for flash message
285        # Here we know that the cookie has been set
286        preferred_language = self.request.cookies.get('kofa.language')
287        for bed_id in child_id:
288            message = self.context[bed_id].switchReservation()
289            switched.append('%s (%s)' % (bed_id,message))
290            m_translated = translate(message, 'waeup.kofa',
291                target_language=preferred_language)
292            switched_translated.append('%s (%s)' % (bed_id,m_translated))
293        if len(switched):
294            message = ', '.join(switched)
295            m_translated = ', '.join(switched_translated)
296            self.flash(_('Successfully switched beds: ${a}',
297                mapping = {'a':m_translated}))
298            write_log_message(self, 'switched: %s' % message)
299            self.redirect(self.url(self.context, '@@manage')+'?tab2')
300        return
301
302    @action(_('Release selected beds'))
303    def releaseBeds(self, **data):
304        form = self.request.form
305        if form.has_key('val_id'):
306            child_id = form['val_id']
307        else:
308            self.flash(_('No item selected.'))
309            self.redirect(self.url(self.context, '@@manage')+'?tab2')
310            return
311        if not isinstance(child_id, list):
312            child_id = [child_id]
313        released = []
314        for bed_id in child_id:
315            message = self.context[bed_id].releaseBed()
316            if message:
317                released.append('%s (%s)' % (bed_id,message))
318        if len(released):
319            message = ', '.join(released)
320            self.flash(_('Successfully released beds: ${a}',
321                mapping = {'a':message}))
322            write_log_message(self, 'released: %s' % message)
323            self.redirect(self.url(self.context, '@@manage')+'?tab2')
324        else:
325            self.flash(_('No allocated bed selected.'))
326            self.redirect(self.url(self.context, '@@manage')+'?tab2')
327        return
328
329class BedManageFormPage(KofaEditFormPage):
330    """ View to edit bed data
331    """
332    grok.context(IBedAllocateStudent)
333    grok.name('index')
334    grok.require('waeup.manageHostels')
335    form_fields = grok.AutoFields(IBedAllocateStudent).omit(
336        'bed_id').omit('bed_number').omit('bed_type')
337    label = _('Allocate student')
338    pnav = 5
339
340    @action(_('Save'))
341    def save(self, **data):
342        msave(self, **data)
343        self.redirect(self.url(self.context.__parent__, '@@manage')+'?tab2')
344        return
345
346    def update(self):
347        if self.context.owner != NOT_OCCUPIED:
348            # Don't use this form for exchanging students.
349            # Beds must be released first before they can be allocated to
350            # other students.
351            self.redirect(self.url(self.context.__parent__, '@@manage')+'?tab2')
352        return
Note: See TracBrowser for help on using the repository browser.