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))