From 1e4c28e99d2b675408bb8b3cda743852b6aedc66 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 23 Apr 2020 15:15:52 +0530 Subject: [PATCH 1/4] fix: quotation have expired status even if sales order exists --- erpnext/patches.txt | 1 + .../v12_0/fix_quotation_expired_status.py | 37 +++++++++++++++++++ .../selling/doctype/quotation/quotation.py | 23 +++++++++--- 3 files changed, 55 insertions(+), 6 deletions(-) create mode 100644 erpnext/patches/v12_0/fix_quotation_expired_status.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 9ef0b8d510b..39ae8e74471 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -667,3 +667,4 @@ erpnext.patches.v12_0.update_healthcare_refactored_changes erpnext.patches.v12_0.set_total_batch_quantity erpnext.patches.v12_0.rename_mws_settings_fields erpnext.patches.v12_0.set_updated_purpose_in_pick_list +erpnext.patches.v12_0.fix_quotation_expired_status diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py new file mode 100644 index 00000000000..a0320feb7b3 --- /dev/null +++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py @@ -0,0 +1,37 @@ +import frappe + + +def execute(): + # fixes status of quotations which have status 'Expired' despite having valid sales order created + + # filter out submitted expired quotations which has sales order created + cond = "qo.docstatus = 1 and qo.status = 'Expired'" + invalid_so_against_quo = """ + SELECT + so.name FROM `tabSales Order` so, `tabSales Order Item` so_item + WHERE + so_item.docstatus = 1 and so.docstatus = 1 + and so_item.parent = so.name + and so_item.prevdoc_docname = qo.name + and qo.valid_till < so.transaction_date""" # check if SO was created after quotation expired + + frappe.db.sql( + """UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and not exists({invalid_so_against_quo})""" + .format(cond=cond, invalid_so_against_quo=invalid_so_against_quo), + (nowdate()) + ) + + valid_so_against_quo = """ + SELECT + so.name FROM `tabSales Order` so, `tabSales Order Item` so_item + WHERE + so_item.docstatus = 1 and so.docstatus = 1 + and so_item.parent = so.name + and so_item.prevdoc_docname = qo.name + and qo.valid_till >= so.transaction_date""" # check if SO was created before quotation expired + + frappe.db.sql( + """UPDATE `tabQuotation` qo SET qo.status = 'Closed' WHERE {cond} and not exists({valid_so_against_quo})""" + .format(cond=cond, valid_so_against_quo=valid_so_against_quo), + (nowdate()) + ) diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 7c47b8ac511..7cfec5a046a 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -193,12 +193,23 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False): return doclist def set_expired_status(): - frappe.db.sql(""" - UPDATE - `tabQuotation` SET `status` = 'Expired' - WHERE - `status` not in ('Ordered', 'Expired', 'Lost', 'Cancelled') AND `valid_till` < %s - """, (nowdate())) + # filter out submitted non expired quotations whose validity has been ended + cond = "qo.docstatus = 1 and qo.status != 'Expired' and qo.valid_till < %s" + # check if those QUO have SO against it + so_against_quo = """ + SELECT + so.name FROM `tabSales Order` so, `tabSales Order Item` so_item + WHERE + so_item.docstatus = 1 and so.docstatus = 1 + and so_item.parent = so.name + and so_item.prevdoc_docname = qo.name""" + + # if not exists any SO, set status as Expired + frappe.db.sql( + """UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and not exists({so_against_quo})""" + .format(cond=cond, so_against_quo=so_against_quo), + (nowdate()) + ) @frappe.whitelist() def make_sales_invoice(source_name, target_doc=None): From 0f2c64cfefb76ad11b2e322c54563abd0a274fd3 Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Thu, 23 Apr 2020 19:19:09 +0530 Subject: [PATCH 2/4] fix: travis --- erpnext/patches/v12_0/fix_quotation_expired_status.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py index a0320feb7b3..0e4419ac50e 100644 --- a/erpnext/patches/v12_0/fix_quotation_expired_status.py +++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py @@ -1,5 +1,5 @@ import frappe - +from frappe.utils import nowdate def execute(): # fixes status of quotations which have status 'Expired' despite having valid sales order created From 22d2970339cf1f4e46829a892c34b4a80dff025e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Fri, 24 Apr 2020 13:47:44 +0530 Subject: [PATCH 3/4] fix: query --- erpnext/patches/v12_0/fix_quotation_expired_status.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py index 0e4419ac50e..fcc7094b557 100644 --- a/erpnext/patches/v12_0/fix_quotation_expired_status.py +++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py @@ -17,8 +17,7 @@ def execute(): frappe.db.sql( """UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and not exists({invalid_so_against_quo})""" - .format(cond=cond, invalid_so_against_quo=invalid_so_against_quo), - (nowdate()) + .format(cond=cond, invalid_so_against_quo=invalid_so_against_quo) ) valid_so_against_quo = """ @@ -32,6 +31,5 @@ def execute(): frappe.db.sql( """UPDATE `tabQuotation` qo SET qo.status = 'Closed' WHERE {cond} and not exists({valid_so_against_quo})""" - .format(cond=cond, valid_so_against_quo=valid_so_against_quo), - (nowdate()) + .format(cond=cond, valid_so_against_quo=valid_so_against_quo) ) From 2fea0735392faf37214fce318ac74abaf7bd449e Mon Sep 17 00:00:00 2001 From: Saqib Ansari Date: Sun, 26 Apr 2020 17:30:23 +0530 Subject: [PATCH 4/4] fix: query logic --- erpnext/patches/v12_0/fix_quotation_expired_status.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/erpnext/patches/v12_0/fix_quotation_expired_status.py b/erpnext/patches/v12_0/fix_quotation_expired_status.py index fcc7094b557..c8708d80134 100644 --- a/erpnext/patches/v12_0/fix_quotation_expired_status.py +++ b/erpnext/patches/v12_0/fix_quotation_expired_status.py @@ -1,5 +1,4 @@ import frappe -from frappe.utils import nowdate def execute(): # fixes status of quotations which have status 'Expired' despite having valid sales order created @@ -16,7 +15,7 @@ def execute(): and qo.valid_till < so.transaction_date""" # check if SO was created after quotation expired frappe.db.sql( - """UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and not exists({invalid_so_against_quo})""" + """UPDATE `tabQuotation` qo SET qo.status = 'Expired' WHERE {cond} and exists({invalid_so_against_quo})""" .format(cond=cond, invalid_so_against_quo=invalid_so_against_quo) ) @@ -30,6 +29,6 @@ def execute(): and qo.valid_till >= so.transaction_date""" # check if SO was created before quotation expired frappe.db.sql( - """UPDATE `tabQuotation` qo SET qo.status = 'Closed' WHERE {cond} and not exists({valid_so_against_quo})""" + """UPDATE `tabQuotation` qo SET qo.status = 'Closed' WHERE {cond} and exists({valid_so_against_quo})""" .format(cond=cond, valid_so_against_quo=valid_so_against_quo) )