def test_sequence_id(self): operations = [{"operation": "Test Operation A", "workstation": "Test Workstation A", "time_in_mins": 30}, {"operation": "Test Operation B", "workstation": "Test Workstation A", "time_in_mins": 20}] make_test_records("UOM") setup_operations(operations) routing_doc = create_routing(routing_name="Testing Route", operations=operations) bom_doc = setup_bom(item_code=self.item_code, routing=routing_doc.name) wo_doc = make_wo_order_test_record(production_item = self.item_code, bom_no=bom_doc.name) for row in routing_doc.operations: self.assertEqual(row.sequence_id, row.idx) for data in frappe.get_all("Job Card", filters={"work_order": wo_doc.name}, order_by="sequence_id desc"): job_card_doc = frappe.get_doc("Job Card", data.name) job_card_doc.time_logs[0].completed_qty = 10 if job_card_doc.sequence_id != 1: self.assertRaises(OperationSequenceError, job_card_doc.save) else: job_card_doc.save() self.assertEqual(job_card_doc.total_completed_qty, 10) wo_doc.cancel() wo_doc.delete()
def test_job_card_overlap(self): wo2 = make_wo_order_test_record(item="_Test FG Item 2", qty=2) jc1 = frappe.get_last_doc("Job Card", {"work_order": self.work_order.name}) jc2 = frappe.get_last_doc("Job Card", {"work_order": wo2.name}) employee = "_T-Employee-00001" # from test records jc1.append( "time_logs", { "from_time": "2021-01-01 00:00:00", "to_time": "2021-01-01 08:00:00", "completed_qty": 1, "employee": employee, }, ) jc1.save() # add a new entry in same time slice jc2.append( "time_logs", { "from_time": "2021-01-01 00:01:00", "to_time": "2021-01-01 06:00:00", "completed_qty": 1, "employee": employee, }, ) self.assertRaises(OverlapError, jc2.save)
def setUp(self): make_bom_for_jc_tests() transfer_material_against, source_warehouse = None, None tests_that_skip_setup = ( "test_job_card_material_transfer_correctness", ) tests_that_transfer_against_jc = ( "test_job_card_multiple_materials_transfer", "test_job_card_excess_material_transfer", "test_job_card_partial_material_transfer", ) if self._testMethodName in tests_that_skip_setup: return if self._testMethodName in tests_that_transfer_against_jc: transfer_material_against = "Job Card" source_warehouse = "Stores - _TC" self.work_order = make_wo_order_test_record( item="_Test FG Item 2", qty=2, transfer_material_against=transfer_material_against, source_warehouse=source_warehouse, )
def test_alternative_item_for_production_rm(self): create_stock_reconciliation(item_code='Alternate Item For A RW 1', warehouse='_Test Warehouse - _TC',qty=5, rate=2000) create_stock_reconciliation(item_code='Test FG A RW 2', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) pro_order = make_wo_order_test_record(production_item='Test Finished Goods - A', qty=5, source_warehouse='_Test Warehouse - _TC', wip_warehouse='Test Supplier Warehouse - _TC') reserved_qty_for_production = frappe.db.get_value('Bin', {'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC'}, 'reserved_qty_for_production') ste = frappe.get_doc(make_stock_entry(pro_order.name, "Material Transfer for Manufacture", 5)) ste.insert() for item in ste.items: if item.item_code == 'Test FG A RW 1': item.item_code = 'Alternate Item For A RW 1' item.item_name = 'Alternate Item For A RW 1' item.description = 'Alternate Item For A RW 1' item.original_item = 'Test FG A RW 1' ste.submit() reserved_qty_for_production_after_transfer = frappe.db.get_value('Bin', {'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC'}, 'reserved_qty_for_production') self.assertEqual(reserved_qty_for_production_after_transfer, flt(reserved_qty_for_production - 5)) ste1 = frappe.get_doc(make_stock_entry(pro_order.name, "Manufacture", 5)) status = False for d in ste1.items: if d.item_code == 'Alternate Item For A RW 1': status = True self.assertEqual(status, True) ste1.submit()
def test_alternative_item_for_production_rm(self): create_stock_reconciliation(item_code='Alternate Item For A RW 1', warehouse='_Test Warehouse - _TC',qty=5, rate=2000) create_stock_reconciliation(item_code='Test FG A RW 2', warehouse='_Test Warehouse - _TC', qty=5, rate=2000) pro_order = make_wo_order_test_record(production_item='Test Finished Goods - A', qty=5, source_warehouse='_Test Warehouse - _TC', wip_warehouse='Test Supplier Warehouse - _TC') reserved_qty_for_production = frappe.db.get_value('Bin', {'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC'}, 'reserved_qty_for_production') ste = frappe.get_doc(make_stock_entry(pro_order.name, "Material Transfer for Manufacture", 5)) ste.insert() for item in ste.items: if item.item_code == 'Test FG A RW 1': item.item_code = 'Alternate Item For A RW 1' item.item_name = 'Alternate Item For A RW 1' item.description = 'Alternate Item For A RW 1' item.original_item = 'Test FG A RW 1' ste.submit() reserved_qty_for_production_after_transfer = frappe.db.get_value('Bin', {'item_code': 'Test FG A RW 1', 'warehouse': '_Test Warehouse - _TC'}, 'reserved_qty_for_production') self.assertEqual(reserved_qty_for_production_after_transfer, flt(reserved_qty_for_production - 5)) ste1 = frappe.get_doc(make_stock_entry(pro_order.name, "Manufacture", 5)) status = False for d in ste1.items: if d.item_code == 'Alternate Item For A RW 1': status = True self.assertEqual(status, True) ste1.submit()
def test_job_card(self): data = frappe.get_cached_value('BOM', { 'docstatus': 1, 'with_operations': 1, 'company': '_Test Company' }, ['name', 'item']) if data: bom, bom_item = data work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom) job_cards = frappe.get_all('Job Card', filters={'work_order': work_order.name}, fields=["operation_id", "name"]) if job_cards: job_card = job_cards[0] frappe.db.set_value("Job Card", job_card.name, "operation_row_number", job_card.operation_id) doc = frappe.get_doc("Job Card", job_card.name) doc.operation_id = "Test Data" self.assertRaises(OperationMismatchError, doc.save) for d in job_cards: frappe.delete_doc("Job Card", d.name)
def test_alternative_item_for_production_rm(self): create_stock_reconciliation(item_code="Alternate Item For A RW 1", warehouse="_Test Warehouse - _TC", qty=5, rate=2000) create_stock_reconciliation(item_code="Test FG A RW 2", warehouse="_Test Warehouse - _TC", qty=5, rate=2000) pro_order = make_wo_order_test_record( production_item="Test Finished Goods - A", qty=5, source_warehouse="_Test Warehouse - _TC", wip_warehouse="Test Supplier Warehouse - _TC", ) reserved_qty_for_production = frappe.db.get_value( "Bin", { "item_code": "Test FG A RW 1", "warehouse": "_Test Warehouse - _TC" }, "reserved_qty_for_production", ) ste = frappe.get_doc( make_stock_entry(pro_order.name, "Material Transfer for Manufacture", 5)) ste.insert() for item in ste.items: if item.item_code == "Test FG A RW 1": item.item_code = "Alternate Item For A RW 1" item.item_name = "Alternate Item For A RW 1" item.description = "Alternate Item For A RW 1" item.original_item = "Test FG A RW 1" ste.submit() reserved_qty_for_production_after_transfer = frappe.db.get_value( "Bin", { "item_code": "Test FG A RW 1", "warehouse": "_Test Warehouse - _TC" }, "reserved_qty_for_production", ) self.assertEqual(reserved_qty_for_production_after_transfer, flt(reserved_qty_for_production - 5)) ste1 = frappe.get_doc( make_stock_entry(pro_order.name, "Manufacture", 5)) status = False for d in ste1.items: if d.item_code == "Alternate Item For A RW 1": status = True self.assertEqual(status, True) ste1.submit()
def work(): frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) from erpnext.projects.doctype.timesheet.timesheet import OverlapError ppt = frappe.get_doc("Production Planning Tool", "Production Planning Tool") ppt.company = erpnext.get_default_company() ppt.use_multi_level_bom = 1 ppt.get_items_from = "Sales Order" ppt.purchase_request_for_warehouse = "Stores - WPL" ppt.run_method("get_open_sales_orders") ppt.run_method("get_items") ppt.run_method("raise_work_orders") ppt.run_method("raise_material_requests") frappe.db.commit() # submit work orders for pro in frappe.db.get_values("Work Order", {"docstatus": 0}, "name"): b = frappe.get_doc("Work Order", pro[0]) b.wip_warehouse = "Work in Progress - WPL" b.submit() frappe.db.commit() # submit material requests for pro in frappe.db.get_values("Material Request", {"docstatus": 0}, "name"): b = frappe.get_doc("Material Request", pro[0]) b.submit() frappe.db.commit() # stores -> wip if random.random() < 0.3: for pro in query_report.run("Open Work Orders")["result"][:how_many("Stock Entry for WIP")]: make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture") # wip -> fg if random.random() < 0.3: for pro in query_report.run("Work Orders in Progress")["result"][:how_many("Stock Entry for FG")]: make_stock_entry_from_pro(pro[0], "Manufacture") for bom in frappe.get_all('BOM', fields=['item'], filters = {'with_operations': 1}): pro_order = make_wo_order_test_record(item=bom.item, qty=2, source_warehouse="Stores - WPL", wip_warehouse = "Work in Progress - WPL", fg_warehouse = "Stores - WPL", company = erpnext.get_default_company(), stock_uom = frappe.db.get_value('Item', bom.item, 'stock_uom'), planned_start_date = frappe.flags.current_date) # submit time logs for timesheet in frappe.get_all("Timesheet", ["name"], {"docstatus": 0, "work_order": ("!=", ""), "to_time": ("<", frappe.flags.current_date)}): timesheet = frappe.get_doc("Timesheet", timesheet.name) try: timesheet.submit() frappe.db.commit() except OverlapError: pass except WorkstationHolidayError: pass
def work_order(self) -> WorkOrder: """Work Order lazily created for tests.""" if not self._work_order: self._work_order = make_wo_order_test_record( item="_Test FG Item 2", qty=2, transfer_material_against=self.transfer_material_against, source_warehouse=self.source_warehouse, ) return self._work_order
def work(): if random.random() < 0.3: return frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) if not frappe.get_all('Sales Order'): return from erpnext.projects.doctype.timesheet.timesheet import OverlapError ppt = frappe.new_doc("Production Plan") ppt.company = erpnext.get_default_company() # ppt.use_multi_level_bom = 1 #refactored ppt.get_items_from = "Sales Order" # ppt.purchase_request_for_warehouse = "Stores - WPL" # refactored ppt.run_method("get_open_sales_orders") if not ppt.get("sales_orders"): return ppt.run_method("get_items") ppt.run_method("raise_material_requests") ppt.save() ppt.submit() ppt.run_method("raise_work_orders") frappe.db.commit() # submit work orders for pro in frappe.db.get_values("Work Order", {"docstatus": 0}, "name"): b = frappe.get_doc("Work Order", pro[0]) b.wip_warehouse = "Work in Progress - WPL" b.submit() frappe.db.commit() # submit material requests for pro in frappe.db.get_values("Material Request", {"docstatus": 0}, "name"): b = frappe.get_doc("Material Request", pro[0]) b.submit() frappe.db.commit() # stores -> wip if random.random() < 0.4: for pro in query_report.run("Open Work Orders")["result"][:how_many("Stock Entry for WIP")]: make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture") # wip -> fg if random.random() < 0.4: for pro in query_report.run("Work Orders in Progress")["result"][:how_many("Stock Entry for FG")]: make_stock_entry_from_pro(pro[0], "Manufacture") for bom in frappe.get_all('BOM', fields=['item'], filters = {'with_operations': 1}): pro_order = make_wo_order_test_record(item=bom.item, qty=2, source_warehouse="Stores - WPL", wip_warehouse = "Work in Progress - WPL", fg_warehouse = "Stores - WPL", company = erpnext.get_default_company(), stock_uom = frappe.db.get_value('Item', bom.item, 'stock_uom'), planned_start_date = frappe.flags.current_date) # submit job card if random.random() < 0.4: submit_job_cards()
def test_job_card_with_different_work_station(self): data = frappe.get_cached_value('BOM', { 'docstatus': 1, 'with_operations': 1, 'company': '_Test Company' }, ['name', 'item']) if data: bom, bom_item = data work_order = make_wo_order_test_record(item=bom_item, qty=1, bom_no=bom) job_cards = frappe.get_all( 'Job Card', filters={'work_order': work_order.name}, fields=["operation_id", "workstation", "name", "for_quantity"]) job_card = job_cards[0] if job_card: workstation = frappe.db.get_value( "Workstation", {"name": ("not in", [job_card.workstation])}, "name") if not workstation or job_card.workstation == workstation: workstation = make_workstation( workstation_name=random_string(5)).name doc = frappe.get_doc("Job Card", job_card.name) doc.workstation = workstation doc.append( "time_logs", { "from_time": "2009-01-01 12:06:25", "to_time": "2009-01-01 12:37:25", "time_in_mins": "31.00002", "completed_qty": job_card.for_quantity }) doc.submit() completed_qty = frappe.db.get_value("Work Order Operation", job_card.operation_id, "completed_qty") self.assertEqual(completed_qty, job_card.for_quantity) doc.cancel() for d in job_cards: frappe.delete_doc("Job Card", d.name)
def test_production_plan_pending_qty_with_sales_order(self): """ Test Prod Plan impact via: SO -> Prod Plan -> WO -> SE -> SE (cancel) """ from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.manufacturing.doctype.work_order.work_order import ( make_stock_entry as make_se_from_wo, ) make_stock_entry(item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100) make_stock_entry(item_code="Raw Material Item 2", target="Work In Progress - _TC", qty=2, basic_rate=100) item = "Test Production Item 1" so = make_sales_order(item_code=item, qty=1) pln = create_production_plan(company=so.company, get_items_from="Sales Order", sales_order=so, skip_getting_mr_items=True) self.assertEqual(pln.po_items[0].pending_qty, 1) wo = make_wo_order_test_record( item_code=item, qty=1, company=so.company, wip_warehouse="Work In Progress - _TC", fg_warehouse="Finished Goods - _TC", skip_transfer=1, use_multi_level_bom=1, do_not_submit=True, ) wo.production_plan = pln.name wo.production_plan_item = pln.po_items[0].name wo.submit() se = frappe.get_doc(make_se_from_wo(wo.name, "Manufacture", 1)) se.submit() pln.reload() self.assertEqual(pln.po_items[0].pending_qty, 0) se.cancel() pln.reload() self.assertEqual(pln.po_items[0].pending_qty, 1)
def make_wo_with_transfer_against_jc(): "Create a WO with multiple operations and Material Transfer against Job Card" work_order = make_wo_order_test_record( item="_Test FG Item 2", qty=4, transfer_material_against="Job Card", source_warehouse="Stores - _TC", do_not_submit=True, ) work_order.required_items[0].operation = "Test Operation A" work_order.required_items[1].operation = "_Test Operation 1" work_order.submit() return work_order
def setUp(self): transfer_material_against, source_warehouse = None, None tests_that_transfer_against_jc = ( "test_job_card_multiple_materials_transfer", "test_job_card_excess_material_transfer") if self._testMethodName in tests_that_transfer_against_jc: transfer_material_against = "Job Card" source_warehouse = "Stores - _TC" self.work_order = make_wo_order_test_record( item="_Test FG Item 2", qty=2, transfer_material_against=transfer_material_against, source_warehouse=source_warehouse)
def test_production_plan_pending_qty_independent_items(self): "Test Prod Plan impact if items are added independently (no from SO or MR)." from erpnext.manufacturing.doctype.work_order.test_work_order import make_wo_order_test_record from erpnext.manufacturing.doctype.work_order.work_order import ( make_stock_entry as make_se_from_wo, ) make_stock_entry(item_code="Raw Material Item 1", target="Work In Progress - _TC", qty=2, basic_rate=100) make_stock_entry(item_code="Raw Material Item 2", target="Work In Progress - _TC", qty=2, basic_rate=100) pln = create_production_plan(item_code="Test Production Item 1", skip_getting_mr_items=True) self.assertEqual(pln.po_items[0].pending_qty, 1) wo = make_wo_order_test_record( item_code="Test Production Item 1", qty=1, company=pln.company, wip_warehouse="Work In Progress - _TC", fg_warehouse="Finished Goods - _TC", skip_transfer=1, use_multi_level_bom=1, do_not_submit=True, ) wo.production_plan = pln.name wo.production_plan_item = pln.po_items[0].name wo.submit() se = frappe.get_doc(make_se_from_wo(wo.name, "Manufacture", 1)) se.submit() pln.reload() self.assertEqual(pln.po_items[0].pending_qty, 0) se.cancel() pln.reload() self.assertEqual(pln.po_items[0].pending_qty, 1)
def work(): if random.random() < 0.3: return frappe.set_user(frappe.db.get_global('demo_manufacturing_user')) if not frappe.get_all('Sales Order'): return ppt = frappe.new_doc("Production Plan") ppt.company = erpnext.get_default_company() # ppt.use_multi_level_bom = 1 #refactored ppt.get_items_from = "Sales Order" # ppt.purchase_request_for_warehouse = "Stores - WPL" # refactored ppt.run_method("get_open_sales_orders") if not ppt.get("sales_orders"): return ppt.run_method("get_items") ppt.run_method("raise_material_requests") ppt.save() ppt.submit() ppt.run_method("raise_work_orders") frappe.db.commit() # submit work orders for pro in frappe.db.get_values("Work Order", {"docstatus": 0}, "name"): b = frappe.get_doc("Work Order", pro[0]) b.wip_warehouse = "Work in Progress - WPL" b.submit() frappe.db.commit() # submit material requests for pro in frappe.db.get_values("Material Request", {"docstatus": 0}, "name"): b = frappe.get_doc("Material Request", pro[0]) b.submit() frappe.db.commit() # stores -> wip if random.random() < 0.4: for pro in query_report.run("Open Work Orders")[ "result"][:how_many("Stock Entry for WIP")]: make_stock_entry_from_pro(pro[0], "Material Transfer for Manufacture") # wip -> fg if random.random() < 0.4: for pro in query_report.run("Work Orders in Progress")[ "result"][:how_many("Stock Entry for FG")]: make_stock_entry_from_pro(pro[0], "Manufacture") for bom in frappe.get_all('BOM', fields=['item'], filters={'with_operations': 1}): pro_order = make_wo_order_test_record( item=bom.item, qty=2, source_warehouse="Stores - WPL", wip_warehouse="Work in Progress - WPL", fg_warehouse="Stores - WPL", company=erpnext.get_default_company(), stock_uom=frappe.db.get_value('Item', bom.item, 'stock_uom'), planned_start_date=frappe.flags.current_date) # submit job card if random.random() < 0.4: submit_job_cards()
def test_serial_no_based_delivery(self): frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1) item = make_item("_Reserved_Serialized_Item", {"is_stock_item": 1, "maintain_stock": 1, "has_serial_no": 1, "serial_no_series": "SI.####", "valuation_rate": 500, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) frappe.db.sql("""delete from `tabSerial No` where item_code=%s""", (item.item_code)) make_item("_Test Item A", {"maintain_stock": 1, "valuation_rate": 100, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) make_item("_Test Item B", {"maintain_stock": 1, "valuation_rate": 200, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom make_bom(item=item.item_code, rate=1000, raw_materials = ['_Test Item A', '_Test Item B']) so = make_sales_order(**{ "item_list": [{ "item_code": item.item_code, "ensure_delivery_based_on_produced_serial_no": 1, "qty": 1, "rate":1000 }] }) so.submit() from erpnext.manufacturing.doctype.work_order.test_work_order import \ make_wo_order_test_record work_order = make_wo_order_test_record(item=item.item_code, qty=1, do_not_save=True) work_order.fg_warehouse = "_Test Warehouse - _TC" work_order.sales_order = so.name work_order.submit() make_stock_entry(item_code=item.item_code, target="_Test Warehouse - _TC", qty=1) item_serial_no = frappe.get_doc("Serial No", {"item_code": item.item_code}) from erpnext.manufacturing.doctype.work_order.work_order import \ make_stock_entry as make_production_stock_entry se = frappe.get_doc(make_production_stock_entry(work_order.name, "Manufacture", 1)) se.submit() reserved_serial_no = se.get("items")[2].serial_no serial_no_so = frappe.get_value("Serial No", reserved_serial_no, "sales_order") self.assertEqual(serial_no_so, so.name) dn = make_delivery_note(so.name) dn.save() self.assertEqual(reserved_serial_no, dn.get("items")[0].serial_no) item_line = dn.get("items")[0] item_line.serial_no = item_serial_no.name item_line = dn.get("items")[0] item_line.serial_no = reserved_serial_no dn.submit() dn.load_from_db() dn.cancel() si = make_sales_invoice(so.name) si.update_stock = 1 si.save() self.assertEqual(si.get("items")[0].serial_no, reserved_serial_no) item_line = si.get("items")[0] item_line.serial_no = item_serial_no.name self.assertRaises(frappe.ValidationError, dn.submit) item_line = si.get("items")[0] item_line.serial_no = reserved_serial_no self.assertTrue(si.submit) si.submit() si.load_from_db() si.cancel() si = make_sales_invoice(so.name) si.update_stock = 0 si.submit() from erpnext.accounts.doctype.sales_invoice.sales_invoice import \ make_delivery_note as make_delivery_note_from_invoice dn = make_delivery_note_from_invoice(si.name) dn.save() dn.submit() self.assertEqual(dn.get("items")[0].serial_no, reserved_serial_no) dn.load_from_db() dn.cancel() si.load_from_db() si.cancel() se.load_from_db() se.cancel() self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))
def test_serial_no_based_delivery(self): frappe.set_value("Stock Settings", None, "automatically_set_serial_nos_based_on_fifo", 1) from erpnext.stock.doctype.item.test_item import make_item item = make_item("_Reserved_Serialized_Item", {"is_stock_item": 1, "maintain_stock": 1, "has_serial_no": 1, "serial_no_series": "SI.####", "valuation_rate": 500, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) frappe.db.sql("""delete from `tabSerial No` where item_code=%s""", (item.item_code)) make_item("_Test Item A", {"maintain_stock": 1, "valuation_rate": 100, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) make_item("_Test Item B", {"maintain_stock": 1, "valuation_rate": 200, "item_defaults": [ { "default_warehouse": "_Test Warehouse - _TC", "company": "_Test Company" }] }) from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom make_bom(item=item.item_code, rate=1000, raw_materials = ['_Test Item A', '_Test Item B']) so = make_sales_order(**{ "item_list": [{ "item_code": item.item_code, "ensure_delivery_based_on_produced_serial_no": 1, "qty": 1, "rate":1000 }] }) so.submit() from erpnext.manufacturing.doctype.work_order.test_work_order import \ make_wo_order_test_record work_order = make_wo_order_test_record(item=item.item_code, qty=1, do_not_save=True) work_order.fg_warehouse = "_Test Warehouse - _TC" work_order.sales_order = so.name work_order.submit() make_stock_entry(item_code=item.item_code, target="_Test Warehouse - _TC", qty=1) item_serial_no = frappe.get_doc("Serial No", {"item_code": item.item_code}) from erpnext.manufacturing.doctype.work_order.work_order import \ make_stock_entry as make_production_stock_entry se = frappe.get_doc(make_production_stock_entry(work_order.name, "Manufacture", 1)) se.submit() reserved_serial_no = se.get("items")[2].serial_no serial_no_so = frappe.get_value("Serial No", reserved_serial_no, "sales_order") self.assertEqual(serial_no_so, so.name) dn = make_delivery_note(so.name) dn.save() self.assertEqual(reserved_serial_no, dn.get("items")[0].serial_no) item_line = dn.get("items")[0] item_line.serial_no = item_serial_no.name self.assertRaises(frappe.ValidationError, dn.submit) item_line = dn.get("items")[0] item_line.serial_no = reserved_serial_no self.assertTrue(dn.submit) dn.load_from_db() dn.cancel() si = make_sales_invoice(so.name) si.update_stock = 1 si.save() self.assertEqual(si.get("items")[0].serial_no, reserved_serial_no) item_line = si.get("items")[0] item_line.serial_no = item_serial_no.name self.assertRaises(frappe.ValidationError, dn.submit) item_line = si.get("items")[0] item_line.serial_no = reserved_serial_no self.assertTrue(si.submit) si.submit() si.load_from_db() si.cancel() si = make_sales_invoice(so.name) si.update_stock = 0 si.submit() from erpnext.accounts.doctype.sales_invoice.sales_invoice import \ make_delivery_note as make_delivery_note_from_invoice dn = make_delivery_note_from_invoice(si.name) dn.save() dn.submit() self.assertEqual(dn.get("items")[0].serial_no, reserved_serial_no) dn.load_from_db() dn.cancel() si.load_from_db() si.cancel() se.load_from_db() se.cancel() self.assertFalse(frappe.db.exists("Serial No", {"sales_order": so.name}))