get_default_contact / get_default_address: raw correlated-subquery SELECTs over
Dynamic Link -> frappe.qb with a LEFT join (preserving the original
correlated-subquery semantics: a Dynamic Link whose parent Contact/Address is
missing still returns, with a NULL flag). Same result on MariaDB; valid under
Postgres.
Tests: pin the converted query output (real linked Contact/Address) and lock
the LEFT-join choice with an orphaned-Dynamic-Link case (fails under an inner
join).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
update_billed_amount_based_on_so: raw "select sum(amount) ... where
dn_detail=%s and docstatus=1" -> frappe.get_all(fields=[{SUM: amount}]); the
bare aggregate needs no GROUP BY and the NULL-sum still resolves to 0. Same
result on MariaDB; valid under Postgres. Covered by the existing billing tests
in test_delivery_note.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
cancel_packing_slips: raw "SELECT name FROM `tabPacking Slip` WHERE
delivery_note=%s AND docstatus=1" -> frappe.get_all(pluck="name") with
pluck-aware iteration. Same result on MariaDB; valid under Postgres.
Covered by test_cancel_packing_slips_cancels_submitted_slips in
test_delivery_note.py.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
set_actual_qty Bin lookup -> frappe.db.get_value; validate_proj_cust raw
"customer=%s OR ifnull(customer,'')=''" -> get_all or_filters with
[customer, is, not set] (correct PG empty-string/NULL handling); the two
check_next_docstatus implicit comma-joins -> get_all on the child table
(Sales Invoice Item / Installation Note Item, docstatus=1). Same result on
MariaDB; valid under Postgres.
Tests: validate_proj_cust mismatch + no-customer (the or_filters branch), and
check_next_docstatus blocking cancel when a submitted Sales Invoice draws from
the DN.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw SELECT with get_match_cond in item_details with
frappe.qb.get_query(ignore_permissions=False) plus a Delivery Note Item
subquery; get_query applies the permission match conditions. Same result on
MariaDB; valid under Postgres.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the get_all(limit=1, pluck) existence checks with frappe.db.exists and
the no-own-valuation-method Stock Ledger Entry EXISTS with a frappe.qb
subquery (null-or-empty valuation_method preserved). Same result on MariaDB;
valid under Postgres.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the on_trash Stock Ledger Entry serial-match SELECT and the
update_maintenance_status expiry SELECT with frappe.get_all (or_filters for
the amc/warranty expiry OR). Same result on MariaDB; valid under Postgres.
Tests: maintenance-status expiry transition, the not-in exclusion (with a
negative-control candidate), and NULL-status handling.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw f-string UPDATE (name + production_item match) that links a
Quality Inspection back to its Job Card with frappe.qb.update. Same result on
MariaDB; valid under Postgres.
Tests: the Job Card reference update and its production_item scoping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw UPDATE ... modified=NOW() in update_item_price with
frappe.qb.update (now() for modified). Same result on MariaDB; valid under
Postgres.
Tests: currency/buying/selling/modified propagation and price-list scoping.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw UNION of forward/two-way alternative-item matches with two
frappe.get_all calls, order-preserving dedup (dict.fromkeys) and Python
pagination. Each leg is bounded to start+page_len rows so the per-keystroke
search round trip stays small (the original bounded with LIMIT/OFFSET);
ItemAlternative forbids duplicate (item_code, alternative_item_code) pairs, so
each leg is internally distinct and that bound is exact. Same result on
MariaDB; valid under Postgres.
Tests: both-direction dedup, txt filtering, pagination, bounded-and-exact
page-walk reconstruction, and case-insensitive (ILIKE-on-Postgres) matching.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw lft/rgt SELECT with frappe.get_all(pluck="name"). Same result
on MariaDB; valid under Postgres.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Replace the raw EXISTS subquery (items within an item-group subtree) with
frappe.qb (item_group.isin(subquery)). Same result on MariaDB; valid under
Postgres' stricter SQL.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
make_timesheet(simulate=True) logs at now_datetime(); when the suite runs late
in the day under the site timezone the 2h log crosses midnight, so its to_time
falls outside the report's `to_time <= end-of-day` bound and the submitted
timesheet is (correctly) excluded — making test_submitted_timesheet_in_summary
fail in an evening window (observed at 22:51 IST in CI). Pin the log to a fixed
mid-day window on today so the assertion is time-of-day independent.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>