source: main/waeup.kofa/backup-trunk/src/waeup/kofa/hostels/browser.py @ 10718

Last change on this file since 10718 was 9199, checked in by Henrik Bettermann, 12 years ago

Add hostels and beds exporter (tests will follow).

  • Property svn:keywords set to Id
File size: 12.8 KB
Line 
1## $Id: browser.py 9199 2012-09-18 21:07:02Z 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.coordinates
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'),
133        _('Clear all hostels'),
134        _('Remove selected')]
135
136    def update(self):
137        tabs.need()
138        self.tab1 = self.tab2 = self.tab3 = self.tab4 = ''
139        qs = self.request.get('QUERY_STRING', '')
140        if not qs:
141            qs = 'tab1'
142        setattr(self, qs, 'active')
143        warning.need()
144        datatable.need()
145        return super(HostelsContainerManagePage, self).update()
146
147    # It's quite dangerous to remove entire hostels with its content (beds).
148    # Thus, this remove method should be combined with an archiving function.
149    @jsaction(_('Remove selected'))
150    def delHostels(self, **data):
151        form = self.request.form
152        if form.has_key('val_id'):
153            deleted = []
154            child_id = form['val_id']
155            if not isinstance(child_id, list):
156                child_id = [child_id]
157            for id in child_id:
158                deleted.append(id)
159            write_log_message(self, 'deleted: % s' % ', '.join(deleted))
160        delSubobjects(self, redirect='@@manage', tab='2')
161        return
162
163    @action(_('Add hostel'), validator=NullValidator)
164    def addSubunit(self, **data):
165        self.redirect(self.url(self.context, 'addhostel'))
166        return
167
168    @jsaction(_('Clear all hostels'))
169    def clearHostels(self, **data):
170        self.context.clearAllHostels()
171        self.flash(_('All hostels cleared.'))
172        write_log_message(self, 'all hostels cleared')
173        self.redirect(self.url(self.context, '@@manage')+'?tab2')
174        return
175
176    @action(_('Save'), style='primary')
177    def save(self, **data):
178        self.applyData(self.context, **data)
179        self.flash(_('Settings have been saved.'))
180        return
181
182class HostelAddFormPage(KofaAddFormPage):
183    """Add-form to add a hostel.
184    """
185    grok.context(IHostelsContainer)
186    grok.require('waeup.manageHostels')
187    grok.name('addhostel')
188    #grok.template('hosteladdpage')
189    form_fields = grok.AutoFields(IHostel).omit('beds_reserved')
190    label = _('Add hostel')
191    pnav = 5
192
193    @action(_('Create hostel'))
194    def addHostel(self, **data):
195        hostel = Hostel()
196        self.applyData(hostel, **data)
197        hostel.hostel_id = data[
198            'hostel_name'].lower().replace(' ','-').replace('_','-')
199        try:
200            self.context.addHostel(hostel)
201        except KeyError:
202            self.flash(_('The hostel already exists.'))
203            return
204        self.flash(_('Hostel created.'))
205        write_log_message(self, 'added: % s' % data['hostel_name'])
206        self.redirect(self.url(self.context[hostel.hostel_id], 'index'))
207        return
208
209class HostelDisplayFormPage(KofaDisplayFormPage):
210    """ Page to display hostel data
211    """
212    grok.context(IHostel)
213    grok.name('index')
214    grok.require('waeup.viewHostels')
215    #grok.template('hostelpage')
216    pnav = 5
217
218    @property
219    def label(self):
220        return self.context.hostel_name
221
222class HostelManageActionButton(ManageActionButton):
223    grok.order(1)
224    grok.context(IHostel)
225    grok.view(HostelDisplayFormPage)
226    grok.require('waeup.manageHostels')
227    text = _('Manage')
228    target = 'manage'
229
230class HostelManageFormPage(KofaEditFormPage):
231    """ View to edit hostel data
232    """
233    grok.context(IHostel)
234    grok.name('manage')
235    grok.require('waeup.manageHostels')
236    form_fields = grok.AutoFields(IHostel).omit('hostel_id')
237    form_fields['beds_reserved'].for_display = True
238    grok.template('hostelmanagepage')
239    label = _('Manage hostel')
240    pnav = 5
241    taboneactions = [_('Save')]
242    tabtwoactions = [_('Update all beds'),
243        _('Switch reservation of selected beds'),
244        _('Release selected beds'),
245        _('Clear hostel')]
246    not_occupied = NOT_OCCUPIED
247
248    @property
249    def students_url(self):
250        return self.url(grok.getSite(),'students')
251
252    def update(self):
253        datepicker.need() # Enable jQuery datepicker in date fields.
254        tabs.need()
255        datatable.need()
256        warning.need()
257        self.tab1 = self.tab2 = ''
258        qs = self.request.get('QUERY_STRING', '')
259        if not qs:
260            qs = 'tab1'
261        setattr(self, qs, 'active')
262        super(HostelManageFormPage, self).update()
263        return
264
265    @action(_('Save'))
266    def save(self, **data):
267        msave(self, **data)
268        return
269
270    @action(_('Update all beds'))
271    def updateBeds(self, **data):
272        removed, added, modified, modified_beds = self.context.updateBeds()
273        message = '%d empty beds removed, %d beds added, %d occupied beds modified (%s)' % (
274            removed, added, modified, modified_beds)
275        flash_message = _(
276            '${a} empty beds removed, ${b} beds added, '
277            + '${c} occupied beds modified (${d})',
278            mapping = {'a':removed, 'b':added, 'c':modified, 'd':modified_beds})
279        self.flash(flash_message)
280        write_log_message(self, message)
281        self.redirect(self.url(self.context, '@@manage')+'?tab2')
282        return
283
284    @action(_('Switch reservation of selected beds'))
285    def switchReservations(self, **data):
286        form = self.request.form
287        if form.has_key('val_id'):
288            child_id = form['val_id']
289        else:
290            self.flash(_('No item selected.'))
291            self.redirect(self.url(self.context, '@@manage')+'?tab2')
292            return
293        if not isinstance(child_id, list):
294            child_id = [child_id]
295        switched = [] # for log file
296        switched_translated = [] # for flash message
297        # Here we know that the cookie has been set
298        preferred_language = self.request.cookies.get('kofa.language')
299        for bed_id in child_id:
300            message = self.context[bed_id].switchReservation()
301            switched.append('%s (%s)' % (bed_id,message))
302            m_translated = translate(message, 'waeup.kofa',
303                target_language=preferred_language)
304            switched_translated.append('%s (%s)' % (bed_id,m_translated))
305        if len(switched):
306            message = ', '.join(switched)
307            m_translated = ', '.join(switched_translated)
308            self.flash(_('Successfully switched beds: ${a}',
309                mapping = {'a':m_translated}))
310            write_log_message(self, 'switched: %s' % message)
311            self.redirect(self.url(self.context, '@@manage')+'?tab2')
312        return
313
314    @action(_('Release selected beds'))
315    def releaseBeds(self, **data):
316        form = self.request.form
317        if form.has_key('val_id'):
318            child_id = form['val_id']
319        else:
320            self.flash(_('No item selected.'))
321            self.redirect(self.url(self.context, '@@manage')+'?tab2')
322            return
323        if not isinstance(child_id, list):
324            child_id = [child_id]
325        released = []
326        for bed_id in child_id:
327            message = self.context[bed_id].releaseBed()
328            if message:
329                released.append('%s (%s)' % (bed_id,message))
330        if len(released):
331            message = ', '.join(released)
332            self.flash(_('Successfully released beds: ${a}',
333                mapping = {'a':message}))
334            write_log_message(self, 'released: %s' % message)
335            self.redirect(self.url(self.context, '@@manage')+'?tab2')
336        else:
337            self.flash(_('No allocated bed selected.'))
338            self.redirect(self.url(self.context, '@@manage')+'?tab2')
339        return
340
341    @jsaction(_('Clear hostel'))
342    def clearHostel(self, **data):
343        self.context.clearHostel()
344        self.flash(_('Hostel cleared.'))
345        write_log_message(self, 'cleared')
346        self.redirect(self.url(self.context, '@@manage')+'?tab2')
347        return
348
349class BedManageFormPage(KofaEditFormPage):
350    """ View to edit bed data
351    """
352    grok.context(IBedAllocateStudent)
353    grok.name('index')
354    grok.require('waeup.manageHostels')
355    form_fields = grok.AutoFields(IBedAllocateStudent).omit(
356        'bed_id', 'bed_number', 'bed_type')
357    label = _('Allocate student')
358    pnav = 5
359
360    @action(_('Save'))
361    def save(self, **data):
362        msave(self, **data)
363        self.redirect(self.url(self.context.__parent__, '@@manage')+'?tab2')
364        return
365
366    def update(self):
367        if self.context.owner != NOT_OCCUPIED:
368            # Don't use this form for exchanging students.
369            # Beds must be released first before they can be allocated to
370            # other students.
371            self.redirect(self.url(self.context.__parent__, '@@manage')+'?tab2')
372        return
Note: See TracBrowser for help on using the repository browser.