feat: [production_plan -> fetching item description] Fetch item description from Material Request or Sales Order (#19541)
* Change packed item * Remove description field on update_packed_items * add possibility to modify description on packed items * Fetch description from Material Request or Sales Order in production plan, add the possibility to modify the description un production plan * sync with fork * Fetch description from Material Request or Sales Order in production plan, Add the possibility to modify description in production plan * code cleaning syncing fork * code cleaning syncing fork * code cleaning syncing fork * code cleaning syncing fork * rewied and add item_details.description in case of blank field
This commit is contained in:
		
							parent
							
								
									29a2e16f62
								
							
						
					
					
						commit
						4fa6194009
					
				| @ -99,7 +99,7 @@ class ProductionPlan(Document): | |||||||
| 			self.get_mr_items() | 			self.get_mr_items() | ||||||
| 
 | 
 | ||||||
| 	def get_so_items(self): | 	def get_so_items(self): | ||||||
| 		so_list = [d.sales_order for d in self.get("sales_orders", []) if d.sales_order] | 		so_list = [d.sales_order for d in self.sales_orders if d.sales_order] | ||||||
| 		if not so_list: | 		if not so_list: | ||||||
| 			msgprint(_("Please enter Sales Orders in the above table")) | 			msgprint(_("Please enter Sales Orders in the above table")) | ||||||
| 			return [] | 			return [] | ||||||
| @ -109,7 +109,7 @@ class ProductionPlan(Document): | |||||||
| 			item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code)) | 			item_condition = ' and so_item.item_code = {0}'.format(frappe.db.escape(self.item_code)) | ||||||
| 
 | 
 | ||||||
| 		items = frappe.db.sql("""select distinct parent, item_code, warehouse, | 		items = frappe.db.sql("""select distinct parent, item_code, warehouse, | ||||||
| 			(qty - work_order_qty) * conversion_factor as pending_qty, name | 			(qty - work_order_qty) * conversion_factor as pending_qty, description, name | ||||||
| 			from `tabSales Order Item` so_item | 			from `tabSales Order Item` so_item | ||||||
| 			where parent in (%s) and docstatus = 1 and qty > work_order_qty | 			where parent in (%s) and docstatus = 1 and qty > work_order_qty | ||||||
| 			and exists (select name from `tabBOM` bom where bom.item=so_item.item_code | 			and exists (select name from `tabBOM` bom where bom.item=so_item.item_code | ||||||
| @ -121,7 +121,7 @@ class ProductionPlan(Document): | |||||||
| 
 | 
 | ||||||
| 		packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse, | 		packed_items = frappe.db.sql("""select distinct pi.parent, pi.item_code, pi.warehouse as warehouse, | ||||||
| 			(((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty) | 			(((so_item.qty - so_item.work_order_qty) * pi.qty) / so_item.qty) | ||||||
| 				as pending_qty, pi.parent_item, so_item.name | 				as pending_qty, pi.parent_item, pi.description, so_item.name | ||||||
| 			from `tabSales Order Item` so_item, `tabPacked Item` pi | 			from `tabSales Order Item` so_item, `tabPacked Item` pi | ||||||
| 			where so_item.parent = pi.parent and so_item.docstatus = 1 | 			where so_item.parent = pi.parent and so_item.docstatus = 1 | ||||||
| 			and pi.parent_item = so_item.item_code | 			and pi.parent_item = so_item.item_code | ||||||
| @ -134,7 +134,7 @@ class ProductionPlan(Document): | |||||||
| 		self.calculate_total_planned_qty() | 		self.calculate_total_planned_qty() | ||||||
| 
 | 
 | ||||||
| 	def get_mr_items(self): | 	def get_mr_items(self): | ||||||
| 		mr_list = [d.material_request for d in self.get("material_requests", []) if d.material_request] | 		mr_list = [d.material_request for d in self.material_requests if d.material_request] | ||||||
| 		if not mr_list: | 		if not mr_list: | ||||||
| 			msgprint(_("Please enter Material Requests in the above table")) | 			msgprint(_("Please enter Material Requests in the above table")) | ||||||
| 			return [] | 			return [] | ||||||
| @ -143,7 +143,7 @@ class ProductionPlan(Document): | |||||||
| 		if self.item_code: | 		if self.item_code: | ||||||
| 			item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code)) | 			item_condition = " and mr_item.item_code ={0}".format(frappe.db.escape(self.item_code)) | ||||||
| 
 | 
 | ||||||
| 		items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, | 		items = frappe.db.sql("""select distinct parent, name, item_code, warehouse, description, | ||||||
| 			(qty - ordered_qty) as pending_qty | 			(qty - ordered_qty) as pending_qty | ||||||
| 			from `tabMaterial Request Item` mr_item | 			from `tabMaterial Request Item` mr_item | ||||||
| 			where parent in (%s) and docstatus = 1 and qty > ordered_qty | 			where parent in (%s) and docstatus = 1 and qty > ordered_qty | ||||||
| @ -162,7 +162,7 @@ class ProductionPlan(Document): | |||||||
| 				'include_exploded_items': 1, | 				'include_exploded_items': 1, | ||||||
| 				'warehouse': data.warehouse, | 				'warehouse': data.warehouse, | ||||||
| 				'item_code': data.item_code, | 				'item_code': data.item_code, | ||||||
| 				'description': item_details and item_details.description or '', | 				'description': data.description or item_details.description, | ||||||
| 				'stock_uom': item_details and item_details.stock_uom or '', | 				'stock_uom': item_details and item_details.stock_uom or '', | ||||||
| 				'bom_no': item_details and item_details.bom_no or '', | 				'bom_no': item_details and item_details.bom_no or '', | ||||||
| 				'planned_qty': data.pending_qty, | 				'planned_qty': data.pending_qty, | ||||||
| @ -174,10 +174,12 @@ class ProductionPlan(Document): | |||||||
| 			if self.get_items_from == "Sales Order": | 			if self.get_items_from == "Sales Order": | ||||||
| 				pi.sales_order = data.parent | 				pi.sales_order = data.parent | ||||||
| 				pi.sales_order_item = data.name | 				pi.sales_order_item = data.name | ||||||
|  | 				pi.description = data.description | ||||||
| 
 | 
 | ||||||
| 			elif self.get_items_from == "Material Request": | 			elif self.get_items_from == "Material Request": | ||||||
| 				pi.material_request = data.parent | 				pi.material_request = data.parent | ||||||
| 				pi.material_request_item = data.name | 				pi.material_request_item = data.name | ||||||
|  | 				pi.description = data.description | ||||||
| 
 | 
 | ||||||
| 	def calculate_total_planned_qty(self): | 	def calculate_total_planned_qty(self): | ||||||
| 		self.total_planned_qty = 0 | 		self.total_planned_qty = 0 | ||||||
| @ -195,7 +197,6 @@ class ProductionPlan(Document): | |||||||
| 		for data in self.po_items: | 		for data in self.po_items: | ||||||
| 			if data.name == production_plan_item: | 			if data.name == production_plan_item: | ||||||
| 				data.produced_qty = produced_qty | 				data.produced_qty = produced_qty | ||||||
| 				data.pending_qty = data.planned_qty - data.produced_qty |  | ||||||
| 				data.db_update() | 				data.db_update() | ||||||
| 
 | 
 | ||||||
| 		self.calculate_total_produced_qty() | 		self.calculate_total_produced_qty() | ||||||
| @ -302,6 +303,7 @@ class ProductionPlan(Document): | |||||||
| 				wo_list.extend(work_orders) | 				wo_list.extend(work_orders) | ||||||
| 
 | 
 | ||||||
| 		frappe.flags.mute_messages = False | 		frappe.flags.mute_messages = False | ||||||
|  | 
 | ||||||
| 		if wo_list: | 		if wo_list: | ||||||
| 			wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \ | 			wo_list = ["""<a href="#Form/Work Order/%s" target="_blank">%s</a>""" % \ | ||||||
| 				(p, p) for p in wo_list] | 				(p, p) for p in wo_list] | ||||||
| @ -309,16 +311,15 @@ class ProductionPlan(Document): | |||||||
| 		else : | 		else : | ||||||
| 			msgprint(_("No Work Orders created")) | 			msgprint(_("No Work Orders created")) | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	def make_work_order_for_sub_assembly_items(self, item): | 	def make_work_order_for_sub_assembly_items(self, item): | ||||||
| 		work_orders = [] | 		work_orders = [] | ||||||
| 		bom_data = {} | 		bom_data = {} | ||||||
| 
 | 
 | ||||||
| 		get_sub_assembly_items(item.get("bom_no"), bom_data, item.get("qty")) | 		get_sub_assembly_items(item.get("bom_no"), bom_data) | ||||||
| 
 | 
 | ||||||
| 		for key, data in bom_data.items(): | 		for key, data in bom_data.items(): | ||||||
| 			data.update({ | 			data.update({ | ||||||
| 				'qty': data.get("stock_qty"), | 				'qty': data.get("stock_qty") * item.get("qty"), | ||||||
| 				'production_plan': self.name, | 				'production_plan': self.name, | ||||||
| 				'company': self.company, | 				'company': self.company, | ||||||
| 				'fg_warehouse': item.get("fg_warehouse"), | 				'fg_warehouse': item.get("fg_warehouse"), | ||||||
| @ -561,7 +562,7 @@ def get_sales_orders(self): | |||||||
| 		item_filter += " and so_item.item_code = %(item)s" | 		item_filter += " and so_item.item_code = %(item)s" | ||||||
| 
 | 
 | ||||||
| 	open_so = frappe.db.sql(""" | 	open_so = frappe.db.sql(""" | ||||||
| 		select distinct so.name, so.transaction_date, so.customer, so.base_grand_total as grand_total | 		select distinct so.name, so.transaction_date, so.customer, so.base_grand_total | ||||||
| 		from `tabSales Order` so, `tabSales Order Item` so_item | 		from `tabSales Order` so, `tabSales Order Item` so_item | ||||||
| 		where so_item.parent = so.name | 		where so_item.parent = so.name | ||||||
| 			and so.docstatus = 1 and so.status not in ("Stopped", "Closed") | 			and so.docstatus = 1 and so.status not in ("Stopped", "Closed") | ||||||
| @ -625,7 +626,7 @@ def get_items_for_material_requests(doc, ignore_existing_ordered_qty=None): | |||||||
| 	for data in po_items: | 	for data in po_items: | ||||||
| 		planned_qty = data.get('required_qty') or data.get('planned_qty') | 		planned_qty = data.get('required_qty') or data.get('planned_qty') | ||||||
| 		ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or ignore_existing_ordered_qty | 		ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') or ignore_existing_ordered_qty | ||||||
| 		warehouse = warehouse or data.get("warehouse") | 		warehouse = data.get("warehouse") or warehouse | ||||||
| 
 | 
 | ||||||
| 		item_details = {} | 		item_details = {} | ||||||
| 		if data.get("bom") or data.get("bom_no"): | 		if data.get("bom") or data.get("bom_no"): | ||||||
| @ -708,11 +709,11 @@ def get_item_data(item_code): | |||||||
| 
 | 
 | ||||||
| 	return { | 	return { | ||||||
| 		"bom_no": item_details.get("bom_no"), | 		"bom_no": item_details.get("bom_no"), | ||||||
| 		"stock_uom": item_details.get("stock_uom"), | 		"stock_uom": item_details.get("stock_uom") | ||||||
| 		"description": item_details.get("description") | #		"description": item_details.get("description") | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| def get_sub_assembly_items(bom_no, bom_data, qty): | def get_sub_assembly_items(bom_no, bom_data): | ||||||
| 	data = get_children('BOM', parent = bom_no) | 	data = get_children('BOM', parent = bom_no) | ||||||
| 	for d in data: | 	for d in data: | ||||||
| 		if d.expandable: | 		if d.expandable: | ||||||
| @ -729,6 +730,6 @@ def get_sub_assembly_items(bom_no, bom_data, qty): | |||||||
| 				}) | 				}) | ||||||
| 
 | 
 | ||||||
| 			bom_item = bom_data.get(key) | 			bom_item = bom_data.get(key) | ||||||
| 			bom_item["stock_qty"] += ((d.stock_qty * qty) / d.parent_bom_qty) | 			bom_item["stock_qty"] += d.stock_qty | ||||||
| 
 | 
 | ||||||
| 			get_sub_assembly_items(bom_item.get("bom_no"), bom_data, bom_item["stock_qty"]) | 			get_sub_assembly_items(bom_item.get("bom_no"), bom_data) | ||||||
|  | |||||||
| @ -11,11 +11,9 @@ from erpnext.manufacturing.doctype.production_plan.production_plan import get_sa | |||||||
| from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation | from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import create_stock_reconciliation | ||||||
| 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 | ||||||
| from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests | from erpnext.manufacturing.doctype.production_plan.production_plan import get_items_for_material_requests | ||||||
| from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt import set_perpetual_inventory |  | ||||||
| 
 | 
 | ||||||
| class TestProductionPlan(unittest.TestCase): | class TestProductionPlan(unittest.TestCase): | ||||||
| 	def setUp(self): | 	def setUp(self): | ||||||
| 		set_perpetual_inventory(0) |  | ||||||
| 		for item in ['Test Production Item 1', 'Subassembly Item 1', | 		for item in ['Test Production Item 1', 'Subassembly Item 1', | ||||||
| 			'Raw Material Item 1', 'Raw Material Item 2']: | 			'Raw Material Item 1', 'Raw Material Item 2']: | ||||||
| 			create_item(item, valuation_rate=100) | 			create_item(item, valuation_rate=100) | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user