예제 #1
0
def payment_method(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment:registration")

    enrolling_through_aktivitet = 'innmelding.aktivitet' in request.session

    # Check conditions needed to enable invoice payment
    invoice_available = all([
        # Invoice payment can be disabled by admin
        Settings.get_cached().enrollment_accept_invoice,

        # If enrolling through aktivitet, you need to pay with card so that the
        # membership is confirmed
        not enrolling_through_aktivitet,

        # Foreign members must pay with card
        enrollment.get_country().code == 'NO',
    ])

    context = {
        'enrollment': enrollment,
        'enrolling_through_aktivitet': enrolling_through_aktivitet,
        'invoice_available': invoice_available,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/payment.html', context)
예제 #2
0
def process_invoice(request):
    if 'enrollment' not in request.session:
        return redirect('enrollment:registration')
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'registration':
        # Whoops, how did we get here without going through payment first? Redirect back.
        return redirect('enrollment:payment_method')
    elif enrollment.state == 'payment':
        # Cool, this is where we want to be.
        pass
    elif enrollment.state == 'complete':
        # Registration has already been completed, redirect forwards to results page
        return redirect('enrollment:result')

    for user in enrollment.users.all():
        user.pending_user = User.create_pending_user(user.memberid)
        user.save()
        librato.increment('sherpa.medlemmer.innmeldinger')

    if enrollment.relation_type == 'family':
        librato.increment('sherpa.familiemedlemskap.innmelding.faktura_valgt')

    prepare_and_send_email(request, enrollment)
    enrollment.save_prices()
    enrollment.state = 'complete'
    enrollment.result = 'success_invoice'
    enrollment.save()
    return redirect('enrollment:result')
예제 #3
0
def result(request):
    if 'enrollment' not in request.session:
        return redirect('enrollment:registration')
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'registration' and enrollment.result not in ['cancel', 'fail']:
        # Whoops, how did we get here without going through payment first? Redirect back.
        return redirect('enrollment:payment_method')
    elif enrollment.state == 'payment':
        # Not done with payments, why is the user here? Redirect back to payment processing
        if enrollment.payment_method == 'invoice':
            return redirect('enrollment:process_invoice')
        elif enrollment.payment_method == 'card':
            return redirect("%s?merchantId=%s&transactionId=%s" % (
                settings.NETS_TERMINAL_URL,
                settings.NETS_MERCHANT_ID,
                enrollment.transactions.get(state='register', active=True).transaction_id,
            ))

    # Collect emails to a separate list for easier template formatting
    emails = [user.email for user in enrollment.users.all() if user.email != '']

    skip_header = enrollment.result == 'success_invoice' or enrollment.result == 'success_card'
    proof_validity_end = datetime.now() + timedelta(days=settings.MEMBERSHIP['TEMPORARY_PROOF_VALIDITY'])
    context = {
        'enrollment': enrollment,
        'skip_header': skip_header,
        'proof_validity_end': proof_validity_end,
        'emails': emails,
        'innmelding_aktivitet': request.session.get('innmelding.aktivitet'),
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/result/%s.html' % enrollment.result, context)
예제 #4
0
        def wrapped_view(request, *args, **kwargs):
            try:
                enrollment = get_or_create_enrollment(request)
                enrollment.validate(require_location, require_existing, require_main_member, require_relation_type)
                return view_func(request, *args, **kwargs)
            except NoUsers:
                return redirect("enrollment:registration")
            except ContactInfoMissing:
                messages.error(request, 'contact_missing')
                return redirect("enrollment:registration")
            except InvalidUser as e:
                messages.error(request, 'user_invalid')
                return redirect("enrollment:registration", e.user.id)
            except UserRequiresConfirmationInfo as e:
                messages.error(request, 'user_requires_confirmation_info')
                return redirect("enrollment:registration", e.user.id)
            except InvalidLocation:
                return redirect("%s?%s" % (reverse("enrollment:household"), invalid_location))
            except InvalidExisting:
                return redirect("%s?%s" % (reverse("enrollment:household"), invalid_existing))
            except MissingRelationType:
                messages.error(request, 'missing_relation_type')
                return redirect("enrollment:verification")
            except NotEligibleForFamilyMembership:
                messages.error(request, 'not_eligible_for_family_membership')
                return redirect("enrollment:verification")
            except MainMemberNotChosen:
                messages.error(request, 'no_main_member')
                return redirect("enrollment:verification")

            return view_func(request, *args, **kwargs)
예제 #5
0
def remove(request, user):
    enrollment = get_or_create_enrollment(request)

    try:
        enrollment.users.get(id=user).delete()
    except EnrollmentUser.DoesNotExist:
        # Ignore it and redirect the user back. Maybe they tried to URL-hack or something.
        pass

    return redirect("enrollment:registration")
예제 #6
0
파일: views.py 프로젝트: simensma/sherpa
def payment_method(request):
    enrollment = get_or_create_enrollment(request)

    validation = validate(enrollment, require_location=True, require_existing=True)
    if not validation['valid']:
        if 'message' in validation:
            messages.error(request, validation['message'])
        return redirect(*validation['redirect'])

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment.views.registration")

    enrollment.users.all().update(chosen_main_member=False)
    if 'main-member' in request.POST and request.POST['main-member'] != '':
        user = enrollment.users.get(id=request.POST['main-member'])

        if not user.can_be_main_member():
            messages.error(request, 'invalid_main_member')
            return redirect('enrollment.views.verification')

        user.chosen_main_member = True
        user.save()
    else:
        # No choice made, in this situation, there should be an existing member specified,
        # only one available main member, or none at all.
        if enrollment.existing_memberid == '':
            main_members = [user for user in enrollment.users.all() if user.can_be_main_member()]
            if len(main_members) == 1:
                main_members[0].chosen_main_member = True
                main_members[0].save()
            elif len(main_members) > 1:
                logger.warning(u"More than one available main members and no choice made. Fix the UI",
                    extra={
                        'request': request,
                        'main_members': main_members,
                        'enrollment': enrollment,
                    }
                )
                messages.error(request, 'no_main_member')
                return redirect('enrollment.views.verification')

    context = {
        'card_available': State.objects.all()[0].card,
        'card_required': 'innmelding.aktivitet' in request.session,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/payment.html', context)
예제 #7
0
def sms(request):
    if not request.is_ajax():
        return redirect('enrollment:result')

    if 'enrollment' not in request.session:
        raise PermissionDenied

    enrollment = get_or_create_enrollment(request)

    # The user might have reset the enrollment state in another tab; verify that it's still complete
    if enrollment.state != 'complete':
        return HttpResponse(json.dumps({'error': 'enrollment_uncompleted'}))

    # Only send receipts to norwegian enrollments
    if enrollment.country != 'NO':
        return HttpResponse(json.dumps({'error': 'foreign_number'}))

    # Retrieve the user
    if request.method == 'GET':
        # This shouldn't happen, but already did happen twice (according to error logs).
        # We're setting type: POST with ajaxSetup in common.js, so I really have no idea why
        # we sometimes receive GET requests, but since it is reoccuring AND I can't recreate
        # it locally, just account for it so the user actually gets their SMS.
        logger.warning(
            "Fikk GET-request på innmeldings-SMS, forventet POST",
            extra={'request': request}
        )
        user_id = int(request.GET['user'])
    else:
        user_id = int(request.POST['user'])

    try:
        user = enrollment.users.get(id=user_id)
    except EnrollmentUser.DoesNotExist:
        # Likely a forged POST request to send SMS to an invalid user by nosy/curious users
        return HttpResponse(json.dumps({'error': 'invalid_user'}))

    # One SMS per user
    if user.sms_sent:
        return HttpResponse(json.dumps({'error': 'already_sent'}))

    # Render and send the SMS template
    try:
        context = {
            'users': enrollment.get_users_by_name(),
        }
        sms_message = render_to_string('central/enrollment/result/sms.txt', context, request=request)
        send_sms(user.phone, sms_message, logging_extra={'request': request, 'enrollment': enrollment})
        user.sms_sent = True
        user.save()
        return HttpResponse(json.dumps({'error': 'none'}))
    except SMSGatewayDeliveryError:
        return HttpResponse(json.dumps({'error': 'service_fail'}))
예제 #8
0
def payment_method(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment:registration")

    enrolling_through_aktivitet = 'innmelding.aktivitet' in request.session
    invoice_available = Settings.get_cached().enrollment_accept_invoice and not enrolling_through_aktivitet

    context = {
        'settings': Settings.get_cached(),
        'enrolling_through_aktivitet': enrolling_through_aktivitet,
        'invoice_available': invoice_available,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/payment.html', context)
예제 #9
0
def process_card(request):
    if 'enrollment' not in request.session:
        return redirect('enrollment:registration')
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'registration':
        # Whoops, how did we get here without going through payment first? Redirect back.
        # Note, *this* makes it impossible to use a previously verified transaction id
        # on a *second* registration by skipping the payment view and going straight to this check.
        return redirect('enrollment:payment_method')
    elif enrollment.state == 'payment':
        # Cool, this is where we want to be.
        pass
    elif enrollment.state == 'complete':
        # Registration has already been completed, redirect forwards to results page
        return redirect('enrollment:result')

    # The client's transaction id CAN differ from the one we think is active. Let them override it,
    # given that the transaction id is already registered. Note that the transaction id from the
    # GET parameter is obviously untrusted input.
    try:
        enrollment.transactions.update(active=False)
        active_transaction = enrollment.transactions.get(transaction_id=request.GET['transactionId'])
        active_transaction.active = True
        active_transaction.save()
    except Transaction.DoesNotExist:
        # They returned with a transaction id which we haven't registered on them - cannot see this happen
        # without them tampering with the GET parameter, we'll have to send them back with an error message.
        messages.error(request, 'invalid_transaction_id')
        enrollment.state = 'payment'
        enrollment.save()
        return redirect('enrollment:payment_method')

    if request.GET.get('responseCode') == 'OK':
        try:
            librato.increment('sherpa.requests.nets.process')
            r = requests.get(settings.NETS_PROCESS_URL, params={
                'merchantId': settings.NETS_MERCHANT_ID,
                'token': settings.NETS_TOKEN,
                'operation': 'SALE',
                'transactionId': active_transaction.transaction_id
            })
            response = r.text.encode('utf-8')

            dom = ET.fromstring(response)
            response_code = dom.find(".//ResponseCode")
            response_text = dom.find(".//ResponseText")
            payment_verified = False

            tx_already_processed_explicit = response_code.text == '98'
            tx_already_processed_general = (
                response_code.text == '99'
                and response_text is not None
                and response_text.text == 'Transaction already processed'
            )

            if response_code is None:
                # Crap, we didn't get the expected response from Nets.
                # This has happened a few times before. We'll have to handle it ourselves.
                logger.error(
                    "Mangler 'ResponseCode' element fra Nets",
                    extra={
                        'request': request,
                        'nets_response': response,
                        'enrollment': enrollment,
                        'transaction_id': active_transaction.transaction_id
                    }
                )
                enrollment.state = 'payment'
                enrollment.save()
                context = current_template_layout(request)
                return render(request, 'central/enrollment/payment-process-error.html', context)
            elif tx_already_processed_explicit or tx_already_processed_general:
                # The transaction might have already been processed if the user resends the process_card
                # request - recheck nets with a Query request and verify those details
                sale_response = response
                librato.increment('sherpa.requests.nets.query')
                r = requests.get(settings.NETS_QUERY_URL, params={
                    'merchantId': settings.NETS_MERCHANT_ID,
                    'token': settings.NETS_TOKEN,
                    'transactionId': active_transaction.transaction_id
                })
                response = r.text.encode('utf-8')
                dom = ET.fromstring(response)
                order_amount = int(dom.find(".//OrderInformation/Amount").text)
                captured_amount = int(dom.find(".//Summary/AmountCaptured").text)
                credited_amount = int(dom.find(".//Summary/AmountCredited").text)

                if order_amount == (captured_amount - credited_amount) == enrollment.total_price() * 100:
                    payment_verified = True
                else:
                    logger.warning(
                        "Nets: Prosessert transaksjon matcher ikke forventet beløp",
                        extra={
                            'request': request,
                            'enrollment': enrollment,
                            'nets_sale_response': sale_response,
                            'nets_query_response': response,
                            'transaction_id': active_transaction.transaction_id,
                            'payment_verified': payment_verified,
                            'order_amount': order_amount,
                            'captured_amount': captured_amount,
                            'credited_amount': credited_amount,
                            'total_price_100': enrollment.total_price() * 100
                        }
                    )

            elif response_code.text == 'OK':
                payment_verified = True

            if payment_verified:
                # Mark the transaction as successful
                active_transaction.state = 'success'
                active_transaction.save()

                # Register the payment in focus
                for user in enrollment.users.all():
                    focus_user = FocusEnrollment.objects.get(memberid=user.memberid)
                    focus_user.paid = True
                    focus_user.save()
                    user.pending_user = User.create_pending_user(user.memberid)
                    user.save()
                    librato.increment('sherpa.medlemmer.innmeldinger')

                if enrollment.relation_type == 'family':
                    librato.increment('sherpa.familiemedlemskap.innmelding.kort_betalt')

                prepare_and_send_email(request, enrollment)
                enrollment.save_prices()
                enrollment.state = 'complete'
                enrollment.result = 'success_card'
                enrollment.save()
            else:
                active_transaction.state = 'fail'
                active_transaction.save()

                enrollment.state = 'registration'
                enrollment.result = 'fail'
                enrollment.save()
        except requests.ConnectionError:
            logger.warning(
                "Nets `process` feil",
                exc_info=sys.exc_info(),
                extra={'request': request}
            )
            enrollment.state = 'payment'
            enrollment.save()
            context = current_template_layout(request)
            return render(request, 'central/enrollment/payment-process-error.html', context)

    else:
        active_transaction.state = 'cancel'
        active_transaction.save()

        enrollment.state = 'registration'
        enrollment.result = 'cancel'
        enrollment.save()
    return redirect('enrollment:result')
예제 #10
0
def registration(request, user):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back to the registration page - why?
        # Maybe it failed, and they want to retry registration?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, but a new one has been initiated.
        # Remove the old one and start over.
        del request.session['enrollment']
        enrollment = get_or_create_enrollment(request)

    if request.method == 'GET':
        if user is not None:
            try:
                user = enrollment.users.all().get(id=user)
            except EnrollmentUser.DoesNotExist:
                return redirect('enrollment:registration')

        # Display the registration form for the first registration, and when editing a user; hide otherwise
        show_registration_form = len(enrollment.users.all()) == 0 or user is not None

        context = {
            'enrollment': enrollment,
            'current_user': user,
            'show_registration_form': show_registration_form,
            'confirmation_age_min': min(settings.MEMBERSHIP['FAMILY']['YOUTH_CONFIRMATION_AGE_RANGE']),
            'confirmation_age_max': max(settings.MEMBERSHIP['FAMILY']['YOUTH_CONFIRMATION_AGE_RANGE']),
            'phone_required': json.dumps(len(enrollment.users.all()) == 0),
            'email_required': json.dumps(True),
        }
        context.update(current_template_layout(request))
        return render(request, 'central/enrollment/registration.html', context)

    elif request.method == 'POST':
        # We want to check provided user details if:
        # - The user has explicitly clicked the save button
        # - They're not editing a user, but added a new member and clicked continue
        # - They're editing an existing user and clicked continue
        just_save = request.POST['button'] == 'save'
        continue_ = request.POST['button'] == 'continue'
        editing_user = '******' in request.POST
        name_defined = len(request.POST['name'].strip()) > 0
        save_and_continue = continue_ and (name_defined or editing_user)

        # Save terms & conditions accepted
        enrollment.accepts_conditions = request.POST.get('conditions') == 'on'
        enrollment.save()

        # Save partneroffers optin
        enrollment.partneroffers_optin = 'partneroffers_optin' in request.POST
        enrollment.save()

        if just_save or save_and_continue:
            if editing_user:
                try:
                    user = enrollment.users.all().get(id=request.POST['user'])
                except EnrollmentUser.DoesNotExist:
                    # They're trying to save a non-existing user - maybe they deleted it in another tab? Just create a
                    # new user
                    user = EnrollmentUser(enrollment=enrollment)
            else:
                user = EnrollmentUser(enrollment=enrollment)

            # Titleize name and strip whitespace before/after dash
            user.name = re.sub('\s*-\s*', '-', polite_title(request.POST['name'].strip()))
            user.phone = request.POST['phone'].strip()
            user.email = request.POST['email'].lower().strip()
            user.gender = request.POST.get('gender', '')
            try:
                user.dob = datetime.strptime(request.POST['dob'], "%d.%m.%Y").date()
            except ValueError:
                user.dob = None
            user.save()

            if not user.is_valid():
                messages.error(request, 'user_invalid')
                return redirect('enrollment:registration', user.id)
            elif user.requires_family_membership_confirmation() and not user.has_confirmation_info():
                messages.error(request, 'user_requires_confirmation_info')
                return redirect('enrollment:registration', user.id)
            else:
                enrollment.users.add(user)
                # The user was saved successfully, so clear the form for the next user
                user = None

        if continue_:
            return redirect("enrollment:household")
        else:
            return redirect('enrollment:registration')
    else:
        raise PermissionDenied
예제 #11
0
def payment(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'registration':
        # All right, enter payment state
        enrollment.state = 'payment'
        enrollment.save()
    elif enrollment.state == 'payment':
        # Already in payment state, redirect them forwards to processing
        if enrollment.payment_method == 'invoice':
            return redirect('enrollment:process_invoice')
        elif enrollment.payment_method == 'card':
            # Let's check for an existing transaction first
            try:
                active_transaction = enrollment.transactions.get(state='register', active=True)
                # Yeah, it's there. Skip payment and redirect forwards to processing
                return redirect("%s?merchantId=%s&transactionId=%s" % (
                    settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, active_transaction.transaction_id
                ))
            except Transaction.DoesNotExist:
                # No active transactions - maybe a problem occured during payment.
                # Assume payment failed and just redo it - if something failed, we'll know
                # through logs and hopefully discover any double-payments
                pass
    elif enrollment.state == 'complete':
        # Registration has already been completed, redirect forwards to results page
        return redirect('enrollment:result')

    enrollment.payment_method = request.POST.get('payment_method', '')

    # Validate chosen payment method
    if enrollment.payment_method not in ['card', 'invoice']:
        messages.error(request, 'invalid_payment_method')
        return redirect('enrollment:payment_method')

    # Ensure card payment is accepted if chosen
    if enrollment.payment_method == 'card' and not Settings.get_cached().enrollment_accept_card:
        messages.error(request, 'invalid_payment_method')
        return redirect('enrollment:payment_method')

    # Ensure invoice is accepted if chosen
    if enrollment.payment_method == 'invoice' and not Settings.get_cached().enrollment_accept_invoice:
        messages.error(request, 'invalid_payment_method')
        return redirect('enrollment:payment_method')

    # Ensure user is not enrolling through aktivitet if invoice is chosen
    if enrollment.payment_method == 'invoice' and 'innmelding.aktivitet' in request.session:
        messages.error(request, 'invalid_payment_method')
        return redirect('enrollment:payment_method')

    # Ok, we're good to go. Save all users to Focus
    enrollment.save()
    enrollment.save_users_to_focus()

    # If we're paying by invoice, skip ahead to invoice processing
    if enrollment.payment_method == 'invoice':
        return redirect('enrollment:process_invoice')

    # Paying with card, move on.
    order_number = Transaction.generate_order_number()

    # Choose a user as the Nets customer; preferably the main member
    try:
        nets_customer = enrollment.get_chosen_main_member()
    except EnrollmentUser.DoesNotExist:
        # There's no main member, so they're either all children or related to an existing member. We still need a
        # 'main' user though, for the customer data. Try to find the oldest one that *has* contact information.
        nets_customer = enrollment.users.exclude(email='').order_by('dob')[0]
    first_name, last_name = nets_customer.name.rsplit(maxsplit=1)

    description = render_to_string('central/enrollment/payment-terminal.html', request=request)

    # Send the transaction registration to Nets
    try:
        librato.increment('sherpa.requests.nets.register')
        r = requests.get(settings.NETS_REGISTER_URL, params={
            'merchantId': settings.NETS_MERCHANT_ID,
            'token': settings.NETS_TOKEN,
            'orderNumber': order_number,
            'customerFirstName': first_name,
            'customerLastName': last_name,
            'customerEmail': nets_customer.email,
            'currencyCode': 'NOK',
            'amount': enrollment.total_price() * 100,
            'orderDescription': description,
            'redirectUrl': "http://%s%s" % (request.site.domain, reverse("enrollment:process_card"))
        })

        # Sweet, almost done, now just send the user to complete the transaction
        # Consider handling errors here (unexpected XML response or connection error)
        # We recieved a random "Unable to create setup string" message once, ignoring it for now
        response = r.text.encode('utf-8')
        enrollment.transactions.update(active=False)
        transaction = Transaction(
            enrollment=enrollment,
            transaction_id=ET.fromstring(response).find("TransactionId").text,
            order_number=order_number,
            state='register',
            active=True,
        )
        transaction.save()
    except Exception as e:
        # Handle any exception that might occur (requests.ConnectionError, invalid response from Nets, etc.)
        logger.warning(
            "Nets `register` feil",
            exc_info=sys.exc_info(),
            extra={'request': request}
        )
        messages.error(request, 'nets_register_connection_error')
        return redirect('enrollment:payment_method')

    return redirect("%s?merchantId=%s&transactionId=%s" % (
        settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, transaction.transaction_id
    ))
예제 #12
0
def set_main_member(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment:registration")

    if request.method != 'POST':
        return redirect("enrollment:verification")

    # Assign the chosen relation type; default to 'household'
    relation_type = request.POST.get('relation-type', 'household')
    if relation_type not in ['family', 'household']:
        raise Exception("Invalid membership relation type '%s' POSTed" % relation_type)
    if relation_type == 'family' and not enrollment.eligible_for_family_membership():
        logger.warning(
            "Enrolling member was able to choose family membership even though not eligible",
            extra={
                'request': request,
                'enrollment': enrollment,
            }
        )
        messages.error(request, 'not_eligible_for_family_membership')
        return redirect('enrollment:verification')
    if relation_type == 'family' and not enrollment.forening.offers_family_membership:
        logger.warning(
            "Enrolling member was able to choose family membership even though their forening doesn't offer it",
            extra={
                'request': request,
                'enrollment': enrollment,
            }
        )
        return redirect('enrollment:verification')
    enrollment.relation_type = relation_type
    enrollment.save()

    # Assign the chosen main member
    enrollment.users.all().update(chosen_main_member=False)
    if request.POST.get('main', '') != '':
        user = enrollment.users.get(id=request.POST['main'])

        if not user.can_be_main_member():
            messages.error(request, 'invalid_main_member')
            return redirect('enrollment:verification')

        user.chosen_main_member = True
        user.save()
    else:
        # No choice for main member was made, which might be OK; check
        if enrollment.existing_memberid != '':
            # There's a relation to an existing member; all right, carry on
            pass
        elif not enrollment.has_potential_main_member():
            # There are only children in this enrollment, no one can be a main member; all right, carry on
            pass
        elif not enrollment.has_multiple_potential_main_members():
            # Okay, there's only one potential main member. We did expect their ID to be POSTed by a hidden input,
            # but no worries; we can deduce who it should be in hindsight. Delegate the logic to the model.
            enrollment.set_single_main_member()
        else:
            # No existing member AND there are multiple potential main members: This shouldn't have happened, might be
            # a UI bug
            logger.warning(
                "More than one available main members and no choice made. Fix the UI",
                extra={
                    'request': request,
                    'enrollment': enrollment,
                }
            )
            messages.error(request, 'no_main_member')
            return redirect('enrollment:verification')

    if enrollment.relation_type == 'family':
        librato.increment('sherpa.familiemedlemskap.innmelding.startet')

    # Successfully set main member; redirect forwards
    return redirect('enrollment:payment_method')
예제 #13
0
def household(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment:registration")

    errors = invalid_location in request.GET
    if request.method == 'POST':
        enrollment.country = request.POST['country']
        enrollment.address1 = polite_title(request.POST['address1'])
        enrollment.address2 = polite_title(request.POST['address2'])
        enrollment.address3 = polite_title(request.POST['address3'])
        enrollment.zipcode = request.POST['zipcode']
        enrollment.area = request.POST.get('area', '')
        enrollment.existing_memberid = request.POST.get('existing', '')[:50]
        enrollment.wants_yearbook = enrollment.country != 'NO' and 'yearbook' in request.POST
        enrollment.attempted_yearbook = False
        if enrollment.wants_yearbook:
            if enrollment.existing_memberid != '' or not enrollment.has_potential_main_member():
                enrollment.wants_yearbook = False
                enrollment.attempted_yearbook = True
        enrollment.save()

        if enrollment.validate_location():
            if enrollment.country != 'NO':
                return redirect('enrollment:verification')
            else:
                try:
                    focus_zipcode = FocusZipcode.objects.get(zipcode=enrollment.zipcode)
                    Forening.objects.get(focus_id=focus_zipcode.main_forening_id) # Verify that the Forening exists
                    return redirect('enrollment:verification')
                except FocusZipcode.DoesNotExist:
                    # We know that this zipcode exists in Zipcode, because validate_location validated, and it checks
                    # for that
                    logger.warning(
                        "Postnummer finnes i Zipcode, men ikke i Focus!",
                        exc_info=sys.exc_info(),
                        extra={
                            'request': request,
                            'postnummer': enrollment.zipcode
                        }
                    )
                    messages.error(request, 'focus_zipcode_missing')
                except Forening.DoesNotExist:
                    logger.warning(
                        "Focus-postnummer mangler foreningstilknytning!",
                        exc_info=sys.exc_info(),
                        extra={'request': request}
                    )
                    messages.error(request, 'focus_zipcode_missing')
        else:
            errors = True

    context = {
        'enrollment': enrollment,
        'invalid_existing': invalid_existing in request.GET,
        'countries': FocusCountry.get_sorted(),
        'foreign_shipment_price': FOREIGN_SHIPMENT_PRICE,
        'errors': errors,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/household.html', context)
예제 #14
0
파일: views.py 프로젝트: simensma/sherpa
def sms(request):
    if not request.is_ajax():
        return redirect('enrollment.views.result')

    if not 'enrollment' in request.session:
        raise PermissionDenied

    enrollment = get_or_create_enrollment(request)

    if request.method == 'GET':
        # This shouldn't happen, but already did happen twice (according to error logs).
        # We're setting type: POST with ajaxSetup in common.js, so I really have no idea why
        # we sometimes receive GET requests, but since it is reoccuring AND I can't recreate
        # it locally, just account for it so the user actually gets their SMS.
        logger.warning(u"Fikk GET-request på innmeldings-SMS, forventet POST",
            extra={'request': request}
        )
        user = int(request.GET['user'])
    else:
        user = int(request.POST['user'])

    user = enrollment.users.get(id=user)

    # Verify that this is a valid SMS request
    if enrollment.state != 'complete':
        return HttpResponse(json.dumps({'error': 'enrollment_uncompleted'}))
    if enrollment.country != 'NO':
        return HttpResponse(json.dumps({'error': 'foreign_number'}))
    if user.sms_sent:
        return HttpResponse(json.dumps({'error': 'already_sent'}))

    # Render the SMS template
    context = RequestContext(request, {
        'users': enrollment.get_users_by_name()
    })
    sms_message = render_to_string('central/enrollment/result/sms.txt', context).encode('utf-8')

    # Send the message
    try:
        r = requests.get(settings.SMS_URL % (quote_plus(user.phone), quote_plus(sms_message)))
        if r.text.find("1 SMS messages added to queue") == -1:
            logger.error(u"Klarte ikke sende SMS-kvittering for innmelding: Ukjent status",
                extra={
                    'request': request,
                    'enrollment': enrollment,
                    'response_text': r.text,
                    'sms_request_object': r
                }
            )
            return HttpResponse(json.dumps({'error': 'service_fail'}))
        user.sms_sent = True
        user.save()
        return HttpResponse(json.dumps({'error': 'none'}))
    except requests.ConnectionError:
        logger.error(u"Klarte ikke sende SMS-kvittering for innmelding: requests.ConnectionError",
            exc_info=sys.exc_info(),
            extra={
                'request': request,
                'enrollment': enrollment,
            }
        )
        return HttpResponse(json.dumps({'error': 'connection_error'}))
예제 #15
0
파일: views.py 프로젝트: simensma/sherpa
def registration(request, user):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back to the registration page - why?
        # Maybe it failed, and they want to retry registration?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, but a new one has been initiated.
        # Remove the old one and start over.
        del request.session['enrollment']
        enrollment = get_or_create_enrollment(request)

    # User set via URL means a GET request to view some user
    if user is not None:
        try:
            user = enrollment.users.all().get(id=user)
        except EnrollmentUser.DoesNotExist:
            return redirect('enrollment.views.registration')

    errors = False
    if request.method == 'POST':

        # We want to check provided user details if:
        # - The user has explicitly clicked the save button
        # - They're not editing a user, but added a new member and clicked continue
        # - They're editing an existing user and clicked continue
        just_save = request.POST['button'] == 'save'
        continue_ = request.POST['button'] == 'continue'
        editing_user = '******' in request.POST
        name_defined = len(request.POST['name'].strip()) > 0
        save_and_continue = continue_ and (name_defined or editing_user)

        if just_save or save_and_continue:
            if editing_user:
                try:
                    user = enrollment.users.all().get(id=request.POST['user'])
                except EnrollmentUser.DoesNotExist:
                    # They're trying to save a non-existing user - maybe they deleted it in
                    # another tab or something - just create a new one
                    user = EnrollmentUser(enrollment=enrollment)
            else:
                user = EnrollmentUser(enrollment=enrollment)

            try:
                dob = datetime.strptime(request.POST['dob'], "%d.%m.%Y").date()
            except ValueError:
                dob = None

            # Titleize and strip whitespace before/after dash
            user.name = re.sub('\s*-\s*', '-', polite_title(request.POST['name'].strip()))
            user.phone = request.POST['phone'].strip()
            user.email = request.POST['email'].lower().strip()
            user.gender = request.POST.get('gender', '')
            user.key = request.POST.get('key') == 'on'
            user.dob = dob
            user.save()

            if user.is_valid():
                enrollment.users.add(user)
                # The user was saved successfully, so clear the form for the next user
                user = None
            else:
                messages.error(request, 'user_invalid')
                errors = True

        # Save partneroffers optin
        enrollment.partneroffers_optin = 'partneroffers_optin' in request.POST
        enrollment.save()

        if not errors and request.POST['button'] == 'continue':
            return redirect("enrollment.views.household")

    context = {
        'enrollment': enrollment,
        'current_user': user,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/registration.html', context)
예제 #16
0
파일: views.py 프로젝트: simensma/sherpa
def payment(request):
    enrollment = get_or_create_enrollment(request)

    validation = validate(enrollment, require_location=True, require_existing=True)
    if not validation['valid']:
        if 'message' in validation:
            messages.error(request, validation['message'])
        return redirect(*validation['redirect'])

    # If for some reason the user managed to POST 'card' as payment_method
    if not State.objects.all()[0].card and request.POST.get('payment_method', '') == 'card':
        return redirect('enrollment.views.payment_method')

    # Enrollments through ordering require card payment
    if 'innmelding.aktivitet' in request.session and request.POST.get('payment_method', '') != 'card':
        return redirect('enrollment.views.payment_method')

    if enrollment.state == 'registration':
        # All right, enter payment state
        enrollment.state = 'payment'
        enrollment.save()
    elif enrollment.state == 'payment':
        # Already in payment state, redirect them forwards to processing
        if enrollment.payment_method == 'invoice':
            return redirect('enrollment.views.process_invoice')
        elif enrollment.payment_method == 'card':
            # Let's check for an existing transaction first
            try:
                active_transaction = enrollment.get_active_transaction()
                # Yeah, it's there. Skip payment and redirect forwards to processing
                return redirect("%s?merchantId=%s&transactionId=%s" % (
                    settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, active_transaction.transaction_id
                ))
            except Transaction.DoesNotExist:
                # No active transactions - maybe a problem occured during payment.
                # Assume payment failed and just redo it - if something failed, we'll know
                # through logs and hopefully discover any double-payments
                pass
    elif enrollment.state == 'complete':
        # Registration has already been completed, redirect forwards to results page
        return redirect('enrollment.views.result')

    if request.POST.get('payment_method', '') != 'card' and request.POST.get('payment_method', '') != 'invoice':
        messages.error(request, 'invalid_payment_method')
        return redirect('enrollment.views.payment_method')
    enrollment.payment_method = request.POST['payment_method']
    enrollment.save()

    # Ok, we're good to go. Save all users to Focus
    enrollment.save_users_to_focus()

    # If we're paying by invoice, skip ahead to invoice processing
    if enrollment.payment_method == 'invoice':
        return redirect('enrollment.views.process_invoice')

    # Paying with card, move on.
    order_number = Transaction.generate_order_number()
    main_or_random_member = enrollment.get_main_or_random_member()
    first_name, last_name = main_or_random_member.name.rsplit(' ', 1)

    context = RequestContext(request)
    description = render_to_string('central/enrollment/payment-terminal.html', context)

    # Send the transaction registration to Nets
    try:
        r = requests.get(settings.NETS_REGISTER_URL, params={
            'merchantId': settings.NETS_MERCHANT_ID,
            'token': settings.NETS_TOKEN,
            'orderNumber': order_number,
            'customerFirstName': first_name,
            'customerLastName': last_name,
            'customerEmail': main_or_random_member.email,
            'currencyCode': 'NOK',
            'amount': enrollment.get_total_price() * 100,
            'orderDescription': description,
            'redirectUrl': "http://%s%s" % (request.site.domain, reverse("enrollment.views.process_card"))
        })

        # Sweet, almost done, now just send the user to complete the transaction
        # Consider handling errors here (unexpected XML response or connection error)
        # We recieved a random "Unable to create setup string" message once, ignoring it for now
        response = r.text.encode('utf-8')
        enrollment.transactions.filter(state='register').update(active=False)
        transaction = Transaction(
            enrollment=enrollment,
            transaction_id=etree.fromstring(response).find("TransactionId").text,
            order_number=order_number,
            state='register',
            active=True,
        )
        transaction.save()
    except Exception as e:
        # Handle any exception that might occur (requests.ConnectionError, invalid response from Nets, etc.)
        logger.warning(e.message,
            exc_info=sys.exc_info(),
            extra={'request': request}
        )
        messages.error(request, 'nets_register_connection_error')
        return redirect('enrollment.views.payment_method')

    return redirect("%s?merchantId=%s&transactionId=%s" % (
        settings.NETS_TERMINAL_URL, settings.NETS_MERCHANT_ID, transaction.transaction_id
    ))
예제 #17
0
def verification(request):
    enrollment = get_or_create_enrollment(request)

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment:registration")

    # If existing member is specified, save details and change to that address
    existing_name = ''
    if enrollment.existing_memberid != '':
        user = User.get_or_create_inactive(memberid=enrollment.existing_memberid)
        existing_name = user.get_full_name()
        enrollment.country = user.address.country.code
        if user.address.country.code == 'NO':
            enrollment.address1 = user.address.field1
        elif user.address.country.code in ['DK', 'SE']:
            # Don't change the user-provided address.
            # The user might potentially provide a different address than the existing member, which isn't allowed,
            # but this is preferable to trying to parse the existing address into zipcode, area etc. In order to
            # enforce the same address, the address logic for DK and SE in enrollment.User.save_to_focus would have to
            # be rewritten.
            pass
        else:
            # Uppercase the country code as Focus doesn't use consistent casing
            enrollment.country = user.address.country.code
            enrollment.address1 = user.address.field1
            enrollment.address2 = user.address.field2
            enrollment.address3 = user.address.field3

    # Get the area name for this zipcode
    if enrollment.country == 'NO':
        enrollment.area = Zipcode.get_by_zipcode(zipcode=enrollment.zipcode).area

    # Figure out which forening this member/these members will belong to
    if enrollment.existing_memberid != '':
        # Use main members' forening if applicable
        existing_user = User.get_or_create_inactive(memberid=enrollment.existing_memberid)
        forening = existing_user.main_forening(convert_dnt_oslo_for_youth=False)
    else:
        if enrollment.country == 'NO':
            focus_forening_id = cache.get('focus.zipcode_forening.%s' % enrollment.zipcode)
            if focus_forening_id is None:
                focus_forening_id = FocusZipcode.objects.get(zipcode=enrollment.zipcode).main_forening_id
                cache.set('focus.zipcode_forening.%s' % enrollment.zipcode, focus_forening_id, 60 * 60 * 24 * 7)
            forening = cache.get('forening.focus.%s' % focus_forening_id)
            if forening is None:
                forening = Forening.objects.get(focus_id=focus_forening_id)
                cache.set('forening.focus.%s' % focus_forening_id, forening, 60 * 60 * 24 * 7)
        else:
            # Foreign members are registered with DNT Oslo og Omegn
            forening = cache.get('forening.%s' % Forening.DNT_OSLO_ID)
            if forening is None:
                forening = Forening.objects.get(id=Forening.DNT_OSLO_ID)
                cache.set('forening.%s' % Forening.DNT_OSLO_ID, forening, 60 * 60 * 24 * 7)
    enrollment.forening = forening
    enrollment.save()

    context = {
        'enrollment': enrollment,
        'existing_name': existing_name,
        'age_senior': settings.MEMBERSHIP['AGES']['SENIOR'],
        'age_main': settings.MEMBERSHIP['AGES']['MAIN'],
        'age_youth': settings.MEMBERSHIP['AGES']['YOUTH'],
        'age_school': settings.MEMBERSHIP['AGES']['SCHOOL'],
        'membership_type_names': {
            'family_primary': get_membership_type_by_codename('family_primary')['name'],
            'main': get_membership_type_by_codename('main')['name'],
            'youth': get_membership_type_by_codename('youth')['name'],
            'senior': get_membership_type_by_codename('senior')['name'],
            'child': get_membership_type_by_codename('child')['name'],
            'school': get_membership_type_by_codename('school')['name'],
            'household': get_membership_type_by_codename('household')['name'],
            'family_household': get_membership_type_by_codename('family_household')['name'],
        },
        'foreign_shipment_price': FOREIGN_SHIPMENT_PRICE,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/verification.html', context)
예제 #18
0
파일: views.py 프로젝트: simensma/sherpa
def verification(request):
    enrollment = get_or_create_enrollment(request)

    validation = validate(enrollment, require_location=True, require_existing=True)
    if not validation['valid']:
        if 'message' in validation:
            messages.error(request, validation['message'])
        return redirect(*validation['redirect'])

    if enrollment.state == 'payment':
        # Payment has been initiated but the user goes back here - why?
        # Reset the state and let them reinitiate payment when they're ready.
        enrollment.state = 'registration'
        enrollment.save()
    elif enrollment.state == 'complete':
        # A previous registration has been completed, so why would the user come directly here?
        # Just redirect them back to registration which will restart a new registration.
        return redirect("enrollment.views.registration")

    # If existing member is specified, save details and change to that address
    existing_name = ''
    if enrollment.existing_memberid != '':
        actor = Actor.get_personal_members().get(memberid=enrollment.existing_memberid)
        existing_name = "%s %s" % (actor.first_name, actor.last_name)
        enrollment.country = actor.get_clean_address().country.code
        if actor.get_clean_address().country.code == 'NO':
            enrollment.address1 = actor.get_clean_address().field1
        elif actor.get_clean_address().country.code == 'DK' or actor.get_clean_address().country.code == 'SE':
            # Don't change the user-provided address.
            # The user might potentially provide a different address than the existing
            # member, which isn't allowed, but this is preferable to trying to parse the
            # existing address into zipcode, area etc.
            # In order to enforce the same address, the address logic for DK and SE in
            # add_focus_user would have to be rewritten.
            pass
        else:
            # Uppercase the country code as Focus doesn't use consistent casing
            enrollment.country = actor.get_clean_address().country.code
            enrollment.address1 = actor.get_clean_address().field1
            enrollment.address2 = actor.get_clean_address().field2
            enrollment.address3 = actor.get_clean_address().field3

    # Get the area name for this zipcode
    if enrollment.country == 'NO':
        enrollment.area = Zipcode.objects.get(zipcode=enrollment.zipcode).area

    # Figure out which forening this member/these members will belong to
    if enrollment.existing_memberid != '':
        # Use main members' forening if applicable
        focus_forening_id = Actor.get_personal_members().get(memberid=enrollment.existing_memberid).main_forening_id
        forening = cache.get('forening.focus.%s' % focus_forening_id)
        if forening is None:
            forening = Forening.objects.get(focus_id=focus_forening_id)
            cache.set('forening.focus.%s' % focus_forening_id, forening, 60 * 60 * 24 * 7)
    else:
        if enrollment.country == 'NO':
            focus_forening_id = cache.get('focus.zipcode_forening.%s' % enrollment.zipcode)
            if focus_forening_id is None:
                focus_forening_id = FocusZipcode.objects.get(zipcode=enrollment.zipcode).main_forening_id
                cache.set('focus.zipcode_forening.%s' % enrollment.zipcode, focus_forening_id, 60 * 60 * 24 * 7)
            forening = cache.get('forening.focus.%s' % focus_forening_id)
            if forening is None:
                forening = Forening.objects.get(focus_id=focus_forening_id)
                cache.set('forening.focus.%s' % focus_forening_id, forening, 60 * 60 * 24 * 7)
        else:
            # Foreign members are registered with DNT Oslo og Omegn
            forening = cache.get('forening.%s' % Forening.DNT_OSLO_ID)
            if forening is None:
                forening = Forening.objects.get(id=Forening.DNT_OSLO_ID)
                cache.set('forening.%s' % Forening.DNT_OSLO_ID, forening, 60 * 60 * 24 * 7)
    enrollment.forening = forening
    enrollment.save()

    keycount = 0
    youth_or_older_count = 0
    main = None
    for user in enrollment.users.all():
        if main is None or (user.get_age() < main.get_age() and user.get_age() >= AGE_YOUTH):
            # The cheapest option will be to set the youngest member, 19 or older, as main member
            main = user
        if user.get_age() >= AGE_YOUTH:
            youth_or_older_count += 1
        if user.key:
            keycount += 1
    keyprice = keycount * KEY_PRICE
    multiple_main = youth_or_older_count > 1
    context = {
        'enrollment': enrollment,
        'existing_name': existing_name,
        'keycount': keycount,
        'keyprice': keyprice,
        'multiple_main': multiple_main,
        'main': main,
        'age_senior': AGE_SENIOR,
        'age_main': AGE_MAIN,
        'age_youth': AGE_YOUTH,
        'age_school': AGE_SCHOOL,
        'membership_type_names': {
            'senior': get_membership_type_by_codename('senior')['name'],
            'main': get_membership_type_by_codename('main')['name'],
            'youth': get_membership_type_by_codename('youth')['name'],
            'school': get_membership_type_by_codename('school')['name'],
            'child': get_membership_type_by_codename('child')['name'],
            'household': get_membership_type_by_codename('household')['name'],
        },
        'foreign_shipment_price': FOREIGN_SHIPMENT_PRICE,
    }
    context.update(current_template_layout(request))
    return render(request, 'central/enrollment/verification.html', context)