mirror of
https://github.com/frappe/erpnext.git
synced 2026-02-15 15:45:01 +00:00
fix: sales return for product bundle items
(cherry picked from commit 13ce7279a8)
This commit is contained in:
committed by
Mergify
parent
6e55f53cf6
commit
ac46b3d1ca
@@ -852,10 +852,10 @@ def get_available_serial_batches(field, doctype, reference_ids, is_rejected=Fals
|
||||
if not _bundle_ids:
|
||||
return frappe._dict({})
|
||||
|
||||
return get_serial_batches_based_on_bundle(field, _bundle_ids)
|
||||
return get_serial_batches_based_on_bundle(doctype, field, _bundle_ids)
|
||||
|
||||
|
||||
def get_serial_batches_based_on_bundle(field, _bundle_ids):
|
||||
def get_serial_batches_based_on_bundle(doctype, field, _bundle_ids):
|
||||
available_dict = frappe._dict({})
|
||||
batch_serial_nos = frappe.get_all(
|
||||
"Serial and Batch Bundle",
|
||||
@@ -867,6 +867,7 @@ def get_serial_batches_based_on_bundle(field, _bundle_ids):
|
||||
"`tabSerial and Batch Bundle`.`voucher_detail_no`",
|
||||
"`tabSerial and Batch Bundle`.`voucher_type`",
|
||||
"`tabSerial and Batch Bundle`.`voucher_no`",
|
||||
"`tabSerial and Batch Bundle`.`item_code`",
|
||||
],
|
||||
filters=[
|
||||
["Serial and Batch Bundle", "name", "in", _bundle_ids],
|
||||
@@ -880,6 +881,9 @@ def get_serial_batches_based_on_bundle(field, _bundle_ids):
|
||||
if frappe.get_cached_value(row.voucher_type, row.voucher_no, "is_return"):
|
||||
key = frappe.get_cached_value(row.voucher_type + " Item", row.voucher_detail_no, field)
|
||||
|
||||
if doctype == "Packed Item":
|
||||
key = (row.item_code, key)
|
||||
|
||||
if row.voucher_type in ["Sales Invoice", "Delivery Note"]:
|
||||
row.qty = -1 * row.qty
|
||||
|
||||
@@ -908,6 +912,8 @@ def get_serial_batches_based_on_bundle(field, _bundle_ids):
|
||||
|
||||
def get_serial_and_batch_bundle(field, doctype, reference_ids, is_rejected=False):
|
||||
filters = {"docstatus": 1, "name": ("in", reference_ids), "serial_and_batch_bundle": ("is", "set")}
|
||||
if doctype == "Packed Item":
|
||||
filters = {"docstatus": 1, field: ("in", reference_ids), "serial_and_batch_bundle": ("is", "set")}
|
||||
|
||||
pluck_field = "serial_and_batch_bundle"
|
||||
if is_rejected:
|
||||
@@ -921,10 +927,14 @@ def get_serial_and_batch_bundle(field, doctype, reference_ids, is_rejected=False
|
||||
pluck=pluck_field,
|
||||
)
|
||||
|
||||
if _bundle_ids and doctype == "Packed Item":
|
||||
return _bundle_ids
|
||||
|
||||
if not _bundle_ids:
|
||||
return {}
|
||||
|
||||
del filters["name"]
|
||||
if "name" in filters:
|
||||
del filters["name"]
|
||||
|
||||
filters[field] = ("in", reference_ids)
|
||||
|
||||
@@ -971,6 +981,9 @@ def filter_serial_batches(parent_doc, data, row, warehouse_field=None, qty_field
|
||||
if not qty_field:
|
||||
qty_field = "stock_qty"
|
||||
|
||||
if not hasattr(row, qty_field):
|
||||
qty_field = "qty"
|
||||
|
||||
if not warehouse_field:
|
||||
warehouse_field = "warehouse"
|
||||
|
||||
@@ -1060,6 +1073,9 @@ def make_serial_batch_bundle_for_return(data, child_doc, parent_doc, warehouse_f
|
||||
if not qty_field:
|
||||
qty_field = "stock_qty"
|
||||
|
||||
if not hasattr(child_doc, qty_field):
|
||||
qty_field = "qty"
|
||||
|
||||
warehouse = child_doc.get(warehouse_field)
|
||||
if parent_doc.get("is_internal_customer"):
|
||||
warehouse = child_doc.get("target_warehouse")
|
||||
|
||||
@@ -517,8 +517,15 @@ class SellingController(StockController):
|
||||
if not frappe.get_cached_value("Item", d.item_code, "is_stock_item"):
|
||||
continue
|
||||
|
||||
item_details = frappe.get_cached_value(
|
||||
"Item", d.item_code, ["has_serial_no", "has_batch_no"], as_dict=1
|
||||
)
|
||||
|
||||
if not self.get("return_against") or (
|
||||
get_valuation_method(d.item_code) == "Moving Average" and self.get("is_return")
|
||||
get_valuation_method(d.item_code) == "Moving Average"
|
||||
and self.get("is_return")
|
||||
and not item_details.has_serial_no
|
||||
and not item_details.has_batch_no
|
||||
):
|
||||
# Get incoming rate based on original item cost based on valuation method
|
||||
qty = flt(d.get("stock_qty") or d.get("actual_qty") or d.get("qty"))
|
||||
|
||||
@@ -335,10 +335,20 @@ class StockController(AccountsController):
|
||||
return
|
||||
|
||||
child_doctype = self.doctype + " Item"
|
||||
if table_name == "packed_items":
|
||||
field = "parent_detail_docname"
|
||||
child_doctype = "Packed Item"
|
||||
|
||||
available_dict = available_serial_batch_for_return(field, child_doctype, reference_ids)
|
||||
|
||||
for row in self.get(table_name):
|
||||
if data := available_dict.get(row.get(field)):
|
||||
value = row.get(field)
|
||||
if table_name == "packed_items" and row.get("parent_detail_docname"):
|
||||
value = self.get_value_for_packed_item(row)
|
||||
if not value:
|
||||
continue
|
||||
|
||||
if data := available_dict.get(value):
|
||||
data = filter_serial_batches(self, data, row)
|
||||
bundle = make_serial_batch_bundle_for_return(data, row, self)
|
||||
row.db_set(
|
||||
@@ -354,6 +364,14 @@ class StockController(AccountsController):
|
||||
"incoming_rate", frappe.db.get_value("Serial and Batch Bundle", bundle, "avg_rate")
|
||||
)
|
||||
|
||||
def get_value_for_packed_item(self, row):
|
||||
parent_items = self.get("items", {"name": row.parent_detail_docname})
|
||||
if parent_items:
|
||||
ref = parent_items[0].get("dn_detail")
|
||||
return (row.item_code, ref)
|
||||
|
||||
return None
|
||||
|
||||
def get_reference_ids(self, table_name, qty_field=None, bundle_field=None) -> tuple[str, list[str]]:
|
||||
field = {
|
||||
"Sales Invoice": "sales_invoice_item",
|
||||
@@ -388,6 +406,12 @@ class StockController(AccountsController):
|
||||
):
|
||||
reference_ids.append(row.get(field))
|
||||
|
||||
if table_name == "packed_items" and row.get("parent_detail_docname"):
|
||||
parent_rows = self.get("items", {"name": row.parent_detail_docname}) or []
|
||||
for d in parent_rows:
|
||||
if d.get(field) and not d.get(bundle_field):
|
||||
reference_ids.append(d.get(field))
|
||||
|
||||
return field, reference_ids
|
||||
|
||||
@frappe.request_cache
|
||||
|
||||
@@ -638,6 +638,17 @@ class SerialandBatchBundle(Document):
|
||||
if not rate and self.voucher_detail_no and self.voucher_no:
|
||||
rate = frappe.db.get_value(child_table, self.voucher_detail_no, valuation_field)
|
||||
|
||||
is_packed_item = False
|
||||
if rate is None and child_table == "Delivery Note Item":
|
||||
rate = frappe.db.get_value(
|
||||
"Packed Item",
|
||||
self.voucher_detail_no,
|
||||
"incoming_rate",
|
||||
)
|
||||
|
||||
if rate is not None:
|
||||
is_packed_item = True
|
||||
|
||||
stock_queue = []
|
||||
batches = []
|
||||
if prev_sle and prev_sle.stock_queue:
|
||||
@@ -659,6 +670,9 @@ class SerialandBatchBundle(Document):
|
||||
elif (d.incoming_rate == rate) and not stock_queue and d.qty and d.stock_value_difference:
|
||||
continue
|
||||
|
||||
if is_packed_item and d.incoming_rate:
|
||||
rate = d.incoming_rate
|
||||
|
||||
d.incoming_rate = flt(rate)
|
||||
if d.qty:
|
||||
d.stock_value_difference = flt(d.qty) * d.incoming_rate
|
||||
|
||||
Reference in New Issue
Block a user