fix: use serial/batch fields for subcontracting receipt and in transit stock entry
This commit is contained in:
@@ -140,6 +140,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
- Create partial SCR against the SCO and check serial nos and batch no.
|
||||
"""
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
@@ -202,6 +203,8 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
if value.get(field):
|
||||
self.assertEqual(value.get(field), transferred_detais.get(field))
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||
|
||||
def test_subcontracting_with_same_components_different_fg(self):
|
||||
"""
|
||||
- Set backflush based on Material Transfer.
|
||||
@@ -211,6 +214,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
- Create partial SCR against the SCO and check serial nos.
|
||||
"""
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
@@ -278,6 +282,8 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
self.assertEqual(value.qty, 6)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[6:12]))
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||
|
||||
def test_return_non_consumed_materials(self):
|
||||
"""
|
||||
- Set backflush based on Material Transfer.
|
||||
@@ -288,6 +294,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
- After that return the non consumed material back to the store from supplier's warehouse.
|
||||
"""
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
@@ -333,6 +340,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
get_serial_nos(doc.items[0].serial_no),
|
||||
itemwise_details.get(doc.items[0].item_code)["serial_no"][5:6],
|
||||
)
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||
|
||||
def test_item_with_batch_based_on_bom(self):
|
||||
"""
|
||||
@@ -578,6 +586,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
- Create SCR for remaining qty against the SCO and change the qty manually.
|
||||
"""
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
@@ -643,6 +652,8 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
self.assertEqual(value.qty, details.qty)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(details.serial_no))
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||
|
||||
def test_incorrect_serial_no_components_based_on_material_transfer(self):
|
||||
"""
|
||||
- Set backflush based on Material Transferred for Subcontract.
|
||||
@@ -652,6 +663,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
- System should throw the error and not allowed to save the SCR.
|
||||
"""
|
||||
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 0)
|
||||
serial_no = "ABC"
|
||||
if not frappe.db.exists("Serial No", serial_no):
|
||||
frappe.get_doc(
|
||||
@@ -712,6 +724,7 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
scr1.save()
|
||||
self.delete_bundle_from_scr(scr1)
|
||||
scr1.delete()
|
||||
frappe.db.set_single_value("Stock Settings", "use_serial_batch_fields", 1)
|
||||
|
||||
@staticmethod
|
||||
def delete_bundle_from_scr(scr):
|
||||
@@ -844,6 +857,223 @@ class TestSubcontractingController(FrappeTestCase):
|
||||
for item in sco.get("supplied_items"):
|
||||
self.assertEqual(item.supplied_qty, 0.0)
|
||||
|
||||
def test_sco_with_material_transfer_with_use_serial_batch_fields(self):
|
||||
"""
|
||||
- Set backflush based on Material Transfer.
|
||||
- Create SCO for the item Subcontracted Item SA1 and Subcontracted Item SA5.
|
||||
- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
|
||||
- Transfer extra item Subcontracted SRM Item 4 for the subcontract item Subcontracted Item SA5.
|
||||
- Create partial SCR against the SCO and check serial nos and batch no.
|
||||
"""
|
||||
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 1",
|
||||
"qty": 5,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA1",
|
||||
"fg_item_qty": 5,
|
||||
},
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 5",
|
||||
"qty": 6,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA5",
|
||||
"fg_item_qty": 6,
|
||||
},
|
||||
]
|
||||
sco = get_subcontracting_order(service_items=service_items)
|
||||
rm_items = get_rm_items(sco.supplied_items)
|
||||
rm_items.append(
|
||||
{
|
||||
"main_item_code": "Subcontracted Item SA5",
|
||||
"item_code": "Subcontracted SRM Item 4",
|
||||
"qty": 6,
|
||||
}
|
||||
)
|
||||
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||
|
||||
for item in rm_items:
|
||||
item["sco_rm_detail"] = sco.items[0].name if item.get("qty") == 5 else sco.items[1].name
|
||||
|
||||
make_stock_transfer_entry(
|
||||
sco_no=sco.name,
|
||||
rm_items=rm_items,
|
||||
itemwise_details=copy.deepcopy(itemwise_details),
|
||||
)
|
||||
|
||||
scr1 = make_subcontracting_receipt(sco.name)
|
||||
scr1.remove(scr1.items[1])
|
||||
scr1.save()
|
||||
scr1.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr1).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
|
||||
for field in ["qty", "serial_no", "batch_no"]:
|
||||
if value.get(field):
|
||||
data = value.get(field)
|
||||
if field == "serial_no":
|
||||
data = sorted(data)
|
||||
|
||||
self.assertEqual(data, transferred_detais.get(field))
|
||||
|
||||
scr2 = make_subcontracting_receipt(sco.name)
|
||||
scr2.save()
|
||||
scr2.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr2).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
|
||||
for field in ["qty", "serial_no", "batch_no"]:
|
||||
if value.get(field):
|
||||
data = value.get(field)
|
||||
if field == "serial_no":
|
||||
data = sorted(data)
|
||||
|
||||
self.assertEqual(data, transferred_detais.get(field))
|
||||
|
||||
def test_subcontracting_with_same_components_different_fg_with_serial_batch_fields(self):
|
||||
"""
|
||||
- Set backflush based on Material Transfer.
|
||||
- Create SCO for the item Subcontracted Item SA2 and Subcontracted Item SA3.
|
||||
- Transfer the components from Stores to Supplier warehouse with serial nos.
|
||||
- Transfer extra qty of components for the item Subcontracted Item SA2.
|
||||
- Create partial SCR against the SCO and check serial nos.
|
||||
"""
|
||||
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 2",
|
||||
"qty": 5,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA2",
|
||||
"fg_item_qty": 5,
|
||||
},
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 3",
|
||||
"qty": 6,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA3",
|
||||
"fg_item_qty": 6,
|
||||
},
|
||||
]
|
||||
sco = get_subcontracting_order(service_items=service_items)
|
||||
rm_items = get_rm_items(sco.supplied_items)
|
||||
rm_items[0]["qty"] += 1
|
||||
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||
|
||||
for item in rm_items:
|
||||
item["sco_rm_detail"] = sco.items[0].name if item.get("qty") == 5 else sco.items[1].name
|
||||
item["use_serial_batch_fields"] = 1
|
||||
|
||||
make_stock_transfer_entry(
|
||||
sco_no=sco.name,
|
||||
rm_items=rm_items,
|
||||
itemwise_details=copy.deepcopy(itemwise_details),
|
||||
)
|
||||
|
||||
scr1 = make_subcontracting_receipt(sco.name)
|
||||
scr1.items[0].qty = 3
|
||||
scr1.remove(scr1.items[1])
|
||||
scr1.save()
|
||||
scr1.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr1).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
|
||||
self.assertEqual(value.qty, 4)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[0:4]))
|
||||
|
||||
scr2 = make_subcontracting_receipt(sco.name)
|
||||
scr2.items[0].qty = 2
|
||||
scr2.remove(scr2.items[1])
|
||||
scr2.save()
|
||||
scr2.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr2).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
|
||||
self.assertEqual(value.qty, 2)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[4:6]))
|
||||
|
||||
scr3 = make_subcontracting_receipt(sco.name)
|
||||
scr3.save()
|
||||
scr3.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr3).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
|
||||
self.assertEqual(value.qty, 6)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[6:12]))
|
||||
|
||||
def test_return_non_consumed_materials_with_serial_batch_fields(self):
|
||||
"""
|
||||
- Set backflush based on Material Transfer.
|
||||
- Create SCO for item Subcontracted Item SA2.
|
||||
- Transfer the components from Stores to Supplier warehouse with serial nos.
|
||||
- Transfer extra qty of component for the subcontracted item Subcontracted Item SA2.
|
||||
- Create SCR for full qty against the SCO and change the qty of raw material.
|
||||
- After that return the non consumed material back to the store from supplier's warehouse.
|
||||
"""
|
||||
|
||||
set_backflush_based_on("Material Transferred for Subcontract")
|
||||
service_items = [
|
||||
{
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"item_code": "Subcontracted Service Item 2",
|
||||
"qty": 5,
|
||||
"rate": 100,
|
||||
"fg_item": "Subcontracted Item SA2",
|
||||
"fg_item_qty": 5,
|
||||
},
|
||||
]
|
||||
sco = get_subcontracting_order(service_items=service_items)
|
||||
rm_items = get_rm_items(sco.supplied_items)
|
||||
rm_items[0]["qty"] += 1
|
||||
itemwise_details = make_stock_in_entry(rm_items=rm_items)
|
||||
|
||||
for item in rm_items:
|
||||
item["use_serial_batch_fields"] = 1
|
||||
item["sco_rm_detail"] = sco.items[0].name
|
||||
|
||||
make_stock_transfer_entry(
|
||||
sco_no=sco.name,
|
||||
rm_items=rm_items,
|
||||
itemwise_details=copy.deepcopy(itemwise_details),
|
||||
)
|
||||
|
||||
scr1 = make_subcontracting_receipt(sco.name)
|
||||
scr1.save()
|
||||
scr1.supplied_items[0].consumed_qty = 5
|
||||
scr1.supplied_items[0].serial_no = "\n".join(
|
||||
sorted(itemwise_details.get("Subcontracted SRM Item 2").get("serial_no")[0:5])
|
||||
)
|
||||
scr1.submit()
|
||||
|
||||
for key, value in get_supplied_items(scr1).items():
|
||||
transferred_detais = itemwise_details.get(key)
|
||||
self.assertTrue(value.use_serial_batch_fields)
|
||||
self.assertEqual(value.qty, 5)
|
||||
self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get("serial_no")[0:5]))
|
||||
|
||||
sco.load_from_db()
|
||||
self.assertEqual(sco.supplied_items[0].consumed_qty, 5)
|
||||
doc = get_materials_from_supplier(sco.name, [d.name for d in sco.supplied_items])
|
||||
self.assertEqual(doc.items[0].qty, 1)
|
||||
self.assertEqual(doc.items[0].s_warehouse, "_Test Warehouse 1 - _TC")
|
||||
self.assertEqual(doc.items[0].t_warehouse, "_Test Warehouse - _TC")
|
||||
self.assertEqual(
|
||||
get_serial_nos(doc.items[0].serial_no),
|
||||
itemwise_details.get(doc.items[0].item_code)["serial_no"][5:6],
|
||||
)
|
||||
|
||||
|
||||
def add_second_row_in_scr(scr):
|
||||
item_dict = {}
|
||||
@@ -914,6 +1144,7 @@ def update_item_details(child_row, details):
|
||||
else child_row.get("consumed_qty")
|
||||
)
|
||||
|
||||
details.use_serial_batch_fields = child_row.get("use_serial_batch_fields")
|
||||
if child_row.serial_and_batch_bundle:
|
||||
doc = frappe.get_doc("Serial and Batch Bundle", child_row.serial_and_batch_bundle)
|
||||
for row in doc.get("entries"):
|
||||
@@ -945,6 +1176,7 @@ def make_stock_transfer_entry(**args):
|
||||
"rate": row.rate or 100,
|
||||
"stock_uom": row.stock_uom or "Nos",
|
||||
"warehouse": row.warehouse or "_Test Warehouse - _TC",
|
||||
"use_serial_batch_fields": row.get("use_serial_batch_fields"),
|
||||
}
|
||||
|
||||
item_details = args.itemwise_details.get(row.item_code)
|
||||
@@ -960,9 +1192,12 @@ def make_stock_transfer_entry(**args):
|
||||
if batch_qty >= row.qty:
|
||||
batches[batch_no] = row.qty
|
||||
item_details.batch_no[batch_no] -= row.qty
|
||||
if row.get("use_serial_batch_fields"):
|
||||
item["batch_no"] = batch_no
|
||||
|
||||
break
|
||||
|
||||
if serial_nos or batches:
|
||||
if not row.get("use_serial_batch_fields") and (serial_nos or batches):
|
||||
item["serial_and_batch_bundle"] = make_serial_batch_bundle(
|
||||
frappe._dict(
|
||||
{
|
||||
@@ -978,6 +1213,9 @@ def make_stock_transfer_entry(**args):
|
||||
)
|
||||
).name
|
||||
|
||||
if serial_nos and row.get("use_serial_batch_fields"):
|
||||
item["serial_no"] = "\n".join(serial_nos)
|
||||
|
||||
items.append(item)
|
||||
|
||||
ste_dict = make_rm_stock_entry(args.sco_no, items)
|
||||
@@ -1132,6 +1370,7 @@ def get_rm_items(supplied_items):
|
||||
"rate": item.rate,
|
||||
"stock_uom": item.stock_uom,
|
||||
"warehouse": item.reserve_warehouse,
|
||||
"use_serial_batch_fields": 0,
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user