Merge branch 'develop' into feat-customer-credit-limit
diff --git a/erpnext/__init__.py b/erpnext/__init__.py
index 2490f3b..ee37c8d 100644
--- a/erpnext/__init__.py
+++ b/erpnext/__init__.py
@@ -5,7 +5,7 @@
 from erpnext.hooks import regional_overrides
 from frappe.utils import getdate
 
-__version__ = '12.0.8'
+__version__ = '12.1.0'
 
 def get_default_company(user=None):
 	'''Get default company for user'''
diff --git a/erpnext/accounts/doctype/bank/bank_dashboard.py b/erpnext/accounts/doctype/bank/bank_dashboard.py
index 4a1dad8..1e2383d 100644
--- a/erpnext/accounts/doctype/bank/bank_dashboard.py
+++ b/erpnext/accounts/doctype/bank/bank_dashboard.py
@@ -8,7 +8,7 @@
 		'fieldname': 'bank',
 		'transactions': [
 			{
-				'label': _('Bank Deatils'),
+				'label': _('Bank Details'),
 				'items': ['Bank Account', 'Bank Guarantee']
 			}
 		]
diff --git a/erpnext/accounts/page/pos/pos.js b/erpnext/accounts/page/pos/pos.js
index 0e73012..2173e7d 100755
--- a/erpnext/accounts/page/pos/pos.js
+++ b/erpnext/accounts/page/pos/pos.js
@@ -1118,7 +1118,8 @@
 		if (key) {
 			return $.grep(this.items_list, function (item) {
 				if (search_status) {
-					if (in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
+					if (me.batch_no_data[item.item_code] &&
+						in_list(me.batch_no_data[item.item_code], me.search_item.$input.val())) {
 						search_status = false;
 						return me.item_batch_no[item.item_code] = me.search_item.$input.val()
 					} else if (me.serial_no_data[item.item_code]
@@ -1126,7 +1127,8 @@
 						search_status = false;
 						me.item_serial_no[item.item_code] = [me.search_item.$input.val(), me.serial_no_data[item.item_code][me.search_item.$input.val()]]
 						return true
-					} else if (in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
+					} else if (me.barcode_data[item.item_code] &&
+						in_list(me.barcode_data[item.item_code], me.search_item.$input.val())) {
 						search_status = false;
 						return true;
 					} else if (reg.test(item.item_code.toLowerCase()) || (item.description && reg.test(item.description.toLowerCase())) ||
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
index 192b6d7..d00bcf6 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.html
@@ -40,7 +40,7 @@
 	</div>
 </div>
 
-{% if(filters.show_pdc_in_print) { %}
+{% if(filters.show_future_payments) { %}
 	{% var balance_row = data.slice(-1).pop();
 		   var range1 = report.columns[11].label;
 		   var range2 = report.columns[12].label;
@@ -122,22 +122,22 @@
 				<th style="width: 10%">{%= __("Date") %}</th>
 				<th style="width: 4%">{%= __("Age (Days)") %}</th>
 
-				{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+				{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
 					<th style="width: 14%">{%= __("Reference") %}</th>
 					<th style="width: 10%">{%= __("Sales Person") %}</th>
 				{% } else { %}
 					<th style="width: 24%">{%= __("Reference") %}</th>
 				{% } %}
-				{% if(!filters.show_pdc_in_print) { %}
+				{% if(!filters.show_future_payments) { %}
 					<th style="width: 20%">{%= (filters.customer || filters.supplier) ? __("Remarks"): __("Party") %}</th>
 				{% } %}
 				<th style="width: 10%; text-align: right">{%= __("Invoiced Amount") %}</th>
-				{% if(!filters.show_pdc_in_print) { %}
+				{% if(!filters.show_future_payments) { %}
 					<th style="width: 10%; text-align: right">{%= __("Paid Amount") %}</th>
 					<th style="width: 10%; text-align: right">{%= report.report_name === "Accounts Receivable" ? __('Credit Note') : __('Debit Note') %}</th>
 				{% } %}
 				<th style="width: 10%; text-align: right">{%= __("Outstanding Amount") %}</th>
-				{% if(filters.show_pdc_in_print) { %}
+				{% if(filters.show_future_payments) { %}
 					{% if(report.report_name === "Accounts Receivable") { %}
 						<th style="width: 12%">{%= __("Customer LPO No.") %}</th>
 					{% } %}
@@ -162,18 +162,18 @@
 					<td>{%= frappe.datetime.str_to_user(data[i]["posting_date"]) %}</td>
 					<td style="text-align: right">{%= data[i][__("Age (Days)")] %}</td>
 					<td>
-						{% if(!filters.show_pdc_in_print) { %}
+						{% if(!filters.show_future_payments) { %}
 							{%= data[i]["voucher_type"] %}
 							<br>
 						{% } %}
 						{%= data[i]["voucher_no"] %}
 					</td>
 
-					{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+					{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
 					<td>{%= data[i]["sales_person"] %}</td>
 					{% } %}
 
-					{% if(!filters.show_pdc_in_print) { %}
+					{% if(!filters.show_future_payments) { %}
 					<td>
 						{% if(!(filters.customer || filters.supplier)) { %}
 							{%= data[i][__("Customer")] || data[i][__("Supplier")] %}
@@ -195,7 +195,7 @@
 					<td style="text-align: right">
 						{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"]) %}</td>
 
-					{% if(!filters.show_pdc_in_print) { %}
+					{% if(!filters.show_future_payments) { %}
 						<td style="text-align: right">
 							{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}</td>
 						<td style="text-align: right">
@@ -204,7 +204,7 @@
 					<td style="text-align: right">
 						{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}</td>
 
-					{% if(filters.show_pdc_in_print) { %}
+					{% if(filters.show_future_payments) { %}
 						{% if(report.report_name === "Accounts Receivable") { %}
 							<td style="text-align: right">
 								{%= data[i]["po_no"] %}</td>
@@ -215,10 +215,10 @@
 					{% } %}
 				{% } else { %}
 					<td></td>
-					{% if(!filters.show_pdc_in_print) { %}
+					{% if(!filters.show_future_payments) { %}
 					<td></td>
 					{% } %}
-					{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person_in_print) { %}
+					{% if(report.report_name === "Accounts Receivable" && filters.show_sales_person) { %}
 					<td></td>
 					{% } %}
 					<td></td>
@@ -226,7 +226,7 @@
 					<td style="text-align: right">
 						{%= format_currency(data[i]["invoiced_amount"], data[i]["currency"] ) %}</td>
 
-					{% if(!filters.show_pdc_in_print) { %}
+					{% if(!filters.show_future_payments) { %}
 						<td style="text-align: right">
 							{%= format_currency(data[i]["paid_amount"], data[i]["currency"]) %}</td>
 						<td style="text-align: right">{%= report.report_name === "Accounts Receivable" ? format_currency(data[i]["credit_note"], data[i]["currency"])  : format_currency(data[i]["debit_note"], data[i]["currency"])  %} </td>
@@ -234,7 +234,7 @@
 					<td style="text-align: right">
 						{%= format_currency(data[i]["outstanding_amount"], data[i]["currency"]) %}</td>
 
-					{% if(filters.show_pdc_in_print) { %}
+					{% if(filters.show_future_payments) { %}
 						{% if(report.report_name === "Accounts Receivable") { %}
 							<td style="text-align: right">
 								{%= data[i][__("Customer LPO")] %}</td>
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
index 4551973..228be18 100644
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js
@@ -130,13 +130,18 @@
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"show_pdc_in_print",
-			"label": __("Show PDC in Print"),
+			"fieldname":"show_future_payments",
+			"label": __("Show Future Payments"),
 			"fieldtype": "Check",
 		},
 		{
-			"fieldname":"show_sales_person_in_print",
-			"label": __("Show Sales Person in Print"),
+			"fieldname":"show_delivery_notes",
+			"label": __("Show Delivery Notes"),
+			"fieldtype": "Check",
+		},
+		{
+			"fieldname":"show_sales_person",
+			"label": __("Show Sales Person"),
 			"fieldtype": "Check",
 		},
 		{
diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
index 0e4ee12..b2bf3f9 100755
--- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.py
@@ -4,9 +4,33 @@
 from __future__ import unicode_literals
 import frappe, erpnext
 from frappe import _, scrub
-from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr
+from frappe.utils import getdate, nowdate, flt, cint, formatdate, cstr, now, time_diff_in_seconds
+from collections import OrderedDict
+from erpnext.accounts.utils import get_currency_precision
 from erpnext.accounts.doctype.accounting_dimension.accounting_dimension import get_accounting_dimensions
 
+#  This report gives a summary of all Outstanding Invoices considering the following
+
+#  1. Invoice can be booked via Sales/Purchase Invoice or Journal Entry
+#  2. Report handles both receivable and payable
+#  3. Key balances for each row are "Invoiced Amount", "Paid Amount", "Credit/Debit Note Amount", "Oustanding Amount"
+#  4. For explicit payment terms in invoice (example: 30% advance, 30% on delivery, 40% post delivery),
+#     the invoice will be broken up into multiple rows, one for each payment term
+#  5. If there are payments after the report date (post dated), these will be updated in additional columns
+#     for future amount
+#  6. Configurable Ageing Groups (0-30, 30-60 etc) can be set via filters
+#  7. For overpayment against an invoice with payment terms, there will be an additional row
+#  8. Invoice details like Sales Persons, Delivery Notes are also fetched comma separated
+#  9. Report amounts are in "Party Currency" if party is selected, or company currency for multi-party
+# 10. This reports is based on all GL Entries that are made against account_type "Receivable" or "Payable"
+
+def execute(filters=None):
+	args = {
+		"party_type": "Customer",
+		"naming_by": ["Selling Settings", "cust_master_name"],
+	}
+	return ReceivablePayableReport(filters).run(args)
+
 class ReceivablePayableReport(object):
 	def __init__(self, filters=None):
 		self.filters = frappe._dict(filters or {})
@@ -16,459 +40,429 @@
 			else self.filters.report_date
 
 	def run(self, args):
-		party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
-		columns = self.get_columns(party_naming_by, args)
-		data = self.get_data(party_naming_by, args)
-		chart = self.get_chart_data(columns, data)
-		return columns, data, None, chart
+		self.filters.update(args)
+		self.set_defaults()
+		self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
+		self.get_columns()
+		self.get_data()
+		self.get_chart_data()
+		return self.columns, self.data, None, self.chart
 
-	def get_columns(self, party_naming_by, args):
-		columns = []
-		columns.append({
-			"label": _("Posting Date"),
-			"fieldtype": "Date",
-			"fieldname": "posting_date",
-			"width": 90
-		})
-
-		columns += [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
-
-		if party_naming_by == "Naming Series":
-			columns += [args.get("party_type") + " Name::110"]
-
-		if args.get("party_type") == 'Customer':
-			columns.append({
-				"label": _("Customer Contact"),
-				"fieldtype": "Link",
-				"fieldname": "contact",
-				"options":"Contact",
-				"width": 100
-			})
-
-		columns.append({
-			"label": _("Voucher Type"),
-			"fieldtype": "Data",
-			"fieldname": "voucher_type",
-			"width": 110
-		})
-
-		columns.append({
-			"label": _("Voucher No"),
-			"fieldtype": "Dynamic Link",
-			"fieldname": "voucher_no",
-			"width": 110,
-			"options": "voucher_type",
-		})
-
-		columns += [_("Due Date") + ":Date:80"]
-
-		if args.get("party_type") == "Supplier":
-			columns += [_("Bill No") + "::80", _("Bill Date") + ":Date:80"]
-
-		credit_or_debit_note = "Credit Note" if args.get("party_type") == "Customer" else "Debit Note"
-
-		if self.filters.based_on_payment_terms:
-			columns.append({
-				"label": _("Payment Term"),
-				"fieldname": "payment_term",
-				"fieldtype": "Data",
-				"width": 120
-			})
-			columns.append({
-				"label": _("Invoice Grand Total"),
-				"fieldname": "invoice_grand_total",
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 120
-			})
-
-		for label in ("Invoiced Amount", "Paid Amount", credit_or_debit_note, "Outstanding Amount"):
-			columns.append({
-				"label": _(label),
-				"fieldname": frappe.scrub(label),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 120
-			})
-
-		columns += [_("Age (Days)") + ":Int:80"]
-
-		self.ageing_col_idx_start = len(columns)
-
-		if not "range1" in self.filters:
-			self.filters["range1"] = "30"
-		if not "range2" in self.filters:
-			self.filters["range2"] = "60"
-		if not "range3" in self.filters:
-			self.filters["range3"] = "90"
-		if not "range4" in self.filters:
-			self.filters["range4"] = "120"
-
-		for label in ("0-{range1}".format(range1=self.filters["range1"]),
-			"{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
-			"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
-			"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
-			"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))):
-				columns.append({
-					"label": label,
-					"fieldname":label,
-					"fieldtype": "Currency",
-					"options": "currency",
-					"width": 120
-				})
-
-		columns += [
-		{
-			"fieldname": "currency",
-			"label": _("Currency"),
-			"fieldtype": "Link",
-			"options": "Currency",
-			"width": 100
-		},
-		{
-			"fieldname": "pdc/lc_ref",
-			"label": _("PDC/LC Ref"),
-			"fieldtype": "Data",
-			"width": 110
-		},
-		{
-			"fieldname": "pdc/lc_amount",
-			"label": _("PDC/LC Amount"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 130
-		},
-		{
-			"fieldname": "remaining_balance",
-			"label": _("Remaining Balance"),
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 130
-		}]
-
-		if args.get('party_type') == 'Customer':
-			columns += [
-				{
-					"label": _("Customer LPO"),
-					"fieldtype": "Data",
-					"fieldname": "po_no",
-					"width": 100,
-				},
-				_("Delivery Note") + ":Data:100",
-				_("Territory") + ":Link/Territory:80",
-				_("Customer Group") + ":Link/Customer Group:120",
-				{
-					"label": _("Sales Person"),
-					"fieldtype": "Data",
-					"fieldname": "sales_person",
-					"width": 120,
-				}
-			]
-		if args.get("party_type") == "Supplier":
-			columns += [_("Supplier Group") + ":Link/Supplier Group:80"]
-
-		columns.append(_("Remarks") + "::200")
-
-		return columns
-
-	def get_data(self, party_naming_by, args):
-		from erpnext.accounts.utils import get_currency_precision
-		self.currency_precision = get_currency_precision() or 2
-		self.dr_or_cr = "debit" if args.get("party_type") == "Customer" else "credit"
-
-		future_vouchers = self.get_entries_after(self.filters.report_date, args.get("party_type"))
-
+	def set_defaults(self):
 		if not self.filters.get("company"):
-			self.filters["company"] = frappe.db.get_single_value('Global Defaults', 'default_company')
-
+			self.filters.company = frappe.db.get_single_value('Global Defaults', 'default_company')
 		self.company_currency = frappe.get_cached_value('Company',  self.filters.get("company"), "default_currency")
+		self.currency_precision = get_currency_precision() or 2
+		self.dr_or_cr = "debit" if self.filters.party_type == "Customer" else "credit"
+		self.party_type = self.filters.party_type
+		self.party_details = {}
+		self.invoices = set()
 
-		return_entries = self.get_return_entries(args.get("party_type"))
+	def get_data(self):
+		t1 = now()
+		self.get_gl_entries()
+		self.voucher_balance = OrderedDict()
+		self.init_voucher_balance() # invoiced, paid, credit_note, outstanding
 
-		data = []
-		self.pdc_details = get_pdc_details(args.get("party_type"), self.filters.report_date)
-		gl_entries_data = self.get_entries_till(self.filters.report_date, args.get("party_type"))
+		# Build delivery note map against all sales invoices
+		self.build_delivery_note_map()
 
-		if gl_entries_data:
-			voucher_nos = [d.voucher_no for d in gl_entries_data] or []
-			dn_details = get_dn_details(args.get("party_type"), voucher_nos)
-			self.voucher_details = get_voucher_details(args.get("party_type"), voucher_nos, dn_details)
+		# Get invoice details like bill_no, due_date etc for all invoices
+		self.get_invoice_details()
 
-		if self.filters.based_on_payment_terms and gl_entries_data:
-			self.payment_term_map = self.get_payment_term_detail(voucher_nos)
+		# fetch future payments against invoices
+		self.get_future_payments()
 
-		self.gle_inclusion_map = {}
-		for gle in gl_entries_data:
-			if self.is_receivable_or_payable(gle, self.dr_or_cr, future_vouchers, return_entries):
-				self.gle_inclusion_map[gle.name] = True
-				outstanding_amount, credit_note_amount, payment_amount = self.get_outstanding_amount(
-					gle,self.filters.report_date, self.dr_or_cr, return_entries)
-				temp_outstanding_amt = outstanding_amount
-				temp_credit_note_amt = credit_note_amount
+		self.data = []
+		for gle in self.gl_entries:
+			self.update_voucher_balance(gle)
 
-				if abs(outstanding_amount) > 0.1/10**self.currency_precision:
-					if self.filters.based_on_payment_terms and self.payment_term_map.get(gle.voucher_no):
-						for d in self.payment_term_map.get(gle.voucher_no):
-							# Allocate payment amount based on payment terms(FIFO order)
-							payment_amount, d.payment_amount = self.allocate_based_on_fifo(payment_amount, d.payment_term_amount)
+		self.build_data()
 
-							term_outstanding_amount = d.payment_term_amount - d.payment_amount
+	def init_voucher_balance(self):
+		# build all keys, since we want to exclude vouchers beyond the report date
+		for gle in self.gl_entries:
+			# get the balance object for voucher_type
+			key = (gle.voucher_type, gle.voucher_no, gle.party)
+			if not key in self.voucher_balance:
+				self.voucher_balance[key] = frappe._dict(
+					voucher_type = gle.voucher_type,
+					voucher_no = gle.voucher_no,
+					party = gle.party,
+					posting_date = gle.posting_date,
+					remarks = gle.remarks,
+					invoiced = 0.0,
+					paid = 0.0,
+					credit_note = 0.0,
+					outstanding = 0.0
+				)
+			self.get_invoices(gle)
 
-							# Allocate credit note based on payment terms(FIFO order)
-							credit_note_amount, d.credit_note_amount = self.allocate_based_on_fifo(credit_note_amount, term_outstanding_amount)
+	def get_invoices(self, gle):
+		if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
+			self.invoices.add(gle.voucher_no)
 
-							term_outstanding_amount -= d.credit_note_amount
+	def update_voucher_balance(self, gle):
+		# get the row where this balance needs to be updated
+		# if its a payment, it will return the linked invoice or will be considered as advance
+		row = self.get_voucher_balance(gle)
 
-							row_outstanding = term_outstanding_amount
-							# Allocate PDC based on payment terms(FIFO order)
-							d.pdc_details, d.pdc_amount = self.allocate_pdc_amount_in_fifo(gle, row_outstanding)
-
-							if term_outstanding_amount > 0:
-								row = self.prepare_row(party_naming_by, args, gle, term_outstanding_amount,
-									d.credit_note_amount, d.due_date, d.payment_amount , d.payment_term_amount,
-									d.description, d.pdc_amount, d.pdc_details)
-								data.append(row)
-
-						if credit_note_amount:
-							row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, temp_outstanding_amt,
-								temp_credit_note_amt)
-							data.append(row)
-
-					else:
-						row = self.prepare_row_without_payment_terms(party_naming_by, args, gle, outstanding_amount,
-							credit_note_amount)
-						data.append(row)
-		return data
-
-	def allocate_pdc_amount_in_fifo(self, gle, row_outstanding):
-		pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
-
-		pdc_details = []
-		pdc_amount = 0
-		for pdc in pdc_list:
-			if row_outstanding <= pdc.pdc_amount:
-				pdc_amount += row_outstanding
-				pdc.pdc_amount -= row_outstanding
-				if row_outstanding and pdc.pdc_ref and pdc.pdc_date:
-					pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
-				row_outstanding = 0
-
+		# gle_balance will be the total "debit - credit" for receivable type reports and
+		# and vice-versa for payable type reports
+		gle_balance = self.get_gle_balance(gle)
+		if gle_balance > 0:
+			if gle.voucher_type in ('Journal Entry', 'Payment Entry') and gle.against_voucher:
+				# debit against sales / purchase invoice
+				row.paid -= gle_balance
 			else:
-				pdc_amount = pdc.pdc_amount
-				if pdc.pdc_amount and pdc.pdc_ref and pdc.pdc_date:
-					pdc_details.append(cstr(pdc.pdc_ref) + "/" + formatdate(pdc.pdc_date))
-				pdc.pdc_amount = 0
-				row_outstanding -= pdc_amount
-
-		return pdc_details, pdc_amount
-
-	def prepare_row_without_payment_terms(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount):
-		pdc_list = self.pdc_details.get((gle.voucher_no, gle.party), [])
-		pdc_amount = 0
-		pdc_details = []
-		for d in pdc_list:
-			pdc_amount += flt(d.pdc_amount)
-			if pdc_amount and d.pdc_ref and d.pdc_date:
-				pdc_details.append(cstr(d.pdc_ref) + "/" + formatdate(d.pdc_date))
-
-		row = self.prepare_row(party_naming_by, args, gle, outstanding_amount,
-			credit_note_amount, pdc_amount=pdc_amount, pdc_details=pdc_details)
-
-		return row
-
-
-	def allocate_based_on_fifo(self, total_amount, row_amount):
-		allocated_amount = 0
-		if row_amount <= total_amount:
-			allocated_amount = row_amount
-			total_amount -= row_amount
+				# invoice
+				row.invoiced += gle_balance
 		else:
-			allocated_amount = total_amount
-			total_amount = 0
+			# payment or credit note for receivables
+			if self.is_invoice(gle):
+				# stand alone debit / credit note
+				row.credit_note -= gle_balance
+			else:
+				# advance / unlinked payment or other adjustment
+				row.paid -= gle_balance
 
-		return total_amount, allocated_amount
+	def get_voucher_balance(self, gle):
+		voucher_balance = None
 
-	def prepare_row(self, party_naming_by, args, gle, outstanding_amount, credit_note_amount,
-		due_date=None, paid_amt=None, payment_term_amount=None, payment_term=None, pdc_amount=None, pdc_details=None):
-		row = [gle.posting_date, gle.party]
+		if gle.against_voucher:
+			# find invoice
+			voucher_balance = self.voucher_balance.get((gle.against_voucher_type, gle.against_voucher, gle.party))
 
-		# customer / supplier name
-		if party_naming_by == "Naming Series":
-			row += [self.get_party_name(gle.party_type, gle.party)]
+		if not voucher_balance:
+			# no invoice, this is an invoice / stand-alone payment / credit note
+			voucher_balance = self.voucher_balance.get((gle.voucher_type, gle.voucher_no, gle.party))
 
-		if args.get("party_type") == 'Customer':
-			row += [self.get_customer_contact(gle.party_type, gle.party)]
+		return voucher_balance
 
-		# get due date
-		if not due_date:
-			due_date = self.voucher_details.get(gle.voucher_no, {}).get("due_date", "")
-		bill_date = self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
+	def build_data(self):
+		# set outstanding for all the accumulated balances
+		# as we can use this to filter out invoices without outstanding
+		for key, row in self.voucher_balance.items():
+			row.outstanding = flt(row.invoiced - row.paid - row.credit_note, self.currency_precision)
+			row.invoice_grand_total = row.invoiced
 
-		row += [gle.voucher_type, gle.voucher_no, due_date]
+			if abs(row.outstanding) > 0.1/10 ** self.currency_precision:
+				# non-zero oustanding, we must consider this row
 
-		# get supplier bill details
-		if args.get("party_type") == "Supplier":
-			row += [
-				self.voucher_details.get(gle.voucher_no, {}).get("bill_no", ""),
-				self.voucher_details.get(gle.voucher_no, {}).get("bill_date", "")
-			]
+				if self.is_invoice(row) and self.filters.based_on_payment_terms:
+					# is an invoice, allocate based on fifo
+					# adds a list `payment_terms` which contains new rows for each term
+					self.allocate_outstanding_based_on_payment_terms(row)
 
-		# invoiced and paid amounts
-		invoiced_amount = gle.get(self.dr_or_cr) if (gle.get(self.dr_or_cr) > 0) else 0
+					if row.payment_terms:
+						# make separate rows for each payment term
+						for d in row.payment_terms:
+							if d.outstanding > 0:
+								self.append_row(d)
 
-		if self.filters.based_on_payment_terms:
-			row+=[payment_term, invoiced_amount]
-			if payment_term_amount:
-				invoiced_amount = payment_term_amount
-
-		if not payment_term_amount:
-			paid_amt = invoiced_amount - outstanding_amount - credit_note_amount
-		row += [invoiced_amount, paid_amt, credit_note_amount, outstanding_amount]
-
-		# ageing data
-		if self.filters.ageing_based_on == "Due Date":
-			entry_date = due_date
-		elif self.filters.ageing_based_on == "Supplier Invoice Date":
-			entry_date = bill_date
-		else:
-			entry_date = gle.posting_date
-
-		row += get_ageing_data(cint(self.filters.range1), cint(self.filters.range2),
-			cint(self.filters.range3), cint(self.filters.range4), self.age_as_on, entry_date, outstanding_amount)
-
-		# issue 6371-Ageing buckets should not have amounts if due date is not reached
-		if self.filters.ageing_based_on == "Due Date" \
-				and getdate(due_date) > getdate(self.filters.report_date):
-			row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
-
-		if self.filters.ageing_based_on == "Supplier Invoice Date" \
-				and getdate(bill_date) > getdate(self.filters.report_date):
-
-			row[-1]=row[-2]=row[-3]=row[-4]=row[-5]=0
-
-		if self.filters.get(scrub(args.get("party_type"))):
-			row.append(gle.account_currency)
-		else:
-			row.append(self.company_currency)
-
-		remaining_balance = outstanding_amount - flt(pdc_amount)
-		pdc_details = ", ".join(pdc_details)
-		row += [pdc_details, pdc_amount, remaining_balance]
-
-		if args.get('party_type') == 'Customer':
-			# customer LPO
-			row += [self.voucher_details.get(gle.voucher_no, {}).get("po_no")]
-
-			# Delivery Note
-			row += [self.voucher_details.get(gle.voucher_no, {}).get("delivery_note")]
-
-		# customer territory / supplier group
-		if args.get("party_type") == "Customer":
-			row += [self.get_territory(gle.party), self.get_customer_group(gle.party),
-				self.voucher_details.get(gle.voucher_no, {}).get("sales_person")]
-		if args.get("party_type") == "Supplier":
-			row += [self.get_supplier_group(gle.party)]
-
-		row.append(gle.remarks)
-
-		return row
-
-	def get_entries_after(self, report_date, party_type):
-		# returns a distinct list
-		return list(set([(e.voucher_type, e.voucher_no) for e in self.get_gl_entries(party_type, report_date, for_future=True)]))
-
-	def get_entries_till(self, report_date, party_type):
-		# returns a generator
-		return self.get_gl_entries(party_type, report_date)
-
-	def is_receivable_or_payable(self, gle, dr_or_cr, future_vouchers, return_entries):
-		return (
-			# advance
-			(not gle.against_voucher) or
-
-			# against sales order/purchase order
-			(gle.against_voucher_type in ["Sales Order", "Purchase Order"]) or
-
-			# sales invoice/purchase invoice
-			(gle.against_voucher==gle.voucher_no and gle.get(dr_or_cr) > 0) or
-
-			# standalone credit notes
-			(gle.against_voucher==gle.voucher_no and gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no)) or
-
-			# entries adjusted with future vouchers
-			((gle.against_voucher_type, gle.against_voucher) in future_vouchers)
-		)
-
-	def get_return_entries(self, party_type):
-		doctype = "Sales Invoice" if party_type=="Customer" else "Purchase Invoice"
-		return_entries = frappe._dict(frappe.get_all(doctype,
-			filters={"is_return": 1, "docstatus": 1}, fields=["name", "return_against"], as_list=1))
-		return return_entries
-
-	def get_outstanding_amount(self, gle, report_date, dr_or_cr, return_entries):
-		payment_amount, credit_note_amount = 0.0, 0.0
-		reverse_dr_or_cr = "credit" if dr_or_cr=="debit" else "debit"
-		for e in self.get_gl_entries_for(gle.party, gle.party_type, gle.voucher_type, gle.voucher_no):
-			if getdate(e.posting_date) <= report_date \
-				and (e.name!=gle.name or (e.voucher_no in return_entries and not return_entries.get(e.voucher_no))):
-				if e.name!=gle.name and self.gle_inclusion_map.get(e.name):
-					continue
-				self.gle_inclusion_map[e.name] = True
-				amount = flt(e.get(reverse_dr_or_cr), self.currency_precision) - flt(e.get(dr_or_cr), self.currency_precision)
-				if e.voucher_no not in return_entries:
-					payment_amount += amount
+						# if there is overpayment, add another row
+						self.allocate_extra_payments_or_credits(row)
+					else:
+						self.append_row(row)
 				else:
-					credit_note_amount += amount
+					self.append_row(row)
 
-		voucher_amount = flt(gle.get(dr_or_cr), self.currency_precision) - flt(gle.get(reverse_dr_or_cr), self.currency_precision)
-		if gle.voucher_no in return_entries and not return_entries.get(gle.voucher_no):
-			voucher_amount = 0
+	def append_row(self, row):
+		self.allocate_future_payments(row)
+		self.set_invoice_details(row)
+		self.set_party_details(row)
+		self.set_ageing(row)
+		self.data.append(row)
 
-		outstanding_amount = flt((voucher_amount - payment_amount - credit_note_amount), self.currency_precision)
-		credit_note_amount = flt(credit_note_amount, self.currency_precision)
+	def set_invoice_details(self, row):
+		row.update(self.invoice_details.get(row.voucher_no, {}))
+		if row.voucher_type == 'Sales Invoice':
+			if self.filters.show_delivery_notes:
+				self.set_delivery_notes(row)
 
-		return outstanding_amount, credit_note_amount, payment_amount
+			if self.filters.show_sales_person and row.sales_team:
+				row.sales_person = ", ".join(row.sales_team)
+				del row['sales_team']
 
-	def get_party_name(self, party_type, party_name):
-		return self.get_party_map(party_type).get(party_name, {}).get("customer_name" if party_type == "Customer" else "supplier_name") or ""
+	def set_delivery_notes(self, row):
+		delivery_notes = self.delivery_notes.get(row.voucher_no, [])
+		if delivery_notes:
+			row.delivery_notes = ', '.join(delivery_notes)
 
-	def get_customer_contact(self, party_type, party_name):
-		return self.get_party_map(party_type).get(party_name, {}).get("customer_primary_contact")
+	def build_delivery_note_map(self):
+		if self.invoices and self.filters.show_delivery_notes:
+			self.delivery_notes = frappe._dict()
 
-	def get_territory(self, party_name):
-		return self.get_party_map("Customer").get(party_name, {}).get("territory") or ""
+			# delivery note link inside sales invoice
+			si_against_dn = frappe.db.sql("""
+				select parent, delivery_note
+				from `tabSales Invoice Item`
+				where docstatus=1 and parent in (%s)
+			""" % (','.join(['%s'] * len(self.invoices))), tuple(self.invoices), as_dict=1)
 
-	def get_customer_group(self, party_name):
-		return self.get_party_map("Customer").get(party_name, {}).get("customer_group") or ""
+			for d in si_against_dn:
+				if d.delivery_note:
+					self.delivery_notes.setdefault(d.parent, set()).add(d.delivery_note)
 
-	def get_supplier_group(self, party_name):
-		return self.get_party_map("Supplier").get(party_name, {}).get("supplier_group") or ""
+			dn_against_si = frappe.db.sql("""
+				select distinct parent, against_sales_invoice
+				from `tabDelivery Note Item`
+				where against_sales_invoice in (%s)
+			""" % (','.join(['%s'] * len(self.invoices))), tuple(self.invoices) , as_dict=1)
 
-	def get_party_map(self, party_type):
-		if not hasattr(self, "party_map"):
-			if party_type == "Customer":
-				select_fields = "name, customer_name, territory, customer_group, customer_primary_contact"
-			elif party_type == "Supplier":
-				select_fields = "name, supplier_name, supplier_group"
+			for d in dn_against_si:
+				self.delivery_notes.setdefault(d.against_sales_invoice, set()).add(d.parent)
 
-			self.party_map = dict(((r.name, r) for r in frappe.db.sql("select {0} from `tab{1}`"
-				.format(select_fields, party_type), as_dict=True)))
+	def get_invoice_details(self):
+		self.invoice_details = frappe._dict()
+		if self.party_type == "Customer":
+			si_list = frappe.db.sql("""
+				select name, due_date, po_no
+				from `tabSales Invoice`
+				where posting_date <= %s
+			""",self.filters.report_date, as_dict=1)
+			for d in si_list:
+				self.invoice_details.setdefault(d.name, d)
 
-		return self.party_map
+			# Get Sales Team
+			if self.filters.show_sales_person:
+				sales_team = frappe.db.sql("""
+					select parent, sales_person
+					from `tabSales Team`
+					where parenttype = 'Sales Invoice'
+				""", as_dict=1)
+				for d in sales_team:
+					self.invoice_details.setdefault(d.parent, {})\
+						.setdefault('sales_team', []).append(d.sales_person)
 
-	def get_gl_entries(self, party_type, date=None, for_future=False):
-		conditions, values = self.prepare_conditions(party_type)
+		if self.party_type == "Supplier":
+			for pi in frappe.db.sql("""
+				select name, due_date, bill_no, bill_date
+				from `tabPurchase Invoice`
+				where posting_date <= %s
+			""", self.filters.report_date, as_dict=1):
+				self.invoice_details.setdefault(pi.name, pi)
 
-		if self.filters.get(scrub(party_type)):
-			select_fields = "sum(debit_in_account_currency) as debit, sum(credit_in_account_currency) as credit"
+		# Invoices booked via Journal Entries
+		journal_entries = frappe.db.sql("""
+			select name, due_date, bill_no, bill_date
+			from `tabJournal Entry`
+			where posting_date <= %s
+		""", self.filters.report_date, as_dict=1)
+
+		for je in journal_entries:
+			if je.bill_no:
+				self.invoice_details.setdefault(je.name, je)
+
+	def set_party_details(self, row):
+		# customer / supplier name
+		party_details = self.get_party_details(row.party)
+		row.update(party_details)
+
+		if self.filters.get(scrub(self.filters.party_type)):
+			row.currency = row.account_currency
 		else:
-			select_fields = "sum(debit) as debit, sum(credit) as credit"
+			row.currency = self.company_currency
 
-		if date and not for_future:
-			conditions += " and posting_date <= '%s'" % date
+	def allocate_outstanding_based_on_payment_terms(self, row):
+		self.get_payment_terms(row)
+		for term in row.payment_terms:
+			term.outstanding = term.invoiced
 
-		if date and for_future:
-			conditions += " and posting_date > '%s'" % date
+			# update "paid" and "oustanding" for this term
+			self.allocate_closing_to_term(row, term, 'paid')
+
+			# update "credit_note" and "oustanding" for this term
+			if term.outstanding:
+				self.allocate_closing_to_term(row, term, 'credit_note')
+
+	def get_payment_terms(self, row):
+		# build payment_terms for row
+		payment_terms_details = frappe.db.sql("""
+			select
+				si.name, si.party_account_currency, si.currency, si.conversion_rate,
+				ps.due_date, ps.payment_amount, ps.description
+			from `tab{0}` si, `tabPayment Schedule` ps
+			where
+				si.name = ps.parent and
+				si.name = %s
+			order by ps.due_date
+		""".format(row.voucher_type), row.voucher_no, as_dict = 1)
+
+
+		original_row = frappe._dict(row)
+		row.payment_terms = []
+
+		# If no or single payment terms, no need to split the row
+		if len(payment_terms_details) <= 1:
+			return
+
+		for d in payment_terms_details:
+			term = frappe._dict(original_row)
+			self.append_payment_term(row, d, term)
+
+	def append_payment_term(self, row, d, term):
+		if self.filters.get("customer") and d.currency == d.party_account_currency:
+			invoiced = d.payment_amount
+		else:
+			invoiced = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+
+		row.payment_terms.append(term.update({
+			"due_date": d.due_date,
+			"invoiced": invoiced,
+			"invoice_grand_total": row.invoiced,
+			"payment_term": d.description,
+			"paid": 0.0,
+			"credit_note": 0.0,
+			"outstanding": 0.0
+		}))
+
+	def allocate_closing_to_term(self, row, term, key):
+		if row[key]:
+			if row[key] > term.outstanding:
+				term[key] = term.outstanding
+				row[key] -= term.outstanding
+			else:
+				term[key] = row[key]
+				row[key] = 0
+		term.outstanding -= term[key]
+
+	def allocate_extra_payments_or_credits(self, row):
+		# allocate extra payments / credits
+		additional_row = None
+		for key in ('paid', 'credit_note'):
+			if row[key] > 0:
+				if not additional_row:
+					additional_row = frappe._dict(row)
+				additional_row.invoiced = 0.0
+				additional_row[key] = row[key]
+
+		if additional_row:
+			additional_row.outstanding = additional_row.invoiced - additional_row.paid - additional_row.credit_note
+			self.append_row(additional_row)
+
+	def get_future_payments(self):
+		if self.filters.show_future_payments:
+			self.future_payments = frappe._dict()
+			future_payments = list(self.get_future_payments_from_payment_entry())
+			future_payments += list(self.get_future_payments_from_journal_entry())
+			if future_payments:
+				for d in future_payments:
+					if d.future_amount and d.invoice_no:
+						self.future_payments.setdefault((d.invoice_no, d.party), []).append(d)
+
+	def get_future_payments_from_payment_entry(self):
+		return frappe.db.sql("""
+			select
+				ref.reference_name as invoice_no,
+				payment_entry.party,
+				payment_entry.party_type,
+				payment_entry.posting_date as future_date,
+				ref.allocated_amount as future_amount,
+				payment_entry.reference_no as future_ref
+			from
+				`tabPayment Entry` as payment_entry inner join `tabPayment Entry Reference` as ref
+			on
+				(ref.parent = payment_entry.name)
+			where
+				payment_entry.docstatus = 1
+				and payment_entry.posting_date > %s
+				and payment_entry.party_type = %s
+			""", (self.filters.report_date, self.party_type), as_dict=1)
+
+	def get_future_payments_from_journal_entry(self):
+		if self.filters.get('party'):
+			amount_field = ("jea.debit_in_account_currency - jea.credit_in_account_currency"
+				if self.party_type == 'Supplier' else "jea.credit_in_account_currency - jea.debit_in_account_currency")
+		else:
+			amount_field = ("jea.debit - " if self.party_type == 'Supplier' else "jea.credit")
+
+		return frappe.db.sql("""
+			select
+				jea.reference_name as invoice_no,
+				jea.party,
+				jea.party_type,
+				je.posting_date as future_date,
+				sum({0}) as future_amount,
+				je.cheque_no as future_ref
+			from
+				`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
+			on
+				(jea.parent = je.name)
+			where
+				je.docstatus = 1
+				and je.posting_date > %s
+				and jea.party_type = %s
+				and jea.reference_name is not null and jea.reference_name != ''
+			group by je.name, jea.reference_name
+			having future_amount > 0
+			""".format(amount_field), (self.filters.report_date, self.party_type), as_dict=1)
+
+	def allocate_future_payments(self, row):
+		# future payments are captured in additional columns
+		# this method allocates pending future payments against a voucher to
+		# the current row (which could be generated from payment terms)
+		if not self.filters.show_future_payments:
+			return
+
+		row.remaining_balance = row.outstanding
+		row.future_amount = 0.0
+		for future in self.future_payments.get((row.voucher_no, row.party), []):
+			if row.remaining_balance > 0 and future.future_amount:
+				if future.future_amount > row.outstanding:
+					row.future_amount = row.outstanding
+					future.future_amount = future.future_amount - row.outstanding
+					row.remaining_balance = 0
+				else:
+					row.future_amount += future.future_amount
+					future.future_amount = 0
+					row.remaining_balance = row.outstanding - row.future_amount
+
+				row.setdefault('future_ref', []).append(cstr(future.future_ref) + '/' + cstr(future.future_date))
+
+		if row.future_ref:
+			row.future_ref = ', '.join(row.future_ref)
+
+	def set_ageing(self, row):
+		if self.filters.ageing_based_on == "Due Date":
+			entry_date = row.due_date
+		elif self.filters.ageing_based_on == "Supplier Invoice Date":
+			entry_date = row.bill_date
+		else:
+			entry_date = row.posting_date
+
+		self.get_ageing_data(entry_date, row)
+
+		# ageing buckets should not have amounts if due date is not reached
+		if getdate(entry_date) > getdate(self.filters.report_date):
+			row.range1 = row.range2 = row.range3 = row.range4 = row.range5 = 0.0
+
+	def get_ageing_data(self, entry_date, row):
+		# [0-30, 30-60, 60-90, 90-120, 120-above]
+		row.range1 = row.range2 = row.range3 = row.range4 = range5 = 0.0
+
+		if not (self.age_as_on and entry_date):
+			return
+
+		row.age = (getdate(self.age_as_on) - getdate(entry_date)).days or 0
+		index = None
+		for i, days in enumerate([self.filters.range1, self.filters.range2, self.filters.range3, self.filters.range4]):
+			if row.age <= days:
+				index = i
+				break
+
+		if index is None: index = 4
+		row['range' + str(index+1)] = row.outstanding
+
+	def get_gl_entries(self):
+		# get all the GL entries filtered by the given filters
+
+		conditions, values = self.prepare_conditions()
+
+		if self.filters.get(scrub(self.party_type)):
+			select_fields = "debit_in_account_currency as debit, credit_in_account_currency as credit"
+		else:
+			select_fields = "debit, credit"
 
 		self.gl_entries = frappe.db.sql("""
 			select
@@ -477,91 +471,95 @@
 			from
 				`tabGL Entry`
 			where
-				docstatus < 2 and party_type=%s and (party is not null and party != '') {1}
-				group by voucher_type, voucher_no, against_voucher_type, against_voucher, party
-				order by posting_date, party"""
+				docstatus < 2
+				and party_type=%s
+				and (party is not null and party != '')
+				and posting_date <= %s
+				{1}
+			order by posting_date, party"""
 			.format(select_fields, conditions), values, as_dict=True)
 
-		return self.gl_entries
-
-	def prepare_conditions(self, party_type):
+	def prepare_conditions(self):
 		conditions = [""]
-		values = [party_type]
+		values = [self.party_type, self.filters.report_date]
+		party_type_field = scrub(self.party_type)
 
-		party_type_field = scrub(party_type)
+		self.add_common_filters(conditions, values, party_type_field)
 
+		if party_type_field=="customer":
+			self.add_customer_filters(conditions, values)
+
+		elif party_type_field=="supplier":
+			self.add_supplier_filters(conditions, values)
+
+		self.add_accounting_dimensions_filters(conditions, values)
+
+		return " and ".join(conditions), values
+
+	def add_common_filters(self, conditions, values, party_type_field):
 		if self.filters.company:
 			conditions.append("company=%s")
 			values.append(self.filters.company)
 
 		if self.filters.finance_book:
-			conditions.append("ifnull(finance_book,'') in (%s, '')")
+			conditions.append("ifnull(finance_book, '') in (%s, '')")
 			values.append(self.filters.finance_book)
 
 		if self.filters.get(party_type_field):
 			conditions.append("party=%s")
 			values.append(self.filters.get(party_type_field))
 
-		if party_type_field=="customer":
-			account_type = "Receivable"
-			if self.filters.get("customer_group"):
-				lft, rgt = frappe.db.get_value("Customer Group",
-					self.filters.get("customer_group"), ["lft", "rgt"])
+		# get GL with "receivable" or "payable" account_type
+		account_type = "Receivable" if self.party_type == "Customer" else "Payable"
+		accounts = [d.name for d in frappe.get_all("Account",
+			filters={"account_type": account_type, "company": self.filters.company})]
+		conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
+		values += accounts
 
-				conditions.append("""party in (select name from tabCustomer
-					where exists(select name from `tabCustomer Group` where lft >= {0} and rgt <= {1}
-						and name=tabCustomer.customer_group))""".format(lft, rgt))
+	def add_customer_filters(self, conditions, values):
+		if self.filters.get("customer_group"):
+			conditions.append(self.get_hierarchical_filters('Customer Group', 'customer_group'))
 
-			if self.filters.get("territory"):
-				lft, rgt = frappe.db.get_value("Territory",
-					self.filters.get("territory"), ["lft", "rgt"])
+		if self.filters.get("territory"):
+			conditions.append(self.get_hierarchical_filters('Territory', 'territory'))
 
-				conditions.append("""party in (select name from tabCustomer
-					where exists(select name from `tabTerritory` where lft >= {0} and rgt <= {1}
-						and name=tabCustomer.territory))""".format(lft, rgt))
+		if self.filters.get("payment_terms_template"):
+			conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
+			values.append(self.filters.get("payment_terms_template"))
 
-			if self.filters.get("payment_terms_template"):
-				conditions.append("party in (select name from tabCustomer where payment_terms=%s)")
-				values.append(self.filters.get("payment_terms_template"))
+		if self.filters.get("sales_partner"):
+			conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
+			values.append(self.filters.get("sales_partner"))
 
-			if self.filters.get("sales_partner"):
-				conditions.append("party in (select name from tabCustomer where default_sales_partner=%s)")
-				values.append(self.filters.get("sales_partner"))
+		if self.filters.get("sales_person"):
+			lft, rgt = frappe.db.get_value("Sales Person",
+				self.filters.get("sales_person"), ["lft", "rgt"])
 
-			if self.filters.get("sales_person"):
-				lft, rgt = frappe.db.get_value("Sales Person",
-					self.filters.get("sales_person"), ["lft", "rgt"])
+			conditions.append("""exists(select name from `tabSales Team` steam where
+				steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
+				and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
+					or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
+					or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
 
-				conditions.append("""exists(select name from `tabSales Team` steam where
-					steam.sales_person in (select name from `tabSales Person` where lft >= {0} and rgt <= {1})
-					and ((steam.parent = voucher_no and steam.parenttype = voucher_type)
-						or (steam.parent = against_voucher and steam.parenttype = against_voucher_type)
-						or (steam.parent = party and steam.parenttype = 'Customer')))""".format(lft, rgt))
+	def add_supplier_filters(self, conditions, values):
+		if self.filters.get("supplier_group"):
+			conditions.append("""party in (select name from tabSupplier
+				where supplier_group=%s)""")
+			values.append(self.filters.get("supplier_group"))
 
-		elif party_type_field=="supplier":
-			account_type = "Payable"
-			if self.filters.get("supplier_group"):
-				conditions.append("""party in (select name from tabSupplier
-					where supplier_group=%s)""")
-				values.append(self.filters.get("supplier_group"))
+		if self.filters.get("payment_terms_template"):
+			conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
+			values.append(self.filters.get("payment_terms_template"))
 
-			if self.filters.get("payment_terms_template"):
-				conditions.append("party in (select name from tabSupplier where payment_terms=%s)")
-				values.append(self.filters.get("payment_terms_template"))
+	def get_hierarchical_filters(self, doctype, key):
+		lft, rgt = frappe.db.get_value(doctype, self.filters.get(key), ["lft", "rgt"])
 
-		if self.filters.get("cost_center"):
-			lft, rgt = frappe.get_cached_value("Cost Center",
-				self.filters.get("cost_center"), ['lft', 'rgt'])
+		return """party in (select name from tabCustomer
+			where exists(select name from `tab{doctype}` where lft >= {lft} and rgt <= {rgt}
+				and name=tabCustomer.{key}))""".format(
+					doctype=doctype, lft=lft, rgt=rgt, key=key)
 
-			conditions.append("""cost_center in (select name from `tabCost Center` where
-				lft >= {0} and rgt <= {1})""".format(lft, rgt))
-
-		if self.filters.company:
-			accounts = [d.name for d in frappe.get_all("Account",
-				filters={"account_type": account_type, "company": self.filters.company})]
-			conditions.append("account in (%s)" % ','.join(['%s'] *len(accounts)))
-			values += accounts
-
+	def add_accounting_dimensions_filters(self, conditions, values):
 		accounting_dimensions = get_accounting_dimensions()
 
 		if accounting_dimensions:
@@ -570,195 +568,133 @@
 					conditions.append("{0} = %s".format(dimension))
 					values.append(self.filters.get(dimension))
 
-		return " and ".join(conditions), values
+	def get_gle_balance(self, gle):
+		# get the balance of the GL (debit - credit) or reverse balance based on report type
+		return gle.get(self.dr_or_cr) - self.get_reverse_balance(gle)
 
-	def get_gl_entries_for(self, party, party_type, against_voucher_type, against_voucher):
-		if not hasattr(self, "gl_entries_map"):
-			self.gl_entries_map = {}
-			for gle in self.get_gl_entries(party_type):
-				if gle.against_voucher_type and gle.against_voucher:
-					self.gl_entries_map.setdefault(gle.party, {})\
-						.setdefault(gle.against_voucher_type, {})\
-						.setdefault(gle.against_voucher, [])\
-						.append(gle)
+	def get_reverse_balance(self, gle):
+		# get "credit" balance if report type is "debit" and vice versa
+		return gle.get('debit' if self.dr_or_cr=='credit' else 'credit')
 
-		return self.gl_entries_map.get(party, {})\
-			.get(against_voucher_type, {})\
-			.get(against_voucher, [])
+	def is_invoice(self, gle):
+		if gle.voucher_type in ('Sales Invoice', 'Purchase Invoice'):
+			return True
 
-	def get_payment_term_detail(self, voucher_nos):
-		payment_term_map = frappe._dict()
-		payment_terms_details = frappe.db.sql(""" select si.name,
-			party_account_currency, currency, si.conversion_rate,
-			ps.due_date, ps.payment_amount, ps.description
-			from `tabSales Invoice` si, `tabPayment Schedule` ps
-			where si.name = ps.parent and
-			si.docstatus = 1 and si.company = %s and
-			si.name in (%s) order by ps.due_date
-		"""	% (frappe.db.escape(self.filters.company), ','.join(['%s'] *len(voucher_nos))),
-		(tuple(voucher_nos)), as_dict = 1)
-
-		for d in payment_terms_details:
-			if self.filters.get("customer") and d.currency == d.party_account_currency:
-				payment_term_amount = d.payment_amount
+	def get_party_details(self, party):
+		if not party in self.party_details:
+			if self.party_type == 'Customer':
+				self.party_details[party] = frappe.db.get_value('Customer', party, ['customer_name',
+					'territory', 'customer_group', 'customer_primary_contact'], as_dict=True)
 			else:
-				payment_term_amount = flt(flt(d.payment_amount) * flt(d.conversion_rate), self.currency_precision)
+				self.party_details[party] = frappe.db.get_value('Supplier', party, ['supplier_name',
+					'supplier_group'], as_dict=True)
 
-			payment_term_map.setdefault(d.name, []).append(frappe._dict({
-				"due_date": d.due_date,
-				"payment_term_amount": payment_term_amount,
-				"description": d.description
-			}))
-		return payment_term_map
+		return self.party_details[party]
 
-	def get_chart_data(self, columns, data):
-		ageing_columns = columns[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
 
+	def get_columns(self):
+		self.columns = []
+		self.add_column('Posting Date', fieldtype='Date')
+		self.add_column(label=_(self.party_type), fieldname='party',
+			fieldtype='Link', options=self.party_type, width=180)
+
+		if self.party_naming_by == "Naming Series":
+			self.add_column(_('{0} Name').format(self.party_type),
+				fieldname = scrub(self.party_type) + '_name', fieldtype='Data')
+
+		if self.party_type == 'Customer':
+			self.add_column(_("Customer Contact"), fieldname='customer_primary_contact',
+				fieldtype='Link', options='Contact')
+
+		self.add_column(label=_('Voucher Type'), fieldname='voucher_type', fieldtype='Data')
+		self.add_column(label=_('Voucher No'), fieldname='voucher_no', fieldtype='Dynamic Link',
+			options='voucher_type', width=180)
+		self.add_column(label='Due Date', fieldtype='Date')
+
+		if self.party_type == "Supplier":
+			self.add_column(label=_('Bill No'), fieldname='bill_no', fieldtype='Data')
+			self.add_column(label=_('Bill Date'), fieldname='bill_date', fieldtype='Date')
+
+		if self.filters.based_on_payment_terms:
+			self.add_column(label=_('Payment Term'), fieldname='payment_term', fieldtype='Data')
+			self.add_column(label=_('Invoice Grand Total'), fieldname='invoice_grand_total')
+
+		self.add_column(_('Invoiced Amount'), fieldname='invoiced')
+		self.add_column(_('Paid Amount'), fieldname='paid')
+		if self.party_type == "Customer":
+			self.add_column(_('Credit Note'), fieldname='credit_note')
+		else:
+			# note: fieldname is still `credit_note`
+			self.add_column(_('Debit Note'), fieldname='credit_note')
+		self.add_column(_('Outstanding Amount'), fieldname='outstanding')
+
+		self.setup_ageing_columns()
+
+		self.add_column(label=_('Currency'), fieldname='currency', fieldtype='Link', options='Currency', width=80)
+
+		if self.filters.show_future_payments:
+			self.add_column(label=_('Future Payment Ref'), fieldname='future_ref', fieldtype='Data')
+			self.add_column(label=_('Future Payment Amount'), fieldname='future_amount')
+			self.add_column(label=_('Remaining Balance'), fieldname='remaining_balance')
+
+		if self.filters.party_type == 'Customer':
+			self.add_column(label=_('Customer LPO'), fieldname='po_no', fieldtype='Data')
+
+			# comma separated list of linked delivery notes
+			if self.filters.show_delivery_notes:
+				self.add_column(label=_('Delivery Notes'), fieldname='delivery_notes', fieldtype='Data')
+			self.add_column(label=_('Territory'), fieldname='territory', fieldtype='Link',
+				options='Territory')
+			self.add_column(label=_('Customer Group'), fieldname='customer_group', fieldtype='Link',
+				options='Customer Group')
+			if self.filters.show_sales_person:
+				self.add_column(label=_('Sales Person'), fieldname='sales_person', fieldtype='Data')
+
+		if self.filters.party_type == "Supplier":
+			self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
+				options='Supplier Group')
+
+		self.add_column(label=_('Remarks'), fieldname='remarks', fieldtype='Text', width=200)
+
+	def add_column(self, label, fieldname=None, fieldtype='Currency', options=None, width=120):
+		if not fieldname: fieldname = scrub(label)
+		if fieldtype=='Currency': options='currency'
+		if fieldtype=='Date': width = 90
+
+		self.columns.append(dict(
+			label=label,
+			fieldname=fieldname,
+			fieldtype=fieldtype,
+			options=options,
+			width=width
+		))
+
+	def setup_ageing_columns(self):
+		# for charts
+		self.ageing_column_labels = []
+		self.add_column(label=_('Age (Days)'), fieldname='age', fieldtype='Int', width=80)
+
+		for i, label in enumerate(["0-{range1}".format(range1=self.filters["range1"]),
+			"{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
+			"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
+			"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
+			"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
+				self.add_column(label=label, fieldname='range' + str(i+1))
+				self.ageing_column_labels.append(label)
+
+	def get_chart_data(self):
 		rows = []
-		for d in data:
-			values = d[self.ageing_col_idx_start : self.ageing_col_idx_start+5]
-			precision = cint(frappe.db.get_default("float_precision")) or 2
-			formatted_values = [frappe.utils.rounded(val, precision) for val in values]
+		for row in self.data:
 			rows.append(
 				{
-					'values': formatted_values
+					'values': [row.range1, row.range2, row.range3, row.range4, row.range5]
 				}
 			)
 
-		return {
+		self.chart = {
 			"data": {
-				'labels': [d.get("label") for d in ageing_columns],
+				'labels': self.ageing_column_labels,
 				'datasets': rows
 			},
 			"type": 'percentage'
 		}
-
-def execute(filters=None):
-	args = {
-		"party_type": "Customer",
-		"naming_by": ["Selling Settings", "cust_master_name"],
-	}
-	return ReceivablePayableReport(filters).run(args)
-
-def get_ageing_data(first_range, second_range, third_range,
-	fourth_range, age_as_on, entry_date, outstanding_amount):
-	# [0-30, 30-60, 60-90, 90-120, 120-above]
-	outstanding_range = [0.0, 0.0, 0.0, 0.0, 0.0]
-
-	if not (age_as_on and entry_date):
-		return [0] + outstanding_range
-
-	age = (getdate(age_as_on) - getdate(entry_date)).days or 0
-	index = None
-	for i, days in enumerate([first_range, second_range, third_range, fourth_range]):
-		if age <= days:
-			index = i
-			break
-
-	if index is None: index = 4
-	outstanding_range[index] = outstanding_amount
-
-	return [age] + outstanding_range
-
-def get_pdc_details(party_type, report_date):
-	pdc_details = frappe._dict()
-	pdc_via_pe = frappe.db.sql("""
-		select
-			pref.reference_name as invoice_no, pent.party, pent.party_type,
-			pent.posting_date as pdc_date, ifnull(pref.allocated_amount,0) as pdc_amount,
-			pent.reference_no as pdc_ref
-		from
-			`tabPayment Entry` as pent inner join `tabPayment Entry Reference` as pref
-		on
-			(pref.parent = pent.name)
-		where
-			pent.docstatus < 2 and pent.posting_date > %s
-			and pent.party_type = %s
-		""", (report_date, party_type), as_dict=1)
-
-	for pdc in pdc_via_pe:
-			pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
-
-	if scrub(party_type):
-		amount_field = ("jea.debit_in_account_currency"
-			if party_type == 'Supplier' else "jea.credit_in_account_currency")
-	else:
-		amount_field = "jea.debit + jea.credit"
-
-	pdc_via_je = frappe.db.sql("""
-		select
-			jea.reference_name as invoice_no, jea.party, jea.party_type,
-			je.posting_date as pdc_date, ifnull({0},0) as pdc_amount,
-			je.cheque_no as pdc_ref
-		from
-			`tabJournal Entry` as je inner join `tabJournal Entry Account` as jea
-		on
-			(jea.parent = je.name)
-		where
-			je.docstatus < 2 and je.posting_date > %s
-			and jea.party_type = %s
-		""".format(amount_field), (report_date, party_type), as_dict=1)
-
-	for pdc in pdc_via_je:
-		pdc_details.setdefault((pdc.invoice_no, pdc.party), []).append(pdc)
-
-	return pdc_details
-
-def get_dn_details(party_type, voucher_nos):
-	dn_details = frappe._dict()
-
-	if party_type == "Customer":
-		for si in frappe.db.sql("""
-			select
-				parent, GROUP_CONCAT(delivery_note SEPARATOR ', ') as dn
-			from
-				`tabSales Invoice Item`
-			where
-				docstatus=1 and delivery_note is not null and delivery_note != ''
-				and parent in (%s) group by parent
-			""" %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1):
-			dn_details.setdefault(si.parent, si.dn)
-
-		for si in frappe.db.sql("""
-			select
-				against_sales_invoice as parent, GROUP_CONCAT(parent SEPARATOR ', ') as dn
-			from
-				`tabDelivery Note Item`
-			where
-				docstatus=1 and against_sales_invoice is not null and against_sales_invoice != ''
-				and against_sales_invoice in (%s)
-				group by against_sales_invoice
-			""" %(','.join(['%s'] * len(voucher_nos))), tuple(voucher_nos) , as_dict=1):
-			if si.parent in dn_details:
-				dn_details[si.parent] += ', %s' %(si.dn)
-			else:
-				dn_details.setdefault(si.parent, si.dn)
-
-	return dn_details
-
-def get_voucher_details(party_type, voucher_nos, dn_details):
-	voucher_details = frappe._dict()
-
-	if party_type == "Customer":
-		for si in frappe.db.sql("""
-			select inv.name, inv.due_date, inv.po_no, GROUP_CONCAT(steam.sales_person SEPARATOR ', ') as sales_person
-			from `tabSales Invoice` inv
-			left join `tabSales Team` steam on steam.parent = inv.name and steam.parenttype = 'Sales Invoice'
-			where inv.docstatus=1 and inv.name in (%s)
-			group by inv.name
-			""" %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
-				si['delivery_note'] = dn_details.get(si.name)
-				voucher_details.setdefault(si.name, si)
-
-	if party_type == "Supplier":
-		for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date
-			from `tabPurchase Invoice` where docstatus = 1 and name in (%s)
-			""" %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
-			voucher_details.setdefault(pi.name, pi)
-
-	for pi in frappe.db.sql("""select name, due_date, bill_no, bill_date from
-		`tabJournal Entry` where docstatus = 1 and bill_no is not NULL and name in (%s)
-		""" %(','.join(['%s'] *len(voucher_nos))), (tuple(voucher_nos)), as_dict=1):
-			voucher_details.setdefault(pi.name, pi)
-
-	return voucher_details
diff --git a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
index 43786a4..f0274b4 100644
--- a/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
+++ b/erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py
@@ -14,33 +14,44 @@
 
 		filters = {
 			'company': '_Test Company 2',
-			'based_on_payment_terms': 1
+			'based_on_payment_terms': 1,
+			'report_date': today(),
+			'range1': 30,
+			'range2': 60,
+			'range3': 90,
+			'range4': 120
 		}
 
+		# check invoice grand total and invoiced column's value for 3 payment terms
 		name = make_sales_invoice()
 		report = execute(filters)
 
-		expected_data = [[100,30], [100,50], [100,20]]
+		expected_data = [[100, 30], [100, 50], [100, 20]]
 
-		self.assertEqual(expected_data[0], report[1][0][7:9])
-		self.assertEqual(expected_data[1], report[1][1][7:9])
-		self.assertEqual(expected_data[2], report[1][2][7:9])
+		for i in range(3):
+			row = report[1][i-1]
+			self.assertEqual(expected_data[i-1], [row.invoice_grand_total, row.invoiced])
 
+		# check invoice grand total, invoiced, paid and outstanding column's value after payment
 		make_payment(name)
 		report = execute(filters)
 
-		expected_data_after_payment = [[100,50], [100,20]]
+		expected_data_after_payment = [[100, 50, 10, 40], [100, 20, 0, 20]]
 
-		self.assertEqual(expected_data_after_payment[0], report[1][0][7:9])
-		self.assertEqual(expected_data_after_payment[1], report[1][1][7:9])
+		for i in range(2):
+			row = report[1][i-1]
+			self.assertEqual(expected_data_after_payment[i-1],
+				[row.invoice_grand_total, row.invoiced, row.paid, row.outstanding])
 
+		# check invoice grand total, invoiced, paid and outstanding column's value after credit note
 		make_credit_note(name)
 		report = execute(filters)
 
-		expected_data_after_credit_note = [[100,100,30,100,-30]]
+		expected_data_after_credit_note = [100, 0, 0, 40, -40]
 
-		self.assertEqual(expected_data_after_credit_note[0], report[1][0][7:12])
-
+		row = report[1][0]
+		self.assertEqual(expected_data_after_credit_note,
+			[row.invoice_grand_total, row.invoiced, row.paid, row.credit_note, row.outstanding])
 
 def make_sales_invoice():
 	frappe.set_user("Administrator")
@@ -64,7 +75,7 @@
 	return si.name
 
 def make_payment(docname):
-	pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=30)
+	pe = get_payment_entry("Sales Invoice", docname, bank_account="Cash - _TC2", party_amount=40)
 	pe.paid_from = "Debtors - _TC2"
 	pe.insert()
 	pe.submit()
diff --git a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
index ec24aec..350e081 100644
--- a/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
+++ b/erpnext/accounts/report/accounts_receivable_summary/accounts_receivable_summary.py
@@ -3,236 +3,11 @@
 
 from __future__ import unicode_literals
 import frappe
-from frappe import _, scrub
-from frappe.utils import flt
+from frappe import _
+from frappe.utils import flt, cint
 from erpnext.accounts.party import get_partywise_advanced_payment_amount
 from erpnext.accounts.report.accounts_receivable.accounts_receivable import ReceivablePayableReport
-
 from six import iteritems
-from six.moves import zip
-
-class AccountsReceivableSummary(ReceivablePayableReport):
-	def run(self, args):
-		party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
-		return self.get_columns(party_naming_by, args), self.get_data(party_naming_by, args)
-
-	def get_columns(self, party_naming_by, args):
-		columns = [_(args.get("party_type")) + ":Link/" + args.get("party_type") + ":200"]
-
-		if party_naming_by == "Naming Series":
-			columns += [ args.get("party_type") + " Name::140"]
-
-		credit_debit_label = "Credit Note Amt" if args.get('party_type') == 'Customer' else "Debit Note Amt"
-
-		columns += [{
-			"label": _("Advance Amount"),
-			"fieldname": "advance_amount",
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 100
-		},{
-			"label": _("Total Invoiced Amt"),
-			"fieldname": "total_invoiced_amt",
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 100
-		},
-		{
-			"label": _("Total Paid Amt"),
-			"fieldname": "total_paid_amt",
-			"fieldtype": "Currency",
-			"options": "currency",
-			"width": 100
-		}]
-
-		columns += [
-			{
-				"label": _(credit_debit_label),
-				"fieldname": scrub(credit_debit_label),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 140
-			},
-			{
-				"label": _("Total Outstanding Amt"),
-				"fieldname": "total_outstanding_amt",
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			},
-			{
-				"label": _("0-" + str(self.filters.range1)),
-				"fieldname": scrub("0-" + str(self.filters.range1)),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			},
-			{
-				"label": _(str(self.filters.range1) + "-" + str(self.filters.range2)),
-				"fieldname": scrub(str(self.filters.range1) + "-" + str(self.filters.range2)),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			},
-			{
-				"label": _(str(self.filters.range2) + "-" + str(self.filters.range3)),
-				"fieldname": scrub(str(self.filters.range2) + "-" + str(self.filters.range3)),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			},
-			{
-				"label": _(str(self.filters.range3) + "-" + str(self.filters.range4)),
-				"fieldname": scrub(str(self.filters.range3) + "-" + str(self.filters.range4)),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			},
-			{
-				"label": _(str(self.filters.range4) + _("-Above")),
-				"fieldname": scrub(str(self.filters.range4) + _("-Above")),
-				"fieldtype": "Currency",
-				"options": "currency",
-				"width": 160
-			}
-		]
-
-		if args.get("party_type") == "Customer":
-			columns += [{
-				"label": _("Territory"),
-				"fieldname": "territory",
-				"fieldtype": "Link",
-				"options": "Territory",
-				"width": 80
-			},
-			{
-				"label": _("Customer Group"),
-				"fieldname": "customer_group",
-				"fieldtype": "Link",
-				"options": "Customer Group",
-				"width": 80
-			},
-			{
-				"label": _("Sales Person"),
-				"fieldtype": "Data",
-				"fieldname": "sales_person",
-				"width": 120,
-			}]
-
-		if args.get("party_type") == "Supplier":
-			columns += [{
-				"label": _("Supplier Group"),
-				"fieldname": "supplier_group",
-				"fieldtype": "Link",
-				"options": "Supplier Group",
-				"width": 80
-			}]
-
-		columns.append({
-			"fieldname": "currency",
-			"label": _("Currency"),
-			"fieldtype": "Link",
-			"options": "Currency",
-			"width": 80
-		})
-
-		return columns
-
-	def get_data(self, party_naming_by, args):
-		data = []
-
-		partywise_total = self.get_partywise_total(party_naming_by, args)
-
-		partywise_advance_amount = get_partywise_advanced_payment_amount(args.get("party_type"),
-			self.filters.get("report_date")) or {}
-		for party, party_dict in iteritems(partywise_total):
-			row = [party]
-
-			if party_naming_by == "Naming Series":
-				row += [self.get_party_name(args.get("party_type"), party)]
-
-			row += [partywise_advance_amount.get(party, 0)]
-
-			paid_amt = 0
-			if party_dict.paid_amt > 0:
-				paid_amt = flt(party_dict.paid_amt - partywise_advance_amount.get(party, 0))
-
-			row += [
-				party_dict.invoiced_amt, paid_amt, party_dict.credit_amt, party_dict.outstanding_amt,
-				party_dict.range1, party_dict.range2, party_dict.range3, party_dict.range4, party_dict.range5
-			]
-
-			if args.get("party_type") == "Customer":
-				row += [self.get_territory(party), self.get_customer_group(party), ", ".join(set(party_dict.sales_person))]
-			if args.get("party_type") == "Supplier":
-				row += [self.get_supplier_group(party)]
-
-			row.append(party_dict.currency)
-			data.append(row)
-
-		return data
-
-	def get_partywise_total(self, party_naming_by, args):
-		party_total = frappe._dict()
-		for d in self.get_voucherwise_data(party_naming_by, args):
-			party_total.setdefault(d.party,
-				frappe._dict({
-					"invoiced_amt": 0,
-					"paid_amt": 0,
-					"credit_amt": 0,
-					"outstanding_amt": 0,
-					"range1": 0,
-					"range2": 0,
-					"range3": 0,
-					"range4": 0,
-					"range5": 0,
-					"sales_person": []
-				})
-			)
-			for k in list(party_total[d.party]):
-				if k not in ["currency", "sales_person"]:
-					party_total[d.party][k] += flt(d.get(k, 0))
-
-			party_total[d.party].currency = d.currency
-
-			if d.sales_person:
-				party_total[d.party].sales_person.append(d.sales_person)
-
-		return party_total
-
-	def get_voucherwise_data(self, party_naming_by, args):
-		voucherwise_data = ReceivablePayableReport(self.filters).run(args)[1]
-
-		cols = ["posting_date", "party"]
-
-		if party_naming_by == "Naming Series":
-			cols += ["party_name"]
-
-		if args.get("party_type") == 'Customer':
-			cols += ["contact"]
-
-		cols += ["voucher_type", "voucher_no", "due_date"]
-
-		if args.get("party_type") == "Supplier":
-			cols += ["bill_no", "bill_date"]
-
-		cols += ["invoiced_amt", "paid_amt", "credit_amt",
-		"outstanding_amt", "age", "range1", "range2", "range3", "range4", "range5", "currency", "pdc/lc_date", "pdc/lc_ref",
-		"pdc/lc_amount"]
-
-		if args.get("party_type") == "Supplier":
-			cols += ["supplier_group", "remarks"]
-		if args.get("party_type") == "Customer":
-			cols += ["po_no", "do_no", "territory", "customer_group", "sales_person", "remarks"]
-
-		return self.make_data_dict(cols, voucherwise_data)
-
-	def make_data_dict(self, cols, data):
-		data_dict = []
-		for d in data:
-			data_dict.append(frappe._dict(zip(cols, d)))
-
-		return data_dict
 
 def execute(filters=None):
 	args = {
@@ -241,3 +16,119 @@
 	}
 
 	return AccountsReceivableSummary(filters).run(args)
+
+class AccountsReceivableSummary(ReceivablePayableReport):
+	def run(self, args):
+		self.party_type = args.get('party_type')
+		self.party_naming_by = frappe.db.get_value(args.get("naming_by")[0], None, args.get("naming_by")[1])
+		self.get_columns()
+		self.get_data(args)
+		return self.columns, self.data
+
+	def get_data(self, args):
+		self.data = []
+
+		self.receivables = ReceivablePayableReport(self.filters).run(args)[1]
+
+		self.get_party_total(args)
+
+		party_advance_amount = get_partywise_advanced_payment_amount(self.party_type,
+			self.filters.report_date) or {}
+
+		for party, party_dict in iteritems(self.party_total):
+			row = frappe._dict()
+
+			row.party = party
+			if self.party_naming_by == "Naming Series":
+				row.party_name = frappe.get_cached_value(self.party_type, party, [self.party_type + "_name"])
+
+			row.update(party_dict)
+
+			# Advance against party
+			row.advance = party_advance_amount.get(party, 0)
+
+			# In AR/AP, advance shown in paid columns,
+			# but in summary report advance shown in separate column
+			row.paid -= row.advance
+
+			self.data.append(row)
+
+	def get_party_total(self, args):
+		self.party_total = frappe._dict()
+
+		for d in self.receivables:
+			self.init_party_total(d)
+
+			# Add all amount columns
+			for k in list(self.party_total[d.party]):
+				if k not in ["currency", "sales_person"]:
+
+					self.party_total[d.party][k] += d.get(k, 0.0)
+
+			# set territory, customer_group, sales person etc
+			self.set_party_details(d)
+
+	def init_party_total(self, row):
+		self.party_total.setdefault(row.party, frappe._dict({
+			"invoiced": 0.0,
+			"paid": 0.0,
+			"credit_note": 0.0,
+			"outstanding": 0.0,
+			"range1": 0.0,
+			"range2": 0.0,
+			"range3": 0.0,
+			"range4": 0.0,
+			"range5": 0.0,
+			"sales_person": []
+		}))
+
+	def set_party_details(self, row):
+		self.party_total[row.party].currency = row.currency
+
+		for key in ('territory', 'customer_group', 'supplier_group'):
+			if row.get(key):
+				self.party_total[row.party][key] = row.get(key)
+
+		if row.sales_person:
+			self.party_total[row.party].sales_person.append(row.sales_person)
+
+	def get_columns(self):
+		self.columns = []
+		self.add_column(label=_(self.party_type), fieldname='party',
+			fieldtype='Link', options=self.party_type, width=180)
+
+		if self.party_naming_by == "Naming Series":
+			self.add_column(_('{0} Name').format(self.party_type),
+				fieldname = 'party_name', fieldtype='Data')
+
+		credit_debit_label = "Credit Note" if self.party_type == 'Customer' else "Debit Note"
+
+		self.add_column(_('Advance Amount'), fieldname='advance')
+		self.add_column(_('Invoiced Amount'), fieldname='invoiced')
+		self.add_column(_('Paid Amount'), fieldname='paid')
+		self.add_column(_(credit_debit_label), fieldname='credit_note')
+		self.add_column(_('Outstanding Amount'), fieldname='outstanding')
+
+		self.setup_ageing_columns()
+
+		if self.party_type == "Customer":
+			self.add_column(label=_('Territory'), fieldname='territory', fieldtype='Link',
+				options='Territory')
+			self.add_column(label=_('Customer Group'), fieldname='customer_group', fieldtype='Link',
+				options='Customer Group')
+			if self.filters.show_sales_person:
+				self.add_column(label=_('Sales Person'), fieldname='sales_person', fieldtype='Data')
+		else:
+			self.add_column(label=_('Supplier Group'), fieldname='supplier_group', fieldtype='Link',
+				options='Supplier Group')
+
+		self.add_column(label=_('Currency'), fieldname='currency', fieldtype='Link',
+			options='Currency', width=80)
+
+	def setup_ageing_columns(self):
+		for i, label in enumerate(["0-{range1}".format(range1=self.filters["range1"]),
+			"{range1}-{range2}".format(range1=cint(self.filters["range1"])+ 1, range2=self.filters["range2"]),
+			"{range2}-{range3}".format(range2=cint(self.filters["range2"])+ 1, range3=self.filters["range3"]),
+			"{range3}-{range4}".format(range3=cint(self.filters["range3"])+ 1, range4=self.filters["range4"]),
+			"{range4}-{above}".format(range4=cint(self.filters["range4"])+ 1, above=_("Above"))]):
+				self.add_column(label=label, fieldname='range' + str(i+1))
\ No newline at end of file
diff --git a/erpnext/change_log/v12/v12_1_0.md b/erpnext/change_log/v12/v12_1_0.md
new file mode 100644
index 0000000..aed09c7
--- /dev/null
+++ b/erpnext/change_log/v12/v12_1_0.md
@@ -0,0 +1,6 @@
+# Version 12.1.0 Release Notes
+
+### Stock
+
+1. [Pick List](https://erpnext.com/docs/user/manual/en/stock/pick-list)
+2. [Refactored Accounts Receivable Reports](https://erpnext.com/docs/user/manual/en/accounts/accounting-reports#2-accounting-statements)
diff --git a/erpnext/communication/doctype/call_log/call_log.py b/erpnext/communication/doctype/call_log/call_log.py
index 35c31a0..5343bef 100644
--- a/erpnext/communication/doctype/call_log/call_log.py
+++ b/erpnext/communication/doctype/call_log/call_log.py
@@ -28,7 +28,7 @@
 			self.trigger_call_popup()
 
 	def trigger_call_popup(self):
-		scheduled_employees = get_scheduled_employees_for_popup(self.to)
+		scheduled_employees = get_scheduled_employees_for_popup(self.medium)
 		employee_emails = get_employees_with_number(self.to)
 
 		# check if employees with matched number are scheduled to receive popup
diff --git a/erpnext/hr/doctype/additional_salary/additional_salary.py b/erpnext/hr/doctype/additional_salary/additional_salary.py
index 82f2a22..8498b3d 100644
--- a/erpnext/hr/doctype/additional_salary/additional_salary.py
+++ b/erpnext/hr/doctype/additional_salary/additional_salary.py
@@ -11,7 +11,7 @@
 class AdditionalSalary(Document):
 	def before_insert(self):
 		if frappe.db.exists("Additional Salary", {"employee": self.employee, "salary_component": self.salary_component,
-			"amount": self.amount, "payroll_date": self.payroll_date, "company": self.company}):
+			"amount": self.amount, "payroll_date": self.payroll_date, "company": self.company, "docstatus": 1}):
 
 			frappe.throw(_("Additional Salary Component Exists."))
 
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.js b/erpnext/hr/doctype/employee_incentive/employee_incentive.js
index d2ddfb6..db0f83a 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.js
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.js
@@ -2,7 +2,21 @@
 // For license information, please see license.txt
 
 frappe.ui.form.on('Employee Incentive', {
-	refresh: function(frm) {
+	setup: function(frm) {
+		frm.set_query("employee", function() {
+			return {
+				filters: {
+					"status": "Active"
+				}
+			};
+		});
 
+		frm.set_query("salary_component", function() {
+			return {
+				filters: {
+					"type": "Earning"
+				}
+			};
+		});
 	}
 });
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.json b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
index 5ba1d63..3bc772c 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.json
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.json
@@ -1,330 +1,130 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 0, 
- "allow_rename": 0, 
- "autoname": "HR-EINV-.YY.-.MM.-.#####", 
- "beta": 0, 
- "creation": "2018-04-13 16:13:43.404546", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "autoname": "HR-EINV-.YY.-.MM.-.#####",
+ "creation": "2018-04-13 16:13:43.404546",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "employee",
+  "incentive_amount",
+  "payroll_date",
+  "salary_component",
+  "amended_from",
+  "column_break_5",
+  "employee_name",
+  "department",
+  "additional_salary"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "employee", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Employee", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Employee", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "incentive_amount", 
-   "fieldtype": "Currency", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Incentive Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "incentive_amount",
+   "fieldtype": "Currency",
+   "label": "Incentive Amount",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "payroll_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Payroll Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "payroll_date",
+   "fieldtype": "Date",
+   "label": "Payroll Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amended_from", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Employee Incentive", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Employee Incentive",
+   "print_hide": 1,
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_5", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_5",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.employee_name", 
-   "fieldname": "employee_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Employee Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.department", 
-   "fieldname": "department", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Department", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Department", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
+  {
+   "fieldname": "additional_salary",
+   "fieldtype": "Link",
+   "label": "Additional Salary",
+   "no_copy": 1,
+   "options": "Additional Salary",
+   "read_only": 1
+  },
+  {
+   "fieldname": "salary_component",
+   "fieldtype": "Link",
+   "label": "Salary Component",
+   "options": "Salary Component",
+   "reqd": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-08-21 16:15:51.811149", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Employee Incentive", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "is_submittable": 1,
+ "modified": "2019-09-03 16:48:16.822252",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Employee Incentive",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 1, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "amend": 1,
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Employee", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
-   "write": 0
-  }, 
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 1, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
+   "create": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
    "write": 1
   }
- ], 
- "quick_entry": 0, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "title_field": "employee_name", 
- "track_changes": 1, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "title_field": "employee_name",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/employee_incentive/employee_incentive.py b/erpnext/hr/doctype/employee_incentive/employee_incentive.py
index 6c9a315..2e138f8 100644
--- a/erpnext/hr/doctype/employee_incentive/employee_incentive.py
+++ b/erpnext/hr/doctype/employee_incentive/employee_incentive.py
@@ -7,4 +7,39 @@
 from frappe.model.document import Document
 
 class EmployeeIncentive(Document):
-	pass
+	def on_submit(self):
+		company = frappe.db.get_value('Employee', self.employee, 'company')
+		additional_salary = frappe.db.exists('Additional Salary', {
+				'employee': self.employee, 
+				'salary_component': self.salary_component,
+				'payroll_date': self.payroll_date, 
+				'company': company,
+				'docstatus': 1
+			})
+
+		if not additional_salary:
+			additional_salary = frappe.new_doc('Additional Salary')
+			additional_salary.employee = self.employee
+			additional_salary.salary_component = self.salary_component
+			additional_salary.amount = self.incentive_amount
+			additional_salary.payroll_date = self.payroll_date
+			additional_salary.company = company
+			additional_salary.submit()
+			self.db_set('additional_salary', additional_salary.name)
+
+		else:
+			incentive_added = frappe.db.get_value('Additional Salary', additional_salary, 'amount') + self.incentive_amount
+			frappe.db.set_value('Additional Salary', additional_salary, 'amount', incentive_added)
+			self.db_set('additional_salary', additional_salary)
+
+	def on_cancel(self):
+		if self.additional_salary:
+			incentive_removed = frappe.db.get_value('Additional Salary', self.additional_salary, 'amount') - self.incentive_amount
+			if incentive_removed == 0:
+				frappe.get_doc('Additional Salary', self.additional_salary).cancel()
+			else:
+				frappe.db.set_value('Additional Salary', self.additional_salary, 'amount', incentive_removed)
+
+			self.db_set('additional_salary', '')
+
+		
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.js b/erpnext/hr/doctype/retention_bonus/retention_bonus.js
index 58f6b53..64e726d 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.js
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.js
@@ -10,8 +10,13 @@
 				}
 			};
 		});
-	},
-	refresh: function(frm) {
 
+		frm.set_query("salary_component", function() {
+			return {
+				filters: {
+					"type": "Earning"
+				}
+			};
+		});
 	}
 });
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.json b/erpnext/hr/doctype/retention_bonus/retention_bonus.json
index 5a92f07..7781053 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.json
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.json
@@ -1,415 +1,165 @@
 {
- "allow_copy": 0, 
- "allow_guest_to_view": 0, 
- "allow_import": 1, 
- "allow_rename": 1, 
- "autoname": "HR-RTB-.YYYY.-.#####", 
- "beta": 0, 
- "creation": "2018-05-13 14:59:42.038964", 
- "custom": 0, 
- "docstatus": 0, 
- "doctype": "DocType", 
- "document_type": "", 
- "editable_grid": 1, 
- "engine": "InnoDB", 
+ "allow_import": 1,
+ "allow_rename": 1,
+ "autoname": "HR-RTB-.YYYY.-.#####",
+ "creation": "2018-05-13 14:59:42.038964",
+ "doctype": "DocType",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "field_order": [
+  "company",
+  "employee",
+  "bonus_payment_date",
+  "bonus_amount",
+  "salary_component",
+  "amended_from",
+  "column_break_6",
+  "employee_name",
+  "department",
+  "date_of_joining",
+  "additional_salary"
+ ],
  "fields": [
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "company", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Company", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Company", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "company",
+   "fieldtype": "Link",
+   "label": "Company",
+   "options": "Company",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "employee", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Employee", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Employee", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "employee",
+   "fieldtype": "Link",
+   "in_list_view": 1,
+   "label": "Employee",
+   "options": "Employee",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bonus_payment_date", 
-   "fieldtype": "Date", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 1, 
-   "in_standard_filter": 0, 
-   "label": "Bonus Payment Date", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 1, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "bonus_payment_date",
+   "fieldtype": "Date",
+   "in_list_view": 1,
+   "label": "Bonus Payment Date",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "bonus_amount", 
-   "fieldtype": "Currency", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Bonus Amount", 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "bonus_amount",
+   "fieldtype": "Currency",
+   "label": "Bonus Amount",
+   "reqd": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "amended_from", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Amended From", 
-   "length": 0, 
-   "no_copy": 1, 
-   "options": "Retention Bonus", 
-   "permlevel": 0, 
-   "print_hide": 1, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "amended_from",
+   "fieldtype": "Link",
+   "label": "Amended From",
+   "no_copy": 1,
+   "options": "Retention Bonus",
+   "print_hide": 1,
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fieldname": "column_break_6", 
-   "fieldtype": "Column Break", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "length": 0, 
-   "no_copy": 0, 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 0, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fieldname": "column_break_6",
+   "fieldtype": "Column Break"
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.employee_name", 
-   "fieldname": "employee_name", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Employee Name", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.employee_name",
+   "fieldname": "employee_name",
+   "fieldtype": "Data",
+   "label": "Employee Name",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.department", 
-   "fieldname": "department", 
-   "fieldtype": "Link", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Department", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "Department", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
-  }, 
+   "fetch_from": "employee.department",
+   "fieldname": "department",
+   "fieldtype": "Link",
+   "label": "Department",
+   "options": "Department",
+   "read_only": 1
+  },
   {
-   "allow_bulk_edit": 0, 
-   "allow_in_quick_entry": 0, 
-   "allow_on_submit": 0, 
-   "bold": 0, 
-   "collapsible": 0, 
-   "columns": 0, 
-   "fetch_from": "employee.date_of_joining", 
-   "fieldname": "date_of_joining", 
-   "fieldtype": "Data", 
-   "hidden": 0, 
-   "ignore_user_permissions": 0, 
-   "ignore_xss_filter": 0, 
-   "in_filter": 0, 
-   "in_global_search": 0, 
-   "in_list_view": 0, 
-   "in_standard_filter": 0, 
-   "label": "Date of Joining", 
-   "length": 0, 
-   "no_copy": 0, 
-   "options": "", 
-   "permlevel": 0, 
-   "precision": "", 
-   "print_hide": 0, 
-   "print_hide_if_no_value": 0, 
-   "read_only": 1, 
-   "remember_last_selected_value": 0, 
-   "report_hide": 0, 
-   "reqd": 0, 
-   "search_index": 0, 
-   "set_only_once": 0, 
-   "translatable": 0, 
-   "unique": 0
+   "fetch_from": "employee.date_of_joining",
+   "fieldname": "date_of_joining",
+   "fieldtype": "Data",
+   "label": "Date of Joining",
+   "read_only": 1
+  },
+  {
+   "fieldname": "additional_salary",
+   "fieldtype": "Link",
+   "label": "Additional Salary",
+   "no_copy": 1,
+   "options": "Additional Salary",
+   "read_only": 1
+  },
+  {
+   "fieldname": "salary_component",
+   "fieldtype": "Link",
+   "label": "Salary Component",
+   "options": "Salary Component",
+   "reqd": 1
   }
- ], 
- "has_web_view": 0, 
- "hide_heading": 0, 
- "hide_toolbar": 0, 
- "idx": 0, 
- "image_view": 0, 
- "in_create": 0, 
- "is_submittable": 1, 
- "issingle": 0, 
- "istable": 0, 
- "max_attachments": 0, 
- "modified": "2018-08-21 16:15:38.710684", 
- "modified_by": "Administrator", 
- "module": "HR", 
- "name": "Retention Bonus", 
- "name_case": "", 
- "owner": "Administrator", 
+ ],
+ "is_submittable": 1,
+ "modified": "2019-09-03 16:47:24.210422",
+ "modified_by": "Administrator",
+ "module": "HR",
+ "name": "Retention Bonus",
+ "owner": "Administrator",
  "permissions": [
   {
-   "amend": 0, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "System Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "System Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR Manager", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR Manager",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 1, 
-   "create": 1, 
-   "delete": 1, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "HR User", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 1, 
+   "cancel": 1,
+   "create": 1,
+   "delete": 1,
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "HR User",
+   "share": 1,
+   "submit": 1,
    "write": 1
-  }, 
+  },
   {
-   "amend": 0, 
-   "cancel": 0, 
-   "create": 0, 
-   "delete": 0, 
-   "email": 1, 
-   "export": 1, 
-   "if_owner": 0, 
-   "import": 0, 
-   "permlevel": 0, 
-   "print": 1, 
-   "read": 1, 
-   "report": 1, 
-   "role": "Employee", 
-   "set_user_permissions": 0, 
-   "share": 1, 
-   "submit": 0, 
-   "write": 0
+   "email": 1,
+   "export": 1,
+   "print": 1,
+   "read": 1,
+   "report": 1,
+   "role": "Employee",
+   "share": 1
   }
- ], 
- "quick_entry": 1, 
- "read_only": 0, 
- "read_only_onload": 0, 
- "show_name_in_global_search": 0, 
- "sort_field": "modified", 
- "sort_order": "DESC", 
- "track_changes": 1, 
- "track_seen": 0, 
- "track_views": 0
+ ],
+ "quick_entry": 1,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1
 }
\ No newline at end of file
diff --git a/erpnext/hr/doctype/retention_bonus/retention_bonus.py b/erpnext/hr/doctype/retention_bonus/retention_bonus.py
index 20d4c13..48637a3 100644
--- a/erpnext/hr/doctype/retention_bonus/retention_bonus.py
+++ b/erpnext/hr/doctype/retention_bonus/retention_bonus.py
@@ -10,7 +10,42 @@
 
 class RetentionBonus(Document):
 	def validate(self):
-		if frappe.get_value("Employee", self.employee, "status") == "Left":
-			frappe.throw(_("Cannot create Retention Bonus for left Employees"))
+		if frappe.get_value('Employee', self.employee, 'status') == 'Left':
+			frappe.throw(_('Cannot create Retention Bonus for left Employees'))
 		if getdate(self.bonus_payment_date) < getdate():
-			frappe.throw(_("Bonus Payment Date cannot be a past date"))
+			frappe.throw(_('Bonus Payment Date cannot be a past date'))
+
+	def on_submit(self):
+		company = frappe.db.get_value('Employee', self.employee, 'company')
+		additional_salary = frappe.db.exists('Additional Salary', {
+				'employee': self.employee, 
+				'salary_component': self.salary_component,
+				'payroll_date': self.bonus_payment_date, 
+				'company': company,
+				'docstatus': 1
+			})
+
+		if not additional_salary:
+			additional_salary = frappe.new_doc('Additional Salary')
+			additional_salary.employee = self.employee
+			additional_salary.salary_component = self.salary_component
+			additional_salary.amount = self.bonus_amount
+			additional_salary.payroll_date = self.bonus_payment_date
+			additional_salary.company = company
+			additional_salary.submit()
+			self.db_set('additional_salary', additional_salary.name)
+
+		else:
+			bonus_added = frappe.db.get_value('Additional Salary', additional_salary, 'amount') + self.bonus_amount
+			frappe.db.set_value('Additional Salary', additional_salary, 'amount', bonus_added)
+			self.db_set('additional_salary', additional_salary)
+
+	def on_cancel(self):
+		if self.additional_salary:
+			bonus_removed = frappe.db.get_value('Additional Salary', self.additional_salary, 'amount') - self.bonus_amount
+			if bonus_removed == 0:
+				frappe.get_doc('Additional Salary', self.additional_salary).cancel()
+			else:
+				frappe.db.set_value('Additional Salary', self.additional_salary, 'amount', bonus_removed)
+			
+			self.db_set('additional_salary', '')
\ No newline at end of file
diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.py b/erpnext/manufacturing/doctype/production_plan/production_plan.py
index 650ab13..048ce0d 100644
--- a/erpnext/manufacturing/doctype/production_plan/production_plan.py
+++ b/erpnext/manufacturing/doctype/production_plan/production_plan.py
@@ -99,7 +99,7 @@
 			self.get_mr_items()
 
 	def get_so_items(self):
-		so_list = [d.sales_order for d in self.sales_orders if d.sales_order]
+		so_list = [d.sales_order for d in self.get("sales_orders", []) if d.sales_order]
 		if not so_list:
 			msgprint(_("Please enter Sales Orders in the above table"))
 			return []
@@ -134,7 +134,7 @@
 		self.calculate_total_planned_qty()
 
 	def get_mr_items(self):
-		mr_list = [d.material_request for d in self.material_requests if d.material_request]
+		mr_list = [d.material_request for d in self.get("material_requests", []) if d.material_request]
 		if not mr_list:
 			msgprint(_("Please enter Material Requests in the above table"))
 			return []
diff --git a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
index 02203d2..9f4c445 100644
--- a/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
+++ b/erpnext/patches/v12_0/move_item_tax_to_item_tax_template.py
@@ -82,7 +82,7 @@
 			account_name = " - ".join(parts[:-1])
 			company = frappe.db.get_value("Company", filters={"abbr": parts[-1]})
 			parent_account = frappe.db.get_value("Account",
-				filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0}, fieldname="parent_account")
+				filters={"account_type": "Tax", "root_type": "Liability", "is_group": 0, "company": company}, fieldname="parent_account")
 
 			frappe.get_doc({
 				"doctype": "Account",
diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py
index 4dd02da..972a610 100644
--- a/erpnext/selling/doctype/customer/customer.py
+++ b/erpnext/selling/doctype/customer/customer.py
@@ -377,7 +377,7 @@
 	return frappe.db.sql("""
 		select `tabContact`.name from `tabContact`, `tabDynamic Link`
 			where `tabContact`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
-			and `tabDynamic Link`.link_doctype = 'Customer' and `tabContact`.is_primary_contact = 1
+			and `tabDynamic Link`.link_doctype = 'Customer'
 			and `tabContact`.name like %(txt)s
 		""", {
 			'customer': customer,
@@ -389,7 +389,7 @@
 	return frappe.db.sql("""
 		select `tabAddress`.name from `tabAddress`, `tabDynamic Link`
 			where `tabAddress`.name = `tabDynamic Link`.parent and `tabDynamic Link`.link_name = %(customer)s
-			and `tabDynamic Link`.link_doctype = 'Customer' and `tabAddress`.is_primary_address = 1
+			and `tabDynamic Link`.link_doctype = 'Customer'
 			and `tabAddress`.name like %(txt)s
 		""", {
 			'customer': customer,
diff --git a/erpnext/shopping_cart/cart.py b/erpnext/shopping_cart/cart.py
index 0922f3d..db2c327 100644
--- a/erpnext/shopping_cart/cart.py
+++ b/erpnext/shopping_cart/cart.py
@@ -336,19 +336,20 @@
 
 def _set_price_list(quotation, cart_settings):
 	"""Set price list based on customer or shopping cart default"""
-	if quotation.selling_price_list:
-		return
+	from erpnext.accounts.party import get_default_price_list
 
 	# check if customer price list exists
 	selling_price_list = None
 	if quotation.party_name:
-		from erpnext.accounts.party import get_default_price_list
-		selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.party_name))
+		selling_price_list = frappe.db.get_value('Customer', quotation.party_name, 'default_price_list')
 
 	# else check for territory based price list
 	if not selling_price_list:
 		selling_price_list = cart_settings.price_list
 
+	if not selling_price_list and quotation.party_name:
+		selling_price_list = get_default_price_list(frappe.get_doc("Customer", quotation.party_name))
+
 	quotation.selling_price_list = selling_price_list
 
 def set_taxes(quotation, cart_settings):
diff --git a/erpnext/stock/stock_ledger.py b/erpnext/stock/stock_ledger.py
index f7deac3..69a4b94 100644
--- a/erpnext/stock/stock_ledger.py
+++ b/erpnext/stock/stock_ledger.py
@@ -181,10 +181,7 @@
 		# rounding as per precision
 		self.stock_value = flt(self.stock_value, self.precision)
 
-		if self.prev_stock_value < 0 and self.stock_value >= 0 and sle.voucher_type != 'Stock Reconciliation':
-			stock_value_difference = sle.actual_qty * self.valuation_rate
-		else:
-			stock_value_difference = self.stock_value - self.prev_stock_value
+		stock_value_difference = self.stock_value - self.prev_stock_value
 
 		self.prev_stock_value = self.stock_value