blog listing + started with products page and listing
diff --git a/erpnext/patches/june_2012/cms2.py b/erpnext/patches/june_2012/cms2.py
index 88e7049..48f0152 100644
--- a/erpnext/patches/june_2012/cms2.py
+++ b/erpnext/patches/june_2012/cms2.py
@@ -33,6 +33,12 @@
 				select name from `tabBlog`
 				where docstatus = 0 and ifnull(published, 0) = 1"""
 		},
+		{
+			'doctype': 'Item',
+			'query': """\
+				select name from `tabItem`
+				where docstatus = 0 and ifnull(show_in_website, 'No') = 'Yes'"""
+		}
 	]
 	
 	for s in save_list:
diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py
index f0fb5e7..85af0bb 100644
--- a/erpnext/stock/doctype/item/item.py
+++ b/erpnext/stock/doctype/item/item.py
@@ -46,6 +46,8 @@
 		return ret
 
 	def on_update(self):
+		self.update_page_name()
+		
 		bin = sql("select stock_uom from `tabBin` where item_code = '%s' " % self.doc.item_code)
 		if bin and cstr(bin[0][0]) != cstr(self.doc.stock_uom):
 			msgprint("Please Update Stock UOM with the help of Stock UOM Replace Utility.")
@@ -79,9 +81,14 @@
 			child.conversion_factor = 1
 			child.save()
 
+		self.clear_web_cache()
+
 	# On delete 1. Delete BIN (if none of the corrosponding transactions present, it gets deleted. if present, rolled back due to exception)
 	def on_trash(self):
 		sql("delete from tabBin where item_code='%s'"%(self.doc.item_code))
+		
+		import website.web_cache
+		website.web_cache.delete_web_cache(self.doc.page_name)
 
 	# Check whether Ref Rate is not entered twice for same Price List and Currency
 	def check_ref_rate_detail(self):
@@ -163,9 +170,9 @@
 		if self.doc.has_serial_no == 'Yes' and self.doc.is_stock_item == 'No':
 			msgprint("'Has Serial No' can not be 'Yes' for non-stock item", raise_exception=1)
 
-		# make product page
-		self.make_page()
-
+		if self.doc.name:
+			self.old_page_name = webnotes.conn.get_value('Item', self.doc.name, 'page_name')
+		
 	def check_non_asset_warehouse(self):
 		if self.doc.is_asset_item == "Yes":
 			existing_qty = sql("select t1.warehouse, t1.actual_qty from tabBin t1, tabWarehouse t2 where t1.item_code=%s and (t2.warehouse_type!='Fixed Asset' or t2.warehouse_type is null) and t1.warehouse=t2.name and t1.actual_qty > 0", self.doc.name)
@@ -218,35 +225,59 @@
 	def on_rename(self,newdn,olddn):
 		sql("update tabItem set item_code = %s where name = %s", (newdn, olddn))
 
-	def make_page(self):
-		if self.doc.show_in_website=='Yes':
-
-			import website.utils
-
-			if self.doc.page_name:
-				import webnotes.model
-				webnotes.model.delete_doc('Page', self.doc.page_name)
-				
-			p = website.utils.add_page("Product " + self.doc.item_name)
-			self.doc.page_name = p.name
-
-			from jinja2 import Template
-			import markdown2
-			import os
-
-
-			self.doc.long_description_html = markdown2.markdown(self.doc.description or '')
-
-			with open(os.path.join(os.path.dirname(__file__), 'template.html'), 'r') as f:
-				p.content = Template(f.read()).render(doc=self.doc)
-
-			with open(os.path.join(os.path.dirname(__file__), 'product_page.js'), 'r') as f:
-				p.script = Template(f.read()).render(doc=self.doc)
-
-			p.save()
-
-			website.utils.add_guest_access_to_page(p.name)
-
-			del self.doc.fields['long_description_html']
-
-			
\ No newline at end of file
+	# def make_page(self):
+	# 	if self.doc.show_in_website=='Yes':
+	# 
+	# 		import website.utils
+	# 
+	# 		if self.doc.page_name:
+	# 			import webnotes.model
+	# 			webnotes.model.delete_doc('Page', self.doc.page_name)
+	# 			
+	# 		p = website.utils.add_page("Product " + self.doc.item_name)
+	# 		self.doc.page_name = p.name
+	# 
+	# 		from jinja2 import Template
+	# 		import markdown2
+	# 		import os
+	# 
+	# 
+	# 		self.doc.long_description_html = markdown2.markdown(self.doc.description or '')
+	# 
+	# 		with open(os.path.join(os.path.dirname(__file__), 'template.html'), 'r') as f:
+	# 			p.content = Template(f.read()).render(doc=self.doc)
+	# 
+	# 		with open(os.path.join(os.path.dirname(__file__), 'product_page.js'), 'r') as f:
+	# 			p.script = Template(f.read()).render(doc=self.doc)
+	# 
+	# 		p.save()
+	# 
+	# 		website.utils.add_guest_access_to_page(p.name)
+	# 
+	# 		del self.doc.fields['long_description_html']
+	# 		
+	def clear_web_cache(self):
+		import website.web_cache
+		
+		if hasattr(self, 'old_page_name') and self.old_page_name and \
+				self.doc.page_name != self.old_page_name:
+			website.web_cache.delete_web_cache(self.old_page_name)
+		
+		if self.doc.show_in_website == 'Yes':
+			website.web_cache.clear_web_cache(self.doc.doctype, self.doc.name, self.doc.page_name)
+		else:
+			website.web_cache.delete_web_cache(self.doc.page_name)
+	
+	def update_page_name(self):
+		import website.utils
+		self.doc.page_name = website.utils.page_name(self.doc.name + " " + self.doc.item_name)
+		webnotes.conn.set_value('Item', self.doc.name, 'page_name', self.doc.page_name)
+	
+		# no need to check for uniqueness, as name is unique
+		
+	def get_html(self):
+		import markdown2
+		self.doc.web_description_html = markdown2.markdown(self.doc.description or '',
+										extras=["wiki-tables"])
+		
+		
\ No newline at end of file
diff --git a/erpnext/website/doctype/website_settings/website_settings.py b/erpnext/website/doctype/website_settings/website_settings.py
index 9390e74..aec5a39 100644
--- a/erpnext/website/doctype/website_settings/website_settings.py
+++ b/erpnext/website/doctype/website_settings/website_settings.py
@@ -54,8 +54,13 @@
 		from webnotes.cms.make import make_web_core
 		make_web_core()
 		
-		get_obj('Page', 'blog').write_cms_page(force=True)
-		get_obj('Page', 'Login Page').write_cms_page(force=True)
+		import website.web_cache
+		for page in ['blog', 'products']:
+			website.web_cache.delete_web_cache(page)
+			website.web_cache.clear_web_cache(None, None, page)
+		
+		#get_obj('Page', 'blog').write_cms_page(force=True)
+		#get_obj('Page', 'Login Page').write_cms_page(force=True)
 		
 		webnotes.msgprint('Rebuilt all blogs and pages')
 		
diff --git a/erpnext/website/templates/blog-old.html b/erpnext/website/templates/blog-old.html
deleted file mode 100644
index d0b9a13..0000000
--- a/erpnext/website/templates/blog-old.html
+++ /dev/null
@@ -1,58 +0,0 @@
-{% extends "outer.html" %}
-
-{% block title %}{{ title }}{% endblock %}
-
-
-{% block content %}
-<div class="layout-wrapper layout-wrapper-background">
-	<div class="web-content" id="content-blog">
-		<div class="layout-main-section">
-			<h1>Blog</h1>
-			<br>
-			<div id="blog-list">
-				<!-- blog list will be generated dynamically -->
-			</div>
-		</div>
-		<div class="layout-side-section">
-			<!-- for later
-			<h4>Get Updates</h4>
-			<p>
-			<input name="blog-subscribe">
-			<button class="btn" id="blog-subscribe">Subscribe</button>
-			</p>-->
-			<h4>Subscribe</h4>
-			<p>
-			<img src="images/feed.png" style="margin-right: 4px; margin-bottom: -4px">
-			<a href="rss.xml" target="_blank">RSS Feed</a>
-			</p>
-		</div>
-		<div style="clear: both"></div>
-	</div>
-</div>
-
-<script>
-
-// if not a specific blog, show listing
-erpnext.blog_list = new wn.ui.Listing({
-	parent: $(wrapper).find('#blog-list').get(0),
-	query: 'select tabBlog.name, title, left(content, 1000) as content, tabBlog.creation, \
-		ifnull(first_name, "") as first_name, ifnull(last_name, "") as last_name \
-		from tabProfile, tabBlog\
-	 	where ifnull(published,0)=1 and tabBlog.owner = tabProfile.name \
-		order by tabBlog.creation desc',
-	hide_refresh: true,
-	no_toolbar: true,
-	render_row: function(parent, data) {
-		if(data.content && data.content.length==1000) data.content += '... (read on)';
-		data.content = wn.markdown(data.content);
-		if(data.last_name) data.last_name = ' ' + data.last_name;
-		data.date = prettyDate(data.creation);
-		parent.innerHTML = repl('<h2>%(title)s</h2>\
-			<p><div class="help">By %(first_name)s%(last_name)s, %(date)s</div></p>\
-			<p>%(content)s</p>\
-			<a href="%(name)s.html">Read Full Text</a><br>', data);
-	},
-	page_length: 10
-});
-erpnext.blog_list.run();
-</script>
\ No newline at end of file
diff --git a/erpnext/website/templates/blog.html b/erpnext/website/templates/blog/blog.html
similarity index 96%
rename from erpnext/website/templates/blog.html
rename to erpnext/website/templates/blog/blog.html
index e188edf..03a2ed7 100644
--- a/erpnext/website/templates/blog.html
+++ b/erpnext/website/templates/blog/blog.html
@@ -1,4 +1,4 @@
-{% extends "blog.js" %}
+{% extends "blog/blog.js" %}
 
 {% block content %}
 	<div class="layout-wrapper layout-wrapper-background">
diff --git a/erpnext/website/templates/blog.js b/erpnext/website/templates/blog/blog.js
similarity index 100%
rename from erpnext/website/templates/blog.js
rename to erpnext/website/templates/blog/blog.js
diff --git a/erpnext/website/templates/blog/blog_list.html b/erpnext/website/templates/blog/blog_list.html
new file mode 100644
index 0000000..242f814
--- /dev/null
+++ b/erpnext/website/templates/blog/blog_list.html
@@ -0,0 +1,43 @@
+{% extends "blog/blog_list.js" %}
+
+{% block title %}Blog{% endblock %}
+
+{% block css %}
+	<style>
+		h2 > a, h2 > a:link, h2 > a:visited, h2 > a:active,
+		h2 > a:hover, h2 > a:focus {
+			text-decoration: none;
+			color: inherit;
+		}
+	</style>
+{% endblock %}
+
+{% block content %}
+	<div class="layout-wrapper layout-wrapper-background">
+		<div class="web-content" id="content-blog">
+			
+			<div class="layout-main-section">
+				<h1>Blog</h1>
+				<br>
+				<div id="blog-list">
+					<!-- blog list will be generated dynamically -->
+				</div>
+			</div>
+			
+			<div class="layout-side-section">
+				<!-- for later
+				<h4>Get Updates</h4>
+				<p>
+				<input name="blog-subscribe">
+				<button class="btn" id="blog-subscribe">Subscribe</button>
+				</p>-->
+				<h4>Subscribe</h4>
+				<p>
+				<img src="images/feed.png" style="margin-right: 4px; margin-bottom: -4px">
+				<a href="rss.xml" target="_blank">RSS Feed</a>
+				</p>
+			</div>
+			<div style="clear: both"></div>
+		</div>
+	</div>
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/website/templates/blog/blog_list.js b/erpnext/website/templates/blog/blog_list.js
new file mode 100644
index 0000000..70628c1
--- /dev/null
+++ b/erpnext/website/templates/blog/blog_list.js
@@ -0,0 +1,48 @@
+{% extends "page.html" %}
+
+{% block javascript %}
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+// js inside blog page
+wn.pages['{{ name }}'].onload = function(wrapper) {
+	erpnext.blog_list = new wn.ui.Listing({
+		parent: $(wrapper).find('#blog-list').get(0),
+		query: 'select tabBlog.name, title, left(content, 1000) as content, tabBlog.creation, \
+			ifnull(first_name, "") as first_name, ifnull(last_name, "") as last_name \
+			from tabProfile, tabBlog\
+		 	where ifnull(published,0)=1 and tabBlog.owner = tabProfile.name \
+			order by tabBlog.creation desc',
+		hide_refresh: true,
+		no_toolbar: true,
+		render_row: function(parent, data) {
+			if(data.content && data.content.length==1000) {
+				data.content += repl('... <a href="%(name)s.html">(read on)</a>', data);
+			}
+			data.content = wn.markdown(data.content);
+			if(data.last_name) data.last_name = ' ' + data.last_name;
+			data.date = prettyDate(data.creation);
+			parent.innerHTML = repl('<h2><a href="%(name)s.html">%(title)s</a></h2>\
+				<p><div class="help">By %(first_name)s%(last_name)s, %(date)s</div></p>\
+				<p>%(content)s</p><br>', data)
+				//<a href="%(name)s.html">Read Full Text</a><br>', data);
+		},
+		page_length: 10
+	});
+	erpnext.blog_list.run();
+}
+
+{% endblock %}
diff --git a/erpnext/website/templates/page.html b/erpnext/website/templates/page.html
index a8e20f6..c6e0715 100644
--- a/erpnext/website/templates/page.html
+++ b/erpnext/website/templates/page.html
@@ -24,9 +24,14 @@
 	});
 	</script>
 	{% endif %}
+	
+	{% block css %}
 	{% if insert_style %}
+	
 	<style>{{ css }}</style>
+
 	{% endif %}
+	{% endblock %}
 {% endblock %}
 
 {% block content %}
diff --git a/erpnext/website/templates/product/product.html b/erpnext/website/templates/product/product.html
new file mode 100644
index 0000000..5a04e79
--- /dev/null
+++ b/erpnext/website/templates/product/product.html
@@ -0,0 +1,31 @@
+{% extends "product/product.js" %}
+
+{% block title %}{{ item_name }} [{{ name }}]{% endblock %}
+
+{% block content %}
+	<div class="layout-wrapper layout-wrapper-background">
+		<div class="web-content" id="content-product-{{ name }}">
+			<div class="layout-main-section">
+				<h1>{{ item_name }}</h1>
+				<div style="float: left;">
+					<br><br>
+					<image src="files/{{ website_image }}" style="width: 300px; 
+						margin-left: 15px;" />
+					<br><br>
+					{{ web_description_html }}
+					<button class="btn primary product-inquiry" 
+						data-product="{{ name }}"
+						data-description="{{ description }}">Send Inquiry</button>
+				</div>
+			</div>
+			<div class="layout-side-section">
+				<h4>More Categories</h4>
+				<div class="more-categories"></div>
+				<br>
+				<h4>Similar Products</h4>
+				<div class="similar-products"></div>
+			</div>
+			<div style="clear: both"></div>
+		</div>
+	</div>
+{% endblock %}
diff --git a/erpnext/website/templates/product/product.js b/erpnext/website/templates/product/product.js
new file mode 100644
index 0000000..ee73e7f
--- /dev/null
+++ b/erpnext/website/templates/product/product.js
@@ -0,0 +1,68 @@
+{% extends "page.html" %}
+
+{% block javascript %}
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+wn.require('js/product_category.js');
+
+wn.pages['{{ name }}'].onload = function(wrapper) {
+	console.log('loaded page');
+	wrapper.product_group = "{{ item_group }}";
+	wrapper.product_name = "{{ name }}";
+	erpnext.make_product_categories(wrapper);
+	$(wrapper).find('.product-inquiry').click(function() {
+		loadpage('contact', function() {
+			$('#content-contact-us [name="contact-message"]').val("Hello,\n\n\
+			Please send me more information on {{ item_name }} (Item Code:{{ name }})\n\n\
+			My contact details are:\n\nThank you!\
+			");
+		})
+	});
+	
+	// similar products
+	wrapper.similar = new wn.ui.Listing({
+		parent: $(wrapper).find('.similar-products').get(0),
+		hide_refresh: true,
+		page_length: 5,
+		get_query: function() {
+			args = {
+				cat: wrapper.product_group,
+				name: wrapper.product_name
+			};
+			return repl('select name, item_name, website_image, \
+				page_name, description \
+				from tabItem \
+				and ifnull(show_in_website, "No")="Yes" \
+				and name != "%(name)s" \
+				and item_group="%(cat)s" order by modified desc', args)
+		},
+		render_row: function(parent, data) {
+			if(data.short_description.length > 100) {
+				data.short_description = data.short_description.substr(0,100) + '...';
+			}
+			parent.innerHTML = repl('<div style="float:left; width: 60px;">\
+				<img src="files/%(website_image)s" style="width:55px;"></div>\
+				<div style="float:left; width: 180px">\
+					<b><a href="%(page_name)s.html">%(item_name)s</a></b>\
+					<p>%(description)s</p></div>\
+				<div style="clear: both; margin-bottom: 15px;"></div>', data);
+		}
+	});
+	wrapper.similar.run();
+}
+
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/website/templates/product/product_list.html b/erpnext/website/templates/product/product_list.html
new file mode 100644
index 0000000..416a2fe
--- /dev/null
+++ b/erpnext/website/templates/product/product_list.html
@@ -0,0 +1,23 @@
+{% extends "product/product_list.js" %}
+
+{% block title %}Products{% endblock %}
+
+{% block content %}
+	<div class="layout-wrapper layout-wrapper-background">
+		<div class="web-content" id="content-products">
+			
+			<div class="layout-main-section">
+				<h1 class="products-category"></h1>
+				<div id="product-list">
+					<!-- product list will be generated dynamically -->
+				</div>
+			</div>
+			
+			<div class="layout-side-section">
+				<h3>Categories</h3>
+				<div class="more-categories"></div>
+			</div>
+			<div style="clear: both"></div>
+		</div>
+	</div>
+{% endblock %}
\ No newline at end of file
diff --git a/erpnext/website/templates/product/product_list.js b/erpnext/website/templates/product/product_list.js
new file mode 100644
index 0000000..82c7886
--- /dev/null
+++ b/erpnext/website/templates/product/product_list.js
@@ -0,0 +1,40 @@
+{% extends "page.html" %}
+
+{% block javascript %}
+// ERPNext - web based ERP (http://erpnext.com)
+// Copyright (C) 2012 Web Notes Technologies Pvt Ltd
+// 
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+// 
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+// 
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+// js inside blog page
+wn.pages['{{ name }}'].onload = function(wrapper) {
+	erpnext.product_list = new wn.ui.Listing({
+		parent: $(wrapper).find('#product-list').get(0),
+		query: "select name, item_code, item_name, description, page_name \
+				from `tabItem` \
+				where docstatus = 0 and ifnull(show_in_website, 'No')='Yes'\
+				order by item_name asc",
+		hide_refresh: true,
+		no_toolbar: true,
+		render_row: function(parent, data) {
+			if(data.description && data.description.length==1000) data.description += '... (read on)';
+			parent.innerHTML = repl('<h4><a href="%(page_name)s.html">%(item_name)s</a></h4>\
+				<p>%(description)s</p>', data);
+		},
+		page_length: 10
+	});
+	erpnext.product_list.run();
+}
+
+{% endblock %}
diff --git a/erpnext/website/web_cache.py b/erpnext/website/web_cache.py
index 30e3f00..c9f196d 100644
--- a/erpnext/website/web_cache.py
+++ b/erpnext/website/web_cache.py
@@ -32,7 +32,7 @@
 		where name = %s""", page_name)
 	
 	# if page doesn't exist, raise exception
-	if not res and page_name not in ['404', 'index']:
+	if not res and page_name not in ['404', 'index', 'blog', 'products']:
 		raise Exception, "Page %s not found" % page_name
 	
 	html, doc_type, doc_name = res and res[0] or (None, None, None)
@@ -52,23 +52,37 @@
 	import webnotes
 	outer_env_dict = get_outer_env()
 	
-	if page_name == '404':
+	if page_name in ['404', 'blog', 'products']:
 		args = outer_env_dict
+		args.update({
+			'name': page_name,
+		})
 	else:
 		if page_name == 'index':
 			page_name, doc_type, doc_name = get_index_page()
 
 		from webnotes.model.code import get_obj
 		obj = get_obj(doc_type, doc_name)
-		obj.get_html()
+		if hasattr(obj, 'get_html'):
+			obj.get_html()
 		args = obj.doc.fields
 		args.update(outer_env_dict)
 	
+	# decide template and update args
 	if doc_type == 'Blog':
-		template = 'blog.html'
-		args['insert_code'] = 1
+		template = 'blog/blog.html'
+		args.update({ 'insert_code': 1 })
+	elif doc_type == 'Item':
+		template = 'product/product.html'
+		args.update({ 'insert_code': 1 })
 	elif doc_type == 'Web Page':
 		template = 'web_page.html'
+	elif page_name == 'blog':
+		template = 'blog/blog_list.html'
+		args.update({ 'insert_code': 1 })
+	elif page_name == 'products':
+		template = 'product/product_list.html'
+		args.update({ 'insert_code': 1 })
 	
 	html = build_html(args, template)
 	
diff --git a/erpnext/website/web_page.py b/erpnext/website/web_page.py
index 4d6f9f0..58ff40b 100644
--- a/erpnext/website/web_page.py
+++ b/erpnext/website/web_page.py
@@ -29,18 +29,14 @@
 	def validate(self):
 		if self.doc.name:
 			self.old_page_name = webnotes.conn.get_value(self.doctype, self.doc.name, 'page_name')
-	
+
 	def on_update(self):
 		# page name updates with the title
 		self.update_page_name()
 		
-		# delete web cache entry of old name
-		if hasattr(self, 'old_page_name') and self.old_page_name != self.doc.page_name:
-			self.delete_web_cache(self.old_page_name)
-
 		self.clear_web_cache()
 
-		self.doc.save(ignore_fields=1)
+		self.doc.save()
 		
 	def on_trash(self):
 		"""delete Web Cache entry"""
@@ -63,6 +59,11 @@
 			if web cache entry doesn't exist, it creates one
 			if duplicate entry exists for another doctype, it raises exception
 		"""
+		# delete web cache entry of old name
+		if hasattr(self, 'old_page_name') and self.old_page_name and \
+				self.old_page_name != self.doc.page_name:
+			self.delete_web_cache(self.old_page_name)
+		
 		website.web_cache.clear_web_cache(self.doctype, self.doc.name, self.doc.page_name)
 		
 	def delete_web_cache(self, page_name):