[website] [minor] moving to framework
diff --git a/accounts/doctype/sales_invoice/sales_invoice.py b/accounts/doctype/sales_invoice/sales_invoice.py
index 17ae216..879ccaf 100644
--- a/accounts/doctype/sales_invoice/sales_invoice.py
+++ b/accounts/doctype/sales_invoice/sales_invoice.py
@@ -148,6 +148,9 @@
 		self.validate_recurring_invoice()
 		self.convert_to_recurring()
 		
+	def get_portal_page(self):
+		return "invoice" if self.doc.docstatus==1 else None
+		
 	def set_missing_values(self, for_validate=False):
 		self.set_pos_fields(for_validate)
 		
diff --git a/accounts/doctype/sales_invoice/templates/__init__.py b/accounts/doctype/sales_invoice/templates/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/accounts/doctype/sales_invoice/templates/__init__.py
diff --git a/accounts/doctype/sales_invoice/templates/pages/__init__.py b/accounts/doctype/sales_invoice/templates/pages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/accounts/doctype/sales_invoice/templates/pages/__init__.py
diff --git a/portal/templates/pages/invoice.html b/accounts/doctype/sales_invoice/templates/pages/invoice.html
similarity index 100%
rename from portal/templates/pages/invoice.html
rename to accounts/doctype/sales_invoice/templates/pages/invoice.html
diff --git a/portal/templates/pages/invoice.py b/accounts/doctype/sales_invoice/templates/pages/invoice.py
similarity index 95%
rename from portal/templates/pages/invoice.py
rename to accounts/doctype/sales_invoice/templates/pages/invoice.py
index ed6e40a..7196a30 100644
--- a/portal/templates/pages/invoice.py
+++ b/accounts/doctype/sales_invoice/templates/pages/invoice.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_transaction_context
 	context = get_transaction_context("Sales Invoice", webnotes.form_dict.name)
diff --git a/portal/templates/pages/invoices.html b/accounts/doctype/sales_invoice/templates/pages/invoices.html
similarity index 100%
rename from portal/templates/pages/invoices.html
rename to accounts/doctype/sales_invoice/templates/pages/invoices.html
diff --git a/portal/templates/pages/invoices.py b/accounts/doctype/sales_invoice/templates/pages/invoices.py
similarity index 97%
rename from portal/templates/pages/invoices.py
rename to accounts/doctype/sales_invoice/templates/pages/invoices.py
index 2bb6490..c72903b 100644
--- a/portal/templates/pages/invoices.py
+++ b/accounts/doctype/sales_invoice/templates/pages/invoices.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_currency_context
 	context = get_currency_context()
diff --git a/config.json b/config.json
index 3f58511..17b01ed 100644
--- a/config.json
+++ b/config.json
@@ -72,111 +72,5 @@
 			"label": "Notes",
 			"icon": "icon-file-alt"
 		}
-	},
-	"web": {
-		"pages": {
-			"account": {
-				"no_cache": true,
-				"template": "app/portal/templates/account.html"
-			},
-			"order": {
-				"no_cache": true,
-				"template": "app/portal/templates/sale.html",
-				"args_method": "utilities.website_transactions.get_order_args",
-				"portal": {
-					"doctype": "Sales Order",
-					"conditions": {
-						"docstatus": 1
-					}
-				}
-			},
-			"orders": {
-				"no_cache": true,
-				"template": "app/portal/templates/sales_transactions.html",
-				"args_method": "utilities.website_transactions.order_list_args"
-			},
-			"invoice": {
-				"no_cache": true,
-				"template": "app/portal/templates/sale.html",
-				"args_method": "utilities.website_transactions.get_invoice_args",
-				"portal": {
-					"doctype": "Sales Invoice",
-					"conditions": {
-						"docstatus": 1
-					}
-				}
-			},
-			"invoices": {
-				"no_cache": true,
-				"template": "app/portal/templates/sales_transactions.html",
-				"args_method": "utilities.website_transactions.invoice_list_args"
-			},
-			"shipment": {
-				"no_cache": true,
-				"template": "app/portal/templates/sale.html",
-				"args_method": "utilities.website_transactions.get_shipment_args",
-				"portal": {
-					"doctype": "Delivery Note",
-					"conditions": {
-						"docstatus": 1
-					}
-				}
-			},
-			"shipments": {
-				"no_cache": true,
-				"template": "app/portal/templates/sales_transactions.html",
-				"args_method": "utilities.website_transactions.shipment_list_args"
-			},
-			"product_search": {
-				"template": "app/stock/doctype/item/templates/product_search.html"
-			},
-			"ticket": {
-				"no_cache": true,
-				"template": "app/support/doctype/support_ticket/templates/ticket.html",
-				"args_method": "support.doctype.support_ticket.support_ticket.get_website_args",
-				"portal": {
-					"doctype": "Support Ticket"
-				}
-			},
-			"tickets": {
-				"template": "app/support/doctype/support_ticket/templates/tickets.html",
-				"args_method": "utilities.website_transactions.ticket_list_args"
-			},
-			"address": {
-				"no_cache": true,
-				"template": "app/utilities/doctype/address/templates/address.html",
-				"args_method": "utilities.doctype.address.address.get_website_args"
-			},
-			"addresses": {
-				"template": "app/utilities/doctype/address/templates/addresses.html"
-			},
-			"profile": {
-				"no_cache": true,
-				"template": "app/portal/templates/profile.html",
-				"args_method": "startup.webutils.get_profile_args"
-			},
-			"cart": {
-				"no_cache": true,
-				"template": "app/portal/templates/cart.html"
-			},
-			"partners": {
-				"template": "app/setup/doctype/sales_partners/templates/partners.html",
-				"args_method": "setup.doctype.sales_partner.sales_partner.get_partner_args"
-			}
-		},
-		"generators": {
-			"Item": {
-				"template": "app/stock/doctype/item/templates/item.html",
-				"condition_field": "show_in_website"
-			},
-			"Item Group":{
-				"template": "app/setup/doctype/item_group/templates/item_group.html",
-				"condition_field": "show_in_website"
-			},
-			"Sales Partner": {
-				"template": "app/setup/doctype/sales_partner/templates/partner_page.html",
-				"condition_field": "show_in_website"
-			}
-		}
 	}
 }
\ No newline at end of file
diff --git a/portal/templates/includes/cart.js b/portal/templates/includes/cart.js
index 63c6463..84d49f3 100644
--- a/portal/templates/includes/cart.js
+++ b/portal/templates/includes/cart.js
@@ -128,7 +128,7 @@
 	render_item_row: function($cart_items, doc) {
 		doc.image_html = doc.image ?
 			'<div style="height: 120px; overflow: hidden;"><img src="' + doc.image + '" /></div>' :
-			'{% include "app/website/templates/html/product_missing_image.html" %}';
+			'{% include "app/stock/doctype/item/templates/includes/product_missing_image.html" %}';
 			
 		if(doc.description === doc.item_name) doc.description = "";
 		
diff --git a/portal/templates/pages/account.py b/portal/templates/pages/account.py
new file mode 100644
index 0000000..24b474a
--- /dev/null
+++ b/portal/templates/pages/account.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+no_cache = True
\ No newline at end of file
diff --git a/portal/templates/pages/cart.html b/portal/templates/pages/cart.html
index 372f524..f210772 100644
--- a/portal/templates/pages/cart.html
+++ b/portal/templates/pages/cart.html
@@ -1,7 +1,7 @@
 {% extends base_template %}
 
 {% block javascript %}
-	{% include "app/website/templates/js/cart.js" %}
+<script>{% include "app/portal/templates/includes/cart.js" %}</script>
 {% endblock %}
 
 {% set title="Shopping Cart" %}
diff --git a/portal/templates/pages/cart.py b/portal/templates/pages/cart.py
new file mode 100644
index 0000000..24b474a
--- /dev/null
+++ b/portal/templates/pages/cart.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+no_cache = True
\ No newline at end of file
diff --git a/portal/templates/pages/profile.html b/portal/templates/pages/profile.html
index 2fe03ba..65f3e37 100644
--- a/portal/templates/pages/profile.html
+++ b/portal/templates/pages/profile.html
@@ -9,7 +9,7 @@
     	<li><a href="account">My Account</a></li>
     	<li class="active"><i class="icon-user icon-fixed-width"></i> My Profile</li>
     </ul>
-	<div class="alert" id="message" style="display: none;"></div>
+	<div class="alert alert-warning" id="message" style="display: none;"></div>
 	<form>
 		<fieldset>
 			<label>Full Name</label>
@@ -39,7 +39,7 @@
 	$("#fullname").val(getCookie("full_name") || "");
 	$("#update_profile").click(function() {
 		wn.call({
-			method: "startup.webutils.update_profile",
+			method: "portal.templates.pages.profile.update_profile",
 			type: "POST",
 			args: {
 				fullname: $("#fullname").val(),
diff --git a/portal/templates/pages/profile.py b/portal/templates/pages/profile.py
new file mode 100644
index 0000000..b7be74c
--- /dev/null
+++ b/portal/templates/pages/profile.py
@@ -0,0 +1,32 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+import webnotes
+from webnotes.utils import cstr
+
+no_cache = True
+
+def get_context():
+	from selling.utils.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}, ["mobile_no", "phone"])
+		
+	return {
+		"company_name": cstr(party.customer_name if party.doctype == "Customer" else party.company_name),
+		"mobile_no": cstr(mobile_no),
+		"phone": cstr(phone)
+	}
+	
+@webnotes.whitelist()
+def update_profile(fullname, password=None, company_name=None, mobile_no=None, phone=None):
+	from selling.utils.cart import update_party
+	update_party(fullname, company_name, mobile_no, phone)
+	
+	from core.doctype.profile import profile
+	return profile.update_profile(fullname, password)
\ No newline at end of file
diff --git a/portal/templates/profile.html b/portal/templates/profile.html
deleted file mode 100644
index e8e60b4..0000000
--- a/portal/templates/profile.html
+++ /dev/null
@@ -1,61 +0,0 @@
-{% extends base_template %}
-
-{% set title="My Profile" %}
-
-{% block content %}
-<div class="col-md-12">
-    <ul class="breadcrumb">
-    	<li><a href="index">Home</a></li>
-    	<li><a href="account">My Account</a></li>
-    	<li class="active"><i class="icon-user icon-fixed-width"></i> My Profile</li>
-    </ul>
-	<div class="alert alert-warning" id="message" style="display: none;"></div>
-	<form>
-		<fieldset>
-			<label>Full Name</label>
-			<input class="form-control" type="text" id="fullname" placeholder="Your Name">
-		</fieldset>
-		<fieldset>
-			<label>Password</label>
-			<input class="form-control" type="password" id="password" placeholder="Password">
-		</fieldset>
-		<fieldset>
-			<label>Company Name</label>
-			<input class="form-control" type="text" id="company_name" placeholder="Company Name" value="{{ company_name }}">
-		</fieldset>
-		<fieldset>
-			<label>Mobile No</label>
-			<input class="form-control" type="text" id="mobile_no" placeholder="Mobile No" value="{{ mobile_no }}">
-		</fieldset>
-		<fieldset>
-			<label>Phone</label>
-			<input class="form-control" type="text" id="phone" placeholder="Phone" value="{{ phone }}">
-		</fieldset>
-		<button id="update_profile" type="submit" class="btn btn-default">Update</button>
-	</form>
-</div>
-<script>
-$(document).ready(function() {
-	$("#fullname").val(getCookie("full_name") || "");
-	$("#update_profile").click(function() {
-		wn.call({
-			method: "startup.webutils.update_profile",
-			type: "POST",
-			args: {
-				fullname: $("#fullname").val(),
-				password: $("#password").val(),
-				company_name: $("#company_name").val(),
-				mobile_no: $("#mobile_no").val(),
-				phone: $("#phone").val()
-			},
-			btn: this,
-			msg: $("#message"),
-			callback: function(r) {
-				if(!r.exc) $("#user-full-name").html($("#fullname").val());
-			}
-		});
-		return false;
-	})
-})
-</script>
-{% endblock %}
\ 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 602674e..3731484 100644
--- a/selling/doctype/sales_order/sales_order.py
+++ b/selling/doctype/sales_order/sales_order.py
@@ -286,6 +286,9 @@
 	def on_update(self):
 		pass
 		
+	def get_portal_page(self):
+		return "order" if self.doc.docstatus==1 else None
+		
 def set_missing_values(source, target):
 	bean = webnotes.bean(target)
 	bean.run_method("onload_post_render")
diff --git a/selling/doctype/sales_order/templates/__init__.py b/selling/doctype/sales_order/templates/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/sales_order/templates/__init__.py
diff --git a/selling/doctype/sales_order/templates/pages/__init__.py b/selling/doctype/sales_order/templates/pages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/sales_order/templates/pages/__init__.py
diff --git a/portal/templates/pages/order.html b/selling/doctype/sales_order/templates/pages/order.html
similarity index 100%
rename from portal/templates/pages/order.html
rename to selling/doctype/sales_order/templates/pages/order.html
diff --git a/portal/templates/pages/order.py b/selling/doctype/sales_order/templates/pages/order.py
similarity index 95%
rename from portal/templates/pages/order.py
rename to selling/doctype/sales_order/templates/pages/order.py
index 47e2c68..f25a521 100644
--- a/portal/templates/pages/order.py
+++ b/selling/doctype/sales_order/templates/pages/order.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_transaction_context
 	context = get_transaction_context("Sales Order", webnotes.form_dict.name)
diff --git a/portal/templates/pages/orders.html b/selling/doctype/sales_order/templates/pages/orders.html
similarity index 100%
rename from portal/templates/pages/orders.html
rename to selling/doctype/sales_order/templates/pages/orders.html
diff --git a/portal/templates/pages/orders.py b/selling/doctype/sales_order/templates/pages/orders.py
similarity index 97%
rename from portal/templates/pages/orders.py
rename to selling/doctype/sales_order/templates/pages/orders.py
index 3c62d35..204e3f7 100644
--- a/portal/templates/pages/orders.py
+++ b/selling/doctype/sales_order/templates/pages/orders.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_currency_context
 	context = get_currency_context()
diff --git a/selling/doctype/shopping_cart_price_list/__init__.py b/selling/doctype/shopping_cart_price_list/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/shopping_cart_price_list/__init__.py
diff --git a/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.py b/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.py
new file mode 100644
index 0000000..784339d
--- /dev/null
+++ b/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+class DocType:
+	def __init__(self, d, dl):
+		self.doc, self.doclist = d, dl
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.txt b/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.txt
new file mode 100644
index 0000000..1737c65
--- /dev/null
+++ b/selling/doctype/shopping_cart_price_list/shopping_cart_price_list.txt
@@ -0,0 +1,36 @@
+[
+ {
+  "creation": "2013-06-20 16:00:18", 
+  "docstatus": 0, 
+  "modified": "2013-08-09 14:47:15", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "DocType", 
+  "istable": 1, 
+  "module": "Selling", 
+  "name": "__common__"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "selling_price_list", 
+  "fieldtype": "Link", 
+  "in_list_view": 1, 
+  "label": "Price List", 
+  "name": "__common__", 
+  "options": "Price List", 
+  "parent": "Shopping Cart Price List", 
+  "parentfield": "fields", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "reqd": 1
+ }, 
+ {
+  "doctype": "DocType", 
+  "name": "Shopping Cart Price List"
+ }, 
+ {
+  "doctype": "DocField"
+ }
+]
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_settings/__init__.py b/selling/doctype/shopping_cart_settings/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/shopping_cart_settings/__init__.py
diff --git a/selling/doctype/shopping_cart_settings/shopping_cart_settings.js b/selling/doctype/shopping_cart_settings/shopping_cart_settings.js
new file mode 100644
index 0000000..c38c757
--- /dev/null
+++ b/selling/doctype/shopping_cart_settings/shopping_cart_settings.js
@@ -0,0 +1,10 @@
+// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+// License: GNU General Public License v3. See license.txt
+
+$.extend(cur_frm.cscript, {
+	onload: function() {
+		if(cur_frm.doc.__quotation_series) {
+			cur_frm.fields_dict.quotation_series.df.options = cur_frm.doc.__quotation_series;
+		}
+	}
+});
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_settings/shopping_cart_settings.py b/selling/doctype/shopping_cart_settings/shopping_cart_settings.py
new file mode 100644
index 0000000..74cc217
--- /dev/null
+++ b/selling/doctype/shopping_cart_settings/shopping_cart_settings.py
@@ -0,0 +1,149 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+from webnotes import _, msgprint
+from webnotes.utils import comma_and
+from webnotes.model.controller import DocListController
+
+class ShoppingCartSetupError(webnotes.ValidationError): pass
+
+class DocType(DocListController):
+	def onload(self):
+		self.doc.fields["__quotation_series"] = webnotes.get_doctype("Quotation").get_options("naming_series")
+	
+	def validate(self):
+		if self.doc.enabled:
+			self.validate_price_lists()
+			self.validate_tax_masters()
+			self.validate_exchange_rates_exist()
+			
+	def on_update(self):
+		webnotes.conn.set_default("shopping_cart_enabled", self.doc.fields.get("enabled") or 0)
+		webnotes.conn.set_default("shopping_cart_quotation_series", self.doc.fields.get("quotation_series"))
+			
+	def validate_overlapping_territories(self, parentfield, fieldname):
+		# for displaying message
+		doctype = self.meta.get_field(parentfield).options
+		
+		# specify atleast one entry in the table
+		self.validate_table_has_rows(parentfield, raise_exception=ShoppingCartSetupError)
+		
+		territory_name_map = self.get_territory_name_map(parentfield, fieldname)
+		for territory, names in territory_name_map.items():
+			if len(names) > 1:
+				msgprint(_("Error for") + " " + _(doctype) + ": " + comma_and(names) +
+					" " + _("have a common territory") + ": " + territory,
+					raise_exception=ShoppingCartSetupError)
+					
+		return territory_name_map
+		
+	def validate_price_lists(self):
+		territory_name_map = self.validate_overlapping_territories("price_lists",
+			"selling_price_list")
+		
+		# validate that a Shopping Cart Price List exists for the root territory
+		# as a catch all!
+		from setup.utils import get_root_of
+		root_territory = get_root_of("Territory")
+		
+		if root_territory not in territory_name_map.keys():
+			msgprint(_("Please specify a Price List which is valid for Territory") + 
+				": " + root_territory, raise_exception=ShoppingCartSetupError)
+		
+	def validate_tax_masters(self):
+		self.validate_overlapping_territories("sales_taxes_and_charges_masters", 
+			"sales_taxes_and_charges_master")
+		
+	def get_territory_name_map(self, parentfield, fieldname):
+		territory_name_map = {}
+		
+		# entries in table
+		names = [doc.fields.get(fieldname) for doc in self.doclist.get({"parentfield": parentfield})]
+		
+		if names:
+			# for condition in territory check
+			parenttype = self.meta.get_field(fieldname, parentfield=parentfield).options
+		
+			# to validate territory overlap
+			# make a map of territory: [list of names]
+			# if list against each territory has more than one element, raise exception
+			territory_name = webnotes.conn.sql("""select `territory`, `parent` 
+				from `tabFor Territory`
+				where `parenttype`=%s and `parent` in (%s)""" %
+				("%s", ", ".join(["%s"]*len(names))), tuple([parenttype] + names))
+		
+			for territory, name in territory_name:
+				territory_name_map.setdefault(territory, []).append(name)
+				
+				if len(territory_name_map[territory]) > 1:
+					territory_name_map[territory].sort(key=lambda val: names.index(val))
+		
+		return territory_name_map
+					
+	def validate_exchange_rates_exist(self):
+		"""check if exchange rates exist for all Price List currencies (to company's currency)"""
+		company_currency = webnotes.conn.get_value("Company", self.doc.company, "default_currency")
+		if not company_currency:
+			msgprint(_("Please specify currency in Company") + ": " + self.doc.company,
+				raise_exception=ShoppingCartSetupError)
+		
+		price_list_currency_map = webnotes.conn.get_values("Price List", 
+			[d.selling_price_list for d in self.doclist.get({"parentfield": "price_lists"})],
+			"currency")
+			
+		expected_to_exist = [currency + "-" + company_currency 
+			for currency in price_list_currency_map.values()
+			if currency != company_currency]
+			
+		if expected_to_exist:
+			exists = webnotes.conn.sql_list("""select name from `tabCurrency Exchange`
+				where name in (%s)""" % (", ".join(["%s"]*len(expected_to_exist)),),
+				tuple(expected_to_exist))
+		
+			missing = list(set(expected_to_exist).difference(exists))
+		
+			if missing:
+				msgprint(_("Missing Currency Exchange Rates for" + ": " + comma_and(missing)),
+					raise_exception=ShoppingCartSetupError)
+				
+	def get_name_from_territory(self, territory, parentfield, fieldname):
+		name = None
+		territory_name_map = self.get_territory_name_map(parentfield, fieldname)
+		
+		if territory_name_map.get(territory):
+			name = territory_name_map.get(territory)
+		else:
+			territory_ancestry = self.get_territory_ancestry(territory)
+			for ancestor in territory_ancestry:
+				if territory_name_map.get(ancestor):
+					name = territory_name_map.get(ancestor)
+					break
+		
+		return name
+				
+	def get_price_list(self, billing_territory):
+		price_list = self.get_name_from_territory(billing_territory, "price_lists", "selling_price_list")
+		return price_list and price_list[0] or None
+		
+	def get_tax_master(self, billing_territory):
+		tax_master = self.get_name_from_territory(billing_territory, "sales_taxes_and_charges_masters", 
+			"sales_taxes_and_charges_master")
+		return tax_master and tax_master[0] or None
+		
+	def get_shipping_rules(self, shipping_territory):
+		return self.get_name_from_territory(shipping_territory, "shipping_rules", "shipping_rule")
+		
+	def get_territory_ancestry(self, territory):
+		from setup.utils import get_ancestors_of
+		
+		if not hasattr(self, "_territory_ancestry"):
+			self._territory_ancestry = {}
+			
+		if not self._territory_ancestry.get(territory):
+			self._territory_ancestry[territory] = get_ancestors_of("Territory", territory)
+
+		return self._territory_ancestry[territory]
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_settings/shopping_cart_settings.txt b/selling/doctype/shopping_cart_settings/shopping_cart_settings.txt
new file mode 100644
index 0000000..531f8da
--- /dev/null
+++ b/selling/doctype/shopping_cart_settings/shopping_cart_settings.txt
@@ -0,0 +1,125 @@
+[
+ {
+  "creation": "2013-06-19 15:57:32", 
+  "docstatus": 0, 
+  "modified": "2013-07-15 17:33:15", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "description": "Default settings for Shopping Cart", 
+  "doctype": "DocType", 
+  "icon": "icon-shopping-cart", 
+  "issingle": 1, 
+  "module": "Selling", 
+  "name": "__common__"
+ }, 
+ {
+  "doctype": "DocField", 
+  "name": "__common__", 
+  "parent": "Shopping Cart Settings", 
+  "parentfield": "fields", 
+  "parenttype": "DocType", 
+  "permlevel": 0
+ }, 
+ {
+  "create": 1, 
+  "doctype": "DocPerm", 
+  "name": "__common__", 
+  "parent": "Shopping Cart Settings", 
+  "parentfield": "permissions", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "read": 1, 
+  "role": "Website Manager", 
+  "write": 1
+ }, 
+ {
+  "doctype": "DocType", 
+  "name": "Shopping Cart Settings"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "enabled", 
+  "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", 
+  "fieldtype": "Link", 
+  "label": "Default Territory", 
+  "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": "quotation_series", 
+  "fieldtype": "Select", 
+  "label": "Quotation Series", 
+  "reqd": 1
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "section_break_6", 
+  "fieldtype": "Section Break"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "price_lists", 
+  "fieldtype": "Table", 
+  "label": "Shopping Cart Price Lists", 
+  "options": "Shopping Cart Price List", 
+  "reqd": 0
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "shipping_rules", 
+  "fieldtype": "Table", 
+  "label": "Shopping Cart Shipping Rules", 
+  "options": "Shopping Cart Shipping Rule", 
+  "reqd": 0
+ }, 
+ {
+  "doctype": "DocField", 
+  "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"
+ }
+]
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_settings/test_shopping_cart_settings.py b/selling/doctype/shopping_cart_settings/test_shopping_cart_settings.py
new file mode 100644
index 0000000..77c7e23
--- /dev/null
+++ b/selling/doctype/shopping_cart_settings/test_shopping_cart_settings.py
@@ -0,0 +1,81 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+import unittest
+from selling.doctype.shopping_cart_settings.shopping_cart_settings import ShoppingCartSetupError
+
+class TestShoppingCartSettings(unittest.TestCase):
+	def setUp(self):
+		webnotes.conn.sql("""delete from `tabSingles` where doctype="Shipping Cart Settings" """)
+		webnotes.conn.sql("""delete from `tabShopping Cart Price List`""")
+		webnotes.conn.sql("""delete from `tabShopping Cart Taxes and Charges Master`""")
+		webnotes.conn.sql("""delete from `tabShopping Cart Shipping Rule`""")
+		
+	def get_cart_settings(self):
+		return webnotes.bean({"doctype": "Shopping Cart Settings",
+			"company": "_Test Company"})
+		
+	def test_price_list_territory_overlap(self):
+		cart_settings = self.get_cart_settings()
+		
+		def _add_price_list(price_list):
+			cart_settings.doclist.append({
+				"doctype": "Shopping Cart Price List",
+				"parentfield": "price_lists",
+				"selling_price_list": price_list
+			})
+		
+		for price_list in ("_Test Price List Rest of the World", "_Test Price List India",
+			"_Test Price List"):
+			_add_price_list(price_list)
+		
+		controller = cart_settings.make_controller()
+		controller.validate_overlapping_territories("price_lists", "selling_price_list")
+		
+		_add_price_list("_Test Price List 2")
+		
+		controller = cart_settings.make_controller()
+		self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
+			"price_lists", "selling_price_list")
+			
+		return cart_settings
+		
+	def test_taxes_territory_overlap(self):
+		cart_settings = self.get_cart_settings()
+		
+		def _add_tax_master(tax_master):
+			cart_settings.doclist.append({
+				"doctype": "Shopping Cart Taxes and Charges Master",
+				"parentfield": "sales_taxes_and_charges_masters",
+				"sales_taxes_and_charges_master": tax_master
+			})
+		
+		for tax_master in ("_Test Sales Taxes and Charges Master", "_Test India Tax Master"):
+			_add_tax_master(tax_master)
+			
+		controller = cart_settings.make_controller()
+		controller.validate_overlapping_territories("sales_taxes_and_charges_masters",
+			"sales_taxes_and_charges_master")
+			
+		_add_tax_master("_Test Sales Taxes and Charges Master 2")
+		
+		controller = cart_settings.make_controller()
+		self.assertRaises(ShoppingCartSetupError, controller.validate_overlapping_territories,
+			"sales_taxes_and_charges_masters", "sales_taxes_and_charges_master")
+		
+	def test_exchange_rate_exists(self):
+		webnotes.conn.sql("""delete from `tabCurrency Exchange`""")
+		
+		cart_settings = self.test_price_list_territory_overlap()
+		controller = cart_settings.make_controller()
+		self.assertRaises(ShoppingCartSetupError, controller.validate_exchange_rates_exist)
+		
+		from setup.doctype.currency_exchange.test_currency_exchange import test_records as \
+			currency_exchange_records
+		webnotes.bean(currency_exchange_records[0]).insert()
+		controller.validate_exchange_rates_exist()
+		
diff --git a/selling/doctype/shopping_cart_shipping_rule/__init__.py b/selling/doctype/shopping_cart_shipping_rule/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/shopping_cart_shipping_rule/__init__.py
diff --git a/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.py b/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.py
new file mode 100644
index 0000000..784339d
--- /dev/null
+++ b/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+class DocType:
+	def __init__(self, d, dl):
+		self.doc, self.doclist = d, dl
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.txt b/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.txt
new file mode 100644
index 0000000..8c9c34a
--- /dev/null
+++ b/selling/doctype/shopping_cart_shipping_rule/shopping_cart_shipping_rule.txt
@@ -0,0 +1,36 @@
+[
+ {
+  "creation": "2013-07-03 13:15:34", 
+  "docstatus": 0, 
+  "modified": "2013-07-10 14:54:25", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "DocType", 
+  "istable": 1, 
+  "module": "Selling", 
+  "name": "__common__"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "shipping_rule", 
+  "fieldtype": "Link", 
+  "in_list_view": 1, 
+  "label": "Shipping Rule", 
+  "name": "__common__", 
+  "options": "Shipping Rule", 
+  "parent": "Shopping Cart Shipping Rule", 
+  "parentfield": "fields", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "reqd": 1
+ }, 
+ {
+  "doctype": "DocType", 
+  "name": "Shopping Cart Shipping Rule"
+ }, 
+ {
+  "doctype": "DocField"
+ }
+]
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_taxes_and_charges_master/__init__.py b/selling/doctype/shopping_cart_taxes_and_charges_master/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/selling/doctype/shopping_cart_taxes_and_charges_master/__init__.py
diff --git a/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py b/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py
new file mode 100644
index 0000000..784339d
--- /dev/null
+++ b/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.py
@@ -0,0 +1,11 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import webnotes
+
+class DocType:
+	def __init__(self, d, dl):
+		self.doc, self.doclist = d, dl
\ No newline at end of file
diff --git a/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt b/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt
new file mode 100644
index 0000000..a61f8db
--- /dev/null
+++ b/selling/doctype/shopping_cart_taxes_and_charges_master/shopping_cart_taxes_and_charges_master.txt
@@ -0,0 +1,36 @@
+[
+ {
+  "creation": "2013-06-20 16:57:03", 
+  "docstatus": 0, 
+  "modified": "2013-07-10 14:54:25", 
+  "modified_by": "Administrator", 
+  "owner": "Administrator"
+ }, 
+ {
+  "doctype": "DocType", 
+  "istable": 1, 
+  "module": "Selling", 
+  "name": "__common__"
+ }, 
+ {
+  "doctype": "DocField", 
+  "fieldname": "sales_taxes_and_charges_master", 
+  "fieldtype": "Link", 
+  "in_list_view": 1, 
+  "label": "Tax Master", 
+  "name": "__common__", 
+  "options": "Sales Taxes and Charges Master", 
+  "parent": "Shopping Cart Taxes and Charges Master", 
+  "parentfield": "fields", 
+  "parenttype": "DocType", 
+  "permlevel": 0, 
+  "reqd": 1
+ }, 
+ {
+  "doctype": "DocType", 
+  "name": "Shopping Cart Taxes and Charges Master"
+ }, 
+ {
+  "doctype": "DocField"
+ }
+]
\ No newline at end of file
diff --git a/selling/page/selling_home/selling_home.js b/selling/page/selling_home/selling_home.js
index 4860d42..9697ccf 100644
--- a/selling/page/selling_home/selling_home.js
+++ b/selling/page/selling_home/selling_home.js
@@ -66,6 +66,12 @@
 				"description": "Settings for Selling Module"
 			},
 			{
+				"route":"Form/Shopping Cart Settings",
+				"label":wn._("Shopping Cart Settings"),
+				"description":wn._("Setup of Shopping Cart."),
+				doctype:"Shopping Cart Settings"
+			},
+			{
 				label: wn._("Sales Taxes and Charges Master"),
 				description: wn._("Sales taxes template."),
 				doctype:"Sales Taxes and Charges Master"
diff --git a/startup/webutils.py b/startup/webutils.py
index b427b40..9f1d12c 100644
--- a/startup/webutils.py
+++ b/startup/webutils.py
@@ -1,34 +1,10 @@
 # Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
 # License: GNU General Public License v3. See license.txt
 
-import webnotes, conf, os
-from webnotes.utils import cint, cstr, encode
+import webnotes
+from webnotes.utils import cint
 
 def get_website_settings():
 	return {
 		"shopping_cart_enabled": cint(webnotes.conn.get_default("shopping_cart_enabled"))
-	}	
-	
-@webnotes.whitelist()
-def update_profile(fullname, password=None, company_name=None, mobile_no=None, phone=None):
-	from selling.utils.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 selling.utils.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}, ["mobile_no", "phone"])
-		
-	return {
-		"company_name": cstr(party.customer_name if party.doctype == "Customer" else party.company_name),
-		"mobile_no": cstr(mobile_no),
-		"phone": cstr(phone)
 	}
\ No newline at end of file
diff --git a/stock/doctype/delivery_note/delivery_note.py b/stock/doctype/delivery_note/delivery_note.py
index eb39944..042b197 100644
--- a/stock/doctype/delivery_note/delivery_note.py
+++ b/stock/doctype/delivery_note/delivery_note.py
@@ -43,6 +43,9 @@
 		if billed_qty:
 			total_qty = sum((item.qty for item in self.doclist.get({"parentfield": "delivery_note_details"})))
 			self.doc.fields["__billing_complete"] = billed_qty[0][0] == total_qty
+			
+	def get_portal_page(self):
+		return "shipment" if self.doc.docstatus==1 else None
 		
 	def get_contact_details(self):
 		return get_obj('Sales Common').get_contact_details(self,0)
diff --git a/stock/doctype/delivery_note/templates/__init__.py b/stock/doctype/delivery_note/templates/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/stock/doctype/delivery_note/templates/__init__.py
diff --git a/stock/doctype/delivery_note/templates/pages/__init__.py b/stock/doctype/delivery_note/templates/pages/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/stock/doctype/delivery_note/templates/pages/__init__.py
diff --git a/portal/templates/pages/shipment.html b/stock/doctype/delivery_note/templates/pages/shipment.html
similarity index 100%
rename from portal/templates/pages/shipment.html
rename to stock/doctype/delivery_note/templates/pages/shipment.html
diff --git a/portal/templates/pages/shipment.py b/stock/doctype/delivery_note/templates/pages/shipment.py
similarity index 95%
rename from portal/templates/pages/shipment.py
rename to stock/doctype/delivery_note/templates/pages/shipment.py
index 5d9d1d1..60dc9d8 100644
--- a/portal/templates/pages/shipment.py
+++ b/stock/doctype/delivery_note/templates/pages/shipment.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_transaction_context
 	context = get_transaction_context("Delivery Note", webnotes.form_dict.name)
diff --git a/portal/templates/pages/shipments.html b/stock/doctype/delivery_note/templates/pages/shipments.html
similarity index 100%
rename from portal/templates/pages/shipments.html
rename to stock/doctype/delivery_note/templates/pages/shipments.html
diff --git a/portal/templates/pages/shipments.py b/stock/doctype/delivery_note/templates/pages/shipments.py
similarity index 97%
rename from portal/templates/pages/shipments.py
rename to stock/doctype/delivery_note/templates/pages/shipments.py
index 4847b9f..48c636d 100644
--- a/portal/templates/pages/shipments.py
+++ b/stock/doctype/delivery_note/templates/pages/shipments.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	from portal.website_transactions import get_currency_context
 	context = get_currency_context()
diff --git a/stock/doctype/item/templates/pages/product_search.html b/stock/doctype/item/templates/pages/product_search.html
index 37e50dc..9c6eeab 100644
--- a/stock/doctype/item/templates/pages/product_search.html
+++ b/stock/doctype/item/templates/pages/product_search.html
@@ -3,7 +3,7 @@
 {% set title="Product Search" %}
 
 {% block javascript %}
-{% include "app/website/templates/js/product_list.js" %}
+<script>{% include "app/stock/doctype/item/templates/includes/product_list.js" %}</script>
 {% endblock %}
 
 {% block content %}
@@ -17,7 +17,7 @@
 });
 </script>
 
-{% include 'app/website/templates/html/product_search_box.html' %}
+{% include "app/stock/doctype/item/templates/includes/product_search_box.html" %}
 <div class="col-md-12">
 	<h3 class="search-results">Search Results</h3>
 	<div id="search-list" class="row">
diff --git a/stock/doctype/item/templates/pages/product_search.py b/stock/doctype/item/templates/pages/product_search.py
new file mode 100644
index 0000000..24b474a
--- /dev/null
+++ b/stock/doctype/item/templates/pages/product_search.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+no_cache = True
\ No newline at end of file
diff --git a/support/doctype/support_ticket/support_ticket.py b/support/doctype/support_ticket/support_ticket.py
index 2cbd65e..bf2a9fb 100644
--- a/support/doctype/support_ticket/support_ticket.py
+++ b/support/doctype/support_ticket/support_ticket.py
@@ -24,6 +24,9 @@
 		if signature:
 			content += '<p>' + signature + '</p>'
 		return content
+		
+	def get_portal_page(self):
+		return "ticket"
 	
 	def validate(self):
 		self.update_status()
diff --git a/support/doctype/support_ticket/templates/pages/ticket.py b/support/doctype/support_ticket/templates/pages/ticket.py
index 2227a6a..999f69f 100644
--- a/support/doctype/support_ticket/templates/pages/ticket.py
+++ b/support/doctype/support_ticket/templates/pages/ticket.py
@@ -4,6 +4,8 @@
 from __future__ import unicode_literals
 import webnotes
 
+no_cache = True
+
 def get_context():
 	bean = webnotes.bean("Support Ticket", webnotes.form_dict.name)
 	if bean.doc.raised_by != webnotes.session.user:
diff --git a/support/doctype/support_ticket/templates/pages/tickets.py b/support/doctype/support_ticket/templates/pages/tickets.py
index 21892a1..f434746 100644
--- a/support/doctype/support_ticket/templates/pages/tickets.py
+++ b/support/doctype/support_ticket/templates/pages/tickets.py
@@ -5,6 +5,8 @@
 import webnotes
 from webnotes.utils import cint, formatdate
 
+no_cache = True
+
 def get_context():
 	return {
 		"title": "My Tickets",
diff --git a/utilities/doctype/address/templates/pages/address.py b/utilities/doctype/address/templates/pages/address.py
index d87974d..d968c92 100644
--- a/utilities/doctype/address/templates/pages/address.py
+++ b/utilities/doctype/address/templates/pages/address.py
@@ -5,6 +5,8 @@
 import webnotes
 from webnotes.utils import cint
 
+no_cache = True
+
 def get_context():
 	def _get_fields(fieldnames):
 		return [webnotes._dict(zip(["label", "fieldname", "fieldtype", "options"], 
diff --git a/utilities/doctype/address/templates/pages/addresses.py b/utilities/doctype/address/templates/pages/addresses.py
new file mode 100644
index 0000000..24b474a
--- /dev/null
+++ b/utilities/doctype/address/templates/pages/addresses.py
@@ -0,0 +1,6 @@
+# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+no_cache = True
\ No newline at end of file