mirror of
https://github.com/frappe/erpnext.git
synced 2026-10-29 22:57:42 +00:00
fix: block invoicing Lost or expired quotations
This commit is contained in:
@@ -416,7 +416,7 @@ erpnext.accounts.SalesInvoiceController = class SalesInvoiceController extends (
|
||||
],
|
||||
get_query_filters: {
|
||||
docstatus: 1,
|
||||
status: ["!=", "Lost"],
|
||||
status: ["not in", ["Lost", "Expired"]],
|
||||
company: me.frm.doc.company,
|
||||
},
|
||||
allow_child_item_selection: true,
|
||||
|
||||
@@ -383,19 +383,22 @@ def get_list_context(context=None):
|
||||
return list_context
|
||||
|
||||
|
||||
def validate_quotation_expiry(source_name):
|
||||
if frappe.db.get_singles_value("Selling Settings", "allow_sales_order_creation_for_expired_quotation"):
|
||||
return
|
||||
|
||||
quotation = frappe.db.get_value("Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1)
|
||||
if (
|
||||
quotation
|
||||
and quotation.valid_till
|
||||
and (quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate()))
|
||||
):
|
||||
frappe.throw(_("Validity period of this quotation has ended."))
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_order(source_name: str, target_doc=None, args=None):
|
||||
if not frappe.db.get_singles_value(
|
||||
"Selling Settings", "allow_sales_order_creation_for_expired_quotation"
|
||||
):
|
||||
quotation = frappe.db.get_value(
|
||||
"Quotation", source_name, ["transaction_date", "valid_till"], as_dict=1
|
||||
)
|
||||
if quotation.valid_till and (
|
||||
quotation.valid_till < quotation.transaction_date or quotation.valid_till < getdate(nowdate())
|
||||
):
|
||||
frappe.throw(_("Validity period of this quotation has ended."))
|
||||
|
||||
validate_quotation_expiry(source_name)
|
||||
return _make_sales_order(source_name, target_doc, args=args)
|
||||
|
||||
|
||||
@@ -540,6 +543,10 @@ def set_expired_status():
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_sales_invoice(source_name, target_doc=None, args=None):
|
||||
if frappe.db.get_value("Quotation", source_name, "status") == "Lost":
|
||||
frappe.throw(_("Cannot create a Sales Invoice against Lost Quotation {0}.").format(source_name))
|
||||
|
||||
validate_quotation_expiry(source_name)
|
||||
return _make_sales_invoice(source_name, target_doc, args=args)
|
||||
|
||||
|
||||
|
||||
@@ -1201,6 +1201,24 @@ class TestQuotation(FrappeTestCase):
|
||||
quotation.reload()
|
||||
self.assertEqual(quotation.status, "Partially Ordered")
|
||||
|
||||
def test_lost_or_expired_quotation_cannot_be_invoiced(self):
|
||||
from erpnext.selling.doctype.quotation.quotation import make_sales_invoice
|
||||
|
||||
if not frappe.db.exists("Quotation Lost Reason", "_Test Quotation Lost Reason"):
|
||||
frappe.get_doc(
|
||||
{"doctype": "Quotation Lost Reason", "order_lost_reason": "_Test Quotation Lost Reason"}
|
||||
).insert()
|
||||
|
||||
lost = make_quotation()
|
||||
lost.declare_enquiry_lost([{"lost_reason": "_Test Quotation Lost Reason"}], [])
|
||||
self.assertRaises(frappe.ValidationError, make_sales_invoice, lost.name)
|
||||
|
||||
expired = make_quotation(do_not_submit=1)
|
||||
expired.transaction_date = add_days(nowdate(), -10)
|
||||
expired.valid_till = add_days(nowdate(), -5)
|
||||
expired.submit()
|
||||
self.assertRaises(frappe.ValidationError, make_sales_invoice, expired.name)
|
||||
|
||||
|
||||
test_records = frappe.get_test_records("Quotation")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user