chore: Stock Entry Tests and fixes

- Maintain item-warehouse wise rules for Stock Entry Material Transfer
- Test cases for Stock Entry with more use cases
- Sider fixes
diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js
index 5463448..2dabb9a 100644
--- a/erpnext/public/js/controllers/transaction.js
+++ b/erpnext/public/js/controllers/transaction.js
@@ -2030,7 +2030,7 @@
 	});
 }
 
-erpnext.apply_putaway_rule = (frm) => {
+erpnext.apply_putaway_rule = (frm, purpose=null) => {
 	if (!frm.doc.company) {
 		frappe.throw({message: __("Please select a Company first."), title: __("Mandatory")});
 	}
@@ -2042,7 +2042,8 @@
 			doctype: frm.doctype,
 			items: frm.doc.items,
 			company: frm.doc.company,
-			sync: true
+			sync: true,
+			purpose: purpose
 		},
 		callback: (result) => {
 			if (!result.exc && result.message) {
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
index 4ed4daf..5675258 100644
--- a/erpnext/stock/doctype/putaway_rule/putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
@@ -64,11 +64,14 @@
 	return free_space if free_space > 0 else 0
 
 @frappe.whitelist()
-def apply_putaway_rule(doctype, items, company, sync=None):
+def apply_putaway_rule(doctype, items, company, sync=None, purpose=None):
 	""" Applies Putaway Rule on line items.
 
-		items: List of Purchase Receipt Item objects
-		company: Company in the Purchase Receipt
+		items: List of Purchase Receipt/Stock Entry Items
+		company: Company in the Purchase Receipt/Stock Entry
+		doctype: Doctype to apply rule on
+		purpose: Purpose of Stock Entry
+		sync (optional): Sync with client side only for client side calls
 	"""
 	if isinstance(items, string_types):
 		items = json.loads(items)
@@ -82,31 +85,36 @@
 
 		source_warehouse = item.get("s_warehouse")
 		serial_nos = get_serial_nos(item.get("serial_no"))
-		item.conversion_factor = flt(item.conversion_factor) or 1
+		item.conversion_factor = flt(item.conversion_factor) or 1.0
 		pending_qty, item_code = flt(item.qty), item.item_code
 		pending_stock_qty = flt(item.transfer_qty) if doctype == "Stock Entry" else flt(item.stock_qty)
-		if not pending_qty or not item_code:
-			updated_table = add_row(item, pending_qty, item.warehouse, updated_table)
-			continue
-
 		uom_must_be_whole_number = frappe.db.get_value('UOM', item.uom, 'must_be_whole_number')
 
+		if not pending_qty or not item_code:
+			updated_table = add_row(item, pending_qty, source_warehouse or item.warehouse, updated_table)
+			continue
+
 		at_capacity, rules = get_ordered_putaway_rules(item_code, company, source_warehouse=source_warehouse)
 
 		if not rules:
-			warehouse = item.warehouse
+			warehouse = source_warehouse or item.warehouse
 			if at_capacity:
-				warehouse = '' # rules available, but no free space
+				# rules available, but no free space
 				items_not_accomodated.append([item_code, pending_qty])
-			updated_table = add_row(item, pending_qty, warehouse, updated_table)
+			else:
+				updated_table = add_row(item, pending_qty, warehouse, updated_table)
 			continue
 
-		# maintain item wise rules, to handle if item is entered twice
+		# maintain item/item-warehouse wise rules, to handle if item is entered twice
 		# in the table, due to different price, etc.
-		if not item_wise_rules[item_code]:
-			item_wise_rules[item_code] = rules
+		key = item_code
+		if doctype == "Stock Entry" and purpose == "Material Transfer" and source_warehouse:
+			key = (item_code, source_warehouse)
 
-		for rule in item_wise_rules[item_code]:
+		if not item_wise_rules[key]:
+			item_wise_rules[key] = rules
+
+		for rule in item_wise_rules[key]:
 			if pending_stock_qty > 0 and rule.free_space:
 				stock_qty_to_allocate = flt(rule.free_space) if pending_stock_qty >= flt(rule.free_space) else pending_stock_qty
 				qty_to_allocate = stock_qty_to_allocate / item.conversion_factor
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
index 17619e0..86f7dc3 100644
--- a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -4,12 +4,11 @@
 from __future__ import unicode_literals
 import frappe
 import unittest
-from frappe.utils import add_days, nowdate
 from erpnext.stock.doctype.item.test_item import make_item
 from erpnext.stock.get_item_details import get_conversion_factor
 from erpnext.stock.doctype.warehouse.test_warehouse import create_warehouse
 from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
-from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
+from erpnext.stock.doctype.batch.test_batch import make_new_batch
 from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import make_purchase_receipt
 
 class TestPutawayRule(unittest.TestCase):
@@ -27,6 +26,9 @@
 		if not frappe.db.exists("Warehouse", {"warehouse_name": "Rack 2"}):
 			create_warehouse("Rack 2")
 
+		self.warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
+		self.warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
+
 		if not frappe.db.exists("UOM", "Bag"):
 			new_uom = frappe.new_doc("UOM")
 			new_uom.uom_name = "Bag"
@@ -34,21 +36,18 @@
 
 	def test_putaway_rules_priority(self):
 		"""Test if rule is applied by priority, irrespective of free space."""
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
 			uom="Kg")
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=300,
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=300,
 			uom="Kg", priority=2)
 
 		pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
 			do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 200)
-		self.assertEqual(pr.items[0].warehouse, warehouse_1)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
 		self.assertEqual(pr.items[1].qty, 100)
-		self.assertEqual(pr.items[1].warehouse, warehouse_2)
+		self.assertEqual(pr.items[1].warehouse, self.warehouse_2)
 
 		pr.delete()
 		rule_1.delete()
@@ -57,26 +56,23 @@
 	def test_putaway_rules_with_same_priority(self):
 		"""Test if rule with more free space is applied,
 		among two rules with same priority and capacity."""
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=500,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=500,
 			uom="Kg")
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=500,
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=500,
 			uom="Kg")
 
 		# out of 500 kg capacity, occupy 100 kg in warehouse_1
-		stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=100, basic_rate=50)
+		stock_receipt = make_stock_entry(item_code="_Rice", target=self.warehouse_1, qty=100, basic_rate=50)
 
 		pr = make_purchase_receipt(item_code="_Rice", qty=700, apply_putaway_rule=1,
 			do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 500)
 		# warehouse_2 has 500 kg free space, it is given priority
-		self.assertEqual(pr.items[0].warehouse, warehouse_2)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
 		self.assertEqual(pr.items[1].qty, 200)
 		# warehouse_1 has 400 kg free space, it is given less priority
-		self.assertEqual(pr.items[1].warehouse, warehouse_1)
+		self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
 
 		stock_receipt.cancel()
 		pr.delete()
@@ -85,21 +81,20 @@
 
 	def test_putaway_rules_with_insufficient_capacity(self):
 		"""Test if qty exceeding capacity, is handled."""
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=100,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=100,
 			uom="Kg")
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=200,
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=200,
 			uom="Kg")
 
 		pr = make_purchase_receipt(item_code="_Rice", qty=350, apply_putaway_rule=1,
 			do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 200)
-		self.assertEqual(pr.items[0].warehouse, warehouse_2)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
 		self.assertEqual(pr.items[1].qty, 100)
-		self.assertEqual(pr.items[1].warehouse, warehouse_1)
+		self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
+		# total 300 assigned, 50 unassigned
+
 		pr.delete()
 		rule_1.delete()
 		rule_2.delete()
@@ -114,26 +109,23 @@
 			})
 			item.save()
 
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=3,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=3,
 			uom="Bag")
 		self.assertEqual(rule_1.stock_capacity, 3000)
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=4,
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=4,
 			uom="Bag")
 		self.assertEqual(rule_2.stock_capacity, 4000)
 
 		# populate 'Rack 1' with 1 Bag, making the free space 2 Bags
-		stock_receipt = make_stock_entry(item_code="_Rice", target=warehouse_1, qty=1000, basic_rate=50)
+		stock_receipt = make_stock_entry(item_code="_Rice", target=self.warehouse_1, qty=1000, basic_rate=50)
 
 		pr = make_purchase_receipt(item_code="_Rice", qty=6, uom="Bag", stock_uom="Kg",
 			conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 4)
-		self.assertEqual(pr.items[0].warehouse, warehouse_2)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_2)
 		self.assertEqual(pr.items[1].qty, 2)
-		self.assertEqual(pr.items[1].warehouse, warehouse_1)
+		self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
 
 		stock_receipt.cancel()
 		pr.delete()
@@ -152,15 +144,12 @@
 
 		frappe.db.set_value("UOM", "Bag", "must_be_whole_number", 1)
 
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
 		# Putaway Rule in different UOM
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=1,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=1,
 			uom="Bag")
 		self.assertEqual(rule_1.stock_capacity, 1000)
 		# Putaway Rule in Stock UOM
-		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_2, capacity=500)
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=500)
 		self.assertEqual(rule_2.stock_capacity, 500)
 		# total capacity is 1500 Kg
 
@@ -168,7 +157,7 @@
 			conversion_factor=1000, apply_putaway_rule=1, do_not_submit=1)
 		self.assertEqual(len(pr.items), 1)
 		self.assertEqual(pr.items[0].qty, 1)
-		self.assertEqual(pr.items[0].warehouse, warehouse_1)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
 		# leftover space was for 500 kg (0.5 Bag)
 		# Since Bag is a whole UOM, 1(out of 2) Bag will be unassigned
 
@@ -177,11 +166,8 @@
 		rule_2.delete()
 
 	def test_putaway_rules_with_reoccurring_item(self):
-		"""Test rules on same item entered multiple times."""
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200,
+		"""Test rules on same item entered multiple times with different rate."""
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
 			uom="Kg")
 		# total capacity is 200 Kg
 
@@ -201,12 +187,12 @@
 		pr.save()
 		self.assertEqual(len(pr.items), 2)
 		self.assertEqual(pr.items[0].qty, 100)
-		self.assertEqual(pr.items[0].warehouse, warehouse_1)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
 		self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
 		# same rule applied to second item row
 		# with previous assignment considered
 		self.assertEqual(pr.items[1].qty, 100) # 100 unassigned in second row from 200
-		self.assertEqual(pr.items[1].warehouse, warehouse_1)
+		self.assertEqual(pr.items[1].warehouse, self.warehouse_1)
 		self.assertEqual(pr.items[1].putaway_rule, rule_1.name)
 
 		pr.delete()
@@ -214,17 +200,14 @@
 
 	def test_validate_over_receipt_in_warehouse(self):
 		"""Test if overreceipt is blocked in the presence of putaway rules."""
-		warehouse_1 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 1"})
-		warehouse_2 = frappe.db.get_value("Warehouse", {"warehouse_name": "Rack 2"})
-
-		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=warehouse_1, capacity=200,
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
 			uom="Kg")
 
 		pr = make_purchase_receipt(item_code="_Rice", qty=300, apply_putaway_rule=1,
 			do_not_submit=1)
 		self.assertEqual(len(pr.items), 1)
 		self.assertEqual(pr.items[0].qty, 200) # 100 is unassigned fro 300 Kg
-		self.assertEqual(pr.items[0].warehouse, warehouse_1)
+		self.assertEqual(pr.items[0].warehouse, self.warehouse_1)
 		self.assertEqual(pr.items[0].putaway_rule, rule_1.name)
 
 		# force overreceipt and disable apply putaway rule in PR
@@ -236,6 +219,156 @@
 		pr.delete()
 		rule_1.delete()
 
+	def test_putaway_rule_on_stock_entry_material_transfer(self):
+		"""Test if source warehouse is considered while applying rules."""
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+			uom="Kg") # higher priority
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=100,
+			uom="Kg", priority=2)
+
+		stock_entry = make_stock_entry(item_code="_Rice", source=self.warehouse_1, qty=200,
+			target="_Test Warehouse - _TC", purpose="Material Transfer",
+			apply_putaway_rule=1, do_not_submit=1)
+
+		stock_entry_item = stock_entry.get("items")[0]
+
+		# since source warehouse is Rack 1, rule 1 (for Rack 1) will be avoided
+		# even though it has more free space and higher priority
+		self.assertEqual(stock_entry_item.t_warehouse, self.warehouse_2)
+		self.assertEqual(stock_entry_item.qty, 100) # unassigned 100 out of 200 Kg
+		self.assertEqual(stock_entry_item.putaway_rule, rule_2.name)
+
+		stock_entry.delete()
+		rule_1.delete()
+		rule_2.delete()
+
+	def test_putaway_rule_on_stock_entry_material_transfer_reoccuring_item(self):
+		"""Test if reoccuring item is correctly considered."""
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=300,
+			uom="Kg")
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=600,
+			uom="Kg", priority=2)
+
+		# create SE with first row having source warehouse as Rack 2
+		stock_entry = make_stock_entry(item_code="_Rice", source=self.warehouse_2, qty=200,
+			target="_Test Warehouse - _TC", purpose="Material Transfer",
+			apply_putaway_rule=1, do_not_submit=1)
+
+		# Add rows with source warehouse as Rack 1
+		stock_entry.extend("items", [
+			{
+				"item_code": "_Rice",
+				"s_warehouse": self.warehouse_1,
+				"t_warehouse": "_Test Warehouse - _TC",
+				"qty": 100,
+				"basic_rate": 50,
+				"conversion_factor": 1.0,
+				"transfer_qty": 100
+			},
+			{
+				"item_code": "_Rice",
+				"s_warehouse": self.warehouse_1,
+				"t_warehouse": "_Test Warehouse - _TC",
+				"qty": 200,
+				"basic_rate": 60,
+				"conversion_factor": 1.0,
+				"transfer_qty": 200
+			}
+		])
+
+		stock_entry.save()
+
+		# since source warehouse was Rack 2, exclude rule_2
+		self.assertEqual(stock_entry.items[0].t_warehouse, self.warehouse_1)
+		self.assertEqual(stock_entry.items[0].qty, 200)
+		self.assertEqual(stock_entry.items[0].putaway_rule, rule_1.name)
+
+		# since source warehouse was Rack 1, exclude rule_1 even though it has
+		# higher priority
+		self.assertEqual(stock_entry.items[1].t_warehouse, self.warehouse_2)
+		self.assertEqual(stock_entry.items[1].qty, 100)
+		self.assertEqual(stock_entry.items[1].putaway_rule, rule_2.name)
+
+		self.assertEqual(stock_entry.items[2].t_warehouse, self.warehouse_2)
+		self.assertEqual(stock_entry.items[2].qty, 200)
+		self.assertEqual(stock_entry.items[2].putaway_rule, rule_2.name)
+
+		stock_entry.delete()
+		rule_1.delete()
+		rule_2.delete()
+
+	def test_putaway_rule_on_stock_entry_material_transfer_batch_serial_item(self):
+		"""Test if batch and serial items are split correctly."""
+		if not frappe.db.exists("Item", "Water Bottle"):
+			make_item("Water Bottle", {
+				"is_stock_item": 1,
+				"has_batch_no" : 1,
+				"create_new_batch": 1,
+				"has_serial_no": 1,
+				"serial_no_series": "BOTTL-.####",
+				"stock_uom": "Nos"
+			})
+
+		rule_1 = create_putaway_rule(item_code="Water Bottle", warehouse=self.warehouse_1, capacity=3,
+			uom="Nos")
+		rule_2 = create_putaway_rule(item_code="Water Bottle", warehouse=self.warehouse_2, capacity=2,
+		uom="Nos")
+
+		make_new_batch(batch_id="BOTTL-BATCH-1", item_code="Water Bottle")
+
+		pr = make_purchase_receipt(item_code="Water Bottle", qty=5, do_not_submit=1)
+		pr.items[0].batch_no = "BOTTL-BATCH-1"
+		pr.save()
+		pr.submit()
+
+		serial_nos = frappe.get_list("Serial No", filters={"purchase_document_no": pr.name, "status": "Active"})
+		serial_nos = [d.name for d in serial_nos]
+
+		stock_entry = make_stock_entry(item_code="Water Bottle", source="_Test Warehouse - _TC", qty=5,
+			target="Finished Goods - _TC", purpose="Material Transfer",
+			apply_putaway_rule=1, do_not_save=1)
+		stock_entry.items[0].batch_no = "BOTTL-BATCH-1"
+		stock_entry.items[0].serial_no = "\n".join(serial_nos)
+		stock_entry.save()
+
+		self.assertEqual(stock_entry.items[0].t_warehouse, self.warehouse_1)
+		self.assertEqual(stock_entry.items[0].qty, 3)
+		self.assertEqual(stock_entry.items[0].putaway_rule, rule_1.name)
+		self.assertEqual(stock_entry.items[0].serial_no, "\n".join(serial_nos[:3]))
+		self.assertEqual(stock_entry.items[0].batch_no, "BOTTL-BATCH-1")
+
+		self.assertEqual(stock_entry.items[1].t_warehouse, self.warehouse_2)
+		self.assertEqual(stock_entry.items[1].qty, 2)
+		self.assertEqual(stock_entry.items[1].putaway_rule, rule_2.name)
+		self.assertEqual(stock_entry.items[1].serial_no, "\n".join(serial_nos[3:]))
+		self.assertEqual(stock_entry.items[1].batch_no, "BOTTL-BATCH-1")
+
+		stock_entry.delete()
+		pr.cancel()
+		rule_1.delete()
+		rule_2.delete()
+
+	def test_putaway_rule_on_stock_entry_material_receipt(self):
+		"""Test if rules are applied in Stock Entry of type Receipt."""
+		rule_1 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_1, capacity=200,
+			uom="Kg") # more capacity
+		rule_2 = create_putaway_rule(item_code="_Rice", warehouse=self.warehouse_2, capacity=100,
+			uom="Kg")
+
+		stock_entry = make_stock_entry(item_code="_Rice", qty=100,
+			target="_Test Warehouse - _TC", purpose="Material Receipt",
+			apply_putaway_rule=1, do_not_submit=1)
+
+		stock_entry_item = stock_entry.get("items")[0]
+
+		self.assertEqual(stock_entry_item.t_warehouse, self.warehouse_1)
+		self.assertEqual(stock_entry_item.qty, 100)
+		self.assertEqual(stock_entry_item.putaway_rule, rule_1.name)
+
+		stock_entry.delete()
+		rule_1.delete()
+		rule_2.delete()
+
 def create_putaway_rule(**args):
 	args = frappe._dict(args)
 	putaway = frappe.new_doc("Putaway Rule")
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.js b/erpnext/stock/doctype/stock_entry/stock_entry.js
index fd920a5..5d9ea8d 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.js
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.js
@@ -574,7 +574,7 @@
 	},
 
 	apply_putaway_rule: function (frm) {
-		if (frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(frm);
+		if (frm.doc.apply_putaway_rule) erpnext.apply_putaway_rule(frm, frm.doc.purpose);
 	}
 });
 
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py
index aed69e1..e37e122 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry.py
@@ -47,7 +47,8 @@
 		apply_rule = self.apply_putaway_rule and (self.purpose in ["Material Transfer", "Material Receipt"])
 
 		if self.get("items") and apply_rule:
-			apply_putaway_rule(self.doctype, self.get("items"), self.company)
+			apply_putaway_rule(self.doctype, self.get("items"), self.company,
+				purpose=self.purpose)
 
 	def validate(self):
 		self.pro_doc = frappe._dict()
diff --git a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
index b78c6be..b12a854 100644
--- a/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
+++ b/erpnext/stock/doctype/stock_entry/stock_entry_utils.py
@@ -53,6 +53,8 @@
 		args.target = args.to_warehouse
 	if args.item_code:
 		args.item = args.item_code
+	if args.apply_putaway_rule:
+		s.apply_putaway_rule = args.apply_putaway_rule
 
 	if isinstance(args.qty, string_types):
 		if '.' in args.qty:
@@ -118,7 +120,8 @@
 		"t_warehouse": args.target,
 		"qty": args.qty,
 		"basic_rate": args.rate or args.basic_rate,
-		"conversion_factor": 1.0,
+		"conversion_factor": args.conversion_factor or 1.0,
+		"transfer_qty": flt(args.qty) * (flt(args.conversion_factor) or 1.0),
 		"serial_no": args.serial_no,
 		'batch_no': args.batch_no,
 		'cost_center': args.cost_center,