diff --git a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py index 7cd6e084562..aee8901fc9b 100644 --- a/erpnext/accounts/doctype/payment_entry/test_payment_entry.py +++ b/erpnext/accounts/doctype/payment_entry/test_payment_entry.py @@ -2317,3 +2317,65 @@ def create_customer(name="_Test Customer 2 USD", currency="USD"): customer.save() customer = customer.name return customer + + +class TestPaymentEntryValidation(ERPNextTestSuite): + """Field-level validations invoked on the document directly, covering branches the + integration suite above doesn't reach (no GL / reconciliation setup needed).""" + + def make_pe(self, **fields): + doc = frappe.new_doc("Payment Entry") + doc.update(fields) + return doc + + def test_payment_type_must_be_a_known_value(self): + self.assertRaises(frappe.ValidationError, self.make_pe(payment_type="Foo").validate_payment_type) + self.make_pe(payment_type="Receive").validate_payment_type() # valid value passes + + def test_nonexistent_party_is_rejected(self): + doc = self.make_pe(party_type="Customer", party="__No Such Customer__") + self.assertRaises(frappe.ValidationError, doc.validate_party_details) + + def test_amount_and_exchange_rate_fields_are_mandatory(self): + # every field but target_exchange_rate is set, so that missing one raises + doc = self.make_pe( + paid_amount=100, received_amount=100, source_exchange_rate=1, target_exchange_rate=0 + ) + self.assertRaises(frappe.ValidationError, doc.validate_mandatory) + + def test_received_amount_cannot_exceed_paid_in_same_currency(self): + doc = self.make_pe( + paid_from_account_currency="INR", + paid_to_account_currency="INR", + paid_amount=100, + received_amount=150, + ) + self.assertRaises(frappe.ValidationError, doc.validate_received_amount) + # received <= paid is fine + doc.received_amount = 50 + doc.validate_received_amount() + + def test_duplicate_reference_rows_are_rejected(self): + doc = self.make_pe() + for _ in range(2): + doc.append( + "references", + {"reference_doctype": "Sales Invoice", "reference_name": "SI-X", "allocated_amount": 100}, + ) + self.assertRaises(frappe.ValidationError, doc.validate_duplicate_entry) + + def test_receive_from_customer_against_negative_outstanding_is_rejected(self): + doc = self.make_pe(party_type="Customer", payment_type="Receive") + doc.append( + "references", + {"reference_doctype": "Sales Invoice", "reference_name": "SI-Y", "allocated_amount": -100}, + ) + self.assertRaises(frappe.ValidationError, doc.validate_payment_type_with_outstanding) + + def test_bank_transaction_requires_a_reference_number(self): + doc = self.make_pe(payment_type="Pay", paid_from="_Test Bank - _TC") + self.assertRaises(frappe.ValidationError, doc.validate_transaction_reference) + # supplying the reference details clears the requirement + doc.reference_no = "TXN-1" + doc.reference_date = "2026-06-15" + doc.validate_transaction_reference()