Files
erpnext/erpnext/templates/pages/material_request_info.py
Mihir Kandoi 96d4c48357 refactor(postgres): port Setup/Utilities/Templates/Regional queries to the query builder
Convert raw `frappe.db.sql` in the Setup, Utilities, Templates and Regional
areas to `frappe.qb` / the ORM so the same code runs on MariaDB and Postgres.
Behaviour is preserved on MariaDB; the conversions also make these paths valid
under Postgres' stricter SQL (GROUP BY, case-sensitivity, reserved words).

Conversions of note (behaviour kept identical to the MariaDB original):
- email_digest: ToDo ordering replicated with a CASE that mirrors MySQL
  `field(priority,'High','Medium','Low')` (unknown/NULL -> 0, sorts first),
  NULL-date-first and a `name` tie-break for a deterministic LIMIT.
- company.get_all_transactions_annual_history: the cross-DocType UNION + GROUP BY
  is replaced by one grouped query per DocType merged with a Counter, so two
  different DocTypes sharing a transaction_date still collapse into one bucket.
- templates/utils.send_message: contact lookup wraps both sides in LOWER() to
  keep MariaDB's case-insensitive email match on case-sensitive Postgres.
- regional/irs_1099 & uae_vat_201: address ranking and emirate aggregation
  rebuilt with CASE/aggregate selects that satisfy Postgres GROUP BY, with a
  deterministic tie-break on the LIMIT-1 address lookups.
- utilities/product.get_item_codes_by_attributes: numeric attribute values are
  cast with cstr() so Postgres doesn't reject `varchar = numeric`.

Tests (run on both MariaDB and Postgres, --lightmode):
- New: company merge test, authorization_rule duplicate-check, youtube report,
  templates/utils, and utilities/templates page reports (partners, rfq,
  material_request_info, product, utilities __init__).
- Existing suites kept green: company, email_digest, transaction_deletion_record,
  irs_1099, uae_vat_201.

Deferred (tracked separately):
- setup/doctype/authorization_control.py still has raw `.format()` SELECTs;
  left for its own PR.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-19 14:37:50 +05:30

65 lines
1.8 KiB
Python

# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
import frappe
from frappe import _
from frappe.utils import flt
def get_context(context):
context.no_cache = 1
context.show_sidebar = True
context.doc = frappe.get_doc(frappe.form_dict.doctype, frappe.form_dict.name)
if hasattr(context.doc, "set_indicator"):
context.doc.set_indicator()
context.parents = frappe.form_dict.parents
context.title = frappe.form_dict.name
if not frappe.has_website_permission(context.doc):
frappe.throw(_("Not Permitted"), frappe.PermissionError)
default_print_format = frappe.db.get_value(
"Property Setter",
dict(property="default_print_format", doc_type=frappe.form_dict.doctype),
"value",
)
if default_print_format:
context.print_format = default_print_format
else:
context.print_format = "Standard"
context.doc.items = get_more_items_info(context.doc.items, context.doc.name)
def get_more_items_info(items, material_request):
for item in items:
item.customer_provided = frappe.get_value("Item", item.item_code, "is_customer_provided_item")
wo = frappe.qb.DocType("Work Order")
wo_item = frappe.qb.DocType("Work Order Item")
item.work_orders = (
frappe.qb.from_(wo_item)
.inner_join(wo)
.on(wo_item.parent == wo.name)
.select(wo.name, wo.status, wo_item.consumed_qty)
.where(
(wo_item.item_code == item.item_code)
& (wo_item.consumed_qty == 0)
& (wo.status.notin(["Completed", "Cancelled", "Stopped"]))
)
.orderby(wo.name)
.run(as_dict=1)
)
item.delivered_qty = flt(
frappe.get_all(
"Stock Entry Detail",
filters={
"material_request": material_request,
"item_code": item.item_code,
"docstatus": 1,
},
fields=[{"SUM": "transfer_qty", "as": "transfer_qty"}],
)[0].transfer_qty
)
return items