def initial_order_data(request): """ Return the initial data for the order form - favours request.POST, then session, then the last order deterined by either the current authenticated user, or from previous the order cookie set with "remember my details". """ if request.method == "POST": return dict(request.POST.items()) if "order" in request.session: return request.session["order"] previous_lookup = {} if request.user.is_authenticated(): previous_lookup["user_id"] = request.user.id remembered = request.COOKIES.get("remember", "").split(":") if len(remembered) == 2 and remembered[0] == sign(remembered[1]): previous_lookup["key"] = remembered[1] initial = {} if previous_lookup: previous_orders = Order.objects.filter(**previous_lookup).values()[:1] if len(previous_orders) > 0: initial.update(previous_orders[0]) # Set initial value for "same billing/shipping" based on # whether both sets of address fields are all equal. shipping = lambda f: "shipping_%s" % f[len("billing_"):] if any([f for f in initial if f.startswith("billing_") and shipping(f) in initial and initial[f] != initial[shipping(f)]]): initial["same_billing_shipping"] = False return initial
def checkout_steps(request): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return redirect(url) # Level C Discount if request.user.profile.is_level_C: request.session['force_discount'] = 'l3v3lC15' # Determine the Form class to use during the checkout process form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) initial = checkout.initial_order_data(request, form_class) cancelled = request.GET.get('c', None) if not cancelled: step = int(request.POST.get("step", None) or initial.get("step", None) or checkout.CHECKOUT_STEP_FIRST) else: step = checkout.CHECKOUT_STEP_FIRST form = form_class(request, step, initial=initial) data = request.POST checkout_errors = [] log.debug('Checkout step %s' % step) if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = form_class(request, step, initial=initial) elif request.method == "POST" and request.cart.has_items(): form = form_class(request, step, initial=initial, data=data) if form.is_valid(): # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: if field in request.session["order"]: del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST: try: billship_handler(request, form) tax_handler(request, form) except checkout.CheckoutError, e: checkout_errors.append(e) form.set_discount() if form.cleaned_data.get('payment_method') == 'paypal': step += 1 try: request.session["order"]["step"] = step request.session.modified = True except KeyError: pass return redirect(Paypal.process(request, form)) # FINAL CHECKOUT STEP - handle payment and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the initial order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order receipt email. order = form.save(commit=False) order.setup(request) # Try payment. try: transaction_id = payment_handler(request, form, order) except checkout.CheckoutError, e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. if form.cleaned_data.get('payment_method') == 'paypal': payment = Paypal.find(request) if payment.shipping_info: order.shipping_detail_first_name = payment.shipping_info.first_name order.shipping_detail_last_name = payment.shipping_info.last_name order.shipping_detail_street = payment.shipping_info.address.line1 order.shipping_detail_city = payment.shipping_info.address.city order.shipping_detail_state = payment.shipping_info.address.state order.shipping_detail_postcode = payment.shipping_info.address.postal_code order.shipping_detail_country = payment.shipping_info.address.country_code order.transaction_id = transaction_id order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = redirect("shop_complete") if form.cleaned_data.get("remember"): remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = form_class(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = form_class(request, step, initial=initial)
def checkout(request): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard login_required # decorator. This means we can check for a custom LOGIN_URL and fall back # to our own login view. if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and \ not request.user.is_authenticated(): return HttpResponseRedirect("%s?next=%s" % (settings.SHOP_LOGIN_URL, reverse("shop_checkout"))) step = int(request.POST.get("step", CHECKOUT_STEP_FIRST)) initial = initial_order_data(request) form = OrderForm(request, step, initial=initial) data = request.POST if request.POST.get("back") is not None: step -= 1 form = OrderForm(request, step, initial=initial) elif request.method == "POST": form = OrderForm(request, step, initial=initial, data=data) if form.is_valid(): checkout_errors = [] request.session["order"] = dict(form.cleaned_data) for field in ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv"): del request.session["order"][field] # Handle shipping and discount code on first step. if step == CHECKOUT_STEP_FIRST: try: billing_shipping(request, form) except CheckoutError, e: checkout_errors.append(e) if hasattr(form, "discount"): cart = Cart.objects.from_request(request) discount_total = discount.calculate(cart.total_price()) request.session["free_shipping"] = discount.free_shipping request.session["discount_total"] = discount_total # Process order on final step. if step == CHECKOUT_STEP_LAST and not checkout_errors: try: payment(request, form) except CheckoutError, e: checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: order = form.save(commit=False) order.process(request) send_order_email(request, order) response = HttpResponseRedirect(reverse("shop_complete")) if form.cleaned_data.get("remember") is not None: remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # Assign checkout errors to new form if any and re-run is_valid # if valid set form to next step. form = OrderForm(request, step, initial=initial, data=data, checkout_errors=checkout_errors) if form.is_valid(): step += 1 form = OrderForm(request, step, initial=initial)
def checkout_steps(request, form_class=OrderForm, extra_context=None): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return redirect(url) try: settings.SHOP_CHECKOUT_FORM_CLASS except AttributeError: pass else: from warnings import warn warn("The SHOP_CHECKOUT_FORM_CLASS setting is deprecated - please " "define your own urlpattern for the checkout_steps view, " "passing in your own form_class argument.") form_class = import_dotted_path(settings.SHOP_CHECKOUT_FORM_CLASS) initial = checkout.initial_order_data(request, form_class) step = int( request.POST.get("step", None) or initial.get("step", None) or checkout.CHECKOUT_STEP_FIRST) form = form_class(request, step, initial=initial) data = request.POST checkout_errors = [] if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = form_class(request, step, initial=initial) elif request.method == "POST" and request.cart.has_items(): form = form_class(request, step, initial=initial, data=data) if form.is_valid(): # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: if field in request.session["order"]: del request.session["order"][field] # FIRST CHECKOUT STEP - handle discount code. This needs to # be set before shipping, to allow for free shipping to be # first set by a discount code. if step == checkout.CHECKOUT_STEP_FIRST: form.set_discount() # ALL STEPS - run billing/tax handlers. These are run on # all steps, since all fields (such as address fields) are # posted on each step, even as hidden inputs when not # visible in the current step. try: billship_handler(request, form) tax_handler(request, form) except checkout.CheckoutError as e: checkout_errors.append(e) # FINAL CHECKOUT STEP - run payment handler and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the initial order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order receipt email. order = form.save(commit=False) order.setup(request) # Try payment. try: transaction_id = payment_handler(request, form, order) except checkout.CheckoutError as e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. order.transaction_id = transaction_id order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = redirect("shop_complete") if form.cleaned_data.get("remember"): remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = form_class(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = form_class(request, step, initial=initial) # Update the step so that we don't rely on POST data to take us back to # the same point in the checkout process. try: request.session["order"]["step"] = step request.session.modified = True except KeyError: pass step_vars = checkout.CHECKOUT_STEPS[step - 1] template = "shop/%s.html" % step_vars["template"] context = { "CHECKOUT_STEP_FIRST": step == checkout.CHECKOUT_STEP_FIRST, "CHECKOUT_STEP_LAST": step == checkout.CHECKOUT_STEP_LAST, "CHECKOUT_STEP_PAYMENT": (settings.SHOP_PAYMENT_STEP_ENABLED and step == checkout.CHECKOUT_STEP_PAYMENT), "step_title": step_vars["title"], "step_url": step_vars["url"], "steps": checkout.CHECKOUT_STEPS, "step": step, "form": form } context.update(extra_context or {}) return TemplateResponse(request, template, context)
def checkout_steps(request): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return redirect(url) # Determine the Form class to use during the checkout process form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) initial = checkout.initial_order_data(request, form_class) step = int(request.POST.get("step", None) or initial.get("step", None) or checkout.CHECKOUT_STEP_FIRST) form = form_class(request, step, initial=initial) data = request.POST checkout_errors = [] if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = form_class(request, step, initial=initial) elif request.method == "POST" and request.cart.has_items(): form = form_class(request, step, initial=initial, data=data) if form.is_valid(): # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: if field in request.session["order"]: del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST: # Discount should be set before shipping, to allow # for free shipping to be first set by a discount # code. form.set_discount() try: billship_handler(request, form) tax_handler(request, form) except checkout.CheckoutError as e: checkout_errors.append(e) # FINAL CHECKOUT STEP - handle payment and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the initial order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order receipt email. order = form.save(commit=False) order.setup(request) # Try payment. try: transaction_id = payment_handler(request, form, order) except checkout.CheckoutError as e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. order.transaction_id = transaction_id order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = redirect("shop_complete") if form.cleaned_data.get("remember"): remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = form_class(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = form_class(request, step, initial=initial) # Update the step so that we don't rely on POST data to take us back to # the same point in the checkout process. try: request.session["order"]["step"] = step request.session.modified = True except KeyError: pass step_vars = checkout.CHECKOUT_STEPS[step - 1] template = "shop/%s.html" % step_vars["template"] context = {"CHECKOUT_STEP_FIRST": step == checkout.CHECKOUT_STEP_FIRST, "CHECKOUT_STEP_LAST": step == checkout.CHECKOUT_STEP_LAST, "step_title": step_vars["title"], "step_url": step_vars["url"], "steps": checkout.CHECKOUT_STEPS, "step": step, "form": form} return render(request, template, context)
def initial_order_data(request, form_class=None): """ Return the initial data for the order form, trying the following in order: - request.POST which is available when moving backward through the checkout steps - current order details in the session which are populated via each checkout step, to support user leaving the checkout entirely and returning - last order made by the user, via user ID or cookie - matching fields on an authenticated user and profile object """ from cartridge.shop.forms import OrderForm initial = {} if request.method == "POST": initial = dict(list(request.POST.items())) try: initial = form_class.preprocess(initial) except (AttributeError, TypeError): # form_class has no preprocess method, or isn't callable. pass # POST on first step won't include the "remember" checkbox if # it isn't checked, and it'll then get an actual value of False # when it's a hidden field - so we give it an empty value when # it's missing from the POST data, to persist it not checked. initial.setdefault("remember", "") # Look for order in current session. if not initial: initial = request.session.get("order", {}) # Look for order in previous session. if not initial: lookup = {} if request.user.is_authenticated(): lookup["user_id"] = request.user.id remembered = request.COOKIES.get("remember", "").split(":") if len(remembered) == 2 and remembered[0] == sign(remembered[1]): lookup["key"] = remembered[1] if lookup: previous = list(Order.objects.filter(**lookup).values())[:1] if len(previous) > 0: initial.update(previous[0]) if not initial and request.user.is_authenticated(): # No previous order data - try and get field values from the # logged in user. Check the profile model before the user model # if it's configured. If the order field name uses one of the # billing/shipping prefixes, also check for it without the # prefix. Finally if a matching attribute is callable, call it # for the field value, to support custom matches on the profile # model. user_models = [request.user] try: user_models.insert(0, request.user.get_profile()) except SiteProfileNotAvailable: pass for order_field in OrderForm._meta.fields: check_fields = [order_field] for prefix in ("billing_detail_", "shipping_detail_"): if order_field.startswith(prefix): check_fields.append(order_field.replace(prefix, "", 1)) for user_model in user_models: for check_field in check_fields: user_value = getattr(user_model, check_field, None) if user_value: if callable(user_value): try: user_value = user_value() except TypeError: continue if not initial.get(order_field): initial[order_field] = user_value # Set initial value for "same billing/shipping" based on # whether both sets of address fields are all equal. shipping = lambda f: "shipping_%s" % f[len("billing_"):] if any([f for f in OrderForm._meta.fields if f.startswith("billing_") and shipping(f) in OrderForm._meta.fields and initial.get(f, "") != initial.get(shipping(f), "")]): initial["same_billing_shipping"] = False # Never prepopulate discount code. try: del initial["discount_code"] except KeyError: pass return initial
def checkout_steps(request): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return redirect(url) # Determine the Form class to use during the checkout process form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) initial = checkout.initial_order_data(request, form_class) step = int( request.POST.get("step", None) or initial.get("step", None) or checkout.CHECKOUT_STEP_FIRST) form = form_class(request, step, initial=initial) data = request.POST checkout_errors = [] if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = form_class(request, step, initial=initial) elif request.method == "POST" and request.cart.has_items(): form = form_class(request, step, initial=initial, data=data) if form.is_valid(): # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: if field in request.session["order"]: del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST: try: billship_handler(request, form) tax_handler(request, form) except checkout.CheckoutError, e: checkout_errors.append(e) form.set_discount() # FINAL CHECKOUT STEP - handle payment and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the initial order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order receipt email. order = form.save(commit=False) order.setup(request) # Try payment. try: transaction_id = payment_handler(request, form, order) except checkout.CheckoutError, e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. order.transaction_id = transaction_id order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = redirect("shop_complete") if form.cleaned_data.get("remember"): remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = form_class(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = form_class(request, step, initial=initial)
def checkout_steps(request): """ Display the order form and handle processing of each step. """ # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return HttpResponseRedirect(url) step = int(request.POST.get("step", checkout.CHECKOUT_STEP_FIRST)) initial = checkout.initial_order_data(request) form = OrderForm(request, step, initial=initial) data = request.POST checkout_errors = [] if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = OrderForm(request, step, initial=initial) elif request.method == "POST": form = OrderForm(request, step, initial=initial, data=data) if form.is_valid(): # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST: try: billship_handler(request, form) except checkout.CheckoutError, e: checkout_errors.append(e) form.set_discount() # FINAL CHECKOUT STEP - handle payment and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the inital order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order reciept email. order = form.save(commit=False) order.setup(request) # Try payment. try: payment_handler(request, form, order) except checkout.CheckoutError, e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = HttpResponseRedirect(reverse("shop_complete")) if form.cleaned_data.get("remember") is not None: remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = OrderForm(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = OrderForm(request, step, initial=initial)
def initial_order_data(request): """ Return the initial data for the order form, trying the following in order: - request.POST which is available when moving backward through the checkout steps - current order details in the session which are populated via each checkout step, to support user leaving the checkout entirely and returning - last order made by the user, via user ID or cookie - matching fields on an authenticated user and profile object """ form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) if request.method == "POST": return dict(request.POST.items()) if "order" in request.session: return request.session["order"] previous_lookup = {} if request.user.is_authenticated(): previous_lookup["user_id"] = request.user.id remembered = request.COOKIES.get("remember", "").split(":") if len(remembered) == 2 and remembered[0] == sign(remembered[1]): previous_lookup["key"] = remembered[1] initial = {} if previous_lookup: previous_orders = Order.objects.filter(**previous_lookup).values()[:1] if len(previous_orders) > 0: initial.update(previous_orders[0]) if not initial and request.user.is_authenticated(): # No previous order data - try and get field values from the # logged in user. Check the profile model before the user model # if it's configured. If the order field name uses one of the # billing/shipping prefixes, also check for it without the # prefix. Finally if a matching attribute is callable, call it # for the field value, to support custom matches on the profile # model. user_models = [request.user] try: user_models.insert(0, request.user.get_profile()) except SiteProfileNotAvailable: pass for order_field in form_class._meta.fields: check_fields = [order_field] for prefix in ("billing_detail_", "shipping_detail_"): if order_field.startswith(prefix): check_fields.append(order_field.replace(prefix, "", 1)) for user_model in user_models: for check_field in check_fields: user_value = getattr(user_model, check_field, None) if user_value: if callable(user_value): try: user_value = user_value() except TypeError: continue if not initial.get(order_field): initial[order_field] = user_value # Set initial value for "same billing/shipping" based on # whether both sets of address fields are all equal. shipping = lambda f: "shipping_%s" % f[len("billing_"):] if any([f for f in form_class._meta.fields if f.startswith("billing_") and shipping(f) in form_class._meta.fields and initial.get(f, "") != initial.get(shipping(f), "")]): initial["same_billing_shipping"] = False return initial
def checkout_steps(request, form_class=OrderForm): """ Display the order form and handle processing of each step. """ #cart(request) # Do the authentication check here rather than using standard # login_required decorator. This means we can check for a custom # LOGIN_URL and fall back to our own login view. authenticated = request.user.is_authenticated() onekey = request.GET.get('keycode', None) checkout_errors = [] #add get instead of request.session['onekeycode'] #when homepage change to network+ style, weixin onekey order error that no onekeycode in session #but pc is OK, guess due to cookie forbidden within weixin browser, not diginto yet, just workaround here if onekey and onekey != request.session.get('onekeycode', None): #raise Exception('code got right!') #checkout_errors.append('您可能存在恶意下单,请联系客服,非常抱歉给您带来不便!') pass if settings.SHOP_CHECKOUT_ACCOUNT_REQUIRED and not authenticated and not onekey: url = "%s?next=%s" % (settings.LOGIN_URL, reverse("shop_checkout")) return redirect(url) #wni: add here for weixin pay #weixincode = request.GET.get('code',None) if settings.WITH_WEIXIN_PAY: weixinopenid = request.session.get('openid', None) if 'micromessenger' in request.META.get('HTTP_USER_AGENT').lower( ) and not weixinopenid: #and not weixincode: api_pub = JsApi_pub() #url = api_pub.createOauthUrlForCode(reverse('weixin:usercode',args=(tmp_no,),current_app=resolve(request.path).namespace)) #url = api_pub.createOauthUrlForCode('http://eason.happydiaosi.com/weixin/getusercode') url = api_pub.createOauthUrlForCode('http://%s' % settings.SITE_DOMAIN + reverse('weixin:usercode')) return redirect(url) try: settings.SHOP_CHECKOUT_FORM_CLASS except AttributeError: pass else: from warnings import warn warn("The SHOP_CHECKOUT_FORM_CLASS setting is deprecated - please " "define your own urlpattern for the checkout_steps view, " "passing in your own form_class argument.") form_class = import_dotted_path(settings.SHOP_CHECKOUT_FORM_CLASS) initial = checkout.initial_order_data(request, form_class) step = int( request.POST.get("step", None) or initial.get("step", None) or checkout.CHECKOUT_STEP_FIRST) form = form_class(request, step, initial=initial) data = request.POST #checkout_errors = [] if request.POST.get("back") is not None: # Back button in the form was pressed - load the order form # for the previous step and maintain the field values entered. step -= 1 form = form_class(request, step, initial=initial) elif request.method == "POST" and request.cart.has_items(): form = form_class(request, step, initial=initial, data=data) if form.is_valid(): #human = True # Copy the current form fields to the session so that # they're maintained if the customer leaves the checkout # process, but remove sensitive fields from the session # such as the credit card fields so that they're never # stored anywhere. request.session["order"] = dict(form.cleaned_data) sensitive_card_fields = ("card_number", "card_expiry_month", "card_expiry_year", "card_ccv") for field in sensitive_card_fields: if field in request.session["order"]: del request.session["order"][field] # FIRST CHECKOUT STEP - handle shipping and discount code. if step == checkout.CHECKOUT_STEP_FIRST: # Discount should be set before shipping, to allow # for free shipping to be first set by a discount # code. form.set_discount() try: billship_handler(request, form) tax_handler(request, form) except checkout.CheckoutError as e: checkout_errors.append(e) #wni: added for wx pay, for get order total on confirmation page #tmp_order = form.save(commit=False) #request.session['wni_wxpay_total'] = tmp_order.get_tmp_total(request) # FINAL CHECKOUT STEP - handle payment and process order. if step == checkout.CHECKOUT_STEP_LAST and not checkout_errors: # Create and save the initial order object so that # the payment handler has access to all of the order # fields. If there is a payment error then delete the # order, otherwise remove the cart items from stock # and send the order receipt email. order = form.save(commit=False) order.setup(request) # Try payment. try: transaction_id = payment_handler(request, form, order) except checkout.CheckoutError as e: # Error in payment handler. order.delete() checkout_errors.append(e) if settings.SHOP_CHECKOUT_STEPS_CONFIRMATION: step -= 1 else: # Finalize order - ``order.complete()`` performs # final cleanup of session and cart. # ``order_handler()`` can be defined by the # developer to implement custom order processing. # Then send the order email to the customer. order.transaction_id = transaction_id order.complete(request) order_handler(request, form, order) checkout.send_order_email(request, order) # Set the cookie for remembering address details # if the "remember" checkbox was checked. response = redirect("shop_complete") if form.cleaned_data.get("remember"): remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response # If any checkout errors, assign them to a new form and # re-run is_valid. If valid, then set form to the next step. form = form_class(request, step, initial=initial, data=data, errors=checkout_errors) #print type(form.errors),form.errors #form.errors.clear() if form.is_valid(): step += 1 #human = True form = form_class(request, step, initial=initial) # Update the step so that we don't rely on POST data to take us back to # the same point in the checkout process. try: request.session["order"]["step"] = step request.session.modified = True except KeyError: pass step_vars = checkout.CHECKOUT_STEPS[step - 1] template = "shop/%s.html" % step_vars["template"] context = { "CHECKOUT_STEP_FIRST": step == checkout.CHECKOUT_STEP_FIRST, "CHECKOUT_STEP_LAST": step == checkout.CHECKOUT_STEP_LAST, "step_title": step_vars["title"], "step_url": step_vars["url"], "steps": checkout.CHECKOUT_STEPS, "step": step, "form": form } return render(request, template, context)
#=========================================================================== # External payment management #=========================================================================== context['CHECKOUT_STEP_PAYMENT'] = step == checkout.CHECKOUT_STEP_PAYMENT if step == checkout.CHECKOUT_STEP_PAYMENT: form = form_class(request, step, initial=initial, data=data) order = form.save(commit=False) order.setup(request) context['start_payment_form'] = provider.get_start_payment_form(request, order) response = render(request, template, context) if step == checkout.CHECKOUT_STEP_PAYMENT: # Set the cookie for remembering address details # if the "remember" checkbox was checked. if form.cleaned_data.get("remember") is not None: remembered = "%s:%s" % (sign(order.key), order.key) set_cookie(response, "remember", remembered, secure=request.is_secure()) else: response.delete_cookie("remember") return response def finalize_order(request): '''Helper function that actually complete the order when the payment provider tells us so. ''' order_id = provider.get_order_id(request) order = Order.objects.get(pk=order_id) #Order is already completed if order.payment_done:
def initial_order_data(request): """ Return the initial data for the order form, trying the following in order: - request.POST which is available when moving backward through the checkout steps - current order details in the session which are populated via each checkout step, to support user leaving the checkout entirely and returning - last order made by the user, via user ID or cookie - matching fields on an authenticated user and profile object """ form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) if request.method == "POST": return dict(request.POST.items()) if "order" in request.session: return request.session["order"] previous_lookup = {} if request.user.is_authenticated(): previous_lookup["user_id"] = request.user.id remembered = request.COOKIES.get("remember", "").split(":") if len(remembered) == 2 and remembered[0] == sign(remembered[1]): previous_lookup["key"] = remembered[1] initial = {} if previous_lookup: previous_orders = Order.objects.filter(**previous_lookup).values()[:1] if len(previous_orders) > 0: initial.update(previous_orders[0]) if not initial and request.user.is_authenticated(): # No previous order data - try and get field values from the # logged in user. Check the profile model before the user model # if it's configured. If the order field name uses one of the # billing/shipping prefixes, also check for it without the # prefix. Finally if a matching attribute is callable, call it # for the field value, to support custom matches on the profile # model. user_models = [request.user] try: user_models.insert(0, request.user.get_profile()) except SiteProfileNotAvailable: pass for order_field in form_class._meta.fields: check_fields = [order_field] for prefix in ("billing_detail_", "shipping_detail_"): if order_field.startswith(prefix): check_fields.append(order_field.replace(prefix, "", 1)) for user_model in user_models: for check_field in check_fields: user_value = getattr(user_model, check_field, None) if user_value: if callable(user_value): try: user_value = user_value() except TypeError: continue if not initial.get(order_field): initial[order_field] = user_value # Set initial value for "same billing/shipping" based on # whether both sets of address fields are all equal. shipping = lambda f: "shipping_%s" % f[len("billing_"):] if any([ f for f in form_class._meta.fields if f.startswith("billing_") and shipping(f) in form_class._meta. fields and initial.get(f, "") != initial.get(shipping(f), "") ]): initial["same_billing_shipping"] = False return initial