def send_certificate_email(request):
    '''
    Send email to a member with a link
    so the member can get her membership certificate.
    '''
    member = request.validated_matchdict['member']

    member.certificate_token = make_random_token()
    email_subject, email_body = make_membership_certificate_email(
        request,
        member)
    the_message = Message(
        subject=email_subject,
        sender=request.registry.settings['c3smembership.notification_sender'],
        recipients=[member.email],
        body=email_body
    )
    send_message(request, the_message)

    member.certificate_email = True
    member.certificate_email_date = datetime.now()

    if hasattr(request, 'referer') and request.referer is not None and \
            'detail' in request.referer:
        return HTTPFound(
            request.route_url(
                'detail',
                member_id=member.id,
                _anchor='certificate'
            )
        )
    else:
        return get_memberhip_listing_redirect(request, member.id)
def send_certificate_email(request):
    """
    Send email to a member with a link
    so the member can get her membership certificate.
    """
    _special_condition = False  # for redirects to referrer

    mid = request.matchdict["id"]
    member = C3sMember.get_by_id(mid)
    if isinstance(member, NoneType) or not member.is_member():
        return Response("that id does not exist or is not an accepted member. go back", status="404 Not Found")
    # create a token for the certificate
    member.certificate_token = make_random_token()

    email_subject, email_body = make_membership_certificate_email(request, member)

    the_message = Message(subject=email_subject, sender="*****@*****.**", recipients=[member.email], body=email_body)
    send_message(request, the_message)

    member.certificate_email = True
    member.certificate_email_date = datetime.now()

    try:  # pragma: no cover
        if "detail" in request.referrer:
            _special_condition = True
    except TypeError:  # pragma: no cover
        pass

    if _special_condition:  # pragma: no cover
        return HTTPFound(location=request.referrer + "#certificate")
    else:
        return get_memberhip_listing_redirect(request, member.id)
Exemple #3
0
def invite_member_bcgv(request):
    """
    Send email to member with link to ticketing.

    === ====================================
    URL http://app:port/invite_member/{m_id}
    === ====================================
    """
    member_id = request.matchdict['m_id']
    member = C3sMember.get_by_id(member_id)
    if isinstance(member, NoneType):
        request.session.flash('id not found. no mail sent.', 'messages')
        return get_memberhip_listing_redirect(request)

    if not member.is_member():
        request.session.flash('Invitations can only be sent to members.',
                              'messages')
        return get_memberhip_listing_redirect(request, member_id)

    # prepare a random token iff none is set
    if member.email_invite_token_bcgv17 is None:
        member.email_invite_token_bcgv17 = make_random_token()
    url = URL_PATTERN.format(
        ticketing_url=request.registry.settings['ticketing.url'],
        token=member.email_invite_token_bcgv17,
        email=member.email)

    LOG.info("mailing event invitation to to member id %s", member.id)

    email_subject, email_body = make_bcga17_invitation_email(member, url)
    message = Message(subject=email_subject,
                      sender='*****@*****.**',
                      recipients=[member.email],
                      body=email_body,
                      extra_headers={
                          'Reply-To': '*****@*****.**',
                      })
    send_message(request, message)

    # member._token = _looong_token
    member.email_invite_flag_bcgv17 = True
    member.email_invite_date_bcgv17 = datetime.now()
    return get_memberhip_listing_redirect(request, member.id)
def send_certificate_email(request):
    '''
    Send email to a member with a link
    so the member can get her membership certificate.
    '''
    _special_condition = False  # for redirects to referrer

    mid = request.matchdict['id']
    member = C3sMember.get_by_id(mid)
    if isinstance(member, NoneType) or not member.is_member():
        return Response(
            'that id does not exist or is not an accepted member. go back',
            status='404 Not Found',
        )
    # create a token for the certificate
    member.certificate_token = make_random_token()

    email_subject, email_body = make_membership_certificate_email(
        request, member)

    the_message = Message(subject=email_subject,
                          sender='*****@*****.**',
                          recipients=[member.email],
                          body=email_body)
    send_message(request, the_message)

    member.certificate_email = True
    member.certificate_email_date = datetime.now()

    try:  # pragma: no cover
        if 'detail' in request.referrer:
            _special_condition = True
    except TypeError:  # pragma: no cover
        pass

    if _special_condition:  # pragma: no cover
        return HTTPFound(location=request.referrer + '#certificate')
    else:
        return get_memberhip_listing_redirect(request, member.id)
def shares_edit(request):
    '''
    Edit details of a package of shares.
    '''
    # load info from DB -- if possible
    share = request.registry.share_information.get(request.matchdict['id'])

    if isinstance(share, NoneType):
        # entry was not found in database
        return get_memberhip_listing_redirect(request)
    else:
        appstruct = {}
        appstruct = {
            'number': share.number,
            'date_of_acquisition': share.date_of_acquisition,
        }

    # construct a form
    class SharesSchema(colander.Schema):
        """
        Defines the colander schema for shares.
        """
        number = colander.SchemaNode(
            colander.Integer(),
            title=_('Number of Shares'),
        )
        date_of_acquisition = colander.SchemaNode(
            colander.Date(), title=_('Date of Acquisition'))

    schema = SharesSchema()
    form = deform.Form(
        schema,
        buttons=[deform.Button('submit', _(u'Submit'))],
    )
    # form generation complete

    # if the form has been used and SUBMITTED, check contents
    if 'submit' in request.POST:
        controls = request.POST.items()
        try:
            appstruct = form.validate(controls)

        except ValidationFailure, validation_failure:  # pragma: no cover
            request.session.flash(_(u'Please note: There were errors, '
                                    'please check the form below.'),
                                  'message_above_form',
                                  allow_duplicate=False)
            return {'form': validation_failure.render()}

        # if no error occurred, persist the changed values info in database

        test1 = (  # changed value through form (different from db)?
            appstruct['number'] == share.number)
        if not test1:
            LOG.info('info about number of shares of %s changed by %s to %s',
                     share.id, request.user.login, appstruct['number'])
            share.number = appstruct['number']
        test2 = (  # changed value through form (different from db)?
            appstruct['date_of_acquisition'] == share.date_of_acquisition)
        if not test2:
            LOG.info(
                'info about date_of_acquisition of %s changed by %s to %s',
                share.id, request.user.login, appstruct['date_of_acquisition'])
            share.date_of_acquisition = appstruct['date_of_acquisition']
Exemple #6
0
def send_dues18_invoice_email(request, m_id=None):
    """
    Send email to a member to prompt her to pay the membership dues.
    - For normal members, also send link to invoice.
    - For investing members that are legal entities,
      ask for additional support depending on yearly turnover.

    This view function works both if called via URL, e.g. /dues_invoice/123
    and if called as a function with a member id as parameter.
    The latter is useful for batch processing.

    When this function is used for the first time for one member,
    some database fields are filled:
    - Invoice number
    - Invoice amount (calculated from date of membership approval by the board)
    - Invoice token
    Also, the database table of invoices (and cancellations) is appended.

    If this function gets called the second time for a member,
    no new invoice is produced, but the same mail sent again.
    """
    # either we are given a member id via url or function parameter
    try:  # view was called via http/s
        member_id = request.matchdict['member_id']
        batch = False
    except KeyError:  # ...or was called as function with parameter (see batch)
        member_id = m_id
        batch = True

    try:  # get member from DB
        member = C3sMember.get_by_id(member_id)
        assert(member is not None)
    except AssertionError:
        if not batch:
            request.session.flash(
                "member with id {} not found in DB!".format(member_id),
                'warning')
            return HTTPFound(request.route_url('dues'))

    # sanity check:is this a member?
    try:
        assert(member.membership_accepted)  # must be accepted member!
    except AssertionError:
        request.session.flash(
            "member {} not accepted by the board!".format(member_id),
            'warning')
        return HTTPFound(request.route_url('dues'))

    if 'normal' not in member.membership_type and \
            'investing' not in member.membership_type:
        request.session.flash(
            'The membership type of member {0} is not specified! The '
            'membership type must either be "normal" or "investing" in order '
            'to be able to send an invoice email.'.format(member.id),
            'warning')
        return get_memberhip_listing_redirect(request)
    if member.membership_date >= date(2019, 1, 1) or (
                member.membership_loss_date is not None
                and member.membership_loss_date < date(2018, 1, 1)
            ):
        request.session.flash(
            'Member {0} was not a member in 2018. Therefore, you cannot send '
            'an invoice for 2018.'.format(member.id),
            'warning')
        return get_memberhip_listing_redirect(request)

    # check if invoice no already exists.
    #     if yes: just send that email again!
    #     also: offer staffers to cancel this invoice

    if member.dues18_invoice is True:
        invoice = DuesInvoiceRepository.get_by_number(
            member.dues18_invoice_no, 2018)
        member.dues18_invoice_date = datetime.now()

    else:  # if no invoice already exists:
        # make dues token and ...
        randomstring = make_random_string()
        # check if dues token is already used
        while DuesInvoiceRepository.token_exists(randomstring, 2018):
            # create a new one, if the new one already exists in the database
            randomstring = make_random_string()  # pragma: no cover

        # prepare invoice number
        try:
            # either we already have an invoice number for that client...
            invoice_no = member.dues18_invoice_no
            assert invoice_no is not None
        except AssertionError:
            # ... or we create a new one and save it
            # get max invoice no from db
            max_invoice_no = DuesInvoiceRepository.get_max_invoice_number(2018)
            # use the next free number, save it to db
            new_invoice_no = int(max_invoice_no) + 1
            DBSession.flush()  # save dataset to DB

        # calculate dues amount (maybe partial, depending on quarter)
        dues_start, dues_amount = calculate_partial_dues18(member)

        # now we have enough info to update the member info
        # and persist invoice info for bookkeeping
        # store some info in DB/member table
        member.dues18_invoice = True
        member.dues18_invoice_no = new_invoice_no  # irrelevant for investing
        member.dues18_invoice_date = datetime.now()
        member.dues18_token = randomstring
        member.dues18_start = dues_start

        if 'normal' in member.membership_type:  # only for normal members
            member.set_dues18_amount(dues_amount)
            # store some more info about invoice in invoice table
            invoice = Dues18Invoice(
                invoice_no=member.dues18_invoice_no,
                invoice_no_string=(
                    u'C3S-dues2018-' + str(member.dues18_invoice_no).zfill(4)),
                invoice_date=member.dues18_invoice_date,
                invoice_amount=u'' + str(member.dues18_amount),
                member_id=member.id,
                membership_no=member.membership_number,
                email=member.email,
                token=member.dues18_token,
            )
            DBSession.add(invoice)
        DBSession.flush()

    # now: prepare that email
    # only normal (not investing) members *have to* pay the dues.
    # only the normal members get an invoice link and PDF produced for them.
    # only investing legalentities are asked for more support.
    if 'investing' not in member.membership_type:
        start_quarter = string_start_quarter_dues18(member)
        invoice_url = (
            request.route_url(
                'make_dues18_invoice_no_pdf',
                email=member.email,
                code=member.dues18_token,
                i=str(member.dues18_invoice_no).zfill(4)
            )
        )
        email_subject, email_body = make_dues18_invoice_email(
            member,
            invoice,
            invoice_url,
            start_quarter)
        message = Message(
            subject=email_subject,
            sender=request.registry.settings[
                'c3smembership.notification_sender'],
            recipients=[member.email],
            body=email_body,
        )
    elif 'investing' in member.membership_type:
        if member.is_legalentity:
            email_subject, email_body = \
                make_dues_invoice_legalentity_email(member)
        else:
            email_subject, email_body = \
                make_dues_invoice_investing_email(member)
        message = Message(
            subject=email_subject,
            sender=request.registry.settings[
                'c3smembership.notification_sender'],
            recipients=[member.email],
            body=email_body,
        )

    # print to console or send mail
    if 'true' in request.registry.settings['testing.mail_to_console']:
        print(message.body.encode('utf-8'))  # pragma: no cover
    else:
        send_message(request, message)

    # now choose where to redirect
    if 'detail' in request.referrer:
        return HTTPFound(
            request.route_url(
                'detail',
                member_id=member.id) +
            '#dues18')
    if 'dues' in request.referrer:
        return HTTPFound(request.route_url('dues'))
    else:
        return get_memberhip_listing_redirect(request, member.id)
Exemple #7
0
def shares_edit(request):
    """
    Edit details of a package of shares.
    """
    # print(request.matchdict['id'])
    from c3smembership.models import Shares

    # load info from DB -- if possible
    _s = Shares.get_by_id(request.matchdict["id"])

    if isinstance(_s, NoneType):
        # entry was not found in database
        return get_memberhip_listing_redirect(request)
    else:
        appstruct = {}
        appstruct = {"number": _s.number, "date_of_acquisition": _s.date_of_acquisition}

    # construct a form
    class Shares(colander.Schema):
        number = colander.SchemaNode(colander.Integer(), title=_("Number of Shares"))
        date_of_acquisition = colander.SchemaNode(colander.Date(), title=_("Date of Acquisition"))

    schema = Shares()
    form = deform.Form(schema, buttons=[deform.Button("submit", _(u"Submit"))])
    # form generation complete

    # if the form has been used and SUBMITTED, check contents
    if "submit" in request.POST:
        controls = request.POST.items()
        try:
            appstruct = form.validate(controls)
            # print("the appstruct from the form: %s \n") % appstruct
            # for thing in appstruct:
            #     print("the thing: %s") % thing
            #     print("type: %s") % type(thing)

        except ValidationFailure, e:  # pragma: no cover
            print(e)
            request.session.flash(
                _(u"Please note: There were errors, " "please check the form below."),
                "message_above_form",
                allow_duplicate=False,
            )
            return {"form": e.render()}

        # if no error occurred, persist the changed values info in database

        test1 = appstruct["number"] == _s.number  # changed value through form (different from db)?
        if not test1:
            log.info(
                "info about number of shares of %s changed by %s to %s"
                % (_s.id, request.user.login, appstruct["number"])
            )
            _s.number = appstruct["number"]
        test2 = (  # changed value through form (different from db)?
            appstruct["date_of_acquisition"] == _s.date_of_acquisition
        )
        if not test2:
            log.info(
                "info about date_of_acquisition of %s changed by %s to %s"
                % (_s.id, request.user.login, appstruct["date_of_acquisition"])
            )
            _s.date_of_acquisition = appstruct["date_of_acquisition"]
def send_dues17_invoice_email(request, m_id=None):
    """
    Send email to a member to prompt her to pay the membership dues.
    - For normal members, also send link to invoice.
    - For investing members that are legal entities,
      ask for additional support depending on yearly turnover.

    This view function works both if called via URL, e.g. /dues_invoice/123
    and if called as a function with a member id as parameter.
    The latter is useful for batch processing.

    When this function is used for the first time for one member,
    some database fields are filled:
    - Invoice number
    - Invoice amount (calculated from date of membership approval by the board)
    - Invoice token
    Also, the database table of invoices (and cancellations) is appended.

    If this function gets called the second time for a member,
    no new invoice is produced, but the same mail sent again.
    """
    # either we are given a member id via url or function parameter
    try:  # view was called via http/s
        member_id = request.matchdict['member_id']
        batch = False
    except KeyError:  # ...or was called as function with parameter (see batch)
        member_id = m_id
        batch = True

    try:  # get member from DB
        member = C3sMember.get_by_id(member_id)
        assert (member is not None)
    except AssertionError:
        if not batch:
            request.session.flash(
                "member with id {} not found in DB!".format(member_id),
                'message_to_staff')
            return HTTPFound(request.route_url('toolbox'))

    # sanity check:is this a member?
    try:
        assert (member.membership_accepted)  # must be accepted member!
    except AssertionError:
        request.session.flash(
            "member {} not accepted by the board!".format(member_id),
            'message_to_staff')
        return HTTPFound(request.route_url('toolbox'))

    if 'normal' not in member.membership_type and \
            'investing' not in member.membership_type:
        request.session.flash(
            'The membership type of member {0} is not specified! The '
            'membership type must either be "normal" or "investing" in order '
            'to be able to send an invoice email.'.format(member.id),
            'message_to_staff')
        return get_memberhip_listing_redirect(request)
    if member.membership_date >= date(2018,1,1) or ( \
                member.membership_loss_date is not None
                and
                member.membership_loss_date < date(2017,1,1)
            ):
        request.session.flash(
            'Member {0} was not a member in 2017. Therefore, you cannot send '
            'an invoice for 2017.'.format(member.id), 'message_to_staff')
        return get_memberhip_listing_redirect(request)

    # check if invoice no already exists.
    #     if yes: just send that email again!
    #     also: offer staffers to cancel this invoice

    if member.dues17_invoice is True:
        invoice = Dues17Invoice.get_by_invoice_no(member.dues17_invoice_no)
        member.dues17_invoice_date = datetime.now()

    else:  # if no invoice already exists:
        # make dues token and ...
        randomstring = make_random_string()
        # check if dues token is already used
        while (Dues17Invoice.check_for_existing_dues17_token(randomstring)):
            # create a new one, if the new one already exists in the database
            randomstring = make_random_string()  # pragma: no cover

        # prepare invoice number
        try:
            # either we already have an invoice number for that client...
            invoice_no = member.dues17_invoice_no
            assert invoice_no is not None
        except AssertionError:
            # ... or we create a new one and save it
            # get max invoice no from db
            max_invoice_no = Dues17Invoice.get_max_invoice_no()
            # use the next free number, save it to db
            new_invoice_no = int(max_invoice_no) + 1
            DBSession.flush()  # save dataset to DB

        # calculate dues amount (maybe partial, depending on quarter)
        dues_start, dues_amount = calculate_partial_dues17(member)

        # now we have enough info to update the member info
        # and persist invoice info for bookkeeping
        # store some info in DB/member table
        member.dues17_invoice = True
        member.dues17_invoice_no = new_invoice_no  # irrelevant for investing
        member.dues17_invoice_date = datetime.now()
        member.dues17_token = randomstring
        member.dues17_start = dues_start

        if 'normal' in member.membership_type:  # only for normal members
            member.set_dues17_amount(dues_amount)
            # store some more info about invoice in invoice table
            invoice = Dues17Invoice(
                invoice_no=member.dues17_invoice_no,
                invoice_no_string=(u'C3S-dues2017-' +
                                   str(member.dues17_invoice_no).zfill(4)),
                invoice_date=member.dues17_invoice_date,
                invoice_amount=u'' + str(member.dues17_amount),
                member_id=member.id,
                membership_no=member.membership_number,
                email=member.email,
                token=member.dues17_token,
            )
            DBSession.add(invoice)
        DBSession.flush()

    # now: prepare that email
    # only normal (not investing) members *have to* pay the dues.
    # only the normal members get an invoice link and PDF produced for them.
    # only investing legalentities are asked for more support.
    if 'investing' not in member.membership_type:
        start_quarter = string_start_quarter_dues17(member)
        invoice_url = (request.route_url(
            'make_dues17_invoice_no_pdf',
            email=member.email,
            code=member.dues17_token,
            i=str(member.dues17_invoice_no).zfill(4)))
        email_subject, email_body = make_dues17_invoice_email(
            member, invoice, invoice_url, start_quarter)
        message = Message(subject=email_subject,
                          sender='*****@*****.**',
                          recipients=[member.email],
                          body=email_body,
                          extra_headers={
                              'Reply-To': '*****@*****.**',
                          })
    elif 'investing' in member.membership_type:
        if member.is_legalentity:
            email_subject, email_body = \
                make_dues_invoice_legalentity_email(member)
        else:
            email_subject, email_body = \
                make_dues_invoice_investing_email(member)
        message = Message(subject=email_subject,
                          sender='*****@*****.**',
                          recipients=[member.email],
                          body=email_body,
                          extra_headers={
                              'Reply-To': '*****@*****.**',
                          })

    # print to console or send mail
    if 'true' in request.registry.settings['testing.mail_to_console']:
        print(message.body.encode('utf-8'))  # pragma: no cover
    else:
        send_message(request, message)

    # now choose where to redirect
    if 'detail' in request.referrer:
        return HTTPFound(
            request.route_url('detail', memberid=member.id) + '#dues17')
    if 'toolbox' in request.referrer:
        return HTTPFound(request.route_url('toolbox'))
    else:
        return get_memberhip_listing_redirect(request, member.id)
Exemple #9
0
def shares_edit(request):
    '''
    Edit details of a package of shares.
    '''
    # load info from DB -- if possible
    share = request.registry.share_information.get(request.matchdict['id'])

    if isinstance(share, NoneType):
        # entry was not found in database
        return get_memberhip_listing_redirect(request)
    else:
        appstruct = {}
        appstruct = {
            'number': share.number,
            'date_of_acquisition': share.date_of_acquisition,
        }

    # construct a form
    class SharesSchema(colander.Schema):
        """
        Defines the colander schema for shares.
        """
        number = colander.SchemaNode(
            colander.Integer(),
            title=_('Number of Shares'),
        )
        date_of_acquisition = colander.SchemaNode(
            colander.Date(),
            title=_('Date of Acquisition')
        )
    schema = SharesSchema()
    form = deform.Form(
        schema,
        buttons=[deform.Button('submit', _(u'Submit'))],
    )
    # form generation complete

    # if the form has been used and SUBMITTED, check contents
    if 'submit' in request.POST:
        controls = request.POST.items()
        try:
            appstruct = form.validate(controls)

        except ValidationFailure, validation_failure:  # pragma: no cover
            request.session.flash(
                _(u'Please note: There were errors, '
                  'please check the form below.'),
                'danger',
                allow_duplicate=False)
            return{'form': validation_failure.render()}

        # if no error occurred, persist the changed values info in database

        test1 = (  # changed value through form (different from db)?
            appstruct['number'] == share.number)
        if not test1:
            LOG.info(
                'info about number of shares of %s changed by %s to %s',
                share.id,
                request.user.login,
                appstruct['number'])
            share.number = appstruct['number']
        test2 = (  # changed value through form (different from db)?
            appstruct['date_of_acquisition'] == share.date_of_acquisition)
        if not test2:
            LOG.info(
                'info about date_of_acquisition of %s changed by %s to %s',
                share.id,
                request.user.login,
                appstruct['date_of_acquisition'])
            share.date_of_acquisition = appstruct['date_of_acquisition']