def product(request, slug, template="shop/product.html"): """ Display a product - convert the product variations to JSON as well as handling adding the product to either the cart or the wishlist. """ published_products = Product.objects.published(for_user=request.user) product = get_object_or_404(published_products, slug=slug) AddProductForm = get_add_product_form(product) add_product_form = AddProductForm(initial={"quantity": 1}) if request.method == "POST": to_cart = request.POST.get("add_wishlist") is None add_product_form = AddProductForm(request.POST, to_cart=to_cart) if add_product_form.is_valid(): if to_cart: Cart.objects.from_request(request).add_item( add_product_form.variation, add_product_form.cleaned_data["quantity"]) info(request, _("Item added to cart"), fail_silently=True) return HttpResponseRedirect(reverse("shop_cart")) else: skus = request.COOKIES.get("wishlist", "").split(",") sku = add_product_form.variation.sku if sku not in skus: skus.append(sku) info(request, _("Item added to wishlist"), fail_silently=True) response = HttpResponseRedirect(reverse("shop_wishlist")) set_cookie(response, "wishlist", ",".join(skus)) return response variations = product.variations.all() variations_json = simplejson.dumps([dict([(f, getattr(v, f)) for f in ["sku", "image_id"] + [f.name for f in ProductVariation.option_fields()]]) for v in variations]) return render_to_response(template, {"product": product, "variations_json": variations_json, "variations": variations, "images": product.images.all(), "add_product_form": add_product_form}, RequestContext(request))
def wishlist(request, template="shop/wishlist.html"): """ Display the wishlist and handle removing items from the wishlist and adding them to the cart. """ skus = request.COOKIES.get("wishlist", "").split(",") error = None if request.method == "POST": sku = request.POST.get("sku") to_cart = request.POST.get("add_cart") is not None if to_cart: quantity = 1 try: variation = ProductVariation.objects.get(sku=sku) except ProductVariation: error = _("This item is no longer available") else: if not variation.has_stock(quantity): error = _("This item is currently out of stock") else: cart = Cart.objects.from_request(request) cart.add_item(variation, quantity) if error is None: if sku in skus: skus.remove(sku) if to_cart: message = _("Item added to cart") response = HttpResponseRedirect(reverse("shop_cart")) else: message = _("Item removed from wishlist") response = HttpResponseRedirect(reverse("shop_wishlist")) info(request, message, fail_silently=True) set_cookie(response, "wishlist", ",".join(skus)) return response # Remove skus from the cookie that no longer exist. published_products = Product.objects.published(for_user=request.user) f = {"product__in": published_products, "sku__in": skus} wishlist = ProductVariation.objects.filter(**f).select_related(depth=1) wishlist = sorted(wishlist, key=lambda v: skus.index(v.sku)) context = {"wishlist": wishlist, "error": error} response = render_to_response(template, context, RequestContext(request)) if len(wishlist) < len(skus): skus = [variation.sku for variation in wishlist] set_cookie(response, "wishlist", ",".join(skus)) return response
def product(request, slug, template="shop/product.html"): """ Display a product - convert the product variations to JSON as well as handling adding the product to either the cart or the wishlist. """ published_products = Product.objects.published(for_user=request.user) product = get_object_or_404(published_products, slug=slug) to_cart = (request.method == "POST" and request.POST.get("add_wishlist") is None) add_product_form = AddProductForm(request.POST or None, product=product, initial={"quantity": 1}, to_cart=to_cart) if request.method == "POST": if add_product_form.is_valid(): if to_cart: quantity = add_product_form.cleaned_data["quantity"] request.cart.add_item(add_product_form.variation, quantity) recalculate_discount(request) info(request, _("Item added to cart")) return HttpResponseRedirect(reverse("shop_cart")) else: skus = request.wishlist sku = add_product_form.variation.sku if sku not in skus: skus.append(sku) info(request, _("Item added to wishlist")) response = HttpResponseRedirect(reverse("shop_wishlist")) set_cookie(response, "wishlist", ",".join(skus)) return response fields = [f.name for f in ProductVariation.option_fields()] fields += ["sku", "image_id"] variations = product.variations.all() variations_json = simplejson.dumps( [dict([(f, getattr(v, f)) for f in fields]) for v in variations]) context = { "product": product, "images": product.images.all(), "variations": variations, "variations_json": variations_json, "has_available_variations": any([v.has_price() for v in variations]), "related": product.related_products.published(for_user=request.user), "add_product_form": add_product_form } return render_to_response(template, context, RequestContext(request))
def product(request, slug, template="shop/product.html"): """ Display a product - convert the product variations to JSON as well as handling adding the product to either the cart or the wishlist. """ published_products = Product.objects.published(for_user=request.user) product = get_object_or_404(published_products, slug=slug) to_cart = (request.method == "POST" and request.POST.get("add_wishlist") is None) add_product_form = AddProductForm(request.POST or None, product=product, initial={"quantity": 1}, to_cart=to_cart) if request.method == "POST": if add_product_form.is_valid(): if to_cart: quantity = add_product_form.cleaned_data["quantity"] request.cart.add_item(add_product_form.variation, quantity) recalculate_discount(request) info(request, _("Item added to cart")) return redirect("shop_cart") else: skus = request.wishlist sku = add_product_form.variation.sku if sku not in skus: skus.append(sku) info(request, _("Item added to wishlist")) response = redirect("shop_wishlist") set_cookie(response, "wishlist", ",".join(skus)) return response fields = [f.name for f in ProductVariation.option_fields()] fields += ["sku", "image_id"] variations = product.variations.all() variations_json = simplejson.dumps([dict([(f, getattr(v, f)) for f in fields]) for v in variations]) context = { "product": product, "images": product.images.all(), "variations": variations, "variations_json": variations_json, "has_available_variations": any([v.has_price() for v in variations]), "related": product.related_products.published(for_user=request.user), "add_product_form": add_product_form } return render(request, template, context)
def wishlist(request, template="shop/wishlist.html"): """ Display the wishlist and handle removing items from the wishlist and adding them to the cart. """ skus = request.wishlist error = None if request.method == "POST": to_cart = request.POST.get("add_cart") add_product_form = AddProductForm(request.POST or None, to_cart=to_cart) if to_cart: if add_product_form.is_valid(): request.cart.add_item(add_product_form.variation, 1) recalculate_discount(request) message = _("Item added to cart") url = reverse("shop_cart") else: error = add_product_form.errors.values()[0] else: message = _("Item removed from wishlist") url = reverse("shop_wishlist") sku = request.POST.get("sku") if sku in skus: skus.remove(sku) if not error: info(request, message) response = HttpResponseRedirect(url) set_cookie(response, "wishlist", ",".join(skus)) return response # Remove skus from the cookie that no longer exist. published_products = Product.objects.published(for_user=request.user) f = {"product__in": published_products, "sku__in": skus} wishlist = ProductVariation.objects.filter(**f).select_related(depth=1) wishlist = sorted(wishlist, key=lambda v: skus.index(v.sku)) context = {"wishlist_items": wishlist, "error": error} response = render_to_response(template, context, RequestContext(request)) if len(wishlist) < len(skus): skus = [variation.sku for variation in wishlist] set_cookie(response, "wishlist", ",".join(skus)) return response
def wishlist(request, template="shop/wishlist.html"): """ Display the wishlist and handle removing items from the wishlist and adding them to the cart. """ skus = request.wishlist error = None if request.method == "POST": to_cart = request.POST.get("add_cart") add_product_form = AddProductForm(request.POST or None, to_cart=to_cart) if to_cart: if add_product_form.is_valid(): request.cart.add_item(add_product_form.variation, 1) recalculate_discount(request) message = _("Item added to cart") url = "shop_cart" else: error = add_product_form.errors.values()[0] else: message = _("Item removed from wishlist") url = "shop_wishlist" sku = request.POST.get("sku") if sku in skus: skus.remove(sku) if not error: info(request, message) response = redirect(url) set_cookie(response, "wishlist", ",".join(skus)) return response # Remove skus from the cookie that no longer exist. published_products = Product.objects.published(for_user=request.user) f = {"product__in": published_products, "sku__in": skus} wishlist = ProductVariation.objects.filter(**f).select_related(depth=1) wishlist = sorted(wishlist, key=lambda v: skus.index(v.sku)) context = {"wishlist_items": wishlist, "error": error} response = render(request, template, context) if len(wishlist) < len(skus): skus = [variation.sku for variation in wishlist] set_cookie(response, "wishlist", ",".join(skus)) return response
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): """ 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 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) # Determine the Form class to use during the checkout process form_class = get_callable(settings.SHOP_CHECKOUT_FORM_CLASS) step = int(request.POST.get("step", checkout.CHECKOUT_STEP_FIRST)) initial = checkout.initial_order_data(request) 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": 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: 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: 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 = 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 = form_class(request, step, initial=initial, data=data, errors=checkout_errors) if form.is_valid(): step += 1 form = form_class(request, step, initial=initial)