refactor(postgres): port quotation.set_expired_status off multisql to the query builder

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Mihir Kandoi
2026-06-19 16:15:25 +05:30
parent bbc684aa80
commit 60e05bdaa6

View File

@@ -6,6 +6,7 @@ import frappe
from frappe import _
from frappe.model.document import Document
from frappe.utils import getdate, nowdate
from pypika.terms import ExistsCriterion
from erpnext.controllers.selling_controller import SellingController
@@ -358,22 +359,31 @@ def get_list_context(context=None):
def set_expired_status():
# filter out submitted non expired quotations whose validity has been ended
cond = "`tabQuotation`.docstatus = 1 and `tabQuotation`.status NOT IN ('Expired', 'Lost') and `tabQuotation`.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 = `tabQuotation`.name"""
quotation = frappe.qb.DocType("Quotation")
so = frappe.qb.DocType("Sales Order")
so_item = frappe.qb.DocType("Sales Order Item")
# if not exists any SO, set status as Expired
frappe.db.multisql(
{
"mariadb": f"""UPDATE `tabQuotation` SET `tabQuotation`.status = 'Expired' WHERE {cond} and not exists({so_against_quo})""",
"postgres": f"""UPDATE `tabQuotation` SET status = 'Expired' FROM `tabSales Order`, `tabSales Order Item` WHERE {cond} and not exists({so_against_quo})""",
},
(nowdate()),
# submitted Sales Orders raised against the quotation (correlated to the quotation being updated)
so_against_quo = (
frappe.qb.from_(so)
.from_(so_item)
.select(so.name)
.where(
(so_item.docstatus == 1)
& (so.docstatus == 1)
& (so_item.parent == so.name)
& (so_item.prevdoc_docname == quotation.name)
)
)
# expire submitted, non-expired/lost quotations whose validity has ended and that have no SO
(
frappe.qb.update(quotation)
.set(quotation.status, "Expired")
.where(
(quotation.docstatus == 1)
& (quotation.status.notin(["Expired", "Lost"]))
& (quotation.valid_till < nowdate())
& ExistsCriterion(so_against_quo).negate()
)
).run()