Merge pull request #62819 from mihir-kandoi/fix/standalone-pos-return-incoming-rate

fix: ask for incoming rate on standalone returns
This commit is contained in:
mergify[bot]
2026-10-28 15:10:02 +00:00
committed by GitHub
6 changed files with 67 additions and 7 deletions
@@ -86,6 +86,7 @@
"serial_and_batch_bundle",
"use_serial_batch_fields",
"col_break5",
"incoming_rate",
"allow_zero_valuation_rate",
"item_tax_rate",
"actual_batch_qty",
@@ -665,6 +666,16 @@
"fieldname": "col_break5",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:parent.is_return && parent.update_stock && !parent.return_against",
"fieldname": "incoming_rate",
"fieldtype": "Currency",
"label": "Incoming Rate (Costing)",
"no_copy": 1,
"non_negative": 1,
"options": "Company:company:default_currency",
"print_hide": 1
},
{
"default": "0",
"fieldname": "allow_zero_valuation_rate",
@@ -901,7 +912,7 @@
],
"istable": 1,
"links": [],
"modified": "2026-10-15 18:00:00.000000",
"modified": "2026-10-28 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice Item",
@@ -48,6 +48,7 @@ class POSInvoiceItem(SalesInvoiceItem):
has_item_scanned: DF.Check
image: DF.Attach | None
income_account: DF.Link
incoming_rate: DF.Currency
is_fixed_asset: DF.Check
is_free_item: DF.Check
item_code: DF.Link | None
@@ -236,7 +236,11 @@ class POSInvoiceMergeLog(Document):
item.amount = item.net_amount
item.base_amount = item.base_net_amount
item.price_list_rate = 0
si_item = map_child_doc(item, invoice, {"doctype": "Sales Invoice Item"})
si_item = map_child_doc(
item,
invoice,
{"doctype": "Sales Invoice Item", "field_map": {"incoming_rate": "incoming_rate"}},
)
si_item.pos_invoice = doc.name
si_item.pos_invoice_item = item.name
if doc.is_return:
@@ -6,6 +6,7 @@ from contextlib import contextmanager
import frappe
from frappe.utils import flt
import erpnext
from erpnext.accounts.doctype.coupon_code.test_coupon_code import test_create_test_data
from erpnext.accounts.doctype.mode_of_payment.test_mode_of_payment import (
set_default_account_for_mode_of_payment,
@@ -37,6 +38,16 @@ def rounding_method(method):
frappe.local.system_settings = None
@contextmanager
def perpetual_inventory(company):
previous = erpnext.is_perpetual_inventory_enabled(company)
frappe.local.enable_perpetual_inventory[company] = 1
try:
yield
finally:
frappe.local.enable_perpetual_inventory[company] = previous
def sell_over_the_counter(lines, discount_percentage=0):
item_code, qty, rate = lines[0]
sale = create_pos_invoice(item_code=item_code, qty=qty, rate=rate, do_not_save=True)
@@ -662,3 +673,23 @@ class TestPOSInvoiceMergeLog(ERPNextTestSuite):
flt(frappe.db.get_value("Sales Invoice", consolidated_name, "grand_total"), 2),
flt(handed_back, 2),
)
def test_consolidating_standalone_return_without_stock_history(self):
from erpnext.stock.doctype.item.test_item import make_item
frappe.db.set_value("Company", "_Test Company", "default_inventory_account", "Stock In Hand - _TC")
item_code = make_item("_Test Standalone POS Return Item", {"is_stock_item": 1}).name
pos_return = create_pos_invoice(item_code=item_code, qty=-1, rate=100, is_return=1, do_not_save=1)
pos_return.append("payments", {"mode_of_payment": "Cash", "account": "Cash - _TC", "amount": -100})
pos_return.paid_amount = pos_return.base_paid_amount = -100
with perpetual_inventory("_Test Company"):
self.assertRaises(frappe.ValidationError, pos_return.insert)
pos_return.items[0].incoming_rate = 80
pos_return.insert().submit()
self.make_closing_entry()
pos_return.load_from_db()
credit_note = frappe.get_doc("Sales Invoice", pos_return.consolidated_invoice)
self.assertEqual(credit_note.items[0].incoming_rate, 80)
+10 -4
View File
@@ -619,10 +619,18 @@ class SellingController(StockController):
):
d.incoming_rate = 0
if self.doctype not in ("Delivery Note", "Sales Invoice"):
is_standalone = self.get("is_return") and not self.get("return_against")
if self.doctype not in ("Delivery Note", "Sales Invoice") and not (
self.doctype == "POS Invoice" and is_standalone
):
return
if self.doctype == "Sales Invoice" and not self.update_stock and not self.is_internal_transfer():
if (
self.doctype in ("Sales Invoice", "POS Invoice")
and not self.update_stock
and not self.is_internal_transfer()
):
return
from erpnext.stock.serial_batch_bundle import get_batch_nos, get_serial_nos
@@ -634,8 +642,6 @@ 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:
+8 -1
View File
@@ -2781,7 +2781,14 @@ def get_valuation_rate(
+ "</li>"
)
sub_solutions = "<ul><li>" + _("Create an incoming stock transaction for the Item.") + "</li>"
sub_solutions += "<li>" + _("Mention Valuation Rate in the Item master.") + "</li></ul>"
if fallbacks:
sub_solutions += "<li>" + _("Mention Valuation Rate in the Item master.") + "</li></ul>"
else:
sub_solutions += (
"<li>"
+ _("Enter the Incoming Rate (Costing) in the {0} Item table.").format(voucher_type)
+ "</li></ul>"
)
msg = message + solutions + sub_solutions + "</li>"
frappe.throw(msg=msg, title=_("Valuation Rate Missing"))