[fix] party status updating bug, fixes #5794, #5796
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index b90cd23..9418372 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -92,8 +92,8 @@
 					"Cost Center", self.cost_center, "company")
 
 			return self.cost_center_company[self.cost_center]
-		
-		if self.cost_center and _get_cost_center_company() != self.company:	
+
+		if self.cost_center and _get_cost_center_company() != self.company:
 			frappe.throw(_("Cost Center {0} does not belong to Company {1}").format(self.cost_center, self.company))
 
 	def validate_party(self):
@@ -181,8 +181,8 @@
 
 	# Update outstanding amt on against voucher
 	if against_voucher_type in ["Sales Invoice", "Purchase Invoice"]:
-		frappe.db.sql("update `tab%s` set outstanding_amount=%s where name=%s" %
-			(against_voucher_type, '%s', '%s'),	(bal, against_voucher))
+		ref_doc = frappe.get_doc(against_voucher_type, against_voucher)
+		ref_doc.db_set('outstanding_amount', bal)
 
 def validate_frozen_account(account, adv_adj=None):
 	frozen_account = frappe.db.get_value("Account", account, "freeze_account")
diff --git a/erpnext/accounts/doctype/payment_request/payment_request.py b/erpnext/accounts/doctype/payment_request/payment_request.py
index a774e54..0c8df02 100644
--- a/erpnext/accounts/doctype/payment_request/payment_request.py
+++ b/erpnext/accounts/doctype/payment_request/payment_request.py
@@ -9,55 +9,54 @@
 from frappe.utils import flt, get_url, nowdate
 from erpnext.accounts.party import get_party_account
 from erpnext.accounts.utils import get_account_currency
-from erpnext.setup.utils import get_exchange_rate
 from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry, get_company_defaults
 
-class PaymentRequest(Document):		
+class PaymentRequest(Document):
 	def validate(self):
 		self.validate_payment_gateway_account()
 		self.validate_payment_request()
 		self.validate_currency()
 
 	def validate_payment_request(self):
-		if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name, 
+		if frappe.db.get_value("Payment Request", {"reference_name": self.reference_name,
 			"name": ("!=", self.name), "status": ("not in", ["Initiated", "Paid"]), "docstatus": 1}, "name"):
 			frappe.throw(_("Payment Request already exists {0}".format(self.reference_name)))
-	
+
 	def validate_currency(self):
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
 		if ref_doc.currency != frappe.db.get_value("Account", self.payment_account, "account_currency"):
 			frappe.throw(_("Transaction currency must be same as Payment Gateway currency"))
-			
+
 	def validate_payment_gateway_account(self):
 		if not self.payment_gateway:
 			frappe.throw(_("Payment Gateway Account is not configured"))
-			
+
 	def validate_payment_gateway(self):
 		if self.payment_gateway == "PayPal":
 			if not frappe.db.get_value("PayPal Settings", None, "api_username"):
 				if not frappe.conf.paypal_username:
 					frappe.throw(_("PayPal Settings missing"))
-			
+
 	def on_submit(self):
 		send_mail = True
 		self.make_communication_entry()
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
-		
+
 		if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
 			send_mail = False
-			
+
 		if send_mail:
 			self.send_payment_request()
 			self.send_email()
-	
+
 	def on_cancel(self):
 		self.set_as_cancelled()
-	
+
 	def get_payment_url(self):
 		""" This is blanck method to trigger hooks call from individual payment gateway app
 		which will return respective payment gateway"""
 		pass
-	
+
 	def make_invoice(self):
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
 		if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
@@ -65,26 +64,26 @@
 			si = make_sales_invoice(self.reference_name, ignore_permissions=True)
 			si = si.insert(ignore_permissions=True)
 			si.submit()
-	
+
 	def send_payment_request(self):
 		self.payment_url = get_url("/api/method/erpnext.accounts.doctype.payment_request.payment_request.generate_payment_request?name={0}".format(self.name))
 		if self.payment_url:
-			frappe.db.set_value(self.doctype, self.name, "payment_url", self.payment_url)
-			frappe.db.set_value(self.doctype, self.name, "status", "Initiated")
-			
+			self.db_set('payment_url', self.payment_url)
+			self.db_set('status', 'Initiated')
+
 	def set_as_paid(self):
 		if frappe.session.user == "Guest":
 			frappe.set_user("Administrator")
-			
+
 		payment_entry = self.create_payment_entry()
 		self.make_invoice()
-		
+
 		return payment_entry
-		
+
 	def create_payment_entry(self):
 		"""create entry"""
 		frappe.flags.ignore_account_permission = True
-		
+
 		ref_doc = frappe.get_doc(self.reference_doctype, self.reference_name)
 
 		if self.reference_doctype == "Sales Invoice":
@@ -93,22 +92,22 @@
 			party_account = ref_doc.credit_to
 		else:
 			party_account = get_party_account("Customer", ref_doc.get("customer"), ref_doc.company)
-			
+
 		party_account_currency = ref_doc.get("party_account_currency") or get_account_currency(party_account)
-		
+
 		bank_amount = self.grand_total
 		if party_account_currency == ref_doc.company_currency and party_account_currency != self.currency:
 			party_amount = ref_doc.base_grand_total
 		else:
 			party_amount = self.grand_total
-					
-		payment_entry = get_payment_entry(self.reference_doctype, self.reference_name, 
+
+		payment_entry = get_payment_entry(self.reference_doctype, self.reference_name,
 			party_amount=party_amount, bank_account=self.payment_account, bank_amount=bank_amount)
-		
+
 		payment_entry.update({
 			"reference_no": self.name,
 			"reference_date": nowdate(),
-			"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(self.reference_doctype, 
+			"remarks": "Payment Entry against {0} {1} via Payment Request {2}".format(self.reference_doctype,
 				self.reference_name, self.name)
 		})
 
@@ -123,32 +122,32 @@
 		payment_entry.submit()
 
 		#set status as paid for Payment Request
-		frappe.db.set_value(self.doctype, self.name, "status", "Paid")
-		
+		self.db_set('status', 'Paid')
+
 		return payment_entry
-		
+
 	def send_email(self):
 		"""send email with payment link"""
 		frappe.sendmail(recipients=self.email_to, sender=None, subject=self.subject,
-			message=self.get_message(), attachments=[frappe.attach_print(self.reference_doctype, 
+			message=self.get_message(), attachments=[frappe.attach_print(self.reference_doctype,
 			self.reference_name, file_name=self.reference_name, print_format=self.print_format)])
-						
+
 	def get_message(self):
 		"""return message with payment gateway link"""
-		
+
 		context = {
 			"doc": frappe.get_doc(self.reference_doctype, self.reference_name),
 			"payment_url": self.payment_url
 		}
-		
+
 		return frappe.render_template(self.message, context)
-		
+
 	def set_failed(self):
 		pass
-	
+
 	def set_as_cancelled(self):
-		frappe.db.set_value(self.doctype, self.name, "status", "Cancelled")
-	
+		self.db_set("status", "Cancelled")
+
 	def make_communication_entry(self):
 		"""Make communication entry"""
 		comm = frappe.get_doc({
@@ -160,28 +159,28 @@
 			"reference_name": self.reference_name
 		})
 		comm.insert(ignore_permissions=True)
-	
+
 	def get_payment_success_url(self):
 		return self.payment_success_url
 
 @frappe.whitelist(allow_guest=True)
 def make_payment_request(**args):
 	"""Make payment request"""
-	
+
 	args = frappe._dict(args)
-	
+
 	ref_doc = frappe.get_doc(args.dt, args.dn)
-	
+
 	gateway_account = get_gateway_details(args)
-	
+
 	grand_total = get_amount(ref_doc, args.dt)
-	
-	existing_payment_request = frappe.db.get_value("Payment Request", 
+
+	existing_payment_request = frappe.db.get_value("Payment Request",
 		{"reference_doctype": args.dt, "reference_name": args.dn, "docstatus": ["!=", 2]})
-	
+
 	if existing_payment_request:
 		pr = frappe.get_doc("Payment Request", existing_payment_request)
-		
+
 	else:
 		pr = frappe.new_doc("Payment Request")
 		pr.update({
@@ -196,67 +195,67 @@
 			"reference_doctype": args.dt,
 			"reference_name": args.dn
 		})
-	
+
 		if args.return_doc:
 			return pr
 		if args.submit_doc:
 			pr.insert(ignore_permissions=True)
 			pr.submit()
-			
+
 	if hasattr(ref_doc, "order_type") and getattr(ref_doc, "order_type") == "Shopping Cart":
 		generate_payment_request(pr.name)
 		frappe.db.commit()
-		
+
 	if not args.cart:
 		return pr
-			
+
 	return pr.as_dict()
 
 def get_amount(ref_doc, dt):
 	"""get amount based on doctype"""
 	if dt == "Sales Order":
 		grand_total = flt(ref_doc.grand_total) - flt(ref_doc.advance_paid)
-		
+
 	if dt == "Sales Invoice":
 		if ref_doc.party_account_currency == ref_doc.currency:
 			grand_total = flt(ref_doc.outstanding_amount)
 		else:
 			grand_total = flt(ref_doc.outstanding_amount) / ref_doc.conversion_rate
-		
+
 	if grand_total > 0 :
 		return grand_total
-		
+
 	else:
 		frappe.throw(_("Payment Entry is already created"))
-		
+
 def get_gateway_details(args):
 	"""return gateway and payment account of default payment gateway"""
 	if args.get("payment_gateway"):
 		return get_payment_gateway_account(args.get("payment_gateway"))
-		
+
 	if args.cart:
 		payment_gateway_account = frappe.get_doc("Shopping Cart Settings").payment_gateway_account
 		return get_payment_gateway_account(payment_gateway_account)
-	
+
 	gateway_account = get_payment_gateway_account({"is_default": 1})
-	
+
 	if not gateway_account:
 		frappe.throw(_("Payment Gateway Account is not configured"))
-	
+
 	return gateway_account
-	
+
 def get_payment_gateway_account(args):
-	return frappe.db.get_value("Payment Gateway Account", args, 
-		["name", "payment_gateway", "payment_account", "message"], 
+	return frappe.db.get_value("Payment Gateway Account", args,
+		["name", "payment_gateway", "payment_account", "message"],
 			as_dict=1)
 
 @frappe.whitelist()
 def get_print_format_list(ref_doctype):
 	print_format_list = ["Standard"]
-	
-	print_format_list.extend([p.name for p in frappe.get_all("Print Format", 
+
+	print_format_list.extend([p.name for p in frappe.get_all("Print Format",
 		filters={"doc_type": ref_doctype})])
-	
+
 	return {
 		"print_format": print_format_list
 	}
@@ -264,8 +263,7 @@
 @frappe.whitelist(allow_guest=True)
 def generate_payment_request(name):
 	frappe.get_doc("Payment Request", name).run_method("get_payment_url")
-	
+
 @frappe.whitelist(allow_guest=True)
 def resend_payment_email(docname):
 	return frappe.get_doc("Payment Request", docname).send_email()
-		
\ No newline at end of file
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index ec63b1f..e7eee5f 100644
--- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
+++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
@@ -450,14 +450,14 @@
 		si = frappe.copy_doc(pos)
 		si.insert()
 		si.submit()
-		
+
 		self.assertEquals(si.paid_amount, 600.0)
 
 		self.pos_gl_entry(si, pos, 300)
-		
+
 	def test_make_pos_invoice(self):
 		from erpnext.accounts.doctype.sales_invoice.pos import make_invoice
-		
+
 		set_perpetual_inventory()
 
 		self.make_pos_profile()
@@ -468,17 +468,17 @@
 		pos["update_stock"] = 1
 		pos["payments"] = [{'mode_of_payment': 'Bank Draft', 'account': '_Test Bank - _TC', 'amount': 300},
 							{'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 330}]
-		
-		invoice_data = [{'09052016142': pos}]					
+
+		invoice_data = [{'09052016142': pos}]
 		si = make_invoice(invoice_data)
 		self.assertEquals(si[0], '09052016142')
-		
+
 		sales_invoice = frappe.get_all('Sales Invoice', fields =["*"], filters = {'offline_pos_name': '09052016142', 'docstatus': 1})
 		si = frappe.get_doc('Sales Invoice', sales_invoice[0].name)
 		self.assertEquals(si.grand_total, 630.0)
-		
+
 		self.pos_gl_entry(si, pos, 330)
-		
+
 	def pos_gl_entry(self, si, pos, cash_amount):
 		# check stock ledger entries
 		sle = frappe.db.sql("""select * from `tabStock Ledger Entry`
@@ -495,7 +495,7 @@
 		self.assertTrue(gl_entries)
 
 		stock_in_hand = frappe.db.get_value("Account", {"warehouse": "_Test Warehouse - _TC"})
-		
+
 		expected_gl_entries = sorted([
 			[si.debit_to, 630.0, 0.0],
 			[pos["items"][0]["income_account"], 0.0, 500.0],
@@ -952,6 +952,40 @@
 
 		self.assertNotEquals(si.get("items")[0].rate, flt((price_list_rate*25)/100 + price_list_rate))
 
+	def test_party_status(self):
+		from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+		from frappe.utils import random_string
+
+		customer_name = 'test customer for status'
+
+		if frappe.db.exists('Customer', customer_name):
+			customer = frappe.get_doc('Customer', customer_name)
+			customer.db_set('status', 'Active')
+		else:
+			customer = frappe.get_doc({
+				'doctype': 'Customer',
+				'customer_name': customer_name,
+				'customer_group': 'Commercial',
+				'customer_type': 'Individual',
+				'territory': 'Rest of the World'
+			}).insert()
+
+		self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active')
+
+		invoice = create_sales_invoice(customer="test customer for status",
+			debit_to="_Test Receivable - _TC",
+			currency="USD", conversion_rate=50)
+
+		self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Open')
+
+		pe = get_payment_entry(invoice.doctype, invoice.name)
+		pe.reference_no = random_string(10)
+		pe.reference_date = invoice.posting_date
+		pe.insert()
+		pe.submit()
+
+		self.assertEquals(frappe.db.get_value('Customer', customer.name, 'status'), 'Active')
+
 def create_sales_invoice(**args):
 	si = frappe.new_doc("Sales Invoice")
 	args = frappe._dict(args)
diff --git a/erpnext/accounts/party_status.py b/erpnext/accounts/party_status.py
index 5a638e5..68b4818 100644
--- a/erpnext/accounts/party_status.py
+++ b/erpnext/accounts/party_status.py
@@ -19,7 +19,7 @@
 	'Supplier': None
 }
 
-def notify_status(doc, method):
+def notify_status(doc, method=None):
 	'''Notify status to customer, supplier'''
 
 	party_type = None
@@ -59,6 +59,7 @@
 			update_status(party)
 
 	party.update_modified()
+	party.notify_update()
 
 def get_party_status(doc):
 	'''return party status based on open documents'''
diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py
index 6ae5bbe..2c25f5c 100644
--- a/erpnext/controllers/status_updater.py
+++ b/erpnext/controllers/status_updater.py
@@ -6,6 +6,7 @@
 from frappe.utils import flt, comma_or
 from frappe import _
 from frappe.model.document import Document
+from erpnext.accounts.party_status import notify_status
 
 def validate_status(status, options):
 	if status not in options:
@@ -106,8 +107,7 @@
 				self.add_comment("Label", _(self.status))
 
 			if update:
-				frappe.db.set_value(self.doctype, self.name, "status", self.status,
-					update_modified=update_modified)
+				self.db_set('status', self.status, update_modified = update_modified)
 
 	def validate_qty(self):
 		"""Validates qty at row level"""
@@ -263,6 +263,7 @@
 			target = frappe.get_doc(args["target_parent_dt"], args["name"])
 			target.set_status(update=True)
 			target.notify_update()
+			notify_status(target)
 
 	def _update_modified(self, args, update_modified):
 		args['update_modified'] = ''
@@ -296,14 +297,16 @@
 
 			per_billed = ((ref_doc_qty if billed_qty > ref_doc_qty else billed_qty)\
 				/ ref_doc_qty)*100
-			frappe.db.set_value(ref_dt, ref_dn, "per_billed", per_billed)
+
+			ref_doc = frappe.get_doc(ref_dt, ref_dn)
+
+			ref_doc.db_set("per_billed", per_billed)
 
 			if frappe.get_meta(ref_dt).get_field("billing_status"):
 				if per_billed < 0.001: billing_status = "Not Billed"
 				elif per_billed >= 99.99: billing_status = "Fully Billed"
 				else: billing_status = "Partly Billed"
-
-				frappe.db.set_value(ref_dt, ref_dn, "billing_status", billing_status)
+				ref_doc.db_set('billing_status', billing_status)
 
 def get_tolerance_for(item_code, item_tolerance={}, global_tolerance=None):
 	"""
diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py
index 4a2b9a9..e4a1aab 100644
--- a/erpnext/selling/doctype/sales_order/sales_order.py
+++ b/erpnext/selling/doctype/sales_order/sales_order.py
@@ -23,7 +23,7 @@
 class SalesOrder(SellingController):
 	def __init__(self, arg1, arg2=None):
 		super(SalesOrder, self).__init__(arg1, arg2)
-		
+
 		self.prev_link_mapper = {
 			"Quotation": {
 				"fieldname": "prevdoc_docname",
@@ -34,7 +34,7 @@
 				]
 			}
 		}
-		
+
 	def validate(self):
 		super(SalesOrder, self).validate()
 
@@ -298,8 +298,8 @@
 			delivered_qty += item.delivered_qty
 			tot_qty += item.qty
 
-		frappe.db.set_value("Sales Order", self.name, "per_delivered", flt(delivered_qty/tot_qty) * 100,
-		update_modified=False)
+		self.db_set("per_delivered", flt(delivered_qty/tot_qty) * 100,
+			update_modified=False)
 
 	def set_indicator(self):
 		"""Set indicator for portal"""
@@ -319,7 +319,7 @@
 		mcount = month_map[reference_doc.recurring_type]
 		self.set("delivery_date", get_next_date(reference_doc.delivery_date, mcount,
 						cint(reference_doc.repeat_on_day_of_month)))
-		
+
 def get_list_context(context=None):
 	from erpnext.controllers.website_list_for_contact import get_list_context
 	list_context = get_list_context(context)