diff --git a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py index 363484d9b1a..7939d8d2253 100644 --- a/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py +++ b/erpnext/accounts/doctype/payment_terms_template/payment_terms_template.py @@ -14,6 +14,7 @@ class PaymentTermsTemplate(Document): def validate(self): self.validate_invoice_portion() self.validate_credit_days() + self.check_duplicate_terms() def validate_invoice_portion(self): total_portion = 0 @@ -28,3 +29,14 @@ class PaymentTermsTemplate(Document): if term.credit_days < 0: frappe.msgprint(_('Credit Days cannot be a negative number'), raise_exception=1, indicator='red') + def check_duplicate_terms(self): + terms = [] + for term in self.terms: + term_info = (term.credit_days, term.due_date_based_on) + if term_info in terms: + frappe.msgprint( + _('The Payment Term at row {0} is possibly a duplicate.').format(term.idx), + raise_exception=1, indicator='red' + ) + else: + terms.append(term_info) diff --git a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py index bf9b75ac325..6daaf1ed74e 100644 --- a/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py +++ b/erpnext/accounts/doctype/payment_terms_template/test_payment_terms_template.py @@ -46,4 +46,27 @@ class TestPaymentTermsTemplate(unittest.TestCase): }] }) - self.assertRaises(frappe.ValidationError, template.insert) \ No newline at end of file + self.assertRaises(frappe.ValidationError, template.insert) + + def test_duplicate_terms(self): + template = frappe.get_doc({ + 'doctype': 'Payment Terms Template', + 'template_name': '_Test Payment Terms Template For Test', + 'terms': [ + { + 'doctype': 'Payment Terms Template Detail', + 'invoice_portion': 50.00, + 'credit_days_based_on': 'Day(s) after invoice date', + 'credit_days': 30 + }, + { + 'doctype': 'Payment Terms Template Detail', + 'invoice_portion': 50.00, + 'credit_days_based_on': 'Day(s) after invoice date', + 'credit_days': 30 + } + + ] + }) + + self.assertRaises(frappe.ValidationError, template.insert) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index cd5b751d015..3907029b8d6 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -645,6 +645,13 @@ class TestPurchaseInvoice(unittest.TestCase): self.assertTrue(pi.get('payment_schedule')) + def test_duplicate_due_date_in_terms(self): + pi = make_purchase_invoice(do_not_save=1) + pi.append('payment_schedule', dict(due_date='2017-01-01', invoice_portion=50.00, payment_amount=50)) + pi.append('payment_schedule', dict(due_date='2017-01-01', invoice_portion=50.00, payment_amount=50)) + + self.assertRaises(frappe.ValidationError, pi.insert) + def unlink_payment_on_cancel_of_invoice(enable=1): accounts_settings = frappe.get_doc("Accounts Settings") diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 5e26f52cf02..4d0fa90c5ae 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -1361,6 +1361,13 @@ class TestSalesInvoice(unittest.TestCase): si.insert() self.assertTrue(si.get('payment_schedule')) + def test_duplicate_due_date_in_terms(self): + si = create_sales_invoice(do_not_save=1) + si.append('payment_schedule', dict(due_date='2017-01-01', invoice_portion=50.00, payment_amount=50)) + si.append('payment_schedule', dict(due_date='2017-01-01', invoice_portion=50.00, payment_amount=50)) + + self.assertRaises(frappe.ValidationError, si.insert) + def create_sales_invoice(**args): si = frappe.new_doc("Sales Invoice") diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 16b22ce47ad..488d2215a02 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -648,12 +648,15 @@ class AccountsController(TransactionBase): self.validate_payment_schedule_amount() def validate_payment_schedule_dates(self): + dates = [] if self.due_date and getdate(self.due_date) < getdate(self.posting_date): frappe.throw(_("Due Date cannot be before posting date")) for d in self.get("payment_schedule"): if getdate(d.due_date) < getdate(self.posting_date): frappe.throw(_("Row {0}: Due Date cannot be before posting date").format(d.idx)) + elif d.due_date in dates: + frappe.throw(_("Row {0}: Duplicate due date found").format(d.idx)) def validate_payment_schedule_amount(self): total = 0