Merge branch 'stock_reco' of github.com:webnotes/erpnext into stock_reco
diff --git a/patches/january_2013/stock_reconciliation_patch.py b/patches/january_2013/stock_reconciliation_patch.py
index 9d72f58..1203595 100644
--- a/patches/january_2013/stock_reconciliation_patch.py
+++ b/patches/january_2013/stock_reconciliation_patch.py
@@ -4,6 +4,7 @@
 	webnotes.reload_doc("stock", "doctype", "stock_ledger_entry")
 	
 	rename_fields()
+	move_remarks_to_comments()
 	store_stock_reco_json()
 	
 def rename_fields():
@@ -13,6 +14,21 @@
 		webnotes.conn.sql("""update `tab%s` set `%s`=`%s`""" % 
 			(doctype, new_fieldname, old_fieldname))
 			
+def move_remarks_to_comments():
+	from webnotes.utils import get_fullname
+	result = webnotes.conn.sql("""select name, remark, modified_by from `tabStock Reconciliation`
+		where ifnull(remark, '')!=''""")
+	fullname_map = {}
+	for reco, remark, modified_by in result:
+		webnotes.model_wrapper([{
+			"doctype": "Comment",
+			"comment": remark,
+			"comment_by": modified_by,
+			"comment_by_fullname": fullname_map.setdefault(modified_by, get_fullname(modified_by)),
+			"comment_doctype": "Stock Reconciliation",
+			"comment_docname": reco
+		}]).insert()
+			
 def store_stock_reco_json():
 	import os
 	import json
@@ -40,6 +56,7 @@
 				with open(stock_reco_file_path, "r") as open_reco_file:
 					content = open_reco_file.read()
 					content = read_csv_content(content)
-					webnotes.conn.set_value("Stock Reconciliation", reco, "reconciliation_json",
-						json.dumps(content, separators=(',', ': ')))
+					reconciliation_json = json.dumps(content, separators=(',', ': '))
+					webnotes.conn.sql("""update `tabStock Reconciliation`
+						set reconciliation_json=%s where name=%s""", (reconciliation_json, name))
 	
\ No newline at end of file
diff --git a/public/js/stock_controller.js b/public/js/stock_controller.js
new file mode 100644
index 0000000..d3511e1
--- /dev/null
+++ b/public/js/stock_controller.js
@@ -0,0 +1,32 @@
+// 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.provide("erpnext.stock");
+
+erpnext.stock.StockController = erpnext.utils.Controller.extend({
+	show_stock_ledger: function() {
+		var me = this;
+		this.frm.add_custom_button("Show Stock Ledger", function() {
+			var args = {
+				voucher_no: cur_frm.doc.name,
+				from_date: wn.datetime.str_to_user(cur_frm.doc.posting_date),
+				to_date: wn.datetime.str_to_user(cur_frm.doc.posting_date)
+			};	
+			wn.set_route('stock-ledger', 
+				$.map(args, function(val, key) { return key+"="+val; }).join("&&"));
+		}, "icon-bar-chart");
+	}
+});
\ No newline at end of file
diff --git a/stock/doctype/bin/bin.py b/stock/doctype/bin/bin.py
index c473a6c..19ce8f9 100644
--- a/stock/doctype/bin/bin.py
+++ b/stock/doctype/bin/bin.py
@@ -31,18 +31,34 @@
 		self.doc = doc
 		self.doclist = doclist
 		
+	def validate(self):
+		if not self.doc.stock_uom:
+			self.doc.stock_uom = webnotes.conn.get_value('Item', self.doc.item_code, 'stock_uom')
+		
+		if not self.doc.warehouse_type:
+			self.doc.warehouse_type = webnotes.conn.get_value("Warehouse", self.doc.warehouse,
+				"warehouse_type")
+		
+		self.validate_mandatory()
+		
+		self.doc.projected_qty = flt(self.doc.actual_qty) + flt(self.doc.ordered_qty) + \
+		 	flt(self.doc.indented_qty) + flt(self.doc.planned_qty) - flt(self.doc.reserved_qty)
+		
+	def validate_mandatory(self):
+		qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
+		for f in qf:
+			if (not self.doc.fields.has_key(f)) or (not self.doc.fields[f]): 
+				self.doc.fields[f] = 0.0
+		
 	def update_stock(self, args):
-		from stock.stock_ledger import update_entries_after
-		if not args.get("posting_date"):
-			posting_date = nowdate()
-			
 		self.update_qty(args)
 		
-		if (flt(args.get("actual_qty")) < 0 or flt(args.get("reserved_qty")) > 0) \
-				and args.get("is_cancelled") == 'No' and args.get("is_amended")=='No':
-			self.reorder_item(args.get("voucher_type"), args.get("voucher_no"))
-		
 		if args.get("actual_qty"):
+			from stock.stock_ledger import update_entries_after
+			
+			if not args.get("posting_date"):
+				posting_date = nowdate()
+			
 			# update valuation and qty after transaction for post dated entry
 			update_entries_after({
 				"item_code": self.doc.item_code,
@@ -53,8 +69,8 @@
 					
 	def update_qty(self, args):
 		# update the stock values (for current quantities)
-		self.doc.actual_qty = flt(self.doc.actual_qty) + flt(args.get("actual_qty", 0))
-		self.doc.ordered_qty = flt(self.doc.ordered_qty) + flt(args.get("ordered_qty", 0))
+		self.doc.actual_qty = flt(self.doc.actual_qty) + flt(args.get("actual_qty"))
+		self.doc.ordered_qty = flt(self.doc.ordered_qty) + flt(args.get("ordered_qty"))
 		self.doc.reserved_qty = flt(self.doc.reserved_qty) + flt(args.get("reserved_qty"))
 		self.doc.indented_qty = flt(self.doc.indented_qty) + flt(args.get("indented_qty"))
 		self.doc.planned_qty = flt(self.doc.planned_qty) + flt(args.get("planned_qty"))
@@ -63,6 +79,10 @@
 		 	flt(self.doc.indented_qty) + flt(self.doc.planned_qty) - flt(self.doc.reserved_qty)
 		
 		self.doc.save()
+		
+		if (flt(args.get("actual_qty")) < 0 or flt(args.get("reserved_qty")) > 0) \
+				and args.get("is_cancelled") == 'No' and args.get("is_amended")=='No':
+			self.reorder_item(args.get("voucher_type"), args.get("voucher_no"))
 	
 	def get_first_sle(self):
 		sle = sql("""
@@ -75,111 +95,6 @@
 		""", (self.doc.item_code, self.doc.warehouse), as_dict=1)
 		return sle and sle[0] or None
 
-	
-			
-	# def get_serialized_inventory_values(self, val_rate, in_rate, opening_qty, \
-	# 		actual_qty, is_cancelled, serial_nos):
-	# 	"""
-	# 		get serialized inventory values
-	# 	"""
-	# 	if flt(in_rate) < 0: # wrong incoming rate
-	# 		in_rate = val_rate
-	# 	elif flt(in_rate) == 0 or flt(actual_qty) < 0: 
-	# 		# In case of delivery/stock issue, get average purchase rate
-	# 		# of serial nos of current entry
-	# 		in_rate = flt(sql("""select ifnull(avg(purchase_rate), 0) 
-	# 			from `tabSerial No` where name in (%s)""" % (serial_nos))[0][0])
-	# 
-	# 	if in_rate and val_rate == 0: # First entry
-	# 		val_rate = in_rate
-	# 	# val_rate is same as previous entry if val_rate is negative
-	# 	# Otherwise it will be calculated as per moving average
-	# 	elif opening_qty + actual_qty > 0 and ((opening_qty * val_rate) + \
-	# 			(actual_qty * in_rate)) > 0:
-	# 		val_rate = ((opening_qty *val_rate) + (actual_qty * in_rate)) / \
-	# 			(opening_qty + actual_qty)
-	# 	return val_rate, in_rate
-	# 
-	# def get_moving_average_inventory_values(self, val_rate, in_rate, opening_qty, actual_qty, is_cancelled):
-	# 	if flt(in_rate) == 0 or flt(actual_qty) < 0: 
-	# 		# In case of delivery/stock issue in_rate = 0 or wrong incoming rate
-	# 		in_rate = val_rate
-	# 
-	# 	# val_rate is same as previous entry if :
-	# 	# 1. actual qty is negative(delivery note / stock entry)
-	# 	# 2. cancelled entry
-	# 	# 3. val_rate is negative
-	# 	# Otherwise it will be calculated as per moving average
-	# 	if actual_qty > 0 and (opening_qty + actual_qty) > 0 and is_cancelled == 'No' \
-	# 			and ((opening_qty * val_rate) + (actual_qty * in_rate)) > 0:
-	# 		opening_qty = opening_qty > 0 and opening_qty or 0
-	# 		val_rate = ((opening_qty *val_rate) + (actual_qty * in_rate)) / \
-	# 			(opening_qty + actual_qty)
-	# 	elif (opening_qty + actual_qty) <= 0:
-	# 		val_rate = 0
-	# 	return val_rate, in_rate
-	# 
-	# def get_fifo_inventory_values(self, in_rate, actual_qty):
-	# 	# add batch to fcfs balance
-	# 	if actual_qty > 0:
-	# 		self.fcfs_bal.append([flt(actual_qty), flt(in_rate)])
-	# 
-	# 	# remove from fcfs balance
-	# 	else:
-	# 		incoming_cost = 0
-	# 		withdraw = flt(abs(actual_qty))
-	# 		while withdraw:
-	# 			if not self.fcfs_bal:
-	# 				break # nothing in store
-	# 			
-	# 			batch = self.fcfs_bal[0]
-	# 			
-	# 			if batch[0] <= withdraw:
-	# 				# not enough or exactly same qty in current batch, clear batch
-	# 				incoming_cost += flt(batch[1])*flt(batch[0])
-	# 				withdraw -= batch[0]
-	# 				self.fcfs_bal.pop(0)
-	# 				
-	# 
-	# 			else:
-	# 				# all from current batch
-	# 				incoming_cost += flt(batch[1])*flt(withdraw)
-	# 				batch[0] -= withdraw
-	# 				withdraw = 0
-	# 		
-	# 		in_rate = incoming_cost / flt(abs(actual_qty))
-	# 
-	# 	fcfs_val = sum([flt(d[0])*flt(d[1]) for d in self.fcfs_bal])
-	# 	fcfs_qty = sum([flt(d[0]) for d in self.fcfs_bal])
-	# 	val_rate = fcfs_qty and fcfs_val / fcfs_qty or 0
-	# 	
-	# 	return val_rate, in_rate
-	# 
-	# def get_valuation_rate(self, val_method, serial_nos, val_rate, in_rate, stock_val, cqty, s):
-	# 	if serial_nos:
-	# 		val_rate, in_rate = self.get_serialized_inventory_values( \
-	# 			val_rate, in_rate, opening_qty = cqty, actual_qty = s['actual_qty'], \
-	# 			is_cancelled = s['is_cancelled'], serial_nos = serial_nos)
-	# 	elif val_method == 'Moving Average':
-	# 		val_rate, in_rate = self.get_moving_average_inventory_values( \
-	# 			val_rate, in_rate, opening_qty = cqty, actual_qty = s['actual_qty'], \
-	# 			is_cancelled = s['is_cancelled'])
-	# 	elif val_method == 'FIFO':
-	# 		val_rate, in_rate = self.get_fifo_inventory_values(in_rate, \
-	# 			actual_qty = s['actual_qty'])
-	# 	return val_rate, in_rate
-
-	# def get_stock_value(self, val_method, cqty, val_rate, serial_nos):
-	# 	if serial_nos:
-	# 		stock_val = flt(val_rate) * flt(cqty)
-	# 	elif val_method == 'Moving Average':
-	# 		stock_val = flt(cqty) > 0 and flt(val_rate) * flt(cqty) or 0
-	# 	elif val_method == 'FIFO':
-	# 		stock_val = sum([flt(d[0])*flt(d[1]) for d in self.fcfs_bal])
-	# 	return stock_val
-
-	
-
 	def reorder_item(self,doc_type,doc_name):
 		""" Reorder item if stock reaches reorder level"""
 
@@ -246,12 +161,3 @@
 		msg="""A Purchase Request has been raised 
 			for item %s: %s on %s """ % (doc_type, doc_name, nowdate())
 		sendmail(email_list, subject='Auto Purchase Request Generation Notification', msg = msg)	
-
-	def validate(self):
-		self.validate_mandatory()
-
-	def validate_mandatory(self):
-		qf = ['actual_qty', 'reserved_qty', 'ordered_qty', 'indented_qty']
-		for f in qf:
-			if (not self.doc.fields.has_key(f)) or (not self.doc.fields[f]): 
-				self.doc.fields[f] = 0.0
diff --git a/stock/doctype/stock_entry/stock_entry.js b/stock/doctype/stock_entry/stock_entry.js
index a6d233e..bb55622 100644
--- a/stock/doctype/stock_entry/stock_entry.js
+++ b/stock/doctype/stock_entry/stock_entry.js
@@ -14,9 +14,10 @@
 // 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("public/app/js/stock_controller.js");
 wn.provide("erpnext.stock");
 
-erpnext.stock.StockEntry = erpnext.utils.Controller.extend({
+erpnext.stock.StockEntry = erpnext.stock.StockController.extend({
 	onload_post_render: function() {
 		this._super();
 		if(this.frm.doc.__islocal && (this.frm.doc.production_order || this.frm.doc.bom_no) 
@@ -30,8 +31,9 @@
 		this._super();
 		this.toggle_related_fields(this.frm.doc);
 		this.toggle_enable_bom();
-		if (this.frm.doc.docstatus==1) this.frm.add_custom_button("Show Stock Ledger", 
-			this.show_stock_ledger)
+		if (this.frm.doc.docstatus==1) {
+			this.show_stock_ledger();
+		}
 	},
 	
 	on_submit: function() {
@@ -108,16 +110,6 @@
 	}
 }
 
-cur_frm.cscript.show_stock_ledger = function() {
-	var args = {
-		voucher_no: cur_frm.doc.name,
-		from_date: wn.datetime.str_to_user(cur_frm.doc.posting_date),
-		to_date: wn.datetime.str_to_user(cur_frm.doc.posting_date)
-	};	
-	wn.set_route('stock-ledger', 
-		$.map(args, function(val, key) { return key+"="+val; }).join("&&"));
-}
-
 cur_frm.cscript.delivery_note_no = function(doc,cdt,cdn){
 	if(doc.delivery_note_no) get_server_fields('get_cust_values','','',doc,cdt,cdn,1);
 }
diff --git a/stock/doctype/stock_entry/stock_entry.txt b/stock/doctype/stock_entry/stock_entry.txt
index d3b39c3..76a8d42 100644
--- a/stock/doctype/stock_entry/stock_entry.txt
+++ b/stock/doctype/stock_entry/stock_entry.txt
@@ -2,27 +2,27 @@
  {
   "owner": "Administrator", 
   "docstatus": 0, 
-  "creation": "2012-12-19 12:29:07", 
+  "creation": "2012-12-24 18:32:32", 
   "modified_by": "Administrator", 
-  "modified": "2012-12-19 18:09:15"
+  "modified": "2013-01-11 11:54:51"
  }, 
  {
-  "is_submittable": 1, 
   "in_create": 0, 
+  "is_submittable": 1, 
   "allow_print": 0, 
   "search_fields": "transfer_date, from_warehouse, to_warehouse, purpose, remarks", 
   "module": "Stock", 
-  "autoname": "naming_series:", 
+  "doctype": "DocType", 
   "read_only_onload": 0, 
   "in_dialog": 0, 
+  "issingle": 0, 
   "allow_attach": 0, 
   "read_only": 0, 
   "allow_email": 0, 
   "hide_heading": 0, 
-  "issingle": 0, 
+  "autoname": "naming_series:", 
   "name": "__common__", 
   "allow_rename": 0, 
-  "doctype": "DocType", 
   "max_attachments": 0, 
   "hide_toolbar": 0, 
   "allow_copy": 0
@@ -47,6 +47,7 @@
   "doctype": "DocType"
  }, 
  {
+  "print_width": "50%", 
   "oldfieldtype": "Column Break", 
   "doctype": "DocField", 
   "width": "50%", 
@@ -93,6 +94,7 @@
   "in_filter": 1
  }, 
  {
+  "print_width": "50%", 
   "oldfieldtype": "Column Break", 
   "doctype": "DocField", 
   "width": "50%", 
@@ -146,7 +148,7 @@
  }, 
  {
   "print_hide": 1, 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "oldfieldtype": "Link", 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -170,7 +172,7 @@
  }, 
  {
   "print_hide": 1, 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "oldfieldtype": "Link", 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -279,7 +281,7 @@
  {
   "print_hide": 1, 
   "depends_on": "eval:doc.purpose==\"Sales Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 1, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -298,7 +300,7 @@
  {
   "print_hide": 1, 
   "depends_on": "eval:doc.purpose==\"Purchase Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 1, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -349,6 +351,7 @@
  }, 
  {
   "print_hide": 1, 
+  "no_copy": 1, 
   "depends_on": "eval:doc.purpose==\"Sales Return\"", 
   "doctype": "DocField", 
   "label": "Sales Invoice No", 
@@ -369,7 +372,7 @@
  {
   "print_hide": 1, 
   "depends_on": "eval:doc.purpose==\"Purchase Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -388,7 +391,7 @@
  {
   "print_hide": 0, 
   "depends_on": "eval:doc.purpose==\"Purchase Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -406,7 +409,7 @@
  {
   "print_hide": 0, 
   "depends_on": "eval:doc.purpose==\"Purchase Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -424,7 +427,7 @@
  {
   "print_hide": 1, 
   "depends_on": "eval:doc.purpose==\"Sales Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -443,7 +446,7 @@
  {
   "print_hide": 0, 
   "depends_on": "eval:doc.purpose==\"Sales Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -461,7 +464,7 @@
  {
   "print_hide": 0, 
   "depends_on": "eval:doc.purpose==\"Sales Return\"", 
-  "no_copy": 0, 
+  "no_copy": 1, 
   "search_index": 0, 
   "allow_on_submit": 0, 
   "doctype": "DocField", 
@@ -485,6 +488,7 @@
   "permlevel": 0
  }, 
  {
+  "print_width": "50%", 
   "doctype": "DocField", 
   "width": "50%", 
   "fieldname": "col4", 
@@ -539,6 +543,7 @@
   "in_filter": 1
  }, 
  {
+  "print_width": "50%", 
   "doctype": "DocField", 
   "width": "50%", 
   "fieldname": "col5", 
@@ -601,16 +606,23 @@
   "permlevel": 1
  }, 
  {
+  "amend": 0, 
   "create": 0, 
   "doctype": "DocPerm", 
+  "submit": 0, 
   "write": 1, 
   "role": "Manufacturing User", 
+  "cancel": 0, 
   "permlevel": 2
  }, 
  {
+  "amend": 0, 
+  "create": 0, 
   "doctype": "DocPerm", 
+  "submit": 0, 
   "write": 1, 
   "role": "Manufacturing Manager", 
+  "cancel": 0, 
   "permlevel": 2
  }, 
  {
@@ -624,8 +636,12 @@
   "permlevel": 0
  }, 
  {
+  "amend": 0, 
+  "create": 0, 
   "doctype": "DocPerm", 
+  "submit": 0, 
   "role": "Manufacturing User", 
+  "cancel": 0, 
   "permlevel": 1
  }, 
  {
@@ -639,8 +655,12 @@
   "permlevel": 0
  }, 
  {
+  "amend": 0, 
+  "create": 0, 
   "doctype": "DocPerm", 
+  "submit": 0, 
   "role": "Manufacturing Manager", 
+  "cancel": 0, 
   "permlevel": 1
  }, 
  {
diff --git a/stock/doctype/stock_entry_detail/stock_entry_detail.txt b/stock/doctype/stock_entry_detail/stock_entry_detail.txt
index 6926c9a..a6b9521 100644
--- a/stock/doctype/stock_entry_detail/stock_entry_detail.txt
+++ b/stock/doctype/stock_entry_detail/stock_entry_detail.txt
@@ -2,9 +2,9 @@
  {
   "owner": "Administrator", 
   "docstatus": 0, 
-  "creation": "2012-12-18 13:47:41", 
+  "creation": "2012-12-20 14:31:18", 
   "modified_by": "Administrator", 
-  "modified": "2012-12-18 17:08:52"
+  "modified": "2013-01-11 11:59:10"
  }, 
  {
   "istable": 1, 
@@ -26,6 +26,7 @@
   "doctype": "DocType"
  }, 
  {
+  "no_copy": 1, 
   "oldfieldtype": "Link", 
   "doctype": "DocField", 
   "label": "Source Warehouse", 
@@ -37,6 +38,7 @@
   "in_filter": 1
  }, 
  {
+  "no_copy": 1, 
   "oldfieldtype": "Link", 
   "doctype": "DocField", 
   "label": "Target Warehouse", 
@@ -61,6 +63,7 @@
   "in_filter": 1
  }, 
  {
+  "print_width": "300px", 
   "oldfieldtype": "Text", 
   "doctype": "DocField", 
   "label": "Description", 
diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.js b/stock/doctype/stock_reconciliation/stock_reconciliation.js
index 1e64965..62bc69f 100644
--- a/stock/doctype/stock_reconciliation/stock_reconciliation.js
+++ b/stock/doctype/stock_reconciliation/stock_reconciliation.js
@@ -13,9 +13,11 @@
 // 
 // 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("public/app/js/stock_controller.js");
 wn.provide("erpnext.stock");
 
-erpnext.stock.StockReconciliation = erpnext.utils.Controller.extend({
+erpnext.stock.StockReconciliation = erpnext.stock.StockController.extend({
 	refresh: function() {
 		if(this.frm.doc.docstatus===0) {
 			this.show_download_template();
@@ -23,22 +25,37 @@
 			if(this.frm.doc.reconciliation_json) {
 				this.frm.set_intro("You can submit this Stock Reconciliation.");
 			} else {
-				this.frm.set_intro("Download the template, fill in data and \
-					upload it.");
+				this.frm.set_intro("Download the Template, fill appropriate data and \
+					attach the modified file.");
 			}
+		} else if(this.frm.doc.docstatus == 1) {
+			this.frm.set_intro("Cancelling this Stock Reconciliation will nullify it's effect.");
+			this.show_stock_ledger();
+		} else {
+			this.frm.set_intro("");
 		}
-		if(this.frm.doc.reconciliation_json) {
-			this.show_reconciliation_data();
-			this.show_download_reconciliation_data();
-		}
+		this.show_reconciliation_data();
+		this.show_download_reconciliation_data();
 	},
 	
 	show_download_template: function() {
 		var me = this;
 		this.frm.add_custom_button("Download Template", function() {
 			this.title = "Stock Reconcilation Template";
-			wn.tools.downloadify([["Item Code", "Warehouse", "Quantity", "Valuation Rate"]], null,
-				this);
+			wn.tools.downloadify([["Stock Reconciliation"],
+				["----"],
+				["Stock Reconciliation can be used to update the stock on a particular date,"
+					+ " usually as per physical inventory."],
+				["When submitted, the system creates difference entries"
+					+ " to set the given stock and valuation on this date."],
+				["It can also be used to create opening stock entries and to fix stock value."],
+				["----"],
+				["Notes:"],
+				["Item Code and Warehouse should already exist."],
+				["You can update either Quantity or Valuation Rate or both."],
+				["If no change in either Quantity or Valuation Rate, leave the cell blank."],
+				["----"],
+				["Item Code", "Warehouse", "Quantity", "Valuation Rate"]], null, this);
 			return false;
 		}, "icon-download");
 	},
@@ -59,22 +76,25 @@
 				$wrapper.find(".dit-progress-area").toggle(false);
 				me.frm.set_value("reconciliation_json", JSON.stringify(r));
 				me.show_reconciliation_data();
+				me.frm.save();
 			}
 		});
 	},
 	
 	show_download_reconciliation_data: function() {
 		var me = this;
-		this.frm.add_custom_button("Download Reconcilation Data", function() {
-			this.title = "Stock Reconcilation Data";
-			wn.tools.downloadify(JSON.parse(me.frm.doc.reconciliation_json), null, this);
-			return false;
-		}, "icon-download");
+		if(this.frm.doc.reconciliation_json) {
+			this.frm.add_custom_button("Download Reconcilation Data", function() {
+				this.title = "Stock Reconcilation Data";
+				wn.tools.downloadify(JSON.parse(me.frm.doc.reconciliation_json), null, this);
+				return false;
+			}, "icon-download");
+		}
 	},
 	
 	show_reconciliation_data: function() {
+		var $wrapper = $(cur_frm.fields_dict.reconciliation_html.wrapper).empty();
 		if(this.frm.doc.reconciliation_json) {
-			var $wrapper = $(cur_frm.fields_dict.reconciliation_html.wrapper).empty();
 			var reconciliation_data = JSON.parse(this.frm.doc.reconciliation_json);
 
 			var _make = function(data, header) {
@@ -92,14 +112,14 @@
 				return result;
 			};
 			
-			var $reconciliation_table = $("<div style='overflow-x: scroll;'>\
+			var $reconciliation_table = $("<div style='overflow-x: auto;'>\
 					<table class='table table-striped table-bordered'>\
 					<thead>" + _make([reconciliation_data[0]], true) + "</thead>\
 					<tbody>" + _make(reconciliation_data.splice(1)) + "</tbody>\
 					</table>\
 				</div>").appendTo($wrapper);
 		}
-	}
+	},
 });
 
 cur_frm.cscript = new erpnext.stock.StockReconciliation({frm: cur_frm});
\ No newline at end of file
diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.py b/stock/doctype/stock_reconciliation/stock_reconciliation.py
index 725bb5f..3a8ffcd 100644
--- a/stock/doctype/stock_reconciliation/stock_reconciliation.py
+++ b/stock/doctype/stock_reconciliation/stock_reconciliation.py
@@ -23,6 +23,9 @@
 from stock.stock_ledger import update_entries_after
 
 class DocType(DocListController):
+	def setup(self):
+		self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"]
+		
 	def validate(self):
 		self.validate_data()
 		
@@ -34,17 +37,22 @@
 		
 	def validate_data(self):
 		data = json.loads(self.doc.reconciliation_json)
-		if data[0] != ["Item Code", "Warehouse", "Quantity", "Valuation Rate"]:
+		if self.head_row not in data:
 			msgprint(_("""Hey! You seem to be using the wrong template. \
 				Click on 'Download Template' button to get the correct template."""),
 				raise_exception=1)
+		
+		# remove the help part and save the json
+		if data.index(self.head_row) != 0:
+			data = data[data.index(self.head_row):]
+			self.doc.reconciliation_json = json.dumps(data)
 				
 		def _get_msg(row_num, msg):
 			return _("Row # ") + ("%d: " % (row_num+2)) + _(msg)
 		
 		self.validation_messages = []
 		item_warehouse_combinations = []
-		for row_num, row in enumerate(data[1:]):
+		for row_num, row in enumerate(data[data.index(self.head_row)+1:]):
 			# find duplicates
 			if [row[0], row[1]] in item_warehouse_combinations:
 				self.validation_messages.append(_get_msg(row_num, "Duplicate entry"))
@@ -111,7 +119,7 @@
 		row_template = ["item_code", "warehouse", "qty", "valuation_rate"]
 		
 		data = json.loads(self.doc.reconciliation_json)
-		for row_num, row in enumerate(data[1:]):
+		for row_num, row in enumerate(data[data.index(self.head_row)+1:]):
 			row = webnotes._dict(zip(row_template, row))
 			previous_sle = get_previous_sle({
 				"item_code": row.item_code,
@@ -148,18 +156,19 @@
 		if change_in_qty:
 			# if change in qty, irrespective of change in rate
 			incoming_rate = _get_incoming_rate(flt(row.qty), flt(row.valuation_rate),
-				flt(previous_sle.qty_after_transaction),
-				flt(previous_sle.valuation_rate))
+				flt(previous_sle.get("qty_after_transaction")),
+				flt(previous_sle.get("valuation_rate")))
 			
 			self.insert_entries({"actual_qty": change_in_qty, 
 				"incoming_rate": incoming_rate}, row)
 			
-		elif change_in_rate and previous_sle.qty_after_transaction >= 0:
+		elif change_in_rate and flt(previous_sle.get("qty_after_transaction")) >= 0:
 			# if no change in qty, but change in rate 
 			# and positive actual stock before this reconciliation
-			incoming_rate = _get_incoming_rate(flt(previous_sle.qty_after_transaction)+1,
-				flt(row.valuation_rate), flt(previous_sle.qty_after_transaction),
-				flt(previous_sle.valuation_rate))
+			incoming_rate = _get_incoming_rate(
+				flt(previous_sle.get("qty_after_transaction"))+1, flt(row.valuation_rate),
+				flt(previous_sle.get("qty_after_transaction")), 
+				flt(previous_sle.get("valuation_rate")))
 				
 			# +1 entry
 			self.insert_entries({"actual_qty": 1, "incoming_rate": incoming_rate}, row)
@@ -169,7 +178,7 @@
 		
 	def sle_for_fifo(self, row, previous_sle, change_in_qty, change_in_rate):
 		"""Insert Stock Ledger Entries for FIFO valuation"""
-		previous_stock_queue = json.loads(previous_sle.stock_queue or "[]")
+		previous_stock_queue = json.loads(previous_sle.get("stock_queue") or "[]")
 		previous_stock_qty = sum((batch[0] for batch in previous_stock_queue))
 		previous_stock_value = sum((batch[0] * batch[1] for batch in \
 			previous_stock_queue))
@@ -181,9 +190,11 @@
 					"incoming_rate": flt(row.valuation_rate)}, row)
 				
 				# Make reverse entry
-				self.insert_entries({"actual_qty": -1 * previous_stock_qty, 
-					"incoming_rate": previous_stock_qty < 0 and \
-					flt(row.valuation_rate) or 0}, row)
+				if previous_stock_qty:
+					self.insert_entries({"actual_qty": -1 * previous_stock_qty, 
+						"incoming_rate": previous_stock_qty < 0 and \
+						flt(row.valuation_rate) or 0}, row)
+					
 					
 		if change_in_qty:
 			if row.valuation_rate == "":
@@ -213,13 +224,17 @@
 			"voucher_type": self.doc.doctype,
 			"voucher_no": self.doc.name,
 			"company": webnotes.conn.get_default("company"),
-			"is_cancelled": "No"
+			"is_cancelled": "No",
 		}
 		args.update(opts)
 
+		# create stock ledger entry
 		sle_wrapper = webnotes.model_wrapper([args]).insert()
+		
+		# update bin
+		webnotes.get_obj('Warehouse', row.warehouse).update_bin(args)
 
-		update_entries_after(args)
+		# update_entries_after(args)
 		
 		return sle_wrapper
 		
diff --git a/stock/doctype/stock_reconciliation/stock_reconciliation.txt b/stock/doctype/stock_reconciliation/stock_reconciliation.txt
index 272bf99..ddd7e08 100644
--- a/stock/doctype/stock_reconciliation/stock_reconciliation.txt
+++ b/stock/doctype/stock_reconciliation/stock_reconciliation.txt
@@ -2,9 +2,9 @@
  {
   "owner": "Administrator", 
   "docstatus": 0, 
-  "creation": "2013-01-09 11:24:35", 
+  "creation": "2013-01-11 12:04:17", 
   "modified_by": "Administrator", 
-  "modified": "2013-01-10 19:26:28"
+  "modified": "2013-01-11 15:36:21"
  }, 
  {
   "allow_attach": 0, 
@@ -29,11 +29,18 @@
   "parentfield": "fields"
  }, 
  {
-  "name": "__common__", 
   "parent": "Stock Reconciliation", 
   "read": 1, 
   "doctype": "DocPerm", 
+  "cancel": 1, 
+  "name": "__common__", 
+  "amend": 1, 
+  "create": 1, 
+  "submit": 1, 
+  "write": 1, 
   "parenttype": "DocType", 
+  "role": "Material Manager", 
+  "permlevel": 0, 
   "parentfield": "permissions"
  }, 
  {
@@ -78,22 +85,6 @@
   "fieldtype": "Column Break"
  }, 
  {
-  "read_only": 0, 
-  "oldfieldtype": "Text", 
-  "doctype": "DocField", 
-  "label": "Remark", 
-  "oldfieldname": "remark", 
-  "fieldname": "remark", 
-  "fieldtype": "Text"
- }, 
- {
-  "depends_on": "eval:doc.docstatus===0", 
-  "doctype": "DocField", 
-  "label": "Upload", 
-  "fieldname": "sb1", 
-  "fieldtype": "Section Break"
- }, 
- {
   "read_only": 1, 
   "print_hide": 1, 
   "doctype": "DocField", 
@@ -102,6 +93,7 @@
   "fieldtype": "HTML"
  }, 
  {
+  "depends_on": "reconciliation_json", 
   "doctype": "DocField", 
   "label": "Reconciliation Data", 
   "fieldname": "sb2", 
@@ -127,32 +119,6 @@
   "hidden": 1
  }, 
  {
-  "amend": 0, 
-  "create": 1, 
-  "doctype": "DocPerm", 
-  "submit": 1, 
-  "write": 1, 
-  "cancel": 1, 
-  "role": "Material Manager", 
-  "permlevel": 0
- }, 
- {
-  "amend": 0, 
-  "create": 0, 
-  "doctype": "DocPerm", 
-  "submit": 0, 
-  "write": 0, 
-  "cancel": 0, 
-  "role": "Material Manager", 
-  "permlevel": 1
- }, 
- {
-  "create": 1, 
-  "doctype": "DocPerm", 
-  "submit": 1, 
-  "write": 1, 
-  "cancel": 1, 
-  "role": "System Manager", 
-  "permlevel": 0
+  "doctype": "DocPerm"
  }
 ]
\ No newline at end of file
diff --git a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
index fadc3b4..224d70e 100644
--- a/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
+++ b/stock/doctype/stock_reconciliation/test_stock_reconciliation.py
@@ -36,18 +36,19 @@
 		webnotes.conn.rollback()
 		
 	def test_reco_for_fifo(self):
-		# [[qty, valuation_rate, posting_date, posting_time]]
+		# [[qty, valuation_rate, posting_date, posting_time, expected_stock_value, bin_qty]]
 		input_data = [
-			[50, 1000, "2012-12-26", "12:00", 50000], 
-			[5, 1000, "2012-12-26", "12:00", 5000], 
-			[15, 1000, "2012-12-26", "12:00", 15000], 
-			[25, 900, "2012-12-26", "12:00", 22500], 
-			[20, 500, "2012-12-26", "12:00", 10000], 
-			[50, 1000, "2013-01-01", "12:00", 50000], 
-			[5, 1000, "2013-01-01", "12:00", 5000],
-			["", 1000, "2012-12-26", "12:05", 15000],
-			[20, "", "2012-12-26", "12:05", 16000],
-			[10, 2000, "2012-12-26", "12:10", 20000]
+			[50, 1000, "2012-12-26", "12:00", 50000, 45, 48000], 
+			[5, 1000, "2012-12-26", "12:00", 5000, 0, 0], 
+			[15, 1000, "2012-12-26", "12:00", 15000, 10, 12000], 
+			[25, 900, "2012-12-26", "12:00", 22500, 20, 22500], 
+			[20, 500, "2012-12-26", "12:00", 10000, 15, 18000], 
+			[50, 1000, "2013-01-01", "12:00", 50000, 65, 68000], 
+			[5, 1000, "2013-01-01", "12:00", 5000, 20, 23000],
+			["", 1000, "2012-12-26", "12:05", 15000, 10, 12000],
+			[20, "", "2012-12-26", "12:05", 16000, 15, 18000],
+			[10, 2000, "2012-12-26", "12:10", 20000, 5, 6000],
+			[1, 1000, "2012-12-01", "00:00", 1000, 11, 13200],
 		]
 			
 		for d in input_data:
@@ -60,14 +61,19 @@
 				and posting_date = %s and posting_time = %s order by name desc limit 1""", 
 				(d[2], d[3]))
 				
-			# stock_value = sum([v[0]*v[1] for v in json.loads(res and res[0][0] or "[]")])
 			self.assertEqual(res and flt(res[0][0]) or 0, d[4])
 			
+			bin = webnotes.conn.sql("""select actual_qty, stock_value from `tabBin`
+				where item_code = 'Android Jack D' and warehouse = 'Default Warehouse'""")
+			
+			self.assertEqual(bin and [flt(bin[0][0]), flt(bin[0][1])] or [], [d[5], d[6]])
+			
+			
 			self.tearDown()
 			self.setUp()
 					
 		
-	def test_reco_for_moving_average(self):
+	def atest_reco_for_moving_average(self):
 		# [[qty, valuation_rate, posting_date, posting_time]]
 		input_data = [
 			[50, 1000, "2012-12-26", "12:00", 50000], 
@@ -79,7 +85,8 @@
 			[5, 1000, "2013-01-01", "12:00", 5000],
 			["", 1000, "2012-12-26", "12:05", 15000],
 			[20, "", "2012-12-26", "12:05", 18000],
-			[10, 2000, "2012-12-26", "12:10", 20000]
+			[10, 2000, "2012-12-26", "12:10", 20000],
+			[1, 1000, "2012-12-01", "00:00", 1000],
 		]
 		
 		for d in input_data:
@@ -96,7 +103,7 @@
 			
 			self.tearDown()
 			self.setUp()
-		
+			
 	def submit_stock_reconciliation(self, qty, rate, posting_date, posting_time):
 		return webnotes.model_wrapper([{
 			"doctype": "Stock Reconciliation",
@@ -168,12 +175,4 @@
 			},
 		]
 		
-		# pprint(webnotes.conn.sql("""select * from `tabBin` where item_code='Android Jack D' 
-		# 			and warehouse='Default Warehouse'""", as_dict=1))
-		
-		webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers)
-		
-		# pprint(webnotes.conn.sql("""select * from `tabBin` where item_code='Android Jack D' 
-		# 	and warehouse='Default Warehouse'""", as_dict=1))
-			
-		
\ No newline at end of file
+		webnotes.get_obj("Stock Ledger").update_stock(existing_ledgers)
\ No newline at end of file
diff --git a/stock/doctype/warehouse/warehouse.py b/stock/doctype/warehouse/warehouse.py
index 775f0d0..8d6065c 100644
--- a/stock/doctype/warehouse/warehouse.py
+++ b/stock/doctype/warehouse/warehouse.py
@@ -35,15 +35,13 @@
 				warehouse = %s", (item_code, warehouse))
 		bin = bin and bin[0][0] or ''
 		if not bin:
-			bin = Document('Bin')
-			bin.item_code = item_code
-			bin.stock_uom = webnotes.conn.get_value('Item', item_code, 'stock_uom')
-			bin.warehouse = warehouse
-			bin.warehouse_type = webnotes.conn.get_value("Warehouse", warehouse, "warehouse_type")
-			bin_obj = get_obj(doc=bin)
-			bin_obj.validate()
-			bin.save(1)
-			bin = bin.name
+			bin_wrapper = webnotes.model_wrapper([{
+				"doctype": "Bin",
+				"item_code": item_code,
+				"warehouse": warehouse,
+			}]).insert()
+			
+			bin_obj = bin_wrapper.make_obj()
 		else:
 			bin_obj = get_obj('Bin', bin)
 		return bin_obj
diff --git a/stock/stock_ledger.py b/stock/stock_ledger.py
index f88ea5d..3cad355 100644
--- a/stock/stock_ledger.py
+++ b/stock/stock_ledger.py
@@ -89,6 +89,14 @@
 		_raise_exceptions(args, verbose)
 	
 	# update bin
+	if not webnotes.conn.exists({"doctype": "Bin", "item_code": args["item_code"], 
+			"warehouse": args["warehouse"]}):
+		webnotes.model_wrapper([{
+			"doctype": "Bin",
+			"item_code": args["item_code"],
+			"warehouse": args["warehouse"],
+		}]).insert()
+	
 	webnotes.conn.sql("""update `tabBin` set valuation_rate=%s, actual_qty=%s,
 		stock_value=%s, 
 		projected_qty = (actual_qty + indented_qty + ordered_qty + planned_qty - reserved_qty)
@@ -209,7 +217,7 @@
 def get_fifo_values(qty_after_transaction, sle, stock_queue):
 	incoming_rate = flt(sle.incoming_rate)
 	actual_qty = flt(sle.actual_qty)
-	
+
 	if not stock_queue:
 		stock_queue.append([0, 0])