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)
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')
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)
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)
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")
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)
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'}))
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)
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')
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
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 ))
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')
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)
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'}))
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)
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 ))
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)
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)