Files
erpnext/erpnext/stock/tests
Jatin3128 c1717d8689 fix: keep source rate on re-fetch when maintain same rate is enabled (#57479)
* fix: keep source rate on re-fetch when maintain same rate is enabled

With "maintain same rate" on, re-fetching item details on a row mapped from a
source document (e.g. a Purchase Order) pulled the latest Item Price, giving a
rate the document can never be saved with. Skip the price list fetch for such
rows and keep the source rate.

Fixes frappe/erpnext#57436

* fix: keep source rate on bulk apply_price_list when maintain same rate is on

The single-row re-fetch guard skipped the bulk apply_price_list path, so
changing the price list, party, or conversion rate on a mapped transaction
re-fetched current Item Prices and overwrote the mapped rates, breaking the
maintain-same-rate check on save.

Guard apply_price_list_on_item with the same source-row lookup, and resolve the
parent doctype via ctx.parenttype since the bulk path carries the child doctype
in ctx.doctype.

* fix: preserve full source pricing on rate-locked rows

Restoring only price_list_rate on a mapped row dropped any manual discount or
margin, so re-running pricing produced a rate that differed from the source and
still failed the maintain-same-rate check on save.

Copy the source row's whole pricing block (rate, discount, margin) and skip
pricing rules for locked rows, in both get_item_details and the bulk
apply_price_list path.

* fix: pass child_docname in server bulk price apply so the rate lock is reachable

The server-side _apply_price_list builds its item ctx from as_dict(), which omits
the child_docname key the desk (JS) callers add, so the maintain-same-rate lock in
apply_price_list could not match rows in that path. Pass child_docname for
consistency with the desk callers.

* test: cover maintain-same-rate preservation on re-fetch of a discounted row

Reproduces the end-to-end symptom: a mapped Purchase Receipt row with a source
discount (rate != price_list_rate) keeps its rate after a re-fetch, so the
document saves under maintain-same-rate. Covers percentage and amount discounts
via process_item_selection, the server recompute the desk mirrors.

* fix: read the locked rate from the persisted source row

get_rate_locked_source_row returned the mutable target row, so an unsaved rate or
discount edit on a mapped row was preserved on re-fetch instead of the source
pricing, and the document still failed maintain-same-rate on save. Read the
pricing straight from the linked source row in the database, and cover the
edit-then-refresh case with a test.

* fix: permission-check the source row before returning its rate

The rate lock reads the linked source row with a direct db.get_value, which
bypasses permissions on a whitelisted endpoint. Only return the source pricing
when the caller can read the source document, so a crafted request cannot
disclose another document's rate. Covered by a test.

* fix: import make_purchase_receipt from its current mapper module

make_purchase_receipt moved from purchase_order.py to
purchase_order/mapper.py in a develop refactor pulled in by this
branch's merge commit. Two tests added afterwards still imported it
from the old path, failing CI with an ImportError.

* fix: Simplify source retrieval logic in get_item_details

Removed permission check for source parent in get_item_details.py.

* Revert "fix: Simplify source retrieval logic in get_item_details"

This reverts commit 58863805bd.
2026-08-04 13:28:57 +05:30
..