Source code for feriennet.views.occasion

from datetime import date
from markupsafe import Markup
from onegov.activity import AttendeeCollection
from onegov.activity import Booking, BookingCollection
from onegov.activity import InvoiceCollection
from onegov.activity import Occasion, OccasionCollection, OccasionNeed
from onegov.activity import PeriodCollection
from onegov.core.security import Private, Personal, Public
from onegov.core.templates import render_template
from onegov.feriennet import _
from onegov.feriennet import FeriennetApp
from onegov.feriennet.collections.billing import BookingInvoiceBridge
from onegov.feriennet.forms import AttendeeSignupForm
from onegov.feriennet.forms import OccasionForm
from onegov.feriennet.forms import OccasionNeedForm
from onegov.feriennet.layout import OccasionFormLayout
from onegov.feriennet.models import VacationActivity
from onegov.org.layout import DefaultMailLayout
from onegov.user import User, UserCollection


from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from onegov.core.types import RenderData
    from onegov.feriennet.request import FeriennetRequest
    from webob import Response


@FeriennetApp.view(
    model=Occasion,
    permission=Public,
)
[docs] def view_occasion(self: Occasion, request: 'FeriennetRequest') -> 'Response': return request.redirect(request.link(self.activity))
@FeriennetApp.form( model=VacationActivity, template='form.pt', form=OccasionForm, permission=Private, name='new-occasion')
[docs] def new_occasion( self: VacationActivity, request: 'FeriennetRequest', form: OccasionForm ) -> 'RenderData | Response': if form.submitted(request): occasions = OccasionCollection(request.session) periods = PeriodCollection(request.session) period = periods.by_id(form.period_id.data) assert period is not None form.populate_obj(occasions.add( activity=self, start=form.parsed_dates[0].start, end=form.parsed_dates[0].end, timezone=form.timezone, period=period )) request.success(_('Your changes were saved')) return request.redirect(request.link(self)) layout = OccasionFormLayout(self, request, _('New Occasion')) layout.edit_mode = True return { 'layout': layout, 'title': _('New Occasion'), 'form': form }
@FeriennetApp.form( model=Occasion, template='form.pt', form=OccasionForm, permission=Private, name='clone')
[docs] def clone_occasion( self: Occasion, request: 'FeriennetRequest', form: OccasionForm ) -> 'RenderData | Response': if form.submitted(request): occasions = OccasionCollection(request.session) periods = PeriodCollection(request.session) period = periods.by_id(form.period_id.data) assert period is not None form.populate_obj(occasions.add( activity=self.activity, start=form.parsed_dates[0].start, end=form.parsed_dates[0].end, timezone=form.timezone, period=period )) request.success(_('Your changes were saved')) return request.redirect(request.link(self.activity)) elif not request.POST: form.process(obj=self) form.dates.data = form.dates_to_json(dates=None) return { 'layout': OccasionFormLayout( self.activity, request, _('Clone Occasion')), 'title': _('Clone Occasion'), 'form': form }
@FeriennetApp.form( model=Occasion, template='form.pt', form=OccasionForm, permission=Private, name='edit')
[docs] def edit_occasion( self: Occasion, request: 'FeriennetRequest', form: OccasionForm ) -> 'RenderData | Response': if self.period.confirmed: warning = _( 'The period of this occasion has already been confirmed. ' 'It is not recommended to change the period associated with ' 'this occasion.' ) else: warning = None if form.submitted(request): form.populate_obj(self) request.success(_('Your changes were saved')) return request.redirect(request.link(self.activity)) elif not request.POST: form.process(obj=self) layout = OccasionFormLayout(self.activity, request, _('Edit Occasion')) layout.edit_mode = True return { 'layout': layout, 'title': _('Edit Occasion'), 'form': form, 'callout': warning }
@FeriennetApp.view( model=Occasion, permission=Private, request_method='DELETE')
[docs] def delete_occasion(self: Occasion, request: 'FeriennetRequest') -> None: request.assert_valid_csrf_token() OccasionCollection(request.session).delete(self)
@FeriennetApp.view( model=Occasion, permission=Private, request_method='POST', name='cancel')
[docs] def cancel_occasion(self: Occasion, request: 'FeriennetRequest') -> None: request.assert_valid_csrf_token() self.cancel()
@FeriennetApp.view( model=Occasion, permission=Private, request_method='POST', name='reinstate')
[docs] def reinstate_occasion(self: Occasion, request: 'FeriennetRequest') -> None: request.assert_valid_csrf_token() self.cancelled = False
@FeriennetApp.form( model=Occasion, form=AttendeeSignupForm, permission=Personal, name='book', template='enroll_form.pt')
[docs] def book_occasion( self: Occasion, request: 'FeriennetRequest', form: AttendeeSignupForm ) -> 'RenderData | Response': # for the "nth. occasion" title number: int = request.session.execute(""" SELECT count(*) FROM occasions WHERE activity_id = :activity_id AND "order" <= :order AND "period_id" = :period_id """, { 'activity_id': self.activity_id, 'order': self.order, 'period_id': self.period.id }).scalar() if form.submitted(request): attendees = AttendeeCollection(request.session) user = form.user if form.is_new_attendee: assert user is not None assert form.birth_date.data is not None attendee = attendees.add( user=user, name=form.name, birth_date=form.birth_date.data, gender=form.gender.data, notes=form.notes.data, differing_address=form.differing_address.data, address=form.address.data if form.differing_address.data else None, zip_code=form.zip_code.data if form.differing_address.data else None, place=form.place.data if form.differing_address.data else None, political_municipality=form.political_municipality.data if form.political_municipality and form.differing_address.data else None ) else: existing_attendee = attendees.by_id(form.attendee.data) assert existing_attendee is not None attendee = existing_attendee assert attendee.username == form.username # should be caught by the form assert not (self.full and self.period.confirmed) assert self.activity.state == 'accepted' bookings = BookingCollection(request.session) # if there's a canceled/denied booking blocking the way, reactivate it booking = None if not form.is_new_attendee: assert user is not None booking = ( bookings.query() .filter(Booking.occasion_id == self.id) .filter(Booking.username == user.username) .filter(Booking.attendee == attendee) .filter(Booking.state.in_(( 'cancelled', 'denied', 'blocked', ))) .first() ) if booking: booking.state = 'open' if booking is None: assert user is not None booking = bookings.add( user=user, attendee=attendee, occasion=self ) # apply the group code, if given if form.group_code.data: booking.group_code = form.group_code.data # if the TOS have been accepted, record this now if hasattr(form, 'accept_tos') and form.accept_tos: if form.accept_tos.data: assert request.current_user is not None request.current_user.data['tos_accepted'] = True # to get the final cost, we need to accept bookings without wishlist if self.period.confirmed: bookings.accept_booking(booking) # if the period has been finalized, an admin is responsible and we # need to create an invoice item that goes with the booking if self.period.finalized: assert request.is_admin or self.period.book_finalized bridge = BookingInvoiceBridge(request.session, self.period) bridge.process(booking) bridge.complete( all_inclusive_booking_text=request.translate(_('Passport'))) if self.period.confirmed: request.success( _('The booking for ${name} was succesfull', mapping={ 'name': attendee.name }) ) bookings_link = Markup('<a href="{}">{}</a>').format( request.class_link(BookingCollection, { 'period_id': self.period.id }), request.translate(_('Bookings')) ) subject = request.translate( _('Booking of ${attendee} for "${title}"', mapping={ 'title': self.activity.title, 'attendee': attendee.name })) if self.period.booking_start <= date.today(): assert user is not None request.app.send_transactional_email( subject=subject, receivers=(user.username, ), content=render_template( 'mail_booking_accepted.pt', request, { 'layout': DefaultMailLayout(self, request), 'title': subject, 'model': self, 'bookings_link': bookings_link, 'name': attendee.name, 'dates': self.dates } ) ) else: request.success( _("The occasion was added to ${name}'s wishlist", mapping={ 'name': attendee.name })) if self.period.finalized: return request.redirect(request.class_link(InvoiceCollection)) else: return request.redirect(request.link(self.activity)) # pre select the attendee if given if 'attendee_id' in request.params: attendee_id = request.params['attendee_id'] assert isinstance(attendee_id, str) form.attendee.data = attendee_id.replace('-', '') group_code = request.params.get('group_code') assert group_code is None or isinstance(group_code, str) form.group_code.data = group_code title = _('Enroll Attendee') users = [] if request.is_admin: u = UserCollection(request.session).query() u = u.with_entities(User.username, User.title) u = u.order_by(User.title) users = u.all() return { 'layout': OccasionFormLayout(self.activity, request, title), 'title': title, 'form': form, 'occasion': self, 'users': users, 'button_text': _('Enroll'), 'number': number, }
@FeriennetApp.form( model=Occasion, permission=Private, form=OccasionNeedForm, template='form.pt', name='add-need')
[docs] def handle_new_occasion_need( self: Occasion, request: 'FeriennetRequest', form: OccasionNeedForm ) -> 'RenderData | Response': if form.submitted(request): assert form.name.data is not None self.needs.append(OccasionNeed( occasion_id=self.id, name=form.name.data, description=form.description.data, number=form.number, accept_signups=form.accept_signups.data, )) request.success(_('Your changes were saved')) return request.redirect(request.link(self)) return { 'layout': OccasionFormLayout( self.activity, request, _('New need')), 'title': _('New need'), 'form': form }
@FeriennetApp.form( model=OccasionNeed, permission=Private, form=OccasionNeedForm, template='form.pt', name='edit')
[docs] def handle_occasion_need( self: OccasionNeed, request: 'FeriennetRequest', form: OccasionNeedForm ) -> 'RenderData | Response': if form.submitted(request): form.populate_obj(self) # XXX the observer only works when we add/remove things from the list, # not when we change something inside the list self.occasion.observe_needs(self.occasion.needs) request.success(_('Your changes were saved')) return request.redirect(request.link(self.occasion)) elif not request.POST: form.process(obj=self) return { 'layout': OccasionFormLayout( self.occasion.activity, request, _('Edit need')), 'title': self.name, 'form': form }
@FeriennetApp.view( model=OccasionNeed, permission=Private, request_method='DELETE')
[docs] def delete_occasion_need( self: OccasionNeed, request: 'FeriennetRequest' ) -> None: request.assert_valid_csrf_token() # Likewise, before flushing the changes, the needs observer is not # triggered by an event. occasion = self.occasion request.session.delete(self) occasion.observe_needs(occasion.needs)