From 2ac0a83bd8bb923a7fca4fd4fb53a7f9755fa86d Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Wed, 10 Jul 2013 20:49:44 +0530 Subject: [PATCH] [webshop] Place Order - submits Quotation, creates Customer if required, creates and submits Sales Order --- config.json | 3 +- public/js/website_utils.js | 10 + selling/doctype/customer/customer.py | 11 +- selling/doctype/lead/lead.py | 5 +- selling/doctype/quotation/quotation.py | 42 +++- selling/doctype/sales_order/sales_order.py | 3 +- startup/event_handlers.py | 10 +- startup/{website.py => webutils.py} | 26 ++- stock/doctype/stock_entry/stock_entry.py | 17 +- utilities/transaction_base.py | 198 ++++++++---------- website/css/website.css | 4 + .../shopping_cart_settings.txt | 56 +++-- website/helpers/cart.py | 75 ++++++- website/templates/html/outer.html | 2 + website/templates/html/product_page.html | 2 +- website/templates/js/cart.js | 29 ++- website/templates/pages/address.html | 8 - website/templates/pages/cart.html | 5 +- website/templates/pages/profile.html | 49 +++-- 19 files changed, 382 insertions(+), 173 deletions(-) rename startup/{website.py => webutils.py} (69%) diff --git a/config.json b/config.json index 5f9ac5e808..bdc874856f 100644 --- a/config.json +++ b/config.json @@ -134,7 +134,8 @@ }, "profile": { "no_cache": true, - "template": "app/website/templates/pages/profile" + "template": "app/website/templates/pages/profile", + "args_method": "startup.webutils.get_profile_args" }, "cart": { "no_cache": true, diff --git a/public/js/website_utils.js b/public/js/website_utils.js index e714514e97..519d630435 100644 --- a/public/js/website_utils.js +++ b/public/js/website_utils.js @@ -95,6 +95,8 @@ $(document).ready(function() { $("#user-full-name").text(full_name); } + wn.cart.set_cart_count(); + $("#user-tools a").tooltip({"placement":"bottom"}); $("#user-tools-post-login a").tooltip({"placement":"bottom"}); }); @@ -212,8 +214,16 @@ $.extend(wn.cart, { callback: function(r) { if(opts.callback) opts.callback(r); + + wn.cart.set_cart_count(); } }); } }, + + set_cart_count: function() { + var cart_count = getCookie("cart_count"); + if(cart_count) + $(".cart-count").html("( "+ cart_count +" )") + } }); \ No newline at end of file diff --git a/selling/doctype/customer/customer.py b/selling/doctype/customer/customer.py index 83c10a5452..e7d46d2405 100644 --- a/selling/doctype/customer/customer.py +++ b/selling/doctype/customer/customer.py @@ -132,8 +132,15 @@ class DocType(TransactionBase): self.doc.name, raise_exception=1) def delete_customer_address(self): - for rec in sql("select * from `tabAddress` where customer=%s", (self.doc.name,), as_dict=1): - sql("delete from `tabAddress` where name=%s", (rec['name'])) + addresses = webnotes.conn.sql("""select name, lead from `tabAddress` + where customer=%s""", (self.doc.name,)) + + for name, lead in addresses: + if lead: + webnotes.conn.sql("""update `tabAddress` set customer=null, customer_name=null + where name=%s""", name) + else: + webnotes.conn.sql("""delete from `tabAddress` where name=%s""", name) def delete_customer_contact(self): for rec in sql("select * from `tabContact` where customer=%s", (self.doc.name,), as_dict=1): diff --git a/selling/doctype/lead/lead.py b/selling/doctype/lead/lead.py index a97611e394..79b296b401 100644 --- a/selling/doctype/lead/lead.py +++ b/selling/doctype/lead/lead.py @@ -99,6 +99,9 @@ class DocType(SellingController): @webnotes.whitelist() def make_customer(source_name, target_doclist=None): + _make_customer(source_name, target_doclist) + +def _make_customer(source_name, target_doclist=None, ignore_permissions=False): from webnotes.model.mapper import get_mapped_doclist def set_missing_values(source, target): @@ -120,7 +123,7 @@ def make_customer(source_name, target_doclist=None): "contact_no": "phone_1", "fax": "fax_1" } - }}, target_doclist, set_missing_values) + }}, target_doclist, set_missing_values, ignore_permissions=ignore_permissions) return [d.fields for d in doclist] diff --git a/selling/doctype/quotation/quotation.py b/selling/doctype/quotation/quotation.py index 3f0974ed0c..9792aced90 100644 --- a/selling/doctype/quotation/quotation.py +++ b/selling/doctype/quotation/quotation.py @@ -230,8 +230,18 @@ class DocType(SellingController): @webnotes.whitelist() def make_sales_order(source_name, target_doclist=None): + return _make_sales_order(source_name, target_doclist) + +def _make_sales_order(source_name, target_doclist=None, ignore_permissions=False): from webnotes.model.mapper import get_mapped_doclist - + + customer = _make_customer(source_name, ignore_permissions) + + def set_missing_values(source, target): + if customer: + target[0].customer = customer.doc.name + target[0].customer_name = customer.doc.customer_name + doclist = get_mapped_doclist("Quotation", source_name, { "Quotation": { "doctype": "Sales Order", @@ -255,8 +265,34 @@ def make_sales_order(source_name, target_doclist=None): "Sales Team": { "doctype": "Sales Team", } - }, target_doclist) + }, target_doclist, set_missing_values, ignore_permissions=ignore_permissions) # postprocess: fetch shipping address, set missing values - return [d.fields for d in doclist] \ No newline at end of file + return [d.fields for d in doclist] + +def _make_customer(source_name, ignore_permissions=False): + quotation = webnotes.conn.get_value("Quotation", source_name, ["lead", "order_type"]) + if quotation and quotation[0]: + lead_name = quotation[0] + customer_name = webnotes.conn.get_value("Customer", {"lead_name": lead_name}) + if not customer_name: + from selling.doctype.lead.lead import _make_customer + customer_doclist = _make_customer(lead_name, ignore_permissions=ignore_permissions) + customer = webnotes.bean(customer_doclist) + customer.ignore_permissions = ignore_permissions + if quotation[1] == "Shopping Cart": + customer.doc.customer_group = webnotes.conn.get_value("Shopping Cart Settings", None, + "default_customer_group") + + try: + customer.insert() + return customer + except NameError, e: + if webnotes.defaults.get_global_default('cust_master_name') == "Customer Name": + customer.run_method("autoname") + customer.doc.name += "-" + lead_name + customer.insert() + return customer + else: + raise e \ No newline at end of file diff --git a/selling/doctype/sales_order/sales_order.py b/selling/doctype/sales_order/sales_order.py index 2761f7eea8..a65490b80b 100644 --- a/selling/doctype/sales_order/sales_order.py +++ b/selling/doctype/sales_order/sales_order.py @@ -319,7 +319,7 @@ def get_orders(): # find customer id customer = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user}, "customer") - + if customer: orders = webnotes.conn.sql("""select name, creation, currency from `tabSales Order` @@ -334,6 +334,7 @@ def get_orders(): from `tabSales Order Item` where parent=%s order by idx""", order.name, as_dict=1) + return orders else: return [] diff --git a/startup/event_handlers.py b/startup/event_handlers.py index f0c73a542b..cd5cebff99 100644 --- a/startup/event_handlers.py +++ b/startup/event_handlers.py @@ -6,7 +6,6 @@ from __future__ import unicode_literals import webnotes import home - def on_login_post_session(login_manager): """ called after login @@ -30,7 +29,14 @@ def on_login_post_session(login_manager): '%s logged in at %s' % (get_user_fullname(login_manager.user), nowtime()), login_manager.user=='Administrator' and '#8CA2B3' or '#1B750D') webnotes.conn.commit() - + + if webnotes.cookies.get("full_name"): + from website.helpers.cart import set_cart_count + set_cart_count() + +def on_logout(login_manager): + webnotes.add_cookies["cart_count"] = "" + def check_if_expired(): """check if account is expired. If expired, do not allow login""" import conf diff --git a/startup/website.py b/startup/webutils.py similarity index 69% rename from startup/website.py rename to startup/webutils.py index dfaba02847..4c1f5283e1 100644 --- a/startup/website.py +++ b/startup/webutils.py @@ -62,6 +62,30 @@ def update_template_args(page_name, args): args.url = quote(str(get_request_site_address(full_address=True)), str("")) args.encoded_title = quote(encode(args.title or ""), str("")) + args.shopping_cart_enabled = cint(webnotes.conn.get_default("shopping_cart_enabled")) return args - \ No newline at end of file + +@webnotes.whitelist() +def update_profile(fullname, password=None, company_name=None, mobile_no=None, phone=None): + from website.helpers.cart import update_party + update_party(fullname, company_name, mobile_no, phone) + + from core.doctype.profile import profile + return profile.update_profile(fullname, password) + +def get_profile_args(): + from website.helpers.cart import get_lead_or_customer + party = get_lead_or_customer() + if party.doctype == "Lead": + mobile_no = party.mobile_no + phone = party.phone + else: + mobile_no, phone = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user, + "customer": party.name}) + + return { + "company_name": party.customer_name if party.doctype == "Customer" else party.company_name, + "mobile_no": mobile_no, + "phone": phone + } \ No newline at end of file diff --git a/stock/doctype/stock_entry/stock_entry.py b/stock/doctype/stock_entry/stock_entry.py index c8babffad9..2595f9b656 100644 --- a/stock/doctype/stock_entry/stock_entry.py +++ b/stock/doctype/stock_entry/stock_entry.py @@ -664,11 +664,15 @@ class DocType(StockController): return result and result[0] or {} def get_cust_addr(self): + from utilities.transaction_base import get_default_address, get_address_display res = sql("select customer_name from `tabCustomer` where name = '%s'"%self.doc.customer) - addr = self.get_address_text(customer = self.doc.customer) + address_display = None + customer_address = get_default_address("customer", self.doc.customer) + if customer_address: + address_display = get_address_display(customer_address) ret = { 'customer_name' : res and res[0][0] or '', - 'customer_address' : addr and addr[0] or ''} + 'customer_address' : address_display} return ret @@ -681,12 +685,17 @@ class DocType(StockController): return result and result[0] or {} def get_supp_addr(self): + from utilities.transaction_base import get_default_address, get_address_display res = sql("""select supplier_name from `tabSupplier` where name=%s""", self.doc.supplier) - addr = self.get_address_text(supplier = self.doc.supplier) + address_display = None + supplier_address = get_default_address("customer", self.doc.customer) + if supplier_address: + address_display = get_address_display(supplier_address) + ret = { 'supplier_name' : res and res[0][0] or '', - 'supplier_address' : addr and addr[0] or ''} + 'supplier_address' : address_display } return ret def validate_with_material_request(self): diff --git a/utilities/transaction_base.py b/utilities/transaction_base.py index 30a40da7ba..a268564a9b 100644 --- a/utilities/transaction_base.py +++ b/utilities/transaction_base.py @@ -32,6 +32,41 @@ class TransactionBase(StatusUpdater): return get_default_address_and_contact(party_field, party_name, fetch_shipping_address=True if self.meta.get_field("shipping_address_name") else False) + def set_address_fields(self): + party_type, party_name = self.get_party_type_and_name() + + if party_type in ("Customer", "Lead"): + if self.doc.customer_address: + self.doc.address_display = get_address_display(self.doc.customer_address) + + if self.doc.shipping_address_name: + self.doc.shipping_address = get_address_display(self.doc.shipping_address_name) + + elif self.doc.supplier_address: + self.doc.address_display = get_address_display(self.doc.supplier_address) + + def set_contact_fields(self): + party_type, party_name = self.get_party_type_and_name() + + if party_type == "Lead": + contact_dict = map_lead_contact_details(party_name) + else: + contact_dict = map_party_contact_details(self.doc.contact_person, party_type, party_name) + + for fieldname, value in contact_dict.items(): + if self.meta.get_field(fieldname): + self.doc.fields[fieldname] = value + + def get_party_type_and_name(self): + if not hasattr(self, "_party_type_and_name"): + for party_type in ("Lead", "Customer", "Supplier"): + party_field = party_type.lower() + if self.meta.get_field(party_field) and self.doc.fields.get(party_field): + self._party_type_and_name = (party_type, self.doc.fields.get(party_field)) + break + + return self._party_type_and_name + def get_customer_defaults(self): out = self.get_default_address_and_contact("customer") @@ -53,12 +88,7 @@ class TransactionBase(StatusUpdater): 3. Clears existing Sales Team and fetches the one mentioned in Customer """ customer_defaults = self.get_customer_defaults() - - # hack! TODO - add shipping_address_field in Delivery Note - if self.doc.doctype == "Delivery Note": - customer_defaults["customer_address"] = customer_defaults["shipping_address_name"] - customer_defaults["address_display"] = customer_defaults["shipping_address"] - + customer_defaults["price_list"] = customer_defaults["price_list"] or \ webnotes.conn.get_value("Customer Group", self.doc.customer_group, "default_price_list") or \ self.doc.price_list @@ -110,91 +140,35 @@ class TransactionBase(StatusUpdater): # ----------------------- def get_customer_address(self, args): args = load_json(args) - address_text, address_name = self.get_address_text(address_name=args['address']) ret = { - 'customer_address' : address_name, - 'address_display' : address_text, + 'customer_address' : args["address"], + 'address_display' : get_address_display(args["address"]), } - ret.update(self.get_contact_text(contact_name=args['contact'])) - - return ret - - # Get Address Text - # ----------------------- - def get_address_text(self, customer=None, address_name=None, supplier=None, is_shipping_address=None): - if customer: - cond = customer and 'customer="%s"' % customer or 'name="%s"' % address_name - elif supplier: - cond = supplier and 'supplier="%s"' % supplier or 'name="%s"' % address_name - else: - cond = 'name="%s"' % address_name + ret.update(map_party_contact_details(args['contact'])) - if is_shipping_address: - details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone, fax from `tabAddress` where %s and docstatus != 2 order by is_shipping_address desc, is_primary_address desc limit 1" % cond, as_dict = 1) - else: - details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone, fax from `tabAddress` where %s and docstatus != 2 order by is_primary_address desc limit 1" % cond, as_dict = 1) - - address_display = "" - - if details: - address_display = get_address_display(details[0]) + return ret - address_name = details and details[0]['name'] or '' - - return address_display, address_name - - # Get Contact Text - # ----------------------- - def get_contact_text(self, customer=None, contact_name=None, supplier=None): - if customer: - cond = customer and 'customer="%s"' % customer or 'name="%s"' % contact_name - elif supplier: - cond = supplier and 'supplier="%s"' % supplier or 'name="%s"' % contact_name - else: - cond = 'name="%s"' % contact_name - - details = webnotes.conn.sql("select name, first_name, last_name, email_id, phone, mobile_no, department, designation from `tabContact` where %s and docstatus != 2 order by is_primary_contact desc limit 1" % cond, as_dict = 1) - - extract = lambda x: details and details[0] and details[0].get(x,'') or '' - contact_fields = [('','first_name'),(' ','last_name')] - contact_display = ''.join([a[0]+cstr(extract(a[1])) for a in contact_fields if extract(a[1])]) - if contact_display.startswith('\n'): contact_display = contact_display[1:] - - return { - "contact_display": contact_display, - "contact_person": details and details[0]["name"] or "", - "contact_email": details and details[0]["email_id"] or "", - "contact_mobile": details and details[0]["mobile_no"] or "", - "contact_designation": details and details[0]["designation"] or "", - "contact_department": details and details[0]["department"] or "", - } - # TODO deprecate this - used only in sales_order.js def get_shipping_address(self, name): - details = webnotes.conn.sql("select name, address_line1, address_line2, city, country, pincode, state, phone from `tabAddress` where customer = '%s' and docstatus != 2 order by is_shipping_address desc, is_primary_address desc limit 1" %(name), as_dict = 1) - - address_display = "" - if details: - address_display = get_address_display(details[0]) - - ret = { - 'shipping_address_name' : details and details[0]['name'] or '', - 'shipping_address' : address_display + shipping_address = get_default_address("customer", name, is_shipping_address=True) + return { + 'shipping_address_name' : shipping_address, + 'shipping_address' : get_address_display(shipping_address) if shipping_address else None } - return ret # Get Supplier Default Primary Address - first load # ----------------------- def get_default_supplier_address(self, args): if isinstance(args, basestring): args = load_json(args) - address_text, address_name = self.get_address_text(supplier=args['supplier']) + + address_name = get_default_address("supplier", args["supplier"]) ret = { 'supplier_address' : address_name, - 'address_display' : address_text, + 'address_display' : get_address_display(address_name), } - ret.update(self.get_contact_text(supplier=args['supplier'])) + ret.update(map_party_contact_details(None, "supplier", args["supplier"])) ret.update(self.get_supplier_details(args['supplier'])) return ret @@ -202,12 +176,11 @@ class TransactionBase(StatusUpdater): # ----------------------- def get_supplier_address(self, args): args = load_json(args) - address_text, address_name = self.get_address_text(address_name=args['address']) ret = { - 'supplier_address' : address_name, - 'address_display' : address_text, + 'supplier_address' : args['address'], + 'address_display' : get_address_display(args["address"]), } - ret.update(self.get_contact_text(contact_name=args['contact'])) + ret.update(map_party_contact_details(contact_name=args['contact'])) return ret # Get Supplier Details @@ -317,23 +290,24 @@ class TransactionBase(StatusUpdater): [d[0] for d in fields], as_dict=1) for field, condition in fields: - self.validate_value(field, condition, prevdoc_values[field], doc) + if prevdoc_values[field] is not None: + self.validate_value(field, condition, prevdoc_values[field], doc) def get_default_address_and_contact(party_field, party_name, fetch_shipping_address=False): out = {} # get addresses - billing_address = get_address_dict(party_field, party_name) + billing_address = get_default_address(party_field, party_name) if billing_address: - out[party_field + "_address"] = billing_address["name"] + out[party_field + "_address"] = billing_address out["address_display"] = get_address_display(billing_address) else: out[party_field + "_address"] = out["address_display"] = None if fetch_shipping_address: - shipping_address = get_address_dict(party_field, party_name, is_shipping_address=True) + shipping_address = get_default_address(party_field, party_name, is_shipping_address=True) if shipping_address: - out["shipping_address_name"] = shipping_address["name"] + out["shipping_address_name"] = shipping_address out["shipping_address"] = get_address_display(shipping_address) else: out["shipping_address_name"] = out["shipping_address"] = None @@ -341,39 +315,47 @@ def get_default_address_and_contact(party_field, party_name, fetch_shipping_addr # get contact if party_field == "lead": out["customer_address"] = out.get("lead_address") - out.update(map_lead_fields(party_name)) + out.update(map_lead_contact_details(party_name)) else: - out.update(map_contact_fields(party_field, party_name)) + out.update(map_party_contact_details(None, party_field, party_name)) return out - -def get_address_dict(party_field, party_name, is_shipping_address=None): - order_by = "is_shipping_address desc, is_primary_address desc, name asc" if \ - is_shipping_address else "is_primary_address desc, name asc" - - address = webnotes.conn.sql("""select * from `tabAddress` where `%s`=%s order by %s - limit 1""" % (party_field, "%s", order_by), party_name, as_dict=True, - update={"doctype": "Address"}) - return address[0] if address else None - +def get_default_address(party_field, party_name, is_shipping_address=False): + if is_shipping_address: + order_by = "is_shipping_address desc, is_primary_address desc, name asc" + else: + order_by = "is_primary_address desc, name asc" + + address = webnotes.conn.sql("""select name from `tabAddress` where `%s`=%s order by %s + limit 1""" % (party_field, "%s", order_by), party_name) + + return address[0][0] if address else None + +def get_default_contact(party_field, party_name): + contact = webnotes.conn.sql("""select name from `tabContact` where `%s`=%s + order by is_primary_contact desc, name asc limit 1""" % (party_field, "%s"), + (party_name,)) + + return contact[0][0] if contact else None + def get_address_display(address_dict): - def _prepare_for_display(a_dict, sequence): - display = "" - for separator, fieldname in sequence: - if a_dict.get(fieldname): - display += separator + a_dict.get(fieldname) - - return display.strip() + if not isinstance(address_dict, dict): + address_dict = webnotes.conn.get_value("Address", address_dict, "*", as_dict=True) meta = webnotes.get_doctype("Address") - address_sequence = (("", "address_line1"), ("\n", "address_line2"), ("\n", "city"), + sequence = (("", "address_line1"), ("\n", "address_line2"), ("\n", "city"), ("\n", "state"), ("\n" + meta.get_label("pincode") + ": ", "pincode"), ("\n", "country"), ("\n" + meta.get_label("phone") + ": ", "phone"), ("\n" + meta.get_label("fax") + ": ", "fax")) - return _prepare_for_display(address_dict, address_sequence) + display = "" + for separator, fieldname in sequence: + if address_dict.get(fieldname): + display += separator + address_dict.get(fieldname) + + return display.strip() -def map_lead_fields(party_name): +def map_lead_contact_details(party_name): out = {} for fieldname in ["contact_display", "contact_email", "contact_mobile", "contact_phone"]: out[fieldname] = None @@ -390,15 +372,19 @@ def map_lead_fields(party_name): return out -def map_contact_fields(party_field, party_name): +def map_party_contact_details(contact_name=None, party_field=None, party_name=None): out = {} for fieldname in ["contact_person", "contact_display", "contact_email", "contact_mobile", "contact_phone", "contact_designation", "contact_department"]: out[fieldname] = None + if not contact_name: + contact_name = get_default_contact(party_field, party_name) + contact = webnotes.conn.sql("""select * from `tabContact` where `%s`=%s order by is_primary_contact desc, name asc limit 1""" % (party_field, "%s"), (party_name,), as_dict=True) + if contact: contact = contact[0] out.update({ diff --git a/website/css/website.css b/website/css/website.css index 816b3efd9d..64cff7f973 100644 --- a/website/css/website.css +++ b/website/css/website.css @@ -136,6 +136,10 @@ img { padding-left: 10px; } +fieldset { + margin-bottom: 20px; +} + /* buttons */ .btn-default { color: #ffffff; diff --git a/website/doctype/shopping_cart_settings/shopping_cart_settings.txt b/website/doctype/shopping_cart_settings/shopping_cart_settings.txt index 8cb148041a..7455864141 100644 --- a/website/doctype/shopping_cart_settings/shopping_cart_settings.txt +++ b/website/doctype/shopping_cart_settings/shopping_cart_settings.txt @@ -2,7 +2,7 @@ { "creation": "2013-06-19 15:57:32", "docstatus": 0, - "modified": "2013-07-05 14:55:05", + "modified": "2013-07-10 18:42:29", "modified_by": "Administrator", "owner": "Administrator" }, @@ -44,6 +44,19 @@ "fieldtype": "Check", "label": "Enable Shopping Cart" }, + { + "doctype": "DocField", + "fieldname": "section_break_2", + "fieldtype": "Section Break" + }, + { + "doctype": "DocField", + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "reqd": 1 + }, { "doctype": "DocField", "fieldname": "default_territory", @@ -52,6 +65,24 @@ "options": "Territory", "reqd": 1 }, + { + "doctype": "DocField", + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "doctype": "DocField", + "fieldname": "default_customer_group", + "fieldtype": "Link", + "label": "Default Customer Group", + "options": "Customer Group", + "reqd": 1 + }, + { + "doctype": "DocField", + "fieldname": "section_break_6", + "fieldtype": "Section Break" + }, { "doctype": "DocField", "fieldname": "price_lists", @@ -60,14 +91,6 @@ "options": "Shopping Cart Price List", "reqd": 0 }, - { - "doctype": "DocField", - "fieldname": "sales_taxes_and_charges_masters", - "fieldtype": "Table", - "label": "Shopping Cart Taxes and Charges Masters", - "options": "Shopping Cart Taxes and Charges Master", - "reqd": 0 - }, { "doctype": "DocField", "fieldname": "shipping_rules", @@ -78,11 +101,16 @@ }, { "doctype": "DocField", - "fieldname": "company", - "fieldtype": "Link", - "label": "Company", - "options": "Company", - "reqd": 1 + "fieldname": "column_break_10", + "fieldtype": "Column Break" + }, + { + "doctype": "DocField", + "fieldname": "sales_taxes_and_charges_masters", + "fieldtype": "Table", + "label": "Shopping Cart Taxes and Charges Masters", + "options": "Shopping Cart Taxes and Charges Master", + "reqd": 0 }, { "doctype": "DocPerm" diff --git a/website/helpers/cart.py b/website/helpers/cart.py index d4ab64dea5..ea72e40ff0 100644 --- a/website/helpers/cart.py +++ b/website/helpers/cart.py @@ -3,17 +3,26 @@ from __future__ import unicode_literals import webnotes +from webnotes import msgprint, _ import webnotes.defaults -from webnotes.utils import flt, get_fullname, fmt_money +from webnotes.utils import flt, get_fullname, fmt_money, cstr class WebsitePriceListMissingError(webnotes.ValidationError): pass +def set_cart_count(quotation=None): + if not quotation: + quotation = _get_cart_quotation() + webnotes.add_cookies["cart_count"] = cstr(len(quotation.doclist.get( + {"parentfield": "quotation_details"})) or "") + @webnotes.whitelist() def get_cart_quotation(doclist=None): party = get_lead_or_customer() if not doclist: - doclist = _get_cart_quotation(party).doclist + quotation = _get_cart_quotation(party) + doclist = quotation.doclist + set_cart_count(quotation) return { "doclist": decorate_quotation_doclist(doclist), @@ -21,6 +30,26 @@ def get_cart_quotation(doclist=None): for address in get_address_docs(party)], "shipping_rules": get_applicable_shipping_rules(party) } + +@webnotes.whitelist() +def place_order(): + quotation = _get_cart_quotation() + controller = quotation.make_controller() + for fieldname in ["customer_address", "shipping_address_name"]: + if not quotation.doc.fields.get(fieldname): + msgprint(_("Please select a") + " " + _(controller.meta.get_label(fieldname)), raise_exception=True) + + quotation.ignore_permissions = True + quotation.submit() + + from selling.doctype.quotation.quotation import _make_sales_order + sales_order = webnotes.bean(_make_sales_order(quotation.doc.name, ignore_permissions=True)) + sales_order.ignore_permissions = True + sales_order.insert() + sales_order.submit() + webnotes.add_cookies["cart_count"] = "" + + return sales_order.doc.name @webnotes.whitelist() def update_cart(item_code, qty, with_doclist=0): @@ -46,6 +75,8 @@ def update_cart(item_code, qty, with_doclist=0): quotation.ignore_permissions = True quotation.save() + set_cart_count(quotation) + if with_doclist: return get_cart_quotation(quotation.doclist) else: @@ -192,11 +223,47 @@ def _get_cart_quotation(party=None): "__islocal": 1, (party.doctype.lower()): party.name }) + + # map_contact_fields(qbean, party) + qbean.run_method("onload_post_render") apply_cart_settings(party, qbean) return qbean + +def update_party(fullname, company_name=None, mobile_no=None, phone=None): + party = get_lead_or_customer() + + if party.doctype == "Lead": + party.company_name = company_name + party.lead_name = fullname + party.mobile_no = mobile_no + party.phone = phone + else: + party.customer_name = company_name or fullname + party.customer_type == "Company" if company_name else "Individual" + + contact_name = webnotes.conn.get_value("Contact", {"email_id": webnotes.session.user, + "customer": party.name}) + contact = webnotes.bean("Contact", contact_name) + contact.doc.first_name = fullname + contact.doc.last_name = None + contact.doc.customer_name = party.customer_name + contact.doc.mobile_no = mobile_no + contact.doc.phone = phone + contact.ignore_permissions = True + contact.save() + party_bean = webnotes.bean(party.fields) + party_bean.ignore_permissions = True + party_bean.save() + + qbean = _get_cart_quotation(party) + qbean.doc.customer_name = company_name or fullname + qbean.run_method("set_contact_fields") + qbean.ignore_permissions = True + qbean.save() + def apply_cart_settings(party=None, quotation=None): if not party: party = get_lead_or_customer() @@ -237,8 +304,8 @@ def set_taxes(quotation, cart_settings, billing_territory): quotation.doc.charge = cart_settings.get_tax_master(billing_territory) # clear table - quotation.doclist = quotation.doc.clear_table(quotation.doclist, "other_charges") - + quotation.set_doclist(quotation.doclist.get({"parentfield": ["!=", "other_charges"]})) + # append taxes controller = quotation.make_controller() controller.append_taxes_from_master("other_charges", "charge") diff --git a/website/templates/html/outer.html b/website/templates/html/outer.html index cc1181cbd2..0102acd0ca 100644 --- a/website/templates/html/outer.html +++ b/website/templates/html/outer.html @@ -10,8 +10,10 @@
| My Account | + {% if shopping_cart_enabled -%} | + {%- endif %}
diff --git a/website/templates/html/product_page.html b/website/templates/html/product_page.html index b3e8be2f87..73520ef643 100644 --- a/website/templates/html/product_page.html +++ b/website/templates/html/product_page.html @@ -32,7 +32,7 @@

Item Code: {{ name }}

Product Description

- {{ web_long_description or web_short_description or + {{ web_long_description or web_short_description or description or "[No description given]" }}
diff --git a/website/templates/js/cart.js b/website/templates/js/cart.js index 27f604f976..bb3fcb96f3 100644 --- a/website/templates/js/cart.js +++ b/website/templates/js/cart.js @@ -17,8 +17,6 @@ // js inside blog page $(document).ready(function() { - // make list of items in the cart - // wn.cart.render(); wn.cart.bind_events(); wn.call({ type: "POST", @@ -36,6 +34,7 @@ $(document).ready(function() { wn.cart.show_error("Oops!", "Something went wrong."); } } else { + wn.cart.set_cart_count(); wn.cart.render(r.message); } } @@ -75,6 +74,10 @@ $.extend(wn.cart, { $("#cart-add-billing-address").on("click", function() { window.location.href = "address?address_fieldname=customer_address"; }); + + $(".btn-place-order").on("click", function() { + wn.cart.place_order(); + }); }, render: function(out) { @@ -282,5 +285,27 @@ $.extend(wn.cart, { $address_wrapper.find('.accordion-body[data-address-name="'+ address_name +'"]') .collapse("show"); + }, + + place_order: function() { + wn.call({ + type: "POST", + method: "website.helpers.cart.place_order", + callback: function(r) { + if(r.exc) { + var msg = ""; + if(r._server_messages) { + msg = JSON.parse(r._server_messages || []).join("
"); + } + + $("#cart-error") + .empty() + .html(msg || "Something went wrong!") + .toggle(true); + } else { + window.location.href = "order?name=" + encodeURIComponent(r.message); + } + } + }); } }); \ No newline at end of file diff --git a/website/templates/pages/address.html b/website/templates/pages/address.html index 5b90928164..cf1fc4b760 100644 --- a/website/templates/pages/address.html +++ b/website/templates/pages/address.html @@ -112,12 +112,4 @@ }; })(); -{% endblock %} - -{% block css %} - {% endblock %} \ No newline at end of file diff --git a/website/templates/pages/cart.html b/website/templates/pages/cart.html index cefcb5afa7..5bfca33363 100644 --- a/website/templates/pages/cart.html +++ b/website/templates/pages/cart.html @@ -13,8 +13,9 @@
- +
+
@@ -50,7 +51,7 @@

- +
{% endblock %} \ No newline at end of file diff --git a/website/templates/pages/profile.html b/website/templates/pages/profile.html index 993839eb79..61ae1b0d53 100644 --- a/website/templates/pages/profile.html +++ b/website/templates/pages/profile.html @@ -12,24 +12,28 @@

My Profile


-
-
- -
- -
-
-
- -
- -
-
-
-
- -
-
+ +
+ + +
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+
-{% endblock %} +{% endblock %} \ No newline at end of file