diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.js b/erpnext/accounts/doctype/payment_entry/payment_entry.js index 12e46c42d3..dc37574ea6 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.js @@ -644,16 +644,9 @@ frappe.ui.form.on('Payment Entry', { if(frm.doc.party) { var party_amount = frm.doc.payment_type=="Receive" ? frm.doc.paid_amount : frm.doc.received_amount; - - var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [], - function(d) { return flt(d.amount) })); if(frm.doc.total_allocated_amount < party_amount) { - if(frm.doc.payment_type == "Receive") { - unallocated_amount = party_amount - (frm.doc.total_allocated_amount - total_deductions); - } else { - unallocated_amount = party_amount - (frm.doc.total_allocated_amount + total_deductions); - } + unallocated_amount = party_amount - frm.doc.total_allocated_amount; } } frm.set_value("unallocated_amount", unallocated_amount); @@ -672,11 +665,10 @@ frappe.ui.form.on('Payment Entry', { difference_amount = flt(frm.doc.base_paid_amount) - flt(frm.doc.base_received_amount); } - $.each(frm.doc.deductions || [], function(i, d) { - if(d.amount) difference_amount -= flt(d.amount); - }) + var total_deductions = frappe.utils.sum($.map(frm.doc.deductions || [], + function(d) { return flt(d.amount) })); - frm.set_value("difference_amount", difference_amount); + frm.set_value("difference_amount", difference_amount - total_deductions); frm.events.hide_unhide_fields(frm); }, diff --git a/erpnext/accounts/doctype/payment_entry/payment_entry.py b/erpnext/accounts/doctype/payment_entry/payment_entry.py index 9832c0527a..908e58eeac 100644 --- a/erpnext/accounts/doctype/payment_entry/payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/payment_entry.py @@ -281,13 +281,8 @@ class PaymentEntry(AccountsController): if self.party: party_amount = self.paid_amount if self.payment_type=="Receive" else self.received_amount - total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) - if self.total_allocated_amount < party_amount: - if self.payment_type == "Receive": - self.unallocated_amount = party_amount - (self.total_allocated_amount - total_deductions) - else: - self.unallocated_amount = party_amount - (self.total_allocated_amount + total_deductions) + self.unallocated_amount = party_amount - self.total_allocated_amount def set_difference_amount(self): base_unallocated_amount = flt(self.unallocated_amount) * (flt(self.source_exchange_rate) @@ -302,11 +297,10 @@ class PaymentEntry(AccountsController): else: self.difference_amount = self.base_paid_amount - flt(self.base_received_amount) - for d in self.get("deductions"): - if d.amount: - self.difference_amount -= flt(d.amount) + total_deductions = sum([flt(d.amount) for d in self.get("deductions")]) - self.difference_amount = flt(self.difference_amount, self.precision("difference_amount")) + self.difference_amount = flt(self.difference_amount - total_deductions, + self.precision("difference_amount")) def clear_unallocated_reference_document_rows(self): self.set("references", self.get("references", {"allocated_amount": ["not in", [0, None, ""]]})) diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 0316ccafe2..60be20dd89 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -267,3 +267,65 @@ class TestPaymentEntry(unittest.TestCase): 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) + + def test_payment_entry_write_off_difference(self): + si = create_sales_invoice() + pe = get_payment_entry("Sales Invoice", si.name, bank_account="_Test Cash - _TC") + pe.reference_no = "1" + pe.reference_date = "2016-01-01" + pe.received_amount = pe.paid_amount = 110 + pe.insert() + + self.assertEqual(pe.unallocated_amount, 10) + + pe.received_amount = pe.paid_amount = 95 + pe.append("deductions", { + "account": "_Test Write Off - _TC", + "cost_center": "_Test Cost Center - _TC", + "amount": 5 + }) + pe.save() + + self.assertEqual(pe.unallocated_amount, 0) + self.assertEqual(pe.difference_amount, 0) + + pe.submit() + + expected_gle = dict((d[0], d) for d in [ + ["Debtors - _TC", 0, 100, si.name], + ["_Test Cash - _TC", 95, 0, None], + ["_Test Write Off - _TC", 5, 0, None] + ]) + + self.validate_gl_entries(pe.name, expected_gle) + + def test_payment_entry_exchange_gain_loss(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 = 55 + + pe.append("deductions", { + "account": "_Test Exchange Gain/Loss - _TC", + "cost_center": "_Test Cost Center - _TC", + "amount": -500 + }) + pe.save() + + self.assertEqual(pe.unallocated_amount, 0) + self.assertEqual(pe.difference_amount, 0) + + pe.submit() + + expected_gle = dict((d[0], d) for d in [ + ["_Test Receivable USD - _TC", 0, 5000, si.name], + ["_Test Bank USD - _TC", 5500, 0, None], + ["_Test Exchange Gain/Loss - _TC", 0, 500, 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) diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js new file mode 100644 index 0000000000..7dea76db80 --- /dev/null +++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js @@ -0,0 +1,51 @@ +QUnit.module('Payment Entry'); + +QUnit.test("test payment entry", function(assert) { + assert.expect(6); + let done = assert.async(); + frappe.run_serially([ + () => { + return frappe.tests.make('Sales Invoice', [ + {customer: 'Test Customer 1'}, + {items: [ + [ + {'qty': 1}, + {'rate': 101}, + {'item_code': 'Test Product 1'}, + ] + ]} + ]); + }, + () => cur_frm.save(), + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(0.5), + () => frappe.tests.click_button('Close'), + () => frappe.timeout(0.5), + () => frappe.click_button('Make'), + () => frappe.click_link('Payment', 1), + () => frappe.timeout(2), + () => { + assert.equal(frappe.get_route()[1], 'Payment Entry', + 'made payment entry'); + assert.equal(cur_frm.doc.party, 'Test Customer 1', + 'customer set in payment entry'); + assert.equal(cur_frm.doc.paid_amount, 101, + 'paid amount set in payment entry'); + assert.equal(cur_frm.doc.references[0].allocated_amount, 101, + 'amount allocated against sales invoice'); + }, + () => cur_frm.set_value('paid_amount', 100), + () => { + cur_frm.doc.references[0].allocated_amount = 101; + }, + () => frappe.click_button('Write Off Difference Amount'), + () => { + assert.equal(cur_frm.doc.difference_amount, 0, + 'difference amount is zero'); + assert.equal(cur_frm.doc.deductions[0].amount, 1, + 'Write off amount = 1'); + }, + () => done() + ]); +}); diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js index a4ef0ca4eb..0c76343fa9 100644 --- a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js +++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry.js @@ -25,5 +25,4 @@ QUnit.test("test payment entry", function(assert) { () => frappe.timeout(0.3), () => done() ]); -}); - +}); \ No newline at end of file diff --git a/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js new file mode 100644 index 0000000000..133f136298 --- /dev/null +++ b/erpnext/accounts/doctype/payment_entry/tests/test_payment_entry_write_off.js @@ -0,0 +1,67 @@ +QUnit.module('Payment Entry'); + +QUnit.test("test payment entry", function(assert) { + assert.expect(8); + let done = assert.async(); + frappe.run_serially([ + () => { + return frappe.tests.make('Sales Invoice', [ + {customer: 'Test Customer 1'}, + {company: '_Test Company'}, + {currency: 'INR'}, + {selling_price_list: '_Test Price List'}, + {items: [ + [ + {'qty': 1}, + {'item_code': 'Test Product 1'}, + ] + ]} + ]); + }, + () => frappe.timeout(1), + () => cur_frm.save(), + () => frappe.tests.click_button('Submit'), + () => frappe.tests.click_button('Yes'), + () => frappe.timeout(1.5), + () => frappe.click_button('Close'), + () => frappe.timeout(0.5), + () => frappe.click_button('Make'), + () => frappe.timeout(1), + () => frappe.click_link('Payment'), + () => frappe.timeout(2), + () => cur_frm.set_value("paid_to", "_Test Cash - _TC"), + () => frappe.timeout(0.5), + () => { + assert.equal(frappe.get_route()[1], 'Payment Entry', 'made payment entry'); + assert.equal(cur_frm.doc.party, 'Test Customer 1', 'customer set in payment entry'); + assert.equal(cur_frm.doc.paid_from, 'Debtors - _TC', 'customer account set in payment entry'); + assert.equal(cur_frm.doc.paid_amount, 100, 'paid amount set in payment entry'); + assert.equal(cur_frm.doc.references[0].allocated_amount, 100, + 'amount allocated against sales invoice'); + }, + () => cur_frm.set_value('paid_amount', 95), + () => frappe.timeout(1), + () => { + frappe.model.set_value("Payment Entry Reference", + cur_frm.doc.references[0].name, "allocated_amount", 100); + }, + () => frappe.timeout(.5), + () => { + assert.equal(cur_frm.doc.difference_amount, 5, 'difference amount is 5'); + }, + () => { + frappe.db.set_value("Company", "_Test Company", "write_off_account", "_Test Write Off - _TC"); + frappe.timeout(1); + frappe.db.set_value("Company", "_Test Company", + "exchange_gain_loss_account", "_Test Exchange Gain/Loss - _TC"); + }, + () => frappe.timeout(1), + () => frappe.click_button('Write Off Difference Amount'), + () => frappe.timeout(2), + () => { + assert.equal(cur_frm.doc.difference_amount, 0, 'difference amount is zero'); + assert.equal(cur_frm.doc.deductions[0].amount, 5, 'Write off amount = 5'); + }, + () => done() + ]); +}); \ No newline at end of file diff --git a/erpnext/tests/ui/make_fixtures.js b/erpnext/tests/ui/make_fixtures.js index 0c5b4beebe..f817c6549a 100644 --- a/erpnext/tests/ui/make_fixtures.js +++ b/erpnext/tests/ui/make_fixtures.js @@ -205,6 +205,18 @@ $.extend(frappe.test_data, { {title: "Test Term 2"} ] }, + "Item Price": { + "ITEM-PRICE-00001": [ + {item_code: 'Test Product 1'}, + {price_list: '_Test Price List'}, + {price_list_rate: 100} + ], + "ITEM-PRICE-00002": [ + {item_code: 'Test Product 2'}, + {price_list: '_Test Price List'}, + {price_list_rate: 200} + ] + } }); diff --git a/erpnext/tests/ui/tests.txt b/erpnext/tests/ui/tests.txt index 313554bd9c..6017f6f67b 100644 --- a/erpnext/tests/ui/tests.txt +++ b/erpnext/tests/ui/tests.txt @@ -125,4 +125,5 @@ erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_transfer_f erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_subcontract.js erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_material_issue_with_serialize_item.js erpnext/stock/doctype/stock_entry/tests/test_stock_entry_for_repack.js -erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js \ No newline at end of file +erpnext/accounts/doctype/sales_invoice/tests/test_sales_invoice_with_serialize_item.js +erpnext/accounts/doctype/payment_entry/tests/test_payment_against_invoice.js