Payment Entry: Test cases and default remarks
diff --git a/erpnext/accounts/doctype/account/test_account.py b/erpnext/accounts/doctype/account/test_account.py
index 4580d02..5744721 100644
--- a/erpnext/accounts/doctype/account/test_account.py
+++ b/erpnext/accounts/doctype/account/test_account.py
@@ -12,6 +12,7 @@
 		["_Test Bank", "Bank Accounts", 0, "Bank", None],
 		["_Test Bank USD", "Bank Accounts", 0, "Bank", "USD"],
 		["_Test Bank EUR", "Bank Accounts", 0, "Bank", "EUR"],
+		["_Test Cash", "Cash In Hand", 0, "Cash", None],
 
 		["_Test Account Stock Expenses", "Direct Expenses", 1, None, None],
 		["_Test Account Shipping Charges", "_Test Account Stock Expenses", 0, "Chargeable", None],
@@ -32,6 +33,7 @@
 		["_Test Account CST", "Direct Expenses", 0, "Tax", None],
 		["_Test Account Discount", "Direct Expenses", 0, None, None],
 		["_Test Write Off", "Indirect Expenses", 0, None, None],
+		["_Test Exchange Gain/Loss", "Indirect Expenses", 0, None, None],
 
 		# related to Account Inventory Integration
 		["_Test Account Stock In Hand", "Current Assets", 0, None, None],
diff --git a/erpnext/accounts/doctype/gl_entry/gl_entry.py b/erpnext/accounts/doctype/gl_entry/gl_entry.py
index 1f95fb8..b90cd23 100644
--- a/erpnext/accounts/doctype/gl_entry/gl_entry.py
+++ b/erpnext/accounts/doctype/gl_entry/gl_entry.py
@@ -38,7 +38,7 @@
 					self.against_voucher)
 
 	def check_mandatory(self):
-		mandatory = ['account','remarks','voucher_type','voucher_no','company']
+		mandatory = ['account','voucher_type','voucher_no','company']
 		for k in mandatory:
 			if not self.get(k):
 				frappe.throw(_("{0} is required").format(_(self.meta.get_label(k))))
diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py
index fc28c54..7738563 100644
--- a/erpnext/accounts/doctype/payment_entry/payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py
@@ -44,7 +44,7 @@
 		self.clear_unallocated_reference_document_rows()
 		self.set_title()
 		self.validate_transaction_reference()
-		
+		self.set_remarks()
 		
 	def on_submit(self):
 		self.make_gl_entries()
@@ -137,7 +137,7 @@
 			frappe.throw(_("Account Type for {0} must be {1}").format(comma_or(account_types)))
 				
 	def set_exchange_rate(self):
-		if self.paid_from:
+		if self.paid_from and not self.source_exchange_rate:
 			if self.paid_from_account_currency == self.company_currency:
 				self.source_exchange_rate = 1
 			elif self.payment_type in ("Pay", "Internal Transfer"):
@@ -146,7 +146,7 @@
 				self.source_exchange_rate = get_exchange_rate(self.paid_from_account_currency, 
 					self.company_currency)
 		
-		if self.paid_to:
+		if self.paid_to and not self.target_exchange_rate:
 			self.target_exchange_rate = get_exchange_rate(self.paid_to_account_currency, 
 				self.company_currency)
 				
@@ -204,7 +204,6 @@
 		self.total_allocated_amount, self.base_total_allocated_amount = 0, 0
 		for d in self.get("references"):
 			if d.allocated_amount:
-				print d.allocated_amount, d.outstanding_amount
 				if d.reference_doctype not in ("Sales Order", "Purchase Order") \
 					and d.allocated_amount > d.outstanding_amount:
 						frappe.throw(_("Row #{0}: Allocated amount cannot be greater than outstanding amount")
@@ -226,7 +225,7 @@
 		base_unallocated_amount = self.unallocated_amount * \
 			(self.source_exchange_rate if self.payment_type=="Receive" else self.target_exchange_rate)
 			
-		base_party_amount = self.base_total_allocated_amount + base_unallocated_amount
+		base_party_amount = flt(self.base_total_allocated_amount) + flt(base_unallocated_amount)
 		
 		if self.payment_type == "Receive":
 			self.difference_amount = base_party_amount - self.base_received_amount
@@ -259,6 +258,37 @@
 			if not self.reference_no or not self.reference_date:
 				frappe.throw(_("Reference No and Reference Date is mandatory for Bank transaction"))
 				
+	def set_remarks(self):
+		if self.remarks: return
+		
+		if self.payment_type=="Internal Transfer":
+			remarks = [_("Amount {0} {1} transferred from {2} to {3}")
+				.format(self.paid_from_account_currency, self.paid_amount, self.paid_from, self.paid_to)]
+		else:
+			
+			remarks = [_("Amount {0} {1} {2} {3}").format(
+				self.party_account_currency,
+				self.paid_amount if self.payment_type=="Receive" else self.received_amount,
+				_("received from") if self.payment_type=="Receive" else _("to"), self.party
+			)]
+			
+		if self.reference_no:
+			remarks.append(_("Transaction reference no {0} dated {1}")
+				.format(self.reference_no, self.reference_date))
+
+		if self.payment_type in ["Receive", "Pay"]:
+			for d in self.get("references"):
+				if d.allocated_amount:
+					remarks.append(_("Amount {0} {1} against {2} {3}").format(self.party_account_currency, 
+						d.allocated_amount, d.reference_doctype, d.reference_name))
+		
+		for d in self.get("deductions"):
+			if d.amount:
+				remarks.append(_("Amount {0} {1} deducted against {2}")
+					.format(self.company_currency, d.amount, d.account))
+
+		self.set("remarks", "\n".join(remarks))
+			
 	def make_gl_entries(self, cancel=0, adv_adj=0):
 		gl_entries = []
 		self.add_party_gl_entries(gl_entries)
@@ -520,7 +550,7 @@
 		received_amount = outstanding_amount
 		if bank_amount:
 			paid_amount = bank_amount
-			
+	
 	pe = frappe.new_doc("Payment Entry")
 	pe.payment_type = payment_type
 	pe.company = doc.company
diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
index 30ee18e..624f405 100644
--- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
+++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py
@@ -5,50 +5,163 @@
 
 import frappe
 import unittest
-from erpnext.accounts.doctype.sales_order.test_sales_order import make_sales_order
-from erpnext.accounts.doctype.payment_entry.payment_entry import make_payment_entry
+from frappe.utils import flt, nowdate
+from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
+from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
+from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
+from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
+
+test_dependencies = ["Item"]
 
 class TestPaymentEntry(unittest.TestCase):
 	def test_payment_entry_against_order(self):
 		so = make_sales_order()
-		pe = make_payment_entry("Sales Order", so.name)
-		pe.paid_to = "_Test Bank - _TC"
+		pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Cash - _TC")
+		pe.paid_from = "Debtors - _TC"
 		pe.insert()
 		pe.submit()
 		
-		expected_gle = {
-			"_Test Bank - _TC": {
-				"account_currency": "INR",
-				"debit": 1000,
-				"debit_in_account_currency": 1000,
-				"credit": 0,
-				"credit_in_account_currency": 0,
-				"against_voucher": None
-			},
-			"_Test Receivable - _TC": {
-				"account_currency": "INR",
-				"debit": 0,
-				"debit_in_account_currency": 0,
-				"credit": 1000,
-				"credit_in_account_currency": 1000,
-				"against_voucher": so.name
-			}
-		}
+		expected_gle = dict((d[0], d) for d in [
+			["Debtors - _TC", 0, 1000, so.name],
+			["_Test Cash - _TC", 1000.0, 0, None]
+		])
 		
 		self.validate_gl_entries(pe.name, expected_gle)
 		
-		so.load_from_db()
+		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+		self.assertEqual(so_advance_paid, 1000)
+		
+		pe.cancel()
+		
+		self.assertFalse(self.get_gle(pe.name))
+		
+		so_advance_paid = frappe.db.get_value("Sales Order", so.name, "advance_paid")
+		self.assertEqual(so_advance_paid, 0)
+		
+	def test_payment_entry_against_si_usd_to_usd(self):
+		si =  create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+			currency="USD", conversion_rate=50)
+		pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Bank USD - _TC")
+		pe.reference_no = "1"
+		pe.reference_date = "2016-01-01"
+		pe.target_exchange_rate = 50		
+		pe.insert()
+		pe.submit()
+		
+		expected_gle = dict((d[0], d) for d in [
+			["_Test Receivable USD - _TC", 0, 5000, si.name],
+			["_Test Bank USD - _TC", 5000.0, 0, None]
+		])
+		
+		self.validate_gl_entries(pe.name, expected_gle)
+		
+		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
+		self.assertEqual(outstanding_amount, 0)
+		
+		pe.cancel()
+		self.assertFalse(self.get_gle(pe.name))
+		
+		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
+		self.assertEqual(outstanding_amount, 100)
+		
+	def test_payment_entry_against_pi(self):
+		pi =  make_purchase_invoice(supplier="_Test Supplier USD", debit_to="_Test Payable USD - _TC",
+			currency="USD", conversion_rate=50)
+		pe = get_payment_entry("Purchase Invoice", pi.name, bank_account="_Test Bank USD - _TC")
+		pe.reference_no = "1"
+		pe.reference_date = "2016-01-01"
+		pe.target_exchange_rate = 50		
+		pe.insert()
+		pe.submit()
+		
+		expected_gle = dict((d[0], d) for d in [
+			["_Test Payable USD - _TC", 12500, 0, pi.name],
+			["_Test Bank USD - _TC", 0, 12500, None]
+		])
+		
+		self.validate_gl_entries(pe.name, expected_gle)
+		
+		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", pi.name, "outstanding_amount"))
+		self.assertEqual(outstanding_amount, 0)
+		
+	def test_payment_entry_against_si_usd_to_inr(self):
+		si =  create_sales_invoice(customer="_Test Customer USD", debit_to="_Test Receivable USD - _TC",
+			currency="USD", conversion_rate=50)
+		pe = get_payment_entry("Sales Invoice", si.name, party_amount=20, 
+			bank_account="_Test Bank - _TC", bank_amount=900)
+		pe.reference_no = "1"
+		pe.reference_date = "2016-01-01"
+		
+		self.assertEqual(pe.difference_amount, 100)
+		
+		pe.append("deductions", {
+			"account": "_Test Exchange Gain/Loss - _TC",
+			"cost_center": "_Test Cost Center - _TC",
+			"amount": 100
+		})
+		pe.insert()
+		pe.submit()
+		
+		expected_gle = dict((d[0], d) for d in [
+			["_Test Receivable USD - _TC", 0, 1000, si.name],
+			["_Test Bank - _TC", 900, 0, None],
+			["_Test Exchange Gain/Loss - _TC", 100.0, 0, None],
+		])
+		
+		self.validate_gl_entries(pe.name, expected_gle)
+		
+		outstanding_amount = flt(frappe.db.get_value("Sales Invoice", si.name, "outstanding_amount"))
+		self.assertEqual(outstanding_amount, 80)
+		
+	def test_internal_transfer_usd_to_inr(self):
+		pe = frappe.new_doc("Payment Entry")
+		pe.payment_type = "Internal Transfer"
+		pe.company = "_Test Company"
+		pe.paid_from = "_Test Bank USD - _TC"
+		pe.paid_to = "_Test Bank - _TC"
+		pe.paid_amount = 100
+		pe.source_exchange_rate = 50
+		pe.received_amount = 4500
+		pe.reference_no = "2"
+		pe.reference_date = nowdate()
+		
+		pe.setup_party_account_field()
+		pe.set_missing_values()
+		pe.set_exchange_rate()
+		pe.set_amounts()
+				
+		self.assertEquals(pe.difference_amount, 500)
+		
+		pe.append("deductions", {
+			"account": "_Test Exchange Gain/Loss - _TC",
+			"cost_center": "_Test Cost Center - _TC",
+			"amount": 500
+		})
+		
+		pe.insert()
+		pe.submit()
+		
+		expected_gle = dict((d[0], d) for d in [
+			["_Test Bank USD - _TC", 0, 5000, None],
+			["_Test Bank - _TC", 4500, 0, None],
+			["_Test Exchange Gain/Loss - _TC", 500.0, 0, None],
+		])
+		
+		self.validate_gl_entries(pe.name, expected_gle)
+		
 		
 	def validate_gl_entries(self, voucher_no, expected_gle):
-		gl_entries = frappe.db.sql("""select account, account_currency, debit, credit,
-			debit_in_account_currency, credit_in_account_currency, against_voucher
+		gl_entries = self.get_gle(voucher_no)
+			
+		self.assertTrue(gl_entries)
+
+		for i, gle in enumerate(gl_entries):
+			self.assertEquals(expected_gle[gle.account][0], gle.account)
+			self.assertEquals(expected_gle[gle.account][1], gle.debit)
+			self.assertEquals(expected_gle[gle.account][2], gle.credit)
+			self.assertEquals(expected_gle[gle.account][3], gle.against_voucher)
+		
+	def get_gle(self, voucher_no):
+		return frappe.db.sql("""select account, debit, credit, against_voucher
 			from `tabGL Entry` where voucher_type='Payment Entry' and voucher_no=%s
 			order by account asc""", voucher_no, as_dict=1)
-
-		self.assertTrue(gl_entries)
-		
-		for field in ("account_currency", "debit", "debit_in_account_currency", 
-			"credit", "credit_in_account_currency"):
-				for i, gle in enumerate(gl_entries):
-					self.assertEquals(expected_gle[gle.account][field], gle[field])
-		
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 0e37e11..2b79219 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -462,7 +462,7 @@
 				formatted_order_total = fmt_money(order_total, precision=self.precision("base_grand_total"),
 					currency=advance.account_currency)
 
-			if self.currency == self.company_currency:
+			if self.currency == self.company_currency and advance_paid > order_total:
 				frappe.throw(_("Total advance ({0}) against Order {1} cannot be greater than the Grand Total ({2})")
 					.format(formatted_advance_paid, self.name, formatted_order_total))