mirror of
https://github.com/frappe/erpnext.git
synced 2026-03-13 07:18:27 +00:00
fix: standalone sales invoice return should not fallback to item master for valuation rate
(cherry picked from commit a85a0aef52)
This commit is contained in:
@@ -843,6 +843,7 @@
|
||||
"fieldtype": "Currency",
|
||||
"label": "Incoming Rate (Costing)",
|
||||
"no_copy": 1,
|
||||
"non_negative": 1,
|
||||
"options": "Company:company:default_currency",
|
||||
"print_hide": 1
|
||||
},
|
||||
@@ -1009,7 +1010,7 @@
|
||||
"idx": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-02-15 21:08:57.341638",
|
||||
"modified": "2026-02-23 14:37:14.853941",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice Item",
|
||||
|
||||
@@ -444,6 +444,7 @@ class TestGrossProfit(IntegrationTestCase):
|
||||
qty=-1, rate=100, posting_date=nowdate(), do_not_save=True, do_not_submit=True
|
||||
)
|
||||
sinv.is_return = 1
|
||||
sinv.items[0].allow_zero_valuation_rate = 1
|
||||
sinv = sinv.save().submit()
|
||||
|
||||
filters = frappe._dict(
|
||||
|
||||
@@ -498,10 +498,34 @@ class SellingController(StockController):
|
||||
sales_order.update_reserved_qty(so_item_rows)
|
||||
|
||||
def set_incoming_rate(self):
|
||||
def reset_incoming_rate():
|
||||
old_item = next(
|
||||
(
|
||||
item
|
||||
for item in (old_doc.get("items") + (old_doc.get("packed_items") or []))
|
||||
if item.name == d.name
|
||||
),
|
||||
None,
|
||||
)
|
||||
if old_item:
|
||||
old_qty = flt(old_item.get("stock_qty") or old_item.get("actual_qty") or old_item.get("qty"))
|
||||
if (
|
||||
old_item.item_code != d.item_code
|
||||
or old_item.warehouse != d.warehouse
|
||||
or old_qty != qty
|
||||
or old_item.serial_no != d.serial_no
|
||||
or get_serial_nos(old_item.serial_and_batch_bundle)
|
||||
!= get_serial_nos(d.serial_and_batch_bundle)
|
||||
or old_item.batch_no != d.batch_no
|
||||
or get_batch_nos(old_item.serial_and_batch_bundle)
|
||||
!= get_batch_nos(d.serial_and_batch_bundle)
|
||||
):
|
||||
d.incoming_rate = 0
|
||||
|
||||
if self.doctype not in ("Delivery Note", "Sales Invoice"):
|
||||
return
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import get_batch_nos
|
||||
from erpnext.stock.serial_batch_bundle import get_batch_nos, get_serial_nos
|
||||
|
||||
allow_at_arms_length_price = frappe.get_cached_value(
|
||||
"Stock Settings", None, "allow_internal_transfer_at_arms_length_price"
|
||||
@@ -510,6 +534,8 @@ class SellingController(StockController):
|
||||
"Selling Settings", "set_zero_rate_for_expired_batch"
|
||||
)
|
||||
|
||||
is_standalone = self.is_return and not self.return_against
|
||||
|
||||
old_doc = self.get_doc_before_save()
|
||||
items = self.get("items") + (self.get("packed_items") or [])
|
||||
for d in items:
|
||||
@@ -541,27 +567,7 @@ class SellingController(StockController):
|
||||
qty = flt(d.get("stock_qty") or d.get("actual_qty") or d.get("qty"))
|
||||
|
||||
if old_doc:
|
||||
old_item = next(
|
||||
(
|
||||
item
|
||||
for item in (old_doc.get("items") + (old_doc.get("packed_items") or []))
|
||||
if item.name == d.name
|
||||
),
|
||||
None,
|
||||
)
|
||||
if old_item:
|
||||
old_qty = flt(
|
||||
old_item.get("stock_qty") or old_item.get("actual_qty") or old_item.get("qty")
|
||||
)
|
||||
if (
|
||||
old_item.item_code != d.item_code
|
||||
or old_item.warehouse != d.warehouse
|
||||
or old_qty != qty
|
||||
or old_item.batch_no != d.batch_no
|
||||
or get_batch_nos(old_item.serial_and_batch_bundle)
|
||||
!= get_batch_nos(d.serial_and_batch_bundle)
|
||||
):
|
||||
d.incoming_rate = 0
|
||||
reset_incoming_rate()
|
||||
|
||||
if (
|
||||
not d.incoming_rate
|
||||
@@ -583,11 +589,12 @@ class SellingController(StockController):
|
||||
"voucher_type": self.doctype,
|
||||
"voucher_no": self.name,
|
||||
"voucher_detail_no": d.name,
|
||||
"allow_zero_valuation": d.get("allow_zero_valuation"),
|
||||
"allow_zero_valuation": d.get("allow_zero_valuation_rate"),
|
||||
"batch_no": d.batch_no,
|
||||
"serial_no": d.serial_no,
|
||||
},
|
||||
raise_error_if_no_rate=False,
|
||||
raise_error_if_no_rate=is_standalone,
|
||||
fallbacks=not is_standalone,
|
||||
)
|
||||
|
||||
if (
|
||||
|
||||
@@ -1910,6 +1910,7 @@ def get_valuation_rate(
|
||||
allow_zero_rate=False,
|
||||
currency=None,
|
||||
company=None,
|
||||
fallbacks=True,
|
||||
raise_error_if_no_rate=True,
|
||||
batch_no=None,
|
||||
serial_and_batch_bundle=None,
|
||||
@@ -1970,23 +1971,20 @@ def get_valuation_rate(
|
||||
):
|
||||
return flt(last_valuation_rate[0][0])
|
||||
|
||||
# If negative stock allowed, and item delivered without any incoming entry,
|
||||
# system does not found any SLE, then take valuation rate from Item
|
||||
valuation_rate = frappe.db.get_value("Item", item_code, "valuation_rate")
|
||||
|
||||
if not valuation_rate:
|
||||
# try Item Standard rate
|
||||
valuation_rate = frappe.db.get_value("Item", item_code, "standard_rate")
|
||||
|
||||
if not valuation_rate:
|
||||
# try in price list
|
||||
valuation_rate = frappe.db.get_value(
|
||||
if fallbacks:
|
||||
# If negative stock allowed, and item delivered without any incoming entry,
|
||||
# system does not found any SLE, then take valuation rate from Item
|
||||
if rate := (
|
||||
frappe.db.get_value("Item", item_code, "valuation_rate")
|
||||
or frappe.db.get_value("Item", item_code, "standard_rate")
|
||||
or frappe.db.get_value(
|
||||
"Item Price", dict(item_code=item_code, buying=1, currency=currency), "price_list_rate"
|
||||
)
|
||||
):
|
||||
return flt(rate)
|
||||
|
||||
if (
|
||||
not allow_zero_rate
|
||||
and not valuation_rate
|
||||
and raise_error_if_no_rate
|
||||
and cint(erpnext.is_perpetual_inventory_enabled(company))
|
||||
):
|
||||
@@ -2016,8 +2014,6 @@ def get_valuation_rate(
|
||||
|
||||
frappe.throw(msg=msg, title=_("Valuation Rate Missing"))
|
||||
|
||||
return valuation_rate
|
||||
|
||||
|
||||
def update_qty_in_future_sle(args, allow_negative_stock=False):
|
||||
"""Recalculate Qty after Transaction in future SLEs based on current SLE."""
|
||||
|
||||
@@ -237,7 +237,7 @@ def _create_bin(item_code, warehouse):
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_incoming_rate(args, raise_error_if_no_rate=True):
|
||||
def get_incoming_rate(args, raise_error_if_no_rate=True, fallbacks: bool = True):
|
||||
"""Get Incoming Rate based on valuation method"""
|
||||
from erpnext.stock.stock_ledger import get_previous_sle, get_valuation_rate
|
||||
|
||||
@@ -325,6 +325,7 @@ def get_incoming_rate(args, raise_error_if_no_rate=True):
|
||||
args.get("allow_zero_valuation"),
|
||||
currency=erpnext.get_company_currency(args.get("company")),
|
||||
company=args.get("company"),
|
||||
fallbacks=fallbacks,
|
||||
raise_error_if_no_rate=raise_error_if_no_rate,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user