diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 79b1cd40b1c..ac6ca8ca2f0 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -1365,7 +1365,418 @@ class TestPaymentEntry(FrappeTestCase): expected_out_str = json.dumps(sorted(expected_pl_entries, key=json.dumps)) self.assertEqual(out_str, expected_out_str) +<<<<<<< HEAD @change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1}) +======= + # Normal Invoice + si = create_sales_invoice(qty=10, rate=100, customer="_Test Customer") + + pre_reconciliation_gle = [ + {"account": advance_account, "debit": 0.0, "credit": 1000.0}, + {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0}, + ] + pre_reconciliation_ple = [ + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": -1000.0, + } + ] + + self.voucher_no = pe.name + self.expected_gle = pre_reconciliation_gle + self.expected_ple = pre_reconciliation_ple + self.check_gl_entries() + self.check_pl_entries() + + # Partially reconcile advance against invoice + pr = frappe.get_doc("Payment Reconciliation") + pr.company = company + pr.party_type = "Customer" + pr.party = "_Test Customer" + pr.receivable_payable_account = si.debit_to + pr.default_advance_account = advance_account + pr.payment_name = pe.name + pr.invoice_name = si.name + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + + invoices = [x.as_dict() for x in pr.get("invoices")] + payments = [x.as_dict() for x in pr.get("payments")] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.allocation[0].allocated_amount = 400 + pr.reconcile() + + # assert General and Payment Ledger entries post partial reconciliation + self.expected_gle = [ + {"account": si.debit_to, "debit": 0.0, "credit": 400.0}, + {"account": advance_account, "debit": 400.0, "credit": 0.0}, + {"account": advance_account, "debit": 0.0, "credit": 1000.0}, + {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0}, + ] + self.expected_ple = [ + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": -1000.0, + }, + { + "account": si.debit_to, + "voucher_no": pe.name, + "against_voucher_no": si.name, + "amount": -400.0, + }, + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": 400.0, + }, + ] + self.check_gl_entries() + self.check_pl_entries() + + # Unreconcile + ( + frappe.get_doc( + { + "doctype": "Unreconcile Payment", + "company": company, + "voucher_type": pe.doctype, + "voucher_no": pe.name, + "allocations": [{"reference_doctype": si.doctype, "reference_name": si.name}], + } + ) + .save() + .submit() + ) + + self.voucher_no = pe.name + self.expected_gle = pre_reconciliation_gle + self.expected_ple = pre_reconciliation_ple + self.check_gl_entries() + self.check_pl_entries() + + def test_advance_as_liability_against_order(self): + from erpnext.buying.doctype.purchase_order.purchase_order import ( + make_purchase_invoice as _make_purchase_invoice, + ) + from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order + + company = "_Test Company" + + advance_account = create_account( + parent_account="Current Liabilities - _TC", + account_name="Advances Paid", + company=company, + account_type="Payable", + ) + + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": 1, + "default_advance_paid_account": advance_account, + }, + ) + + po = create_purchase_order(supplier="_Test Supplier") + pe = get_payment_entry("Purchase Order", po.name, bank_account="Cash - _TC") + pe.save().submit() + + pre_reconciliation_gle = [ + {"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0}, + {"account": advance_account, "debit": 5000.0, "credit": 0.0}, + ] + + self.voucher_no = pe.name + self.expected_gle = pre_reconciliation_gle + self.check_gl_entries() + + # Make Purchase Invoice against the order + pi = _make_purchase_invoice(po.name) + pi.append( + "advances", + { + "reference_type": pe.doctype, + "reference_name": pe.name, + "reference_row": pe.references[0].name, + "advance_amount": 5000, + "allocated_amount": 5000, + }, + ) + pi.save().submit() + + # # assert General and Payment Ledger entries post partial reconciliation + self.expected_gle = [ + {"account": pi.credit_to, "debit": 5000.0, "credit": 0.0}, + {"account": "Cash - _TC", "debit": 0.0, "credit": 5000.0}, + {"account": advance_account, "debit": 5000.0, "credit": 0.0}, + {"account": advance_account, "debit": 0.0, "credit": 5000.0}, + ] + + self.voucher_no = pe.name + self.check_gl_entries() + + def check_pl_entries(self): + ple = frappe.qb.DocType("Payment Ledger Entry") + pl_entries = ( + frappe.qb.from_(ple) + .select(ple.account, ple.voucher_no, ple.against_voucher_no, ple.amount) + .where((ple.voucher_no == self.voucher_no) & (ple.delinked == 0)) + .orderby(ple.creation) + ).run(as_dict=True) + for row in range(len(self.expected_ple)): + for field in ["account", "voucher_no", "against_voucher_no", "amount"]: + self.assertEqual(self.expected_ple[row][field], pl_entries[row][field]) + + def check_gl_entries(self): + gle = frappe.qb.DocType("GL Entry") + gl_entries = ( + frappe.qb.from_(gle) + .select( + gle.account, + gle.debit, + gle.credit, + ) + .where((gle.voucher_no == self.voucher_no) & (gle.is_cancelled == 0)) + .orderby(gle.account, gle.debit, gle.credit, order=frappe.qb.desc) + ).run(as_dict=True) + for row in range(len(self.expected_gle)): + for field in ["account", "debit", "credit"]: + self.assertEqual(self.expected_gle[row][field], gl_entries[row][field]) + + def test_reverse_payment_reconciliation(self): + customer = create_customer(frappe.generate_hash(length=10), "INR") + pe = create_payment_entry( + party_type="Customer", + party=customer, + payment_type="Receive", + paid_from="Debtors - _TC", + paid_to="_Test Cash - _TC", + ) + pe.submit() + + reverse_pe = create_payment_entry( + party_type="Customer", + party=customer, + payment_type="Pay", + paid_from="_Test Cash - _TC", + paid_to="Debtors - _TC", + ) + reverse_pe.submit() + + pr = frappe.get_doc("Payment Reconciliation") + pr.company = "_Test Company" + pr.party_type = "Customer" + pr.party = customer + pr.receivable_payable_account = "Debtors - _TC" + pr.get_unreconciled_entries() + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + + self.assertEqual(reverse_pe.name, pr.invoices[0].invoice_number) + self.assertEqual(pe.name, pr.payments[0].reference_name) + + invoices = [x.as_dict() for x in pr.invoices] + payments = [pr.payments[0].as_dict()] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + + def test_advance_reverse_payment_reconciliation(self): + company = "_Test Company" + customer = create_customer(frappe.generate_hash(length=10), "INR") + advance_account = create_account( + parent_account="Current Liabilities - _TC", + account_name="Advances Received", + company=company, + account_type="Receivable", + ) + + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": 1, + "default_advance_received_account": advance_account, + }, + ) + # Reverse Payment(essentially an Invoice) + reverse_pe = create_payment_entry( + party_type="Customer", + party=customer, + payment_type="Pay", + paid_from="_Test Cash - _TC", + paid_to=advance_account, + ) + reverse_pe.save() # use save() to trigger set_liability_account() + reverse_pe.submit() + + # Advance Payment + pe = create_payment_entry( + party_type="Customer", + party=customer, + payment_type="Receive", + paid_from=advance_account, + paid_to="_Test Cash - _TC", + ) + pe.save() # use save() to trigger set_liability_account() + pe.submit() + + # Partially reconcile advance against invoice + pr = frappe.get_doc("Payment Reconciliation") + pr.company = company + pr.party_type = "Customer" + pr.party = customer + pr.receivable_payable_account = "Debtors - _TC" + pr.default_advance_account = advance_account + pr.get_unreconciled_entries() + + self.assertEqual(len(pr.invoices), 1) + self.assertEqual(len(pr.payments), 1) + + invoices = [x.as_dict() for x in pr.get("invoices")] + payments = [x.as_dict() for x in pr.get("payments")] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.allocation[0].allocated_amount = 400 + pr.reconcile() + + # assert General and Payment Ledger entries post partial reconciliation + self.expected_gle = [ + {"account": advance_account, "debit": 400.0, "credit": 0.0}, + {"account": advance_account, "debit": 0.0, "credit": 1000.0}, + {"account": advance_account, "debit": 0.0, "credit": 400.0}, + {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0}, + ] + self.expected_ple = [ + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": -1000.0, + }, + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": reverse_pe.name, + "amount": -400.0, + }, + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": 400.0, + }, + ] + self.voucher_no = pe.name + self.check_gl_entries() + self.check_pl_entries() + + # Unreconcile + ( + frappe.get_doc( + { + "doctype": "Unreconcile Payment", + "company": company, + "voucher_type": pe.doctype, + "voucher_no": pe.name, + "allocations": [ + {"reference_doctype": reverse_pe.doctype, "reference_name": reverse_pe.name} + ], + } + ) + .save() + .submit() + ) + + # assert General and Payment Ledger entries post unreconciliation + self.expected_gle = [ + {"account": advance_account, "debit": 0.0, "credit": 1000.0}, + {"account": "_Test Cash - _TC", "debit": 1000.0, "credit": 0.0}, + ] + self.expected_ple = [ + { + "account": advance_account, + "voucher_no": pe.name, + "against_voucher_no": pe.name, + "amount": -1000.0, + }, + ] + self.voucher_no = pe.name + self.check_gl_entries() + self.check_pl_entries() + + def test_opening_flag_for_advance_as_liability(self): + company = "_Test Company" + + advance_account = create_account( + parent_account="Current Assets - _TC", + account_name="Advances Received", + company=company, + account_type="Receivable", + ) + + # Enable Advance in separate party account + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": 1, + "default_advance_received_account": advance_account, + }, + ) + # Advance Payment + adv = create_payment_entry( + party_type="Customer", + party="_Test Customer", + payment_type="Receive", + paid_from="Debtors - _TC", + paid_to="_Test Cash - _TC", + ) + adv.is_opening = "Yes" + adv.save() # use save() to trigger set_liability_account() + adv.submit() + + gl_with_opening_set = frappe.db.get_all( + "GL Entry", filters={"voucher_no": adv.name, "is_opening": "Yes"} + ) + # 'Is Opening' can be 'Yes' for Advances in separate party account + self.assertNotEqual(gl_with_opening_set, []) + + # Disable Advance in separate party account + frappe.db.set_value( + "Company", + company, + { + "book_advance_payments_in_separate_party_account": 0, + "default_advance_received_account": None, + }, + ) + payment = create_payment_entry( + party_type="Customer", + party="_Test Customer", + payment_type="Receive", + paid_from="Debtors - _TC", + paid_to="_Test Cash - _TC", + ) + payment.is_opening = "Yes" + payment.save() + payment.submit() + gl_with_opening_set = frappe.db.get_all( + "GL Entry", filters={"voucher_no": payment.name, "is_opening": "Yes"} + ) + # 'Is Opening' should always be 'No' for normal advance payments + self.assertEqual(gl_with_opening_set, []) + + @IntegrationTestCase.change_settings("Accounts Settings", {"delete_linked_ledger_entries": 1}) +>>>>>>> 8abbece7c4 (fix: Set account type payable for advance account) def test_delete_linked_exchange_gain_loss_journal(self): from erpnext.accounts.doctype.account.test_account import create_account from erpnext.accounts.doctype.opening_invoice_creation_tool.test_opening_invoice_creation_tool import (