Merge pull request #56033 from mihir-kandoi/pg-zero-date

fix(postgres): db-aware zero-date (0000-00-00) item end-of-life checks
This commit is contained in:
Mihir Kandoi
2026-06-17 12:57:22 +05:30
committed by GitHub
3 changed files with 32 additions and 38 deletions

View File

@@ -56,11 +56,12 @@ def _item_master_details(item):
def _item_is_alive(item_table):
return (
item_table.end_of_life.isnull()
| (item_table.end_of_life == "0000-00-00")
| (item_table.end_of_life > nowdate())
)
# "not set" end_of_life is NULL on postgres (the MariaDB zero-date '0000-00-00' is an invalid
# date constant there), so only add the zero-date term on MariaDB.
is_alive = item_table.end_of_life.isnull() | (item_table.end_of_life > nowdate())
if frappe.db.db_type != "postgres":
is_alive |= item_table.end_of_life == "0000-00-00"
return is_alive
def _default_bom_for_item(item, project):

View File

@@ -24,14 +24,9 @@ def reorder_item():
def _reorder_item():
material_requests = {"Purchase": {}, "Transfer": {}, "Material Issue": {}, "Manufacture": {}}
warehouse_company = frappe._dict(
frappe.db.sql(
"""select name, company from `tabWarehouse`
where disabled=0"""
)
)
default_company = (
erpnext.get_default_company() or frappe.db.sql("""select name from tabCompany limit 1""")[0][0]
frappe.get_all("Warehouse", filters={"disabled": 0}, fields=["name", "company"], as_list=True)
)
default_company = erpnext.get_default_company() or frappe.db.get_value("Company", {}, "name")
items_to_consider = get_items_for_reorder()
@@ -110,6 +105,16 @@ def _reorder_item():
return create_material_request(material_requests)
def _item_is_alive(item_table):
# An item counts as alive when end_of_life is unset, in the future, or the MariaDB zero-date
# '0000-00-00'. On postgres '0000-00-00' is an invalid date literal and a "not set" end_of_life
# is NULL (already covered by IS NULL), so add the zero-date term on MariaDB only.
alive = item_table.end_of_life.isnull() | (item_table.end_of_life > nowdate())
if frappe.db.db_type != "postgres":
alive |= item_table.end_of_life == "0000-00-00"
return alive
def get_items_for_reorder() -> dict[str, list]:
reorder_table = frappe.qb.DocType("Item Reorder")
item_table = frappe.qb.DocType("Item")
@@ -135,15 +140,7 @@ def get_items_for_reorder() -> dict[str, list]:
item_table.has_variants,
item_table.lead_time_days,
)
.where(
(item_table.disabled == 0)
& (item_table.is_stock_item == 1)
& (
(item_table.end_of_life.isnull())
| (item_table.end_of_life > nowdate())
| (item_table.end_of_life == "0000-00-00")
)
)
.where((item_table.disabled == 0) & (item_table.is_stock_item == 1) & _item_is_alive(item_table))
)
data = query.run(as_dict=True)
@@ -168,11 +165,7 @@ def get_reorder_levels_for_variants(itemwise_reorder):
.where(
(item_table.disabled == 0)
& (item_table.is_stock_item == 1)
& (
(item_table.end_of_life.isnull())
| (item_table.end_of_life > nowdate())
| (item_table.end_of_life == "0000-00-00")
)
& _item_is_alive(item_table)
& (item_table.variant_of.notnull())
)
)
@@ -189,13 +182,11 @@ def get_item_warehouse_projected_qty(items_to_consider):
item_warehouse_projected_qty = {}
items_to_consider = list(items_to_consider.keys())
for item_code, warehouse, projected_qty in frappe.db.sql(
"""select item_code, warehouse, projected_qty
from tabBin where item_code in ({})
and (warehouse != '' and warehouse is not null)""".format(
", ".join(["%s"] * len(items_to_consider))
),
items_to_consider,
for item_code, warehouse, projected_qty in frappe.get_all(
"Bin",
filters={"item_code": ["in", items_to_consider], "warehouse": ["is", "set"]},
fields=["item_code", "warehouse", "projected_qty"],
as_list=True,
):
if item_code not in item_warehouse_projected_qty:
item_warehouse_projected_qty.setdefault(item_code, {})

View File

@@ -284,17 +284,19 @@ def get_item_map(item_code, include_uom):
bin = frappe.qb.DocType("Bin")
item = frappe.qb.DocType("Item")
# alive = end_of_life unset / future / MariaDB zero-date '0000-00-00' (an invalid date literal on
# postgres, where "not set" is NULL — already covered by IS NULL); zero-date term on MariaDB only.
alive = (item.end_of_life > today()) | item.end_of_life.isnull()
if frappe.db.db_type != "postgres":
alive |= item.end_of_life == "0000-00-00"
query = (
frappe.qb.from_(item)
.select(item.name, item.item_name, item.description, item.item_group, item.brand, item.stock_uom)
.where(
(item.is_stock_item == 1)
& (item.disabled == 0)
& (
(item.end_of_life > today())
| (item.end_of_life.isnull())
| (item.end_of_life == "0000-00-00")
)
& alive
& (ExistsCriterion(frappe.qb.from_(bin).select(bin.name).where(bin.item_code == item.name)))
)
)