Пример #1
0
    def validate_period(self, field):
        periods = PeriodCollection(self.request.session)
        period = periods.by_id(field.data)

        if not period.finalized:
            raise ValidationError(
                "The billing of this period has not been finalized yet")
Пример #2
0
def clone_occasion(self, request, form):

    if form.submitted(request):
        occasions = OccasionCollection(request.session)
        periods = PeriodCollection(request.session)

        form.populate_obj(occasions.add(
            activity=self.activity,
            start=form.parsed_dates[0].start,
            end=form.parsed_dates[0].end,
            timezone=form.timezone,
            period=periods.by_id(form.period_id.data)
        ))

        request.success(_("Your changes were saved"))
        return request.redirect(request.link(self.activity))
    elif not request.POST:
        form.process(obj=self)

    return {
        'layout': OccasionFormLayout(
            self.activity, request, _("Clone Occasion")),
        'title': _("Clone Occasion"),
        'form': form
    }
Пример #3
0
    def period_choices(self):
        periods = PeriodCollection(self.request.session)

        q = periods.query()
        q = q.with_entities(Period.id, Period.title)
        q = q.order_by(desc(Period.active), desc(Period.prebooking_start))

        def choice(row):
            return row.id.hex, row.title

        return [choice(p) for p in q]
Пример #4
0
def get_occasion_attendee_collection(request, app, activity_name,
                                     period_id=None):

    # load the activity
    activity = get_vacation_activity(request, app, activity_name)

    if not activity:
        return None

    # the default period is the active period or the first we can find
    if not period_id:
        period = app.default_period
    else:
        period = PeriodCollection(app.session()).by_id(period_id)

    if not period:
        return None

    # non-admins are automatically limited to the activites they own
    if request.is_admin:
        username = None
    else:
        username = request.current_username

    return OccasionAttendeeCollection(
        app.session(), period, activity, username)
Пример #5
0
    def setup_period_choices(self):
        query = PeriodCollection(self.request.session).query()
        query = query.order_by(desc(Period.active), Period.title)

        def choice(period):
            return str(period.id), '{} ({:%d.%m.%Y} - {:%d.%m.%Y})'.format(
                period.title,
                period.execution_start,
                period.execution_end
            )

        periods = query.all()
        self.period_id.choices = [choice(p) for p in periods]

        if self.period_id.data == '0xdeadbeef':
            self.period_id.data = periods[0].id
Пример #6
0
def get_variables(request):
    period = PeriodCollection(request.session).active()
    variables = TemplateVariables(request, period).bound

    return OrderedDict(
        (token, variables[token].__doc__) for token in sorted(variables)
    )
Пример #7
0
def handle_send_notification(self, request, form):

    period = PeriodCollection(request.session).active()
    variables = TemplateVariables(request, period)
    layout = NotificationTemplateLayout(self, request)

    if form.submitted(request):
        recipients = form.recipients

        if not recipients:
            request.alert(_("There are no recipients matching the selection"))
        else:
            current = request.current_username

            if current not in recipients:
                recipients.add(current)

            subject = variables.render(self.subject)
            content = render_template('mail_notification.pt', request, {
                'layout': DefaultMailLayout(self, request),
                'title': subject,
                'notification': variables.render(self.text)
            })
            plaintext = html_to_text(content)

            for recipient in recipients:
                request.app.send_marketing_email(
                    receivers=(recipient, ),
                    subject=subject,
                    content=content,
                    plaintext=plaintext,
                )

            self.last_sent = utcnow()

            request.success(_(
                "Successfully sent the e-mail to ${count} recipients",
                mapping={
                    'count': len(recipients)
                }
            ))

            return request.redirect(
                request.class_link(NotificationTemplateCollection))

    return {
        'title': _("Mailing"),
        'layout': layout,
        'form': form,
        'preview_subject': variables.render(self.subject),
        'preview_body': variables.render(self.text),
        'edit_link': request.return_here(request.link(self, 'edit')),
        'button_text': _("Send E-Mail Now")
    }
Пример #8
0
def get_billing(request, app, period_id, username=None, expand=False):
    # the default period is the active period or the first we can find
    if not period_id:
        period = app.default_period
    else:
        period = PeriodCollection(app.session()).by_id(period_id)

    if not period:
        return None

    return BillingCollection(request, period, username, expand)
Пример #9
0
def get_matches(request, app, period_id, states=None):
    # the default period is the active period or the first we can find
    if not period_id:
        period = app.default_period
    else:
        period = PeriodCollection(app.session()).by_id(period_id)

    if not period:
        return None

    return MatchCollection(app.session(), period, states)
Пример #10
0
def get_period(request, app, id):
    return PeriodCollection(app.session()).by_id(id)
Пример #11
0
 def selected_period(self):
     return PeriodCollection(self.request.session).by_id(self.period.data)
Пример #12
0
    def period_choices(self):
        q = PeriodCollection(self.request.session).query()
        q = q.with_entities(Period.id, Period.title)
        q = q.order_by(Period.execution_start)

        return [(row.id.hex, row.title) for row in q]
Пример #13
0
 def periods_by_id(self):
     return {
         p.id.hex: p for p in PeriodCollection(self.session()).query()
     }
Пример #14
0
    def periods(self):
        p = PeriodCollection(self.session()).query()
        p = p.order_by(Period.execution_start)

        return p
Пример #15
0
 def active_period(self):
     return PeriodCollection(self.session()).active()
Пример #16
0
def get_periods(request, app):
    return PeriodCollection(app.session())
Пример #17
0
def test_notification_template_send_form(session):
    activities = ActivityCollection(session, type='vacation')
    attendees = AttendeeCollection(session)
    periods = PeriodCollection(session)
    occasions = OccasionCollection(session)
    bookings = BookingCollection(session)

    users = UserCollection(session)
    admin = users.add(username='******',
                      realname='Robert Baratheon',
                      password='******',
                      role='admin')
    organiser = users.add(username='******',
                          realname=None,
                          password='******',
                          role='editor')
    users.add(username='******',
              realname=None,
              password='******',
              role='member')

    prebooking = tuple(d.date() for d in (datetime.now() - timedelta(days=1),
                                          datetime.now() + timedelta(days=1)))

    execution = tuple(d.date() for d in (datetime.now() + timedelta(days=10),
                                         datetime.now() + timedelta(days=12)))

    period = periods.add(title="Ferienpass 2016",
                         prebooking=prebooking,
                         execution=execution,
                         active=True)

    foo = activities.add("Foo", username='******')
    foo.propose().accept()

    bar = activities.add("Bar", username='******')
    bar.propose().accept()

    o1 = occasions.add(
        start=datetime(2016, 11, 25, 8),
        end=datetime(2016, 11, 25, 16),
        age=(0, 10),
        spots=(0, 2),
        timezone="Europe/Zurich",
        activity=foo,
        period=period,
    )
    o1.username = admin.username

    o2 = occasions.add(
        start=datetime(2016, 11, 25, 17),
        end=datetime(2016, 11, 25, 20),
        age=(0, 10),
        spots=(0, 2),
        timezone="Europe/Zurich",
        activity=bar,
        period=period,
    )
    o2.username = organiser.username

    a1 = attendees.add(admin, 'Dustin', date(2000, 1, 1), 'male')
    a2 = attendees.add(organiser, 'Mike', date(2000, 1, 1), 'female')

    b1 = bookings.add(admin, a1, o1)
    b1.state = 'accepted'
    b1.cost = 100

    b2 = bookings.add(organiser, a2, o2)
    b2.state = 'accepted'
    b2.cost = 100

    transaction.commit()

    # create a mock request
    def invoice_collection(user_id=None, period_id=None):
        return InvoiceCollection(session, user_id=user_id, period_id=period_id)

    def request(admin):
        return Bunch(app=Bunch(
            active_period=periods.active(),
            org=Bunch(geo_provider='geo-mapbox'),
            invoice_collection=invoice_collection,
            periods=periods.query().all(),
        ),
                     session=session,
                     include=lambda *args: None,
                     model=None,
                     is_admin=admin,
                     is_organiser_only=not admin and True or False,
                     is_manager=admin and True or False,
                     translate=lambda text, *args, **kwargs: text,
                     locale='de_CH',
                     current_username=(admin and '*****@*****.**'
                                       or '*****@*****.**'))

    # in the beginning there are no recipients
    form = NotificationTemplateSendForm()
    form.model = None
    form.request = request(admin=True)

    assert form.has_choices  # we still have choices (like send to users)
    assert not form.occasion.choices

    # once the request is processed, the occasions are added
    form.on_request()

    assert form.has_choices
    assert len(form.occasion.choices) == 2
    assert len(form.send_to.choices) == 7

    # if the period is inactive, there are no occasions
    periods.query().one().active = False
    transaction.commit()

    form = NotificationTemplateSendForm()
    form.model = None
    form.request = request(admin=True)

    form.on_request()
    assert len(form.occasion.choices) == 0

    # if the period is active but not confirmed, there are no recipients
    period = periods.query().one()
    period.active = True
    period.confirmed = False
    transaction.commit()

    form = NotificationTemplateSendForm()
    form.model = None
    form.request = request(admin=True)

    form.on_request()

    occasions = [c[0] for c in form.occasion.choices]

    # with organisers
    assert len(form.recipients_by_occasion(occasions, True)) == 2

    # without
    assert len(form.recipients_by_occasion(occasions, False)) == 0

    # the number of users is indepenedent of the period
    assert len(form.recipients_by_role(('admin', 'editor', 'member'))) == 3
    assert len(form.recipients_by_role(('admin', 'editor'))) == 2
    assert len(form.recipients_by_role(('admin', ))) == 1

    # if the period is confirmed, there are accepted recipients
    period = periods.query().one()
    period.active = True
    period.confirmed = True

    transaction.commit()
    assert len(form.recipients_by_occasion(occasions)) == 2

    # only accepted bookings are counted
    parent = admin.username
    bookings.query().filter_by(username=parent).one().state = 'cancelled'
    transaction.commit()

    # without organisers
    assert len(form.recipients_by_occasion(occasions, False)) == 1

    # with
    assert len(form.recipients_by_occasion(occasions, True)) == 2

    # inactive users may be exluded
    form.state.data = ['active']
    assert len(form.recipients_pool) == 3

    form.state.data = ['active', 'inactive']
    assert len(form.recipients_pool) == 3

    form.state.data = ['inactive']
    assert len(form.recipients_pool) == 0

    # bookings count towards the wishlist if the period is active,
    period = periods.query().one()
    period.active = True
    period.confirmed = False

    transaction.commit()

    form.request = request(admin=True)

    # do not count cancelled bookings...
    assert len(form.recipients_with_wishes()) == 2
    assert len(form.recipients_with_bookings()) == 0

    # otherwise they count towards the bookings
    period = periods.query().one()
    period.confirmed = True

    transaction.commit()

    form.request = request(admin=True)
    assert len(form.recipients_with_wishes()) == 0
    assert len(form.recipients_with_bookings()) == 2

    # count the active organisers
    form.request = request(admin=True)
    assert len(form.recipients_which_are_active_organisers()) == 2

    # count the users with unpaid bills
    form.request = request(admin=True)
    assert len(form.recipients_with_unpaid_bills()) == 0

    period = periods.query().one()
    billing = BillingCollection(request=Bunch(
        session=session, app=Bunch(invoice_collection=invoice_collection)),
                                period=period)
    billing.create_invoices()
    transaction.commit()

    form.request = request(admin=True)
    assert len(form.recipients_with_unpaid_bills()) == 1

    # organisers are not counted as active if the occasion has been cancelled
    occasions = OccasionCollection(session)

    occasions.query().first().cancelled = True
    transaction.commit()

    form.request = request(admin=True)
    assert len(form.recipients_which_are_active_organisers()) == 1

    for occasion in occasions.query():
        occasion.cancelled = False

    transaction.commit()

    form.request = request(admin=True)
    assert len(form.recipients_which_are_active_organisers()) == 2