fix: test case

This commit is contained in:
Rohit Waghchaure
2025-06-19 16:22:48 +05:30
parent 8c3ed5eccf
commit 2f0c0c2b59
6 changed files with 52 additions and 13 deletions

View File

@@ -839,7 +839,7 @@ class SellingController(StockController):
sre_doc = frappe.get_doc("Stock Reservation Entry", sre) sre_doc = frappe.get_doc("Stock Reservation Entry", sre)
qty_can_be_deliver = 0 qty_can_be_deliver = 0
if sre_doc.reservation_based_on == "Serial and Batch" and item.serial_and_batch_bundle: if sre_doc.reservation_based_on == "Serial and Batch":
sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle) sbb = frappe.get_doc("Serial and Batch Bundle", item.serial_and_batch_bundle)
if sre_doc.has_serial_no: if sre_doc.has_serial_no:
delivered_serial_nos = [d.serial_no for d in sbb.entries] delivered_serial_nos = [d.serial_no for d in sbb.entries]

View File

@@ -1100,7 +1100,13 @@ def make_delivery_note(source_name, target_doc=None, kwargs=None):
dn_item.qty = flt(sre.reserved_qty) / flt(dn_item.get("conversion_factor", 1)) dn_item.qty = flt(sre.reserved_qty) / flt(dn_item.get("conversion_factor", 1))
dn_item.warehouse = sre.warehouse dn_item.warehouse = sre.warehouse
if sre.reservation_based_on == "Serial and Batch" and (sre.has_serial_no or sre.has_batch_no): use_serial_batch_fields = frappe.get_single_value("Stock Settings", "use_serial_batch_fields")
if (
not use_serial_batch_fields
and sre.reservation_based_on == "Serial and Batch"
and (sre.has_serial_no or sre.has_batch_no)
):
dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre) dn_item.serial_and_batch_bundle = get_ssb_bundle_for_voucher(sre)
target_doc.append("items", dn_item) target_doc.append("items", dn_item)

View File

@@ -444,8 +444,6 @@ class DeliveryNote(SellingController):
self.update_prevdoc_status() self.update_prevdoc_status()
self.update_billing_status() self.update_billing_status()
self.update_stock_reservation_entries()
if not self.is_return: if not self.is_return:
self.check_credit_limit() self.check_credit_limit()
elif self.issue_credit_note: elif self.issue_credit_note:
@@ -458,6 +456,8 @@ class DeliveryNote(SellingController):
self.make_bundle_for_sales_purchase_return(table_name) self.make_bundle_for_sales_purchase_return(table_name)
self.make_bundle_using_old_serial_batch_fields(table_name) self.make_bundle_using_old_serial_batch_fields(table_name)
self.update_stock_reservation_entries()
# Updating stock ledger should always be called after updating prevdoc status, # Updating stock ledger should always be called after updating prevdoc status,
# because updating reserved qty in bin depends upon updated delivered qty in SO # because updating reserved qty in bin depends upon updated delivered qty in SO
self.update_stock_ledger() self.update_stock_ledger()

View File

@@ -1802,7 +1802,10 @@ def get_available_serial_nos(kwargs):
filters["warehouse"] = kwargs.warehouse filters["warehouse"] = kwargs.warehouse
# Since SLEs are not present against Reserved Stock [POS invoices, SRE], need to ignore reserved serial nos. # Since SLEs are not present against Reserved Stock [POS invoices, SRE], need to ignore reserved serial nos.
ignore_serial_nos = get_reserved_serial_nos(kwargs) ignore_serial_nos, consider_serial_nos = get_reserved_serial_nos(kwargs)
if consider_serial_nos:
filters["name"] = ("in", consider_serial_nos)
# To ignore serial nos in the same record for the draft state # To ignore serial nos in the same record for the draft state
if kwargs.get("ignore_serial_nos"): if kwargs.get("ignore_serial_nos"):
@@ -1911,19 +1914,23 @@ def get_reserved_serial_nos(kwargs) -> list:
"""Returns a list of `Serial No` reserved in POS Invoice and Stock Reservation Entry.""" """Returns a list of `Serial No` reserved in POS Invoice and Stock Reservation Entry."""
ignore_serial_nos = [] ignore_serial_nos = []
consider_serial_nos = []
# Extend the list by serial nos reserved in POS Invoice # Extend the list by serial nos reserved in POS Invoice
ignore_serial_nos.extend(get_reserved_serial_nos_for_pos(kwargs)) ignore_serial_nos.extend(get_reserved_serial_nos_for_pos(kwargs))
reserved_entries = get_reserved_serial_nos_for_sre(kwargs) reserved_entries = get_reserved_serial_nos_for_sre(kwargs)
if not reserved_entries: if not reserved_entries:
return ignore_serial_nos return ignore_serial_nos, consider_serial_nos
reserved_voucher_details = get_reserved_voucher_details(kwargs) reserved_voucher_details = get_reserved_voucher_details(kwargs)
if not reserved_voucher_details:
return ignore_serial_nos, consider_serial_nos
serial_nos = [] serial_nos = []
for entry in reserved_entries: for entry in reserved_entries:
if entry.voucher_no in reserved_voucher_details: if entry.voucher_no in reserved_voucher_details:
consider_serial_nos.append(entry.serial_no)
continue continue
if kwargs.get("serial_nos") and entry.serial_no in kwargs.get("serial_nos"): if kwargs.get("serial_nos") and entry.serial_no in kwargs.get("serial_nos"):
@@ -1939,7 +1946,7 @@ def get_reserved_serial_nos(kwargs) -> list:
# Extend the list by serial nos reserved via SRE # Extend the list by serial nos reserved via SRE
ignore_serial_nos.extend(serial_nos) ignore_serial_nos.extend(serial_nos)
return ignore_serial_nos return ignore_serial_nos, consider_serial_nos
def get_reserved_voucher_details(kwargs): def get_reserved_voucher_details(kwargs):
@@ -1958,15 +1965,15 @@ def get_reserved_voucher_details(kwargs):
"Delivery Note": { "Delivery Note": {
"name": kwargs.get("sabb_voucher_detail_no"), "name": kwargs.get("sabb_voucher_detail_no"),
"parent": kwargs.get("sabb_voucher_no"), "parent": kwargs.get("sabb_voucher_no"),
"docstatus": 1, "docstatus": ("<", 2),
}, },
"Stock Entry": { "Stock Entry": {
"name": kwargs.get("sabb_voucher_no"), "name": kwargs.get("sabb_voucher_no"),
"docstatus": 1, "docstatus": ("<", 2),
}, },
"Work Order": { "Work Order": {
"name": kwargs.get("sabb_voucher_no"), "name": kwargs.get("sabb_voucher_no"),
"docstatus": 1, "docstatus": ("<", 2),
}, },
}.get(kwargs.get("sabb_voucher_type")) }.get(kwargs.get("sabb_voucher_type"))

View File

@@ -5,7 +5,7 @@ from random import randint
import frappe import frappe
from frappe.tests import IntegrationTestCase from frappe.tests import IntegrationTestCase
from frappe.utils import today from frappe.utils import cint, today
from erpnext.selling.doctype.sales_order.sales_order import create_pick_list, make_delivery_note from erpnext.selling.doctype.sales_order.sales_order import create_pick_list, make_delivery_note
from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order
@@ -250,6 +250,8 @@ class TestStockReservationEntry(IntegrationTestCase):
}, },
) )
def test_stock_reservation_against_sales_order(self) -> None: def test_stock_reservation_against_sales_order(self) -> None:
from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
items_details = create_items() items_details = create_items()
se = create_material_receipt(items_details, self.warehouse, qty=10) se = create_material_receipt(items_details, self.warehouse, qty=10)
@@ -326,16 +328,29 @@ class TestStockReservationEntry(IntegrationTestCase):
so = make_sales_order( so = make_sales_order(
item_list=item_list, item_list=item_list,
warehouse=self.warehouse, warehouse=self.warehouse,
do_not_submit=True,
) )
for row in so.items:
row.qty = 80
so.save()
so.submit()
so.create_stock_reservation_entries() so.create_stock_reservation_entries()
# Test - 7: Partial Delivery against Sales Order. # Test - 7: Partial Delivery against Sales Order.
dn1 = make_delivery_note(so.name) dn1 = make_delivery_note(so.name)
item_wise_serial_nos = {}
for item in dn1.items: for item in dn1.items:
item.qty = randint(1, 10) item.qty = 10
dn1.save() dn1.save()
for row in dn1.items:
if row.serial_no:
item_wise_serial_nos.setdefault(row.item_code, []).extend(get_serial_nos(row.serial_no))
dn1.submit() dn1.submit()
for item in so.items: for item in so.items:
@@ -350,9 +365,17 @@ class TestStockReservationEntry(IntegrationTestCase):
dn2 = make_delivery_note(so.name) dn2 = make_delivery_note(so.name)
for item in dn2.items: for item in dn2.items:
item.qty += randint(1, 10) item.qty = 80
dn2.save() dn2.save()
for row in dn2.items:
if row.item_code in item_wise_serial_nos:
consumed_serial_no = ", ".join(item_wise_serial_nos[row.item_code])
picked_serial_no = get_serial_nos(row.serial_no)
serial_nos = list(set(picked_serial_no) - set(consumed_serial_no))
row.serial_no = "\n".join(serial_nos)
dn2.submit() dn2.submit()
for item in so.items: for item in so.items:

View File

@@ -202,6 +202,9 @@ def update_stock(ctx, out, doc=None):
"item_code": ctx.item_code, "item_code": ctx.item_code,
"warehouse": ctx.warehouse, "warehouse": ctx.warehouse,
"based_on": frappe.get_single_value("Stock Settings", "pick_serial_and_batch_based_on"), "based_on": frappe.get_single_value("Stock Settings", "pick_serial_and_batch_based_on"),
"sabb_voucher_no": doc.get("name"),
"sabb_voucher_detail_no": ctx.child_docname,
"sabb_voucher_type": ctx.doctype,
} }
) )