[cart] add to cart, update cart
diff --git a/public/js/website_utils.js b/public/js/website_utils.js
index 1484f00..83becc6 100644
--- a/public/js/website_utils.js
+++ b/public/js/website_utils.js
@@ -15,7 +15,6 @@
wn.call = function(opts) {
if(opts.btn) {
- var $spinner = $('<img src="lib/images/ui/button-load.gif">').appendTo($(opts.btn).parent())
$(opts.btn).attr("disabled", "disabled");
}
@@ -23,6 +22,8 @@
$(opts.msg).toggle(false);
}
+ if(!opts.args) opts.args = {};
+
// get or post?
if(!opts.args._type) {
opts.args._type = opts.type || "GET";
@@ -48,10 +49,17 @@
success: function(data) {
if(opts.btn) {
$(opts.btn).attr("disabled", false);
- $spinner.remove();
}
if(data.exc) {
- console.log(data.exc);
+ if(opts.btn) {
+ $(opts.btn).addClass("btn-danger");
+ setTimeout(function() { $(opts.btn).removeClass("btn-danger"); }, 1000);
+ }
+ } else{
+ if(opts.btn) {
+ $(opts.btn).addClass("btn-success");
+ setTimeout(function() { $(opts.btn).removeClass("btn-success"); }, 1000);
+ }
}
if(opts.msg && data.message) {
$(opts.msg).html(data.message).toggle(true);
@@ -75,11 +83,8 @@
$("#user-full-name").text(full_name);
}
- wn.cart.update_display();
$("#user-tools a").tooltip({"placement":"bottom"});
$("#user-tools-post-login a").tooltip({"placement":"bottom"});
-
- $(window).on("storage", function() { wn.cart.update_display(); });
});
// Utility functions
@@ -101,6 +106,12 @@
return decodeURIComponent(results[1]);
}
+function make_query_string(obj) {
+ var query_params = [];
+ $.each(obj, function(k, v) { query_params.push(encodeURIComponent(k) + "=" + encodeURIComponent(v)); });
+ return "?" + query_params.join("&");
+}
+
function repl(s, dict) {
if(s==null)return '';
for(key in dict) {
@@ -166,48 +177,30 @@
// shopping cart
if(!wn.cart) wn.cart = {};
+var full_name = getCookie("full_name");
+
$.extend(wn.cart, {
- get_count: function() {
- return Object.keys(this.get_cart()).length;
- },
-
- add_to_cart: function(itemprop) {
- var cart = this.get_cart();
- cart[itemprop.item_code] = $.extend(itemprop, {qty: 1});
- this.set_cart(cart);
- console.log(this.get_cart());
- },
-
- remove_from_cart: function(item_code) {
- var cart = this.get_cart();
- delete cart[item_code];
- this.set_cart(cart);
- console.log(this.get_cart());
- },
-
- get_cart: function() {
- if( !("localStorage" in window) ) {
- alert("Your browser seems to be ancient. Please use a modern browser.");
- throw "ancient browser error";
+ update_cart: function(opts) {
+ if(!full_name) {
+ if(localStorage) {
+ localStorage.setItem("last_visited", window.location.pathname.slice(1));
+ localStorage.setItem("pending_add_to_cart", opts.item_code);
+ }
+ window.location.href = "login";
+ } else {
+ wn.call({
+ type: "POST",
+ method: "website.helpers.cart.update_cart",
+ args: {
+ item_code: opts.item_code,
+ qty: opts.qty
+ },
+ btn: opts.btn,
+ callback: function(r) {
+ if(opts.callback)
+ opts.callback(r);
+ }
+ });
}
-
- return JSON.parse(localStorage.getItem("cart")) || {};
},
-
- set_cart: function(cart) {
- localStorage.setItem("cart", JSON.stringify(cart));
- wn.cart.update_display();
- },
-
- update_display: function() {
- $(".cart-count").text("( " + wn.cart.get_count() + " )");
- },
-
- set_value_in_cart: function(item_code, fieldname, value) {
- var cart = this.get_cart();
- if(cart[item_code]) {
- cart[item_code][fieldname] = value;
- this.set_cart(cart);
- }
- }
});
\ No newline at end of file
diff --git a/website/css/website.css b/website/css/website.css
index 4af35dc..7efceb2 100644
--- a/website/css/website.css
+++ b/website/css/website.css
@@ -6,6 +6,10 @@
font-weight: bold;
}
+a {
+ cursor: pointer;
+}
+
.content {
padding-bottom: 30px;
}
diff --git a/website/helpers/cart.py b/website/helpers/cart.py
index efeb975..b62e0bb 100644
--- a/website/helpers/cart.py
+++ b/website/helpers/cart.py
@@ -7,20 +7,13 @@
import webnotes.defaults
from webnotes.utils import today, get_fullname
-@webnotes.whitelist()
-def add_to_cart(item_code):
- update_qty(item_code, 1)
-
-@webnotes.whitelist()
-def remove_from_cart(item_code):
- update_qty(item_code, 0)
+class WebsitePriceListMissingError(webnotes.ValidationError): pass
@webnotes.whitelist()
-def update_qty(item_code, qty_to_set):
- party = get_lead_or_customer()
- quotation = get_shopping_cart_quotation(party)
+def update_cart(item_code, qty):
+ quotation = _get_cart_quotation()
- if qty_to_set == 0:
+ if qty == 0:
quotation.set_doclist(quotation.doclist.get({"item_code": ["!=", item_code]}))
else:
quotation_items = quotation.doclist.get({"item_code": item_code})
@@ -29,10 +22,10 @@
"doctype": "Quotation Item",
"parentfield": "quotation_details",
"item_code": item_code,
- "qty": qty_to_set
+ "qty": qty
})
else:
- quotation_items[0].qty = qty_to_set
+ quotation_items[0].qty = qty
quotation.ignore_permissions = True
quotation.save()
@@ -59,7 +52,16 @@
return lead_bean.doc
-def get_shopping_cart_quotation(party):
+
+@webnotes.whitelist()
+def get_cart_quotation():
+ return [d.fields for d in _get_cart_quotation(get_lead_or_customer()).doclist]
+
+
+def _get_cart_quotation(party=None):
+ if not party:
+ party = get_lead_or_customer()
+
quotation = webnotes.conn.get_value("Quotation",
{party.doctype.lower(): party.name, "order_type": "Shopping Cart", "docstatus": 0})
@@ -104,15 +106,14 @@
{"use_for_website": 1, "valid_for_all_countries": 1})
if not price_list_name:
- raise Exception, "No website Price List specified"
+ raise WebsitePriceListMissingError, "No website Price List specified"
return price_list_name
@webnotes.whitelist()
def checkout():
- party = get_lead_or_customer()
- quotation = get_shopping_cart_quotation(party)
+ quotation = _get_cart_quotation()
quotation.ignore_permissions = True
quotation.submit()
@@ -143,21 +144,21 @@
def test_add_to_cart(self):
webnotes.session.user = "test@example.com"
- add_to_cart("_Test Item")
+ update_cart("_Test Item", 1)
- quotation = get_shopping_cart_quotation(get_lead_or_customer())
+ quotation = _get_cart_quotation()
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertTrue(quotation_items)
self.assertEquals(quotation_items[0].qty, 1)
return quotation
- def test_update_qty(self):
+ def test_update_cart(self):
self.test_add_to_cart()
- update_qty("_Test Item", 5)
+ update_cart("_Test Item", 5)
- quotation = get_shopping_cart_quotation(get_lead_or_customer())
+ quotation = _get_cart_quotation()
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertTrue(quotation_items)
self.assertEquals(quotation_items[0].qty, 5)
@@ -167,16 +168,16 @@
def test_remove_from_cart(self):
quotation0 = self.test_add_to_cart()
- remove_from_cart("_Test Item")
+ update_cart("_Test Item", 0)
- quotation = get_shopping_cart_quotation(get_lead_or_customer())
+ quotation = _get_cart_quotation()
self.assertEquals(quotation0.doc.name, quotation.doc.name)
quotation_items = quotation.doclist.get({"parentfield": "quotation_details", "item_code": "_Test Item"})
self.assertEquals(quotation_items, [])
def test_checkout(self):
- quotation = self.test_update_qty()
+ quotation = self.test_update_cart()
sales_order = checkout()
self.assertEquals(sales_order.doclist.getone({"item_code": "_Test Item"}).prevdoc_docname, quotation.doc.name)
\ No newline at end of file
diff --git a/website/helpers/product.py b/website/helpers/product.py
index fb4d4e4..e513c2d 100644
--- a/website/helpers/product.py
+++ b/website/helpers/product.py
@@ -25,18 +25,26 @@
(item_code, price_list), as_dict=1) or []
price = price and price[0] or None
-
+ qty = 0
+
if price:
price["formatted_price"] = fmt_money(price["ref_rate"], currency=price["ref_currency"])
price["ref_currency"] = not cint(webnotes.conn.get_default("hide_currency_symbol")) \
and (webnotes.conn.get_value("Currency", price.ref_currency, "symbol") or price.ref_currency) \
or ""
+
+ if webnotes.session.user != "Guest":
+ from website.helpers.cart import _get_cart_quotation
+ item = _get_cart_quotation().doclist.get({"item_code": item_code})
+ if item:
+ qty = item[0].qty
return {
"price": price,
"stock": in_stock,
- "uom": webnotes.conn.get_value("Item", item_code, "stock_uom")
+ "uom": webnotes.conn.get_value("Item", item_code, "stock_uom"),
+ "qty": qty
}
@webnotes.whitelist(allow_guest=True)
diff --git a/website/templates/css/product_page.css b/website/templates/css/product_page.css
index e2f4293..566b6b5 100644
--- a/website/templates/css/product_page.css
+++ b/website/templates/css/product_page.css
@@ -7,7 +7,4 @@
font-size: 18px;
line-height: 200%;
}
- .item-price-info {
- margin-top: 20px;
- }
</style>
\ No newline at end of file
diff --git a/website/templates/html/product_page.html b/website/templates/html/product_page.html
index ac1af5a..837b105 100644
--- a/website/templates/html/product_page.html
+++ b/website/templates/html/product_page.html
@@ -35,11 +35,20 @@
{{ web_long_description or web_short_description or
"[No description given]" }}
</div>
- <div class="item-price-info" itemprop="offers" itemscope itemtype="http://schema.org/Offer">
- <div class="item-price hide" itemprop="price"></div>
- <div class="item-stock" itemprop="availablity"></div>
- <button class="btn btn-primary item-add-to-cart hide">Add to Cart</button>
- <button class="btn btn-default item-remove-from-cart hide">Remove from Cart</button>
+ <div style="min-height: 100px; margin: 10px 0;">
+ <div class="item-price-info" style="display: none;">
+ <h4 class="item-price" itemprop="price"></h4>
+ <div class="item-stock" itemprop="availablity"></div>
+ <div id="item-add-to-cart">
+ <button class="btn btn-primary">Add to Cart</button>
+ </div>
+ <div id="item-update-cart" class="input-group col-lg-6" style="display: none;">
+ <input type="text">
+ <div class="input-group-btn">
+ <button class="btn btn-primary">Update</button>
+ </div>
+ </div>
+ </div>
</div>
</div>
</div>
diff --git a/website/templates/js/cart.js b/website/templates/js/cart.js
index eaa1fab..121ca6a 100644
--- a/website/templates/js/cart.js
+++ b/website/templates/js/cart.js
@@ -18,15 +18,45 @@
$(document).ready(function() {
// make list of items in the cart
- wn.cart.render();
- wn.cart.bind_events();
+ // wn.cart.render();
+ // wn.cart.bind_events();
+ wn.call({
+ method: "website.helpers.cart.get_cart_quotation",
+ args: {
+ _type: "POST"
+ },
+ callback: function(r) {
+ console.log(r);
+ $("#cart-container").removeClass("hide");
+ $(".progress").remove();
+ if(r.exc) {
+ if(r.exc.indexOf("WebsitePriceListMissingError")!==-1) {
+ wn.cart.show_error("Oops!", "Price List not configured.");
+ } else {
+ wn.cart.show_error("Oops!", "Something went wrong.");
+ }
+ } else {
+ if(r.message[0].__islocal) {
+ wn.cart.show_error("Empty :-(", "Go ahead and add something to your cart.");
+ } else {
+ wn.cart.render(r.message);
+ }
+ }
+
+ }
+ });
});
// shopping cart
if(!wn.cart) wn.cart = {};
$.extend(wn.cart, {
- render: function() {
- var $cart_wrapper = $("#cart-added-items").empty();
+ show_error: function(title, text) {
+ $("#cart-container").html('<div class="well"><h4>' + title + '</h4> ' + text + '</div>');
+ },
+
+ render: function(doclist) {
+ return;
+ var $cart_wrapper = $("#cart-items").empty();
if(Object.keys(wn.cart.get_cart()).length) {
$('<div class="row">\
<div class="col col-lg-9 col-sm-9">\
diff --git a/website/templates/js/product_page.js b/website/templates/js/product_page.js
index e3e4c61..adfeb5e 100644
--- a/website/templates/js/product_page.js
+++ b/website/templates/js/product_page.js
@@ -15,55 +15,77 @@
// along with this program. If not, see <http://www.gnu.org/licenses/>.
$(document).ready(function() {
- $.ajax({
- method: "GET",
- url:"server.py",
- dataType: "json",
- data: {
- cmd: "website.helpers.product.get_product_info",
+ var item_code = $('[itemscope] [itemprop="name"]').text().trim();
+ var qty = 0;
+
+ wn.call({
+ type: "POST",
+ method: "website.helpers.product.get_product_info",
+ args: {
item_code: "{{ name }}"
},
- success: function(data) {
- if(data.message) {
- if(data.message.price) {
- $("<h4>")
- .html(data.message.price.formatted_price + " per " + data.message.uom)
- .appendTo(".item-price");
- $(".item-price").removeClass("hide");
- }
- if(data.message.stock==0) {
+ callback: function(r) {
+ if(r.message && r.message.price) {
+ $(".item-price")
+ .html(r.message.price.formatted_price + " per " + r.message.uom);
+
+ if(r.message.stock==0) {
$(".item-stock").html("<div class='help'>Not in stock</div>");
}
- else if(data.message.stock==1) {
+ else if(r.message.stock==1) {
$(".item-stock").html("<div style='color: green'>\
<i class='icon-check'></i> Available (in stock)</div>");
}
+
+ $(".item-price-info").toggle(true);
+
+ if(r.message.qty) {
+ qty = r.message.qty;
+ toggle_update_cart(qty);
+ $("#item-update-cart input").val(qty);
+ }
}
}
- });
+ })
- if(wn.cart.get_cart()[$('[itemscope] [itemprop="name"]').text().trim()]) {
- $(".item-remove-from-cart").removeClass("hide");
- } else {
- $(".item-add-to-cart").removeClass("hide");
- }
-
- $("button.item-add-to-cart").on("click", function() {
- wn.cart.add_to_cart({
- url: window.location.href,
- image: $('[itemscope] [itemprop="image"]').attr("src"),
- item_code: $('[itemscope] [itemprop="name"]').text().trim(),
- item_name: $('[itemscope] [itemprop="productID"]').text().trim(),
- description: $('[itemscope] [itemprop="description"]').html().trim(),
- price: $('[itemscope] [itemprop="price"]').text().trim()
+ $("#item-add-to-cart button").on("click", function() {
+ wn.cart.update_cart({
+ item_code: item_code,
+ qty: 1,
+ callback: function(r) {
+ if(!r.exc) {
+ toggle_update_cart(1);
+ qty = 1;
+ }
+ },
+ btn: this,
});
- $(".item-add-to-cart").addClass("hide");
- $(".item-remove-from-cart").removeClass("hide");
});
- $("button.item-remove-from-cart").on("click", function() {
- wn.cart.remove_from_cart($('[itemscope] [itemprop="name"]').text().trim());
- $(".item-add-to-cart").removeClass("hide");
- $(".item-remove-from-cart").addClass("hide");
+ $("#item-update-cart button").on("click", function() {
+ wn.cart.update_cart({
+ item_code: item_code,
+ qty: $("#item-update-cart input").val(),
+ btn: this,
+ callback: function(r) {
+ if(r.exc) {
+ $("#item-update-cart input").val(qty);
+ } else {
+ qty = $("#item-update-cart input").val();
+ }
+ },
+ });
});
-})
\ No newline at end of file
+
+ if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) {
+ localStorage.removeItem("pending_add_to_cart");
+ $("#item-add-to-cart button").trigger("click");
+ }
+});
+
+var toggle_update_cart = function(qty) {
+ $("#item-add-to-cart").toggle(qty ? false : true);
+ $("#item-update-cart")
+ .toggle(qty ? true : false)
+ .find("input").val(qty);
+}
\ No newline at end of file
diff --git a/website/templates/pages/cart.html b/website/templates/pages/cart.html
index 31d5084..ada1577 100644
--- a/website/templates/pages/cart.html
+++ b/website/templates/pages/cart.html
@@ -9,9 +9,21 @@
{% block content %}
<div class="col col-lg-12">
<h2>Shopping Cart</h2>
- <hr>
- <div id="cart-added-items">
- <!-- list of items in the cart will be generated using javascript -->
+ <div class="progress progress-striped active">
+ <div class="progress-bar progress-bar-info" style="width: 100%;"></div>
+ </div>
+ <div id="cart-container" class="hide">
+ <button class="btn btn-success pull-right" type="button">Place Order</button>
+ <div class="clearfix"></div>
+ <hr>
+ <div id="cart-items">
+ </div>
+ <hr>
+ <div id="cart-taxes">
+ </div>
+ <div id="cart-addresses">
+ </div>
+ <button class="btn btn-success pull-right" type="button">Place Order</button>
</div>
</div>
{% endblock %}
\ No newline at end of file