884 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			884 lines
		
	
	
		
			34 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import copy
 | |
| import unittest
 | |
| from collections import defaultdict
 | |
| 
 | |
| import frappe
 | |
| from frappe.utils import cint
 | |
| 
 | |
| from erpnext.buying.doctype.purchase_order.purchase_order import (
 | |
| 	get_materials_from_supplier,
 | |
| 	make_purchase_invoice,
 | |
| 	make_purchase_receipt,
 | |
| 	make_rm_stock_entry,
 | |
| )
 | |
| from erpnext.buying.doctype.purchase_order.test_purchase_order import create_purchase_order
 | |
| from erpnext.manufacturing.doctype.production_plan.test_production_plan import make_bom
 | |
| from erpnext.stock.doctype.item.test_item import make_item
 | |
| from erpnext.stock.doctype.serial_no.serial_no import get_serial_nos
 | |
| from erpnext.stock.doctype.stock_entry.test_stock_entry import make_stock_entry
 | |
| 
 | |
| 
 | |
| class TestSubcontracting(unittest.TestCase):
 | |
| 	def setUp(self):
 | |
| 		make_subcontract_items()
 | |
| 		make_raw_materials()
 | |
| 		make_bom_for_subcontracted_items()
 | |
| 
 | |
| 	def test_po_with_bom(self):
 | |
| 		'''
 | |
| 			- Set backflush based on BOM
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA1 and add same item two times.
 | |
| 			- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
 | |
| 			- Create purchase receipt against the PO and check serial nos and batch no.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('BOM')
 | |
| 		item_code = 'Subcontracted Item SA1'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 5, 'rate': 100},
 | |
| 			{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 6, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 5},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 5},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 5},
 | |
| 			{'item_code': 'Subcontracted SRM Item 1', 'qty': 6},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 6},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 6}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name if d.get('qty') == 5 else po.items[1].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			transferred_detais = itemwise_details.get(key)
 | |
| 
 | |
| 			for field in ['qty', 'serial_no', 'batch_no']:
 | |
| 				if value.get(field):
 | |
| 					transfer, consumed = (transferred_detais.get(field), value.get(field))
 | |
| 					if field == 'serial_no':
 | |
| 						transfer, consumed = (sorted(transfer), sorted(consumed))
 | |
| 
 | |
| 					self.assertEqual(transfer, consumed)
 | |
| 
 | |
| 	def test_po_with_material_transfer(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transfer
 | |
| 			- Create subcontracted PO 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 purchase receipt against the PO and check serial nos and batch no.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': 'Subcontracted Item SA1', 'qty': 5, 'rate': 100},
 | |
| 			{'warehouse': '_Test Warehouse - _TC', 'item_code': 'Subcontracted Item SA5', 'qty': 6, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 5, 'main_item_code': 'Subcontracted Item SA1'},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 5, 'main_item_code': 'Subcontracted Item SA1'},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 5, 'main_item_code': 'Subcontracted Item SA1'},
 | |
| 			{'item_code': 'Subcontracted SRM Item 5', 'qty': 6, 'main_item_code': 'Subcontracted Item SA5'},
 | |
| 			{'item_code': 'Subcontracted SRM Item 4', 'qty': 6, 'main_item_code': 'Subcontracted Item SA5'}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name if d.get('qty') == 5 else po.items[1].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.remove(pr1.items[1])
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			transferred_detais = itemwise_details.get(key)
 | |
| 
 | |
| 			for field in ['qty', 'serial_no', 'batch_no']:
 | |
| 				if value.get(field):
 | |
| 					self.assertEqual(value.get(field), transferred_detais.get(field))
 | |
| 
 | |
| 		pr2 = make_purchase_receipt(po.name)
 | |
| 		pr2.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr2).items():
 | |
| 			transferred_detais = itemwise_details.get(key)
 | |
| 
 | |
| 			for field in ['qty', 'serial_no', 'batch_no']:
 | |
| 				if value.get(field):
 | |
| 					self.assertEqual(value.get(field), transferred_detais.get(field))
 | |
| 
 | |
| 	def test_subcontract_with_same_components_different_fg(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transfer
 | |
| 			- Create subcontracted PO 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 purchase receipt against the PO and check serial nos and batch no.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': 'Subcontracted Item SA2', 'qty': 5, 'rate': 100},
 | |
| 			{'warehouse': '_Test Warehouse - _TC', 'item_code': 'Subcontracted Item SA3', 'qty': 6, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 2', 'qty': 6, 'main_item_code': 'Subcontracted Item SA2'},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 6, 'main_item_code': 'Subcontracted Item SA3'}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name if d.get('qty') == 5 else po.items[1].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 3
 | |
| 		pr1.remove(pr1.items[1])
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).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]))
 | |
| 
 | |
| 		pr2 = make_purchase_receipt(po.name)
 | |
| 		pr2.items[0].qty = 2
 | |
| 		pr2.remove(pr2.items[1])
 | |
| 		pr2.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr2).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]))
 | |
| 
 | |
| 		pr3 = make_purchase_receipt(po.name)
 | |
| 		pr3.submit()
 | |
| 		for key, value in get_supplied_items(pr3).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(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transfer
 | |
| 			- Create subcontracted PO for the 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 purchase receipt for full qty against the PO 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')
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': 'Subcontracted Item SA2', 'qty': 5, 'rate': 100}]
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 2', 'qty': 6, 'main_item_code': 'Subcontracted Item SA2'}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.save()
 | |
| 		pr1.supplied_items[0].consumed_qty = 5
 | |
| 		pr1.supplied_items[0].serial_no = '\n'.join(sorted(
 | |
| 			itemwise_details.get('Subcontracted SRM Item 2').get('serial_no')[0:5]
 | |
| 		))
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			transferred_detais = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, 5)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(transferred_detais.get('serial_no')[0:5]))
 | |
| 
 | |
| 		po.load_from_db()
 | |
| 		self.assertEqual(po.supplied_items[0].consumed_qty, 5)
 | |
| 		doc = get_materials_from_supplier(po.name, [d.name for d in po.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 test_item_with_batch_based_on_bom(self):
 | |
| 		'''
 | |
| 			- Set backflush based on BOM
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA4 (has batch no).
 | |
| 			- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
 | |
| 			- Transfer the components in multiple batches.
 | |
| 			- Create the 3 purchase receipt against the PO and split Subcontracted Items into two batches.
 | |
| 			- Keep the qty as 2 for Subcontracted Item in the purchase receipt.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('BOM')
 | |
| 		item_code = 'Subcontracted Item SA4'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 1}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 2)
 | |
| 
 | |
| 	def test_item_with_batch_based_on_material_transfer(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA4 (has batch no).
 | |
| 			- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
 | |
| 			- Transfer the components in multiple batches with extra 2 qty for the batched item.
 | |
| 			- Create the 3 purchase receipt against the PO and split Subcontracted Items into two batches.
 | |
| 			- Keep the qty as 2 for Subcontracted Item in the purchase receipt.
 | |
| 			- In the first purchase receipt the batched raw materials will be consumed 2 extra qty.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA4'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			qty = 4 if key != 'Subcontracted SRM Item 3' else 6
 | |
| 			self.assertEqual(value.qty, qty)
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 2)
 | |
| 
 | |
| 	def test_partial_transfer_serial_no_components_based_on_material_transfer(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA2.
 | |
| 			- Transfer the partial components from Stores to Supplier warehouse with serial nos.
 | |
| 			- Create partial purchase receipt against the PO and change the qty manually.
 | |
| 			- Transfer the remaining components from Stores to Supplier warehouse with serial nos.
 | |
| 			- Create purchase receipt for remaining qty against the PO and change the qty manually.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA2'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 2', 'qty': 5}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 5
 | |
| 		pr1.save()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, 3)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no[0:3]))
 | |
| 
 | |
| 		pr1.load_from_db()
 | |
| 		pr1.supplied_items[0].consumed_qty = 5
 | |
| 		pr1.supplied_items[0].serial_no = '\n'.join(itemwise_details[pr1.supplied_items[0].rm_item_code]['serial_no'])
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no))
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no))
 | |
| 
 | |
| 	def test_incorrect_serial_no_components_based_on_material_transfer(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA2.
 | |
| 			- Transfer the serialized componenets to the supplier.
 | |
| 			- Create purchase receipt and change the serial no which is not transferred.
 | |
| 			- System should throw the error and not allowed to save the purchase receipt.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA2'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 2', 'qty': 10}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.save()
 | |
| 		pr1.supplied_items[0].serial_no = 'ABCD'
 | |
| 		self.assertRaises(frappe.ValidationError, pr1.save)
 | |
| 		pr1.delete()
 | |
| 
 | |
| 	def test_partial_transfer_batch_based_on_material_transfer(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA6.
 | |
| 			- Transfer the partial components from Stores to Supplier warehouse with batch.
 | |
| 			- Create partial purchase receipt against the PO and change the qty manually.
 | |
| 			- Transfer the remaining components from Stores to Supplier warehouse with batch.
 | |
| 			- Create purchase receipt for remaining qty against the PO and change the qty manually.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA6'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 3', 'qty': 5}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.items[0].qty = 5
 | |
| 		pr1.save()
 | |
| 
 | |
| 		transferred_batch_no = ''
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, 3)
 | |
| 			transferred_batch_no = details.batch_no
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 		pr1.load_from_db()
 | |
| 		pr1.supplied_items[0].consumed_qty = 5
 | |
| 		pr1.supplied_items[0].batch_no = list(transferred_batch_no.keys())[0]
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_receipt(po.name)
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 
 | |
| 	def test_item_with_batch_based_on_material_transfer_for_purchase_invoice(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA4 (has batch no).
 | |
| 			- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
 | |
| 			- Transfer the components in multiple batches with extra 2 qty for the batched item.
 | |
| 			- Create the 3 purchase receipt against the PO and split Subcontracted Items into two batches.
 | |
| 			- Keep the qty as 2 for Subcontracted Item in the purchase receipt.
 | |
| 			- In the first purchase receipt the batched raw materials will be consumed 2 extra qty.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA4'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			qty = 4 if key != 'Subcontracted SRM Item 3' else 6
 | |
| 			self.assertEqual(value.qty, qty)
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.items[0].qty = 2
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 2)
 | |
| 
 | |
| 	def test_partial_transfer_serial_no_components_based_on_material_transfer_for_purchase_invoice(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA2.
 | |
| 			- Transfer the partial components from Stores to Supplier warehouse with serial nos.
 | |
| 			- Create partial purchase receipt against the PO and change the qty manually.
 | |
| 			- Transfer the remaining components from Stores to Supplier warehouse with serial nos.
 | |
| 			- Create purchase receipt for remaining qty against the PO and change the qty manually.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA2'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 2', 'qty': 5}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 5
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.save()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, 3)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no[0:3]))
 | |
| 
 | |
| 		pr1.load_from_db()
 | |
| 		pr1.supplied_items[0].consumed_qty = 5
 | |
| 		pr1.supplied_items[0].serial_no = '\n'.join(itemwise_details[pr1.supplied_items[0].rm_item_code]['serial_no'])
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no))
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(sorted(value.serial_no), sorted(details.serial_no))
 | |
| 
 | |
| 	def test_partial_transfer_batch_based_on_material_transfer_for_purchase_invoice(self):
 | |
| 		'''
 | |
| 			- Set backflush based on Material Transferred for Subcontract
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA6.
 | |
| 			- Transfer the partial components from Stores to Supplier warehouse with batch.
 | |
| 			- Create partial purchase receipt against the PO and change the qty manually.
 | |
| 			- Transfer the remaining components from Stores to Supplier warehouse with batch.
 | |
| 			- Create purchase receipt for remaining qty against the PO and change the qty manually.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('Material Transferred for Subcontract')
 | |
| 		item_code = 'Subcontracted Item SA6'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 3', 'qty': 5}]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 5
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.save()
 | |
| 
 | |
| 		transferred_batch_no = ''
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, 3)
 | |
| 			transferred_batch_no = details.batch_no
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 		pr1.load_from_db()
 | |
| 		pr1.supplied_items[0].consumed_qty = 5
 | |
| 		pr1.supplied_items[0].batch_no = list(transferred_batch_no.keys())[0]
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			details = itemwise_details.get(key)
 | |
| 			self.assertEqual(value.qty, details.qty)
 | |
| 			self.assertEqual(value.batch_no, details.batch_no)
 | |
| 
 | |
| 	def test_item_with_batch_based_on_bom_for_purchase_invoice(self):
 | |
| 		'''
 | |
| 			- Set backflush based on BOM
 | |
| 			- Create subcontracted PO for the item Subcontracted Item SA4 (has batch no).
 | |
| 			- Transfer the components from Stores to Supplier warehouse with batch no and serial nos.
 | |
| 			- Transfer the components in multiple batches.
 | |
| 			- Create the 3 purchase receipt against the PO and split Subcontracted Items into two batches.
 | |
| 			- Keep the qty as 2 for Subcontracted Item in the purchase receipt.
 | |
| 		'''
 | |
| 
 | |
| 		set_backflush_based_on('BOM')
 | |
| 		item_code = 'Subcontracted Item SA4'
 | |
| 		items = [{'warehouse': '_Test Warehouse - _TC', 'item_code': item_code, 'qty': 10, 'rate': 100}]
 | |
| 
 | |
| 		rm_items = [{'item_code': 'Subcontracted SRM Item 1', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 2', 'qty': 10},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 3},
 | |
| 			{'item_code': 'Subcontracted SRM Item 3', 'qty': 1}
 | |
| 		]
 | |
| 
 | |
| 		itemwise_details = make_stock_in_entry(rm_items=rm_items)
 | |
| 		po = create_purchase_order(rm_items = items, is_subcontracted="Yes",
 | |
| 			supplier_warehouse="_Test Warehouse 1 - _TC")
 | |
| 
 | |
| 		for d in rm_items:
 | |
| 			d['po_detail'] = po.items[0].name
 | |
| 
 | |
| 		make_stock_transfer_entry(po_no = po.name, main_item_code=item_code,
 | |
| 			rm_items=rm_items, itemwise_details=copy.deepcopy(itemwise_details))
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		add_second_row_in_pr(pr1)
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 4)
 | |
| 
 | |
| 		pr1 = make_purchase_invoice(po.name)
 | |
| 		pr1.update_stock = 1
 | |
| 		pr1.items[0].qty = 2
 | |
| 		pr1.items[0].expense_account = 'Stock Adjustment - _TC'
 | |
| 		pr1.save()
 | |
| 		pr1.submit()
 | |
| 
 | |
| 		for key, value in get_supplied_items(pr1).items():
 | |
| 			self.assertEqual(value.qty, 2)
 | |
| 
 | |
| def add_second_row_in_pr(pr):
 | |
| 	item_dict = {}
 | |
| 	for column in ['item_code', 'item_name', 'qty', 'uom', 'warehouse', 'stock_uom',
 | |
| 		'purchase_order', 'purchase_order_item', 'conversion_factor', 'rate', 'expense_account', 'po_detail']:
 | |
| 		item_dict[column] = pr.items[0].get(column)
 | |
| 
 | |
| 	pr.append('items', item_dict)
 | |
| 	pr.set_missing_values()
 | |
| 
 | |
| def get_supplied_items(pr_doc):
 | |
| 	supplied_items = {}
 | |
| 	for row in pr_doc.get('supplied_items'):
 | |
| 		if row.rm_item_code not in supplied_items:
 | |
| 			supplied_items.setdefault(row.rm_item_code,
 | |
| 				frappe._dict({'qty': 0, 'serial_no': [], 'batch_no': defaultdict(float)}))
 | |
| 
 | |
| 		details = supplied_items[row.rm_item_code]
 | |
| 		update_item_details(row, details)
 | |
| 
 | |
| 	return supplied_items
 | |
| 
 | |
| def make_stock_in_entry(**args):
 | |
| 	args = frappe._dict(args)
 | |
| 
 | |
| 	items = {}
 | |
| 	for row in args.rm_items:
 | |
| 		row = frappe._dict(row)
 | |
| 
 | |
| 		doc = make_stock_entry(target=row.warehouse or '_Test Warehouse - _TC',
 | |
| 			item_code=row.item_code, qty=row.qty or 1, basic_rate=row.rate or 100)
 | |
| 
 | |
| 		if row.item_code not in items:
 | |
| 			items.setdefault(row.item_code, frappe._dict({'qty': 0, 'serial_no': [], 'batch_no': defaultdict(float)}))
 | |
| 
 | |
| 		child_row = doc.items[0]
 | |
| 		details = items[child_row.item_code]
 | |
| 		update_item_details(child_row, details)
 | |
| 
 | |
| 	return items
 | |
| 
 | |
| def update_item_details(child_row, details):
 | |
| 	details.qty += (child_row.get('qty') if child_row.doctype == 'Stock Entry Detail'
 | |
| 		else child_row.get('consumed_qty'))
 | |
| 
 | |
| 	if child_row.serial_no:
 | |
| 		details.serial_no.extend(get_serial_nos(child_row.serial_no))
 | |
| 
 | |
| 	if child_row.batch_no:
 | |
| 		details.batch_no[child_row.batch_no] += (child_row.get('qty') or child_row.get('consumed_qty'))
 | |
| 
 | |
| def make_stock_transfer_entry(**args):
 | |
| 	args = frappe._dict(args)
 | |
| 
 | |
| 	items = []
 | |
| 	for row in args.rm_items:
 | |
| 		row = frappe._dict(row)
 | |
| 
 | |
| 		item = {'item_code': row.main_item_code or args.main_item_code, 'rm_item_code': row.item_code,
 | |
| 			'qty': row.qty or 1, 'item_name': row.item_code, 'rate': row.rate or 100,
 | |
| 			'stock_uom': row.stock_uom or 'Nos', 'warehouse': row.warehuose or '_Test Warehouse - _TC'}
 | |
| 
 | |
| 		item_details = args.itemwise_details.get(row.item_code)
 | |
| 
 | |
| 		if item_details and item_details.serial_no:
 | |
| 			serial_nos = item_details.serial_no[0:cint(row.qty)]
 | |
| 			item['serial_no'] = '\n'.join(serial_nos)
 | |
| 			item_details.serial_no = list(set(item_details.serial_no) - set(serial_nos))
 | |
| 
 | |
| 		if item_details and item_details.batch_no:
 | |
| 			for batch_no, batch_qty in item_details.batch_no.items():
 | |
| 				if batch_qty >= row.qty:
 | |
| 					item['batch_no'] = batch_no
 | |
| 					item_details.batch_no[batch_no] -= row.qty
 | |
| 					break
 | |
| 
 | |
| 		items.append(item)
 | |
| 
 | |
| 	ste_dict = make_rm_stock_entry(args.po_no, items)
 | |
| 	doc = frappe.get_doc(ste_dict)
 | |
| 	doc.insert()
 | |
| 	doc.submit()
 | |
| 
 | |
| 	return doc
 | |
| 
 | |
| def make_subcontract_items():
 | |
| 	sub_contracted_items = {'Subcontracted Item SA1': {}, 'Subcontracted Item SA2': {}, 'Subcontracted Item SA3': {},
 | |
| 		'Subcontracted Item SA4': {'has_batch_no': 1, 'create_new_batch': 1, 'batch_number_series': 'SBAT.####'},
 | |
| 		'Subcontracted Item SA5': {}, 'Subcontracted Item SA6': {}}
 | |
| 
 | |
| 	for item, properties in sub_contracted_items.items():
 | |
| 		if not frappe.db.exists('Item', item):
 | |
| 			properties.update({'is_stock_item': 1, 'is_sub_contracted_item': 1})
 | |
| 			make_item(item, properties)
 | |
| 
 | |
| def make_raw_materials():
 | |
| 	raw_materials = {'Subcontracted SRM Item 1': {},
 | |
| 		'Subcontracted SRM Item 2': {'has_serial_no': 1, 'serial_no_series': 'SRI.####'},
 | |
| 		'Subcontracted SRM Item 3': {'has_batch_no': 1, 'create_new_batch': 1, 'batch_number_series': 'BAT.####'},
 | |
| 		'Subcontracted SRM Item 4': {'has_serial_no': 1, 'serial_no_series': 'SRII.####'},
 | |
| 		'Subcontracted SRM Item 5': {'has_serial_no': 1, 'serial_no_series': 'SRII.####'}}
 | |
| 
 | |
| 	for item, properties in raw_materials.items():
 | |
| 		if not frappe.db.exists('Item', item):
 | |
| 			properties.update({'is_stock_item': 1})
 | |
| 			make_item(item, properties)
 | |
| 
 | |
| def make_bom_for_subcontracted_items():
 | |
| 	boms = {
 | |
| 		'Subcontracted Item SA1': ['Subcontracted SRM Item 1', 'Subcontracted SRM Item 2', 'Subcontracted SRM Item 3'],
 | |
| 		'Subcontracted Item SA2': ['Subcontracted SRM Item 2'],
 | |
| 		'Subcontracted Item SA3': ['Subcontracted SRM Item 2'],
 | |
| 		'Subcontracted Item SA4': ['Subcontracted SRM Item 1', 'Subcontracted SRM Item 2', 'Subcontracted SRM Item 3'],
 | |
| 		'Subcontracted Item SA5': ['Subcontracted SRM Item 5'],
 | |
| 		'Subcontracted Item SA6': ['Subcontracted SRM Item 3']
 | |
| 	}
 | |
| 
 | |
| 	for item_code, raw_materials in boms.items():
 | |
| 		if not frappe.db.exists('BOM', {'item': item_code}):
 | |
| 			make_bom(item=item_code, raw_materials=raw_materials, rate=100)
 | |
| 
 | |
| def set_backflush_based_on(based_on):
 | |
| 	frappe.db.set_value('Buying Settings', None,
 | |
| 		'backflush_raw_materials_of_subcontract_based_on', based_on)
 |