feat: Putaway
diff --git a/erpnext/stock/doctype/putaway_rule/__init__.py b/erpnext/stock/doctype/putaway_rule/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/__init__.py
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.js b/erpnext/stock/doctype/putaway_rule/putaway_rule.js
new file mode 100644
index 0000000..ae08e82
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.js
@@ -0,0 +1,18 @@
+// Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Putaway Rule', {
+	setup: function(frm) {
+		frm.set_query("warehouse", function() {
+			return {
+				"filters": {
+					"company": frm.doc.company,
+					"is_group": 0
+				}
+			};
+		});
+	}
+	// refresh: function(frm) {
+
+	// }
+});
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.json b/erpnext/stock/doctype/putaway_rule/putaway_rule.json
new file mode 100644
index 0000000..6a132c7
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.json
@@ -0,0 +1,111 @@
+{
+ "actions": [],
+ "autoname": "format:{item_code}-{warehouse}",
+ "creation": "2020-11-09 11:39:46.489501",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "disable",
+  "item_code",
+  "item_name",
+  "warehouse",
+  "col_break_capacity",
+  "company",
+  "capacity",
+  "priority",
+  "stock_uom"
+ ],
+ "fields": [
+  {
+   "fieldname": "item_code",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Item",
+   "options": "Item",
+   "reqd": 1
+  },
+  {
+   "fetch_from": "item_code.item_name",
+   "fieldname": "item_name",
+   "fieldtype": "Data",
+   "label": "Item Name",
+   "read_only": 1
+  },
+  {
+   "fieldname": "warehouse",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "in_standard_filter": 1,
+   "label": "Warehouse",
+   "options": "Warehouse",
+   "reqd": 1
+  },
+  {
+   "fieldname": "col_break_capacity",
+   "fieldtype": "Column Break"
+  },
+  {
+   "default": "0",
+   "fieldname": "capacity",
+   "fieldtype": "Float",
+   "in_list_view": 1,
+   "label": "Capacity",
+   "reqd": 1
+  },
+  {
+   "default": "item_code.stock_uom",
+   "fieldname": "stock_uom",
+   "fieldtype": "Link",
+   "label": "Stock UOM",
+   "options": "UOM",
+   "read_only": 1
+  },
+  {
+   "default": "1",
+   "fieldname": "priority",
+   "fieldtype": "Int",
+   "label": "Priority"
+  },
+  {
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "in_standard_filter": 1,
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
+  {
+   "default": "0",
+   "depends_on": "eval:!doc.__islocal",
+   "fieldname": "disable",
+   "fieldtype": "Check",
+   "label": "Disable"
+  }
+ ],
+ "index_web_pages_for_search": 1,
+ "links": [],
+ "modified": "2020-11-10 17:06:27.151335",
+ "modified_by": "Administrator",
+ "module": "Stock",
+ "name": "Putaway Rule",
+ "owner": "Administrator",
+ "permissions": [
+  {
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "write": 1
+  }
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
+}
\ No newline at end of file
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule.py b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
new file mode 100644
index 0000000..9f02833
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule.py
@@ -0,0 +1,93 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe
+import copy
+from frappe import _
+from frappe.utils import flt
+from frappe.model.document import Document
+
+class PutawayRule(Document):
+	def validate(self):
+		self.validate_duplicate_rule()
+		self.validate_warehouse_and_company()
+		self.validate_capacity()
+		self.validate_priority()
+
+	def validate_duplicate_rule(self):
+		existing_rule = frappe.db.exists("Putaway Rule", {"item_code": self.item_code, "warehouse": self.warehouse})
+		if existing_rule and existing_rule != self.name:
+			frappe.throw(_("Putaway Rule already exists for Item {0} in Warehouse {1}.")
+				.format(frappe.bold(self.item_code), frappe.bold(self.warehouse)),
+				title=_("Duplicate"))
+
+	def validate_priority(self):
+		if self.priority < 1:
+			frappe.throw(_("Priority cannot be lesser than 1."), title=_("Invalid Priority"))
+
+	def validate_warehouse_and_company(self):
+		company = frappe.db.get_value("Warehouse", self.warehouse, "company")
+		if company != self.company:
+			frappe.throw(_("Warehouse {0} does not belong to Company {1}.")
+				.format(frappe.bold(self.warehouse), frappe.bold(self.company)),
+				title=_("Invalid Warehouse"))
+
+	def validate_capacity(self):
+		# check if capacity is lesser than current balance in warehouse
+		pass
+
+@frappe.whitelist()
+def get_ordered_putaway_rules(item_code, company, qty):
+	"""Returns an ordered list of putaway rules to apply on an item."""
+
+	# get enabled putaway rules for this item code in this company that have pending capacity
+	# order the rules by priority first
+	# if same priority, order by pending capacity (capacity - get how much stock is in the warehouse)
+	# return this list
+	# [{'name': "something", "free space": 20}, {'name': "something", "free space": 10}]
+
+@frappe.whitelist()
+def apply_putaway_rule(items, company):
+	""" Applies Putaway Rule on line items.
+
+		items: List of line items in a Purchase Receipt
+		company: Company in Purchase Receipt
+	"""
+	items_not_accomodated = []
+	for item in items:
+		item_qty = item.qty
+		at_capacity, rules = get_ordered_putaway_rules(item.item_code, company, item_qty)
+
+		if not rules:
+			if at_capacity:
+				items_not_accomodated.append([item.item_code, item_qty])
+			continue
+
+		item_row_updated = False
+		for rule in rules:
+			while item_qty > 0:
+				if not item_row_updated:
+					# update pre-existing row
+					item.qty = rule.qty
+					item.warehouse = rule.warehouse
+					item_row_updated = True
+				else:
+					# add rows for split quantity
+					added_row = copy.deepcopy(item)
+					added_row.qty = rule.qty
+					added_row.warehouse = rule.warehouse
+					items.append(added_row)
+
+				item_qty -= flt(rule.qty)
+
+		# if pending qty after applying rules, add row without warehouse
+		if item_qty > 0:
+			added_row = copy.deepcopy(item)
+			added_row.qty = item_qty
+			added_row.warehouse = ''
+			items.append(added_row)
+			items_not_accomodated.append([item.item_code, item_qty])
+
+	# need to check pricing rule, item tax impact
\ No newline at end of file
diff --git a/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js b/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js
new file mode 100644
index 0000000..bb1654c
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/putaway_rule_list.js
@@ -0,0 +1,10 @@
+frappe.listview_settings['Putaway Rule'] = {
+	add_fields: ["disable"],
+	get_indicator: (doc) => {
+		if (doc.disable) {
+			return [__("Disabled"), "darkgrey", "disable,=,1"];
+		} else {
+			return [__("Active"), "blue", "disable,=,0"];
+		};
+	}
+};
diff --git a/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
new file mode 100644
index 0000000..e262217
--- /dev/null
+++ b/erpnext/stock/doctype/putaway_rule/test_putaway_rule.py
@@ -0,0 +1,10 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and Contributors
+# See license.txt
+from __future__ import unicode_literals
+
+# import frappe
+import unittest
+
+class TestPutawayRule(unittest.TestCase):
+	pass