mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-11 05:31:48 +00:00
fix(stock): keep supplier-based Material Request picker valid on Postgres
get_material_requests_based_on_supplier deduplicated requests with
SELECT DISTINCT (name, transaction_date, company) while ordering by
mr_item.item_code, which is not in the select list. MariaDB allows this;
PostgreSQL rejects it:
psycopg2.errors.InvalidColumnReference: for SELECT DISTINCT,
ORDER BY expressions must appear in select list
so the picker errored out there.
Group by the three selected columns (equivalent to the DISTINCT, so the
same set of requests is returned) and order by Min(item_code). The order
key stays item_code but is now a well-defined aggregate, making the query
valid - and the ordering deterministic and identical - on both engines.
This commit is contained in:
@@ -12,7 +12,7 @@ import frappe.defaults
|
||||
from frappe import _, msgprint
|
||||
from frappe.model.document import Document
|
||||
from frappe.query_builder import Order
|
||||
from frappe.query_builder.functions import Sum
|
||||
from frappe.query_builder.functions import Min, Sum
|
||||
from frappe.utils import cint, flt, get_datetime, get_link_to_form, getdate, new_line_sep, nowdate
|
||||
|
||||
from erpnext.buying.utils import check_on_hold_or_closed_status, validate_for_items
|
||||
@@ -483,9 +483,7 @@ def get_material_requests_based_on_supplier(
|
||||
query = (
|
||||
frappe.qb.from_(mr)
|
||||
.from_(mr_item)
|
||||
.select(mr.name)
|
||||
.distinct()
|
||||
.select(mr.transaction_date, mr.company)
|
||||
.select(mr.name, mr.transaction_date, mr.company)
|
||||
.where(
|
||||
(mr.name == mr_item.parent)
|
||||
& (mr_item.item_code.isin(supplier_items))
|
||||
@@ -495,7 +493,8 @@ def get_material_requests_based_on_supplier(
|
||||
& (mr.status != "Stopped")
|
||||
& (mr.company == filters.get("company"))
|
||||
)
|
||||
.orderby(mr_item.item_code, order=Order.asc)
|
||||
.groupby(mr.name, mr.transaction_date, mr.company)
|
||||
.orderby(Min(mr_item.item_code), order=Order.asc)
|
||||
.limit(cint(page_len))
|
||||
.offset(cint(start))
|
||||
)
|
||||
|
||||
@@ -1252,6 +1252,44 @@ class TestMaterialRequest(ERPNextTestSuite):
|
||||
over.items[0].qty = 4
|
||||
over.validate_qty_against_so()
|
||||
|
||||
def test_get_material_requests_based_on_supplier(self):
|
||||
"""The supplier-based Material Request picker must run on every engine.
|
||||
|
||||
It deduplicated requests with SELECT DISTINCT while ordering by an item
|
||||
column that is not in the select list; PostgreSQL rejects that, so the
|
||||
picker has to group and order by an aggregate instead.
|
||||
"""
|
||||
from erpnext.stock.doctype.material_request.material_request import (
|
||||
get_material_requests_based_on_supplier,
|
||||
)
|
||||
|
||||
item = create_item("_Test MR Default Supplier Item")
|
||||
item.set("item_defaults", [])
|
||||
item.append(
|
||||
"item_defaults",
|
||||
{
|
||||
"company": "_Test Company",
|
||||
"default_warehouse": "_Test Warehouse - _TC",
|
||||
"default_supplier": "_Test Supplier",
|
||||
},
|
||||
)
|
||||
item.save()
|
||||
|
||||
mr1 = make_material_request(item_code=item.name, qty=5)
|
||||
mr2 = make_material_request(item_code=item.name, qty=7)
|
||||
|
||||
result = get_material_requests_based_on_supplier(
|
||||
doctype="Material Request",
|
||||
txt="",
|
||||
searchfield="name",
|
||||
start=0,
|
||||
page_len=20,
|
||||
filters={"supplier": "_Test Supplier", "company": "_Test Company"},
|
||||
)
|
||||
returned = {row["name"] for row in result}
|
||||
self.assertIn(mr1.name, returned)
|
||||
self.assertIn(mr2.name, returned)
|
||||
|
||||
|
||||
def get_in_transit_warehouse(company):
|
||||
if not frappe.db.exists("Warehouse Type", "Transit"):
|
||||
|
||||
Reference in New Issue
Block a user