Exemple #1
0
def confirm(request, aktivitet_id, aktivitet_date_id):
    if request.method != 'POST':
        return redirect('aktiviteter:signup_participants', aktivitet_id,
                        aktivitet_date_id)

    try:
        aktivitet_date = AktivitetDate.objects.select_related(
            *default_select_related,
        ).prefetch_related(
            *default_prefetch_related,
        ).get(id=aktivitet_date_id)

        for validation_func in [require_accepts_signups, require_stripe_account]:
            response = validation_func(request, aktivitet_date)
            if response is not None:
                return response
    except AktivitetDate.DoesNotExist:
        raise Http404

    signup_session = SignupSession(request, aktivitet_date)
    if not signup_session.is_valid():
        return redirect('aktiviteter:signup_participants',
                        aktivitet_date.aktivitet.id, aktivitet_date.id)

    # Create participant group
    participant_group = ParticipantGroup.objects.create(
        aktivitet_date=aktivitet_date,
        signee=request.user if not request.user.is_anonymous else None,
        comment=signup_session.comment,
        extras=signup_session.extras,
        participate_together=signup_session.get_participate_together(),
    )

    # Signup questions
    questions = aktivitet_date.aktivitet.get_signup_questions()

    # Create participants, and add them to the participant group
    for participant in signup_session.participating_participants:
        db_participant = Participant(
            participant_group=participant_group,
            user=participant.user,
            first_name=participant.first_name,
            last_name=participant.last_name,
            email=participant.chosen_email,
            phone_mobile=participant.chosen_phone,
            birth_date=participant.birth_date,
            price=None,
            discount_code=participant.discount_code,
            state=participant.state,
            extras=participant.extras,
        )
        db_participant.save()

        # If participant is related to a user (of any kind) and the user does
        # not have a birth_date, update user with participant birth_date
        if participant.user and not participant.user.get_birth_date():
            participant.user.set_contact_info({'birth_date': participant.birth_date})

        # Save answers
        for question in questions:
            answer = participant.get_answer_for_question(question.id)
            if answer:
                if question.field_type == 'select_multiple':
                    answer = "\r\n".join(answer)
                SignupAnswer.objects.create(
                    aktivitet_date=aktivitet_date,
                    question=question,
                    answer=answer,
                    participant=db_participant,
                )

    if aktivitet_date.payment_enabled:
        # Store the current price and payment method for all signed-up users
        for participant in participant_group.participants.all():
            price = participant.calculate_price()
            participant.price = price['price']
            participant.discount_amount = price['discount']

            if participant.price == 0:
                # If there is no fee, set the payment method to free
                participant.payment_method = 'free'
            else:
                # Otherwise, set the payment method to online, but only for the participants who are paying now - leave
                # payment method for waitinglist participants undefined
                if participant.state == 'signed_up':
                    participant.payment_method = 'online'

            participant.save()

    # If payment is actually due (ie. payment is enabled AND total price is > 0), handle Stripe online payment
    if signup_session.payment_due():
        if not 'stripe_token' in request.POST:
            raise ValidationError

        token = request.POST['stripe_token']

        # Description of the Stripe charge
        description = 'Deltakeravgift for "%s" (%s kl %s)' % (
            aktivitet_date.aktivitet.title,
            aktivitet_date.start_date,
            aktivitet_date.start_time,
        )

        # Extra data attached to the Stripe charge
        metadata = {
            'Aktivitet': aktivitet_date.aktivitet.title,
            'Aktivitet Dato': 'Fra %s kl %s, til %s kl %s' % (
                aktivitet_date.start_date,
                aktivitet_date.start_time,
                aktivitet_date.end_date,
                aktivitet_date.end_time,
            ),
            'Aktivitet ID': aktivitet_date.aktivitet.id,
            'Aktivitet Dato ID': aktivitet_date.id,
            'Deltakere': ', '.join([
                '%s' % p.full_name
                 for p in participant_group.participants.all()
            ]),
        }

        forening = aktivitet_date.aktivitet.get_forening_or_cabin_owner()
        stripe_account = forening.payment_auth()['stripe_user_id']

        with transaction.atomic():
            try:
                # Create and execute the Stripe charge
                charge = Charge.new_charge(
                    stripe_account,
                    request.user if not request.user.is_anonymous else None,
                    token,
                    signup_session.current_price(),
                    description,
                    metadata,
                )
            except Exception:
                # Unexpected and unhandled error during Stripe charge creation.
                # This must be logged for further research (as opposed to
                # expected card charge errors).
                errmsg = (
                    "Feil ved oppretting av Stripe charge ved "
                    "aktivitetspåmelding"
                )
                logger.error(
                    errmsg,
                    exc_info=sys.exc_info(),
                    extra={
                        'request': request,
                        'aktivitet_date': aktivitet_date,
                        'participant_group': participant_group,
                    }
                )

                # Discard the signup and send the user back to try again.
                request.session['aktivitet.signup.%s.payment_failure' % aktivitet_date.id] = {
                    'error_display': "",
                    'error_message': "Betalingen kunne ikke gjennomføres.",
                }
                participant_group.delete() # cascade deletes related participants and stripe charge
                return redirect('aktiviteter:signup_summary',
                                aktivitet_date.aktivitet.id, aktivitet_date.id)

        if not charge.was_success():
            # Unsuccessful payment. If the problem is of a technical nature (not the user's fault), keep the
            # participants signed up and ask them to pay later. If not, discard the signup and send the user back to try
            # again.
            if charge.error_type == 'card_error':
                request.session['aktivitet.signup.%s.payment_failure' % aktivitet_date.id] = {
                    'error_display': charge.get_error_code_display(),
                    'error_message': charge.error_message,
                }
                participant_group.delete() # cascade deletes related participants and stripe charge
                return redirect('aktiviteter:signup_summary',
                                aktivitet_date.aktivitet.id, aktivitet_date.id)

        # Create the payment-participants relation
        with transaction.atomic():
            payment = ParticipantPayment.objects.create(
                payee=request.user if not request.user.is_anonymous else None,
                stripe_charge=charge,
            )
            payment.participants = participant_group.participants.all()

    # The signup is now complete; delete the session so that it will be reset if user starts a new session
    signup_session.delete()

    participant_group.send_signup_receipts()

    return redirect(
        'aktiviteter:signup_done',
        aktivitet_id=aktivitet_date.aktivitet.id,
        aktivitet_date_id=aktivitet_date.id,
        participant_group_id=participant_group.id,
    )
Exemple #2
0
def renew_membership(request):
    if request.method != 'POST':
        return redirect('user:account')

    if 'stripeToken' not in request.POST:
        return redirect('user:account')

    description = "Fornying av medlemskap"

    if date.today() < membership_year_start()['public_date']:
        applicable_year = membership_year_start()['public_date'].year
    else:
        applicable_year = membership_year_start()['public_date'].year + 1

    metadata = {
        'Periode': 'Medlemsåret %s' % applicable_year,
    }

    if not request.user.has_family():
        # Single member, pay their own invoice
        amount = request.user.payment.status['amount_due']
        metadata['Medlemskap'] = request.user.membership_type()['name']
        metadata['Medlem'] = '%s (medlemsnr: %s)' % (request.user.get_full_name(), request.user.memberid)
        request.user.clear_cache()
    elif request.user.family.relation == 'family':
        # Family membership, pay the invoice of the parent
        amount = request.user.payment.status['amount_due']
        metadata['Medlemskap'] = 'Familiemedlemskap'
        metadata['Familie hovedmedlem'] = '%s (medlemsnr: %s)' % (
            request.user.family.parent.get_full_name(),
            request.user.family.parent.memberid,
        )
        metadata['Alle familiemedlemmer'] = ', '.join([
            '%s (medlemsnr: %s)' % (u.get_full_name(), u.memberid)
            for u in request.user.family.all_members()
        ])
        request.user.family.clear_cache()
    elif request.user.family.relation == 'household':
        # Household membership, each member has their own invoice.
        amount = request.user.family.payment_amount_due()
        metadata['Medlemskap'] = 'Husstandsmedlemskap'
        metadata['Medlemmer'] = ', '.join([
            '%s (medlemsnr: %s, %s, %s)' % (
                u.get_full_name(),
                u.memberid,
                u.membership_type()['name'],
                currency(u.payment.status['amount_due']),
            )
            for u in request.user.family.payment_members()
        ])
        request.user.family.clear_cache()

    charge = Charge.new_charge(
        Forening.get_cached_forening(id=Forening.DNT_CENTRAL_ID).payment_auth()['stripe_user_id'],
        request.user,
        request.POST['stripeToken'],
        amount,
        description,
        metadata,
    )

    try:
        if not charge.was_success():
            # Unsuccessful payment. Store the error message and display it on the account page
            request.session['membership.%s.payment_failure' % request.user.memberid] = {
                'error_display': charge.get_error_code_display(),
                'error_message': charge.error_message,
            }
        else:
            # Payment was succesful; save it to Focus
            if not request.user.has_family() or request.user.family.relation == 'family':
                request.user.payment.save_pending_payment(charge.charge_id, amount)
            else:
                for household_member in request.user.family.payment_members():
                    household_member.payment.save_pending_payment(
                        charge.charge_id,
                        household_member.payment.status['amount_due'],
                    )
    except:
        # Problem during pending payment registration - likely connection issue with Focus.
        # - Since the payment isn't stored in Focus, the user will not get the confirmation, so add an error message
        #   explaining the situation.
        # - Manual followup is required by memberservice, so send email to memberservice with required information
        # - Log an error to be able to trace events, in case it's ever needed
        messages.error(request, 'payment_registration_failure')
        logger.error(
            "Feil ved lagring av medlemskapsfornyelse i Focus",
            exc_info=sys.exc_info(),
            extra={
                'request': request,
                'amount': amount,
                'metadata': metadata,
                'charge': charge,
            },
        )
        try:
            context = {
                'amount': amount,
                'metadata': metadata,
                'charge': charge,
            }
            message = render_to_string('common/focus/payment_registration_failure.txt', context, request=request)
            send_mail(
                "Fornying av medlemskap kunne ikke lagres i Focus",
                message,
                settings.DEFAULT_FROM_EMAIL,
                [settings.MEMBERSERVICE_EMAIL],
            )
        except (SMTPException, SSLError, UnicodeEncodeError):
            # Jesus. Error upon error. Log it, hopefully devs will be able to follow up.
            logger.error(
                "Kunne ikke sende varselsepost til medlemsservice, beskjed må gis manuelt",
                extra={
                    'request': request,
                    'message': message,
                    'amount': amount,
                    'metadata': metadata,
                    'charge': charge,
                },
            )
    finally:
        return redirect('%s#forny-medlemskap' % reverse('user:account'))
Exemple #3
0
def confirm(request, aktivitet_date_id):
    if request.method != "POST":
        return redirect("aktiviteter:signup_participants", aktivitet_date_id)

    try:
        aktivitet_date = (
            AktivitetDate.objects.select_related(*default_select_related)
            .prefetch_related(*default_prefetch_related)
            .get(id=aktivitet_date_id)
        )

        for validation_func in [require_accepts_signups, require_stripe_account]:
            response = validation_func(request, aktivitet_date)
            if response is not None:
                return response
    except AktivitetDate.DoesNotExist:
        raise Http404

    signup_session = SignupSession(request, aktivitet_date)
    if not signup_session.is_valid():
        return redirect("aktiviteter:signup_participants", aktivitet_date.id)

    # Create participant group
    participant_group = ParticipantGroup.objects.create(
        aktivitet_date=aktivitet_date,
        signee=request.user,
        comment=signup_session.comment,
        participate_together=signup_session.get_participate_together(),
    )

    # Create participants, and add them to the participant group
    for participant in signup_session.participating_participants:
        Participant.objects.create(
            participant_group=participant_group,
            user=participant.user,
            price=None,
            discount_code=participant.discount_code,
            use_guardian_contact_info=participant.use_guardian_contact_info,
            state=participant.state,
        )

    if aktivitet_date.payment_enabled:
        # Store the current price and payment method for all signed-up users
        for participant in participant_group.participants.all():
            price = participant.get_price_for_user()
            participant.price = price["price"]
            participant.discount_amount = price["discount"]

            if participant.price == 0:
                # If there is no fee, set the payment method to free
                participant.payment_method = "free"
            else:
                # Otherwise, set the payment method to online, but only for the participants who are paying now - leave
                # payment method for waitinglist participants undefined
                if participant.state == "signed_up":
                    participant.payment_method = "online"

            participant.save()

    # If payment is actually due (ie. payment is enabled AND total price is > 0), handle Stripe online payment
    if signup_session.payment_due():
        if not "stripe_token" in request.POST:
            raise ValidationError

        token = request.POST["stripe_token"]

        # Description of the Stripe charge
        description = 'Deltakeravgift for "%s" (%s kl %s)' % (
            aktivitet_date.aktivitet.title,
            aktivitet_date.start_date,
            aktivitet_date.start_time,
        )

        # Extra data attached to the Stripe charge
        metadata = {
            "Aktivitet": aktivitet_date.aktivitet.title,
            "Aktivitet Dato": "Fra %s kl %s, til %s kl %s"
            % (aktivitet_date.start_date, aktivitet_date.start_time, aktivitet_date.end_date, aktivitet_date.end_time),
            "Aktivitet ID": aktivitet_date.aktivitet.id,
            "Aktivitet Dato ID": aktivitet_date.id,
            "Deltakere": ", ".join(
                ["%s (%s)" % (p.user.get_full_name(), p.user.id) for p in participant_group.participants.all()]
            ),
        }

        forening = aktivitet_date.aktivitet.get_forening_or_cabin_owner()
        stripe_account = forening.payment_auth()["stripe_user_id"]

        with transaction.atomic():
            # Create and execute the Stripe charge
            charge = Charge.new_charge(
                stripe_account, request.user, token, signup_session.current_price(), description, metadata
            )

        if not charge.was_success():
            # Unsuccessful payment. If the problem is of a technical nature (not the user's fault), keep the
            # participants signed up and ask them to pay later. If not, discard the signup and send the user back to try
            # again.
            if charge.error_type == "card_error":
                request.session["aktivitet.signup.%s.payment_failure" % aktivitet_date.id] = {
                    "error_display": charge.get_error_code_display(),
                    "error_message": charge.error_message,
                }
                participant_group.delete()  # cascade deletes related participants and stripe charge
                return redirect("aktiviteter:signup_summary", aktivitet_date.id)

        # Create the payment-participants relation
        with transaction.atomic():
            payment = ParticipantPayment.objects.create(payee=request.user, stripe_charge=charge)
            payment.participants = participant_group.participants.all()

    # The signup is now complete; delete the session so that it will be reset if user starts a new session
    signup_session.delete()

    participant_group.send_signup_receipts()
    return redirect("user:aktiviteter_show", participant_group.id)