BIS issue fixes
This commit is contained in:
		
							parent
							
								
									29552c1ec4
								
							
						
					
					
						commit
						34766c0c50
					
				| @ -678,7 +678,9 @@ class BuyingController(StockController): | |||||||
| 		frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name) | 		frappe.db.sql("delete from `tabSerial No` where purchase_document_no=%s", self.name) | ||||||
| 
 | 
 | ||||||
| 	def validate_schedule_date(self): | 	def validate_schedule_date(self): | ||||||
| 		if not self.schedule_date and self.get("items"): | 		if not self.get("items"): | ||||||
|  | 			return | ||||||
|  | 		if not self.schedule_date: | ||||||
| 			self.schedule_date = min([d.schedule_date for d in self.get("items")]) | 			self.schedule_date = min([d.schedule_date for d in self.get("items")]) | ||||||
| 
 | 
 | ||||||
| 		if self.schedule_date: | 		if self.schedule_date: | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ import frappe, json | |||||||
| from frappe import msgprint, _ | from frappe import msgprint, _ | ||||||
| from frappe.model.document import Document | from frappe.model.document import Document | ||||||
| from erpnext.manufacturing.doctype.bom.bom import validate_bom_no | from erpnext.manufacturing.doctype.bom.bom import validate_bom_no | ||||||
| from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime | from frappe.utils import cstr, flt, cint, nowdate, add_days, comma_and, now_datetime, ceil | ||||||
| from erpnext.manufacturing.doctype.work_order.work_order import get_item_details | from erpnext.manufacturing.doctype.work_order.work_order import get_item_details | ||||||
| from six import string_types | from six import string_types | ||||||
| from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults | from erpnext.setup.doctype.item_group.item_group import get_item_group_defaults | ||||||
| @ -376,13 +376,16 @@ def get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock | |||||||
| 	for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, | 	for d in frappe.db.sql("""select bei.item_code, item.default_bom as bom, | ||||||
| 			ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name, | 			ifnull(sum(bei.stock_qty/ifnull(bom.quantity, 1)), 0) as qty, item.item_name, | ||||||
| 			bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, | 			bei.description, bei.stock_uom, item.min_order_qty, bei.source_warehouse, | ||||||
| 			item.default_material_request_type, item.min_order_qty, item_default.default_warehouse | 			item.default_material_request_type, item.min_order_qty, item_default.default_warehouse, | ||||||
|  | 			item.purchase_uom, item_uom.conversion_factor | ||||||
| 		from | 		from | ||||||
| 			`tabBOM Explosion Item` bei | 			`tabBOM Explosion Item` bei | ||||||
| 			JOIN `tabBOM` bom ON bom.name = bei.parent | 			JOIN `tabBOM` bom ON bom.name = bei.parent | ||||||
| 			JOIN `tabItem` item ON item.name = bei.item_code | 			JOIN `tabItem` item ON item.name = bei.item_code | ||||||
| 			LEFT JOIN `tabItem Default` item_default | 			LEFT JOIN `tabItem Default` item_default | ||||||
| 				ON item_default.parent = item.name and item_default.company=%s | 				ON item_default.parent = item.name and item_default.company=%s | ||||||
|  | 			LEFT JOIN `tabUOM Conversion Detail` item_uom | ||||||
|  | 				ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom | ||||||
| 		where | 		where | ||||||
| 			bei.docstatus < 2 | 			bei.docstatus < 2 | ||||||
| 			and bom.name=%s and item.is_stock_item in (1, {0}) | 			and bom.name=%s and item.is_stock_item in (1, {0}) | ||||||
| @ -399,13 +402,15 @@ def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_ | |||||||
| 			item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, | 			item.is_sub_contracted_item as is_sub_contracted, bom_item.source_warehouse, | ||||||
| 			item.default_bom as default_bom, bom_item.description as description, | 			item.default_bom as default_bom, bom_item.description as description, | ||||||
| 			bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, | 			bom_item.stock_uom as stock_uom, item.min_order_qty as min_order_qty, | ||||||
| 			item_default.default_warehouse | 			item_default.default_warehouse, item.purchase_uom, item_uom.conversion_factor | ||||||
| 		FROM | 		FROM | ||||||
| 			`tabBOM Item` bom_item | 			`tabBOM Item` bom_item | ||||||
| 			JOIN `tabBOM` bom ON bom.name = bom_item.parent | 			JOIN `tabBOM` bom ON bom.name = bom_item.parent | ||||||
| 			JOIN tabItem item ON bom_item.item_code = item.name | 			JOIN tabItem item ON bom_item.item_code = item.name | ||||||
| 			LEFT JOIN `tabItem Default` item_default | 			LEFT JOIN `tabItem Default` item_default | ||||||
| 				ON item.name = item_default.parent and item_default.company = %(company)s | 				ON item.name = item_default.parent and item_default.company = %(company)s | ||||||
|  | 			LEFT JOIN `tabUOM Conversion Detail` item_uom | ||||||
|  | 				ON item.name = item_uom.parent and item_uom.uom = item.purchase_uom | ||||||
| 		where | 		where | ||||||
| 			bom.name = %(bom)s | 			bom.name = %(bom)s | ||||||
| 			and bom_item.docstatus < 2 | 			and bom_item.docstatus < 2 | ||||||
| @ -431,17 +436,30 @@ def get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_ | |||||||
| 	return bom_wise_item_details | 	return bom_wise_item_details | ||||||
| 
 | 
 | ||||||
| def add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, row, data, warehouse, company): | def add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, row, data, warehouse, company): | ||||||
|  | 	print("add item in material request") | ||||||
| 	total_qty = row.qty * planned_qty | 	total_qty = row.qty * planned_qty | ||||||
| 	projected_qty, actual_qty = get_bin_details(row) | 	projected_qty, actual_qty = get_bin_details(row) | ||||||
| 
 | 
 | ||||||
| 	requested_qty = 0 | 	requested_qty = 0 | ||||||
| 	if ignore_existing_ordered_qty: | 	if ignore_existing_ordered_qty: | ||||||
| 		requested_qty = total_qty | 		requested_qty = total_qty | ||||||
| 	else: | 	elif total_qty > projected_qty: | ||||||
| 		requested_qty = total_qty - projected_qty | 		requested_qty = total_qty - projected_qty | ||||||
| 	if requested_qty > 0 and requested_qty < row.min_order_qty: | 	if requested_qty > 0 and requested_qty < row.min_order_qty: | ||||||
| 		requested_qty = row.min_order_qty | 		requested_qty = row.min_order_qty | ||||||
| 	item_group_defaults = get_item_group_defaults(item, company) | 	item_group_defaults = get_item_group_defaults(item, company) | ||||||
|  | 
 | ||||||
|  | 	if not row.purchase_uom: | ||||||
|  | 		row.purchase_uom = row.stock_uom | ||||||
|  | 
 | ||||||
|  | 	if row.purchase_uom != row.stock_uom: | ||||||
|  | 		if not row.conversion_factor: | ||||||
|  | 			frappe.throw(_("UOM Conversion factor ({0} -> {1}) not found for item: {2}").format(row.purchase_uom, row.stock_uom, item)) | ||||||
|  | 
 | ||||||
|  | 		requested_qty = requested_qty / row.conversion_factor | ||||||
|  | 	if frappe.db.get_value("UOM", row.purchase_uom, "must_be_whole_number"): | ||||||
|  | 		requested_qty = ceil(requested_qty) | ||||||
|  | 	print(row) | ||||||
| 	if requested_qty > 0: | 	if requested_qty > 0: | ||||||
| 		doc.setdefault('mr_items', []).append({ | 		doc.setdefault('mr_items', []).append({ | ||||||
| 			'item_code': item, | 			'item_code': item, | ||||||
| @ -487,8 +505,8 @@ def get_sales_orders(self): | |||||||
| 			"project": self.project, | 			"project": self.project, | ||||||
| 			"item": self.item_code, | 			"item": self.item_code, | ||||||
| 			"company": self.company | 			"company": self.company | ||||||
| 		}, as_dict=1) |  | ||||||
| 
 | 
 | ||||||
|  | 		}, as_dict=1) | ||||||
| 	return open_so | 	return open_so | ||||||
| 
 | 
 | ||||||
| @frappe.whitelist() | @frappe.whitelist() | ||||||
| @ -511,6 +529,7 @@ def get_bin_details(row): | |||||||
| 
 | 
 | ||||||
| @frappe.whitelist() | @frappe.whitelist() | ||||||
| def get_items_for_material_requests(doc, company=None): | def get_items_for_material_requests(doc, company=None): | ||||||
|  | 	print("get items for material request") | ||||||
| 	if isinstance(doc, string_types): | 	if isinstance(doc, string_types): | ||||||
| 		doc = frappe._dict(json.loads(doc)) | 		doc = frappe._dict(json.loads(doc)) | ||||||
| 
 | 
 | ||||||
| @ -520,34 +539,69 @@ def get_items_for_material_requests(doc, company=None): | |||||||
| 	for data in po_items: | 	for data in po_items: | ||||||
| 		warehouse = None | 		warehouse = None | ||||||
| 		bom_wise_item_details = {} | 		bom_wise_item_details = {} | ||||||
| 
 | 		if data.get("bom"): | ||||||
| 		if data.get('required_qty'): | 			print(doc),print("-------------------------------------------------") | ||||||
| 			planned_qty = data.get('required_qty') | 			if data.get('required_qty'): | ||||||
| 			bom_no = data.get('bom') | 				planned_qty = data.get('required_qty') | ||||||
| 			ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') | 				bom_no = data.get('bom') | ||||||
| 			include_non_stock_items = 1 | 				ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') | ||||||
| 			warehouse = data.get('for_warehouse') | 				include_non_stock_items = 1 | ||||||
| 			if data.get('include_exploded_items'): | 				warehouse = data.get('for_warehouse') | ||||||
| 				include_subcontracted_items = 1 | 				if data.get('include_exploded_items'): | ||||||
|  | 					include_subcontracted_items = 1 | ||||||
|  | 				else: | ||||||
|  | 					include_subcontracted_items = 0 | ||||||
| 			else: | 			else: | ||||||
| 				include_subcontracted_items = 0 | 				planned_qty = data.get('planned_qty') | ||||||
| 		else: | 				bom_no = data.get('bom_no') | ||||||
| 			planned_qty = data.get('planned_qty') | 				include_subcontracted_items = doc.get('include_subcontracted_items') | ||||||
| 			bom_no = data.get('bom_no') | 				company = doc.get('company') | ||||||
| 			include_subcontracted_items = doc.get('include_subcontracted_items') | 				include_non_stock_items = doc.get('include_non_stock_items') | ||||||
| 			company = doc.get('company') | 				ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty') | ||||||
| 			include_non_stock_items = doc.get('include_non_stock_items') | 			if not planned_qty: | ||||||
| 			ignore_existing_ordered_qty = doc.get('ignore_existing_ordered_qty') | 				frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx'))) | ||||||
| 		if not planned_qty: |  | ||||||
| 			frappe.throw(_("For row {0}: Enter Planned Qty").format(data.get('idx'))) |  | ||||||
| 
 | 
 | ||||||
| 		if data.get('include_exploded_items') and bom_no and include_subcontracted_items: | 			if data.get('include_exploded_items') and bom_no and include_subcontracted_items: | ||||||
| 			# fetch exploded items from BOM | 				# fetch exploded items from BOM | ||||||
| 			bom_wise_item_details = get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items) | 				bom_wise_item_details = get_exploded_items(bom_wise_item_details, company, bom_no, include_non_stock_items) | ||||||
|  | 			else: | ||||||
|  | 				bom_wise_item_details = get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1) | ||||||
|  | 			for item, item_details in bom_wise_item_details.items(): | ||||||
|  | 				print(item),print(item_details) | ||||||
|  | 				if item_details.qty > 0: | ||||||
|  | 					add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company) | ||||||
| 		else: | 		else: | ||||||
| 			bom_wise_item_details = get_subitems(doc, data, bom_wise_item_details, bom_no, company, include_non_stock_items, include_subcontracted_items, 1) | 			sales_order_item = frappe.get_doc('Sales OrderItem', data.sales_order_item).as_dict() | ||||||
| 		for item, item_details in bom_wise_item_details.items(): | 			planned_qty = data.get('required_qty') | ||||||
|  | 			ignore_existing_ordered_qty = data.get('ignore_existing_ordered_qty') | ||||||
|  | 			item = doc.item_code | ||||||
|  | 			purchase_uom = sales_order_item.uom | ||||||
|  | 			stock_uom = sales_order_item.stock_uom | ||||||
|  | 			conversion_factor = sales_order_item.conversion_factor | ||||||
|  | 			qty = doc.required_qty | ||||||
|  | 			if not purchase_uom == stock_uom: | ||||||
|  | 				qty = qty / conversion_factor | ||||||
|  | 			if frappe.db.get_value("UOM", purchase_uom, "must_be_whole_number"): | ||||||
|  | 					qty = ceil(qty) | ||||||
|  | 			item_details = { | ||||||
|  | 			'item_name' = sales_order_item.item_name, | ||||||
|  | 			'default_bom' = doc.bom, | ||||||
|  | 			'purchase_uom' = purchase_uom, | ||||||
|  | 			'default_warehouse' = doc.warehouse, | ||||||
|  | 			'min_order_qty' = | ||||||
|  | 			'default_material_request_type' = | ||||||
|  | 			'qty' = qty, | ||||||
|  | 			'is_sub_contracted' = , | ||||||
|  | 			'item_code' = doc.item_code, | ||||||
|  | 			'description' = sales_order_item.description, | ||||||
|  | 			'stock_uom' = stock_uom, | ||||||
|  | 			'conversion_factor' = conversion_factor, | ||||||
|  | 			'source_warehouse' = , | ||||||
|  | 			} | ||||||
|  | 			warehouse = doc.warehouse | ||||||
|  | 			company = | ||||||
| 			if item_details.qty > 0: | 			if item_details.qty > 0: | ||||||
| 				add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company) | 				add_item_in_material_request_items(doc, planned_qty, ignore_existing_ordered_qty, item, item_details, data, warehouse, company) | ||||||
|  | 			print(doc),print("-------------------------------------------------") | ||||||
| 
 | 
 | ||||||
| 	return doc['mr_items'] | 	return doc['mr_items'] | ||||||
|  | |||||||
| @ -344,6 +344,8 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( | |||||||
| 				label: __('Include Exploded Items')}, | 				label: __('Include Exploded Items')}, | ||||||
| 			{fieldtype:'Check', fieldname:'ignore_existing_ordered_qty', | 			{fieldtype:'Check', fieldname:'ignore_existing_ordered_qty', | ||||||
| 				label: __('Ignore Existing Ordered Qty')}, | 				label: __('Ignore Existing Ordered Qty')}, | ||||||
|  | 			{fieldtype:'Check', fieldname:'include_raw_materials_from_sales_order', | ||||||
|  | 				label: __('Include raw materials from sales order')}, | ||||||
| 			{ | 			{ | ||||||
| 				fieldtype:'Table', fieldname: 'items', | 				fieldtype:'Table', fieldname: 'items', | ||||||
| 				description: __('Select BOM, Qty and For Warehouse'), | 				description: __('Select BOM, Qty and For Warehouse'), | ||||||
| @ -367,7 +369,7 @@ erpnext.selling.SalesOrderController = erpnext.selling.SellingController.extend( | |||||||
| 			} | 			} | ||||||
| 		] | 		] | ||||||
| 		var d = new frappe.ui.Dialog({ | 		var d = new frappe.ui.Dialog({ | ||||||
| 			title: __("Select from Items having BOM"), | 			title: __("Items for Raw Material Request"), | ||||||
| 			fields: fields, | 			fields: fields, | ||||||
| 			primary_action: function() { | 			primary_action: function() { | ||||||
| 				var data = d.get_values(); | 				var data = d.get_values(); | ||||||
|  | |||||||
| @ -341,11 +341,11 @@ class SalesOrder(SellingController): | |||||||
| 
 | 
 | ||||||
| 			delivered_qty += item.delivered_qty | 			delivered_qty += item.delivered_qty | ||||||
| 			tot_qty += item.qty | 			tot_qty += item.qty | ||||||
| 		 | 
 | ||||||
| 		if tot_qty != 0: | 		if tot_qty != 0: | ||||||
| 			self.db_set("per_delivered", flt(delivered_qty/tot_qty) * 100, | 			self.db_set("per_delivered", flt(delivered_qty/tot_qty) * 100, | ||||||
| 				update_modified=False) | 				update_modified=False) | ||||||
| 		 | 
 | ||||||
| 
 | 
 | ||||||
| 	def set_indicator(self): | 	def set_indicator(self): | ||||||
| 		"""Set indicator for portal""" | 		"""Set indicator for portal""" | ||||||
| @ -372,20 +372,19 @@ class SalesOrder(SellingController): | |||||||
| 	def get_work_order_items(self, for_raw_material_request=0): | 	def get_work_order_items(self, for_raw_material_request=0): | ||||||
| 		'''Returns items with BOM that already do not have a linked work order''' | 		'''Returns items with BOM that already do not have a linked work order''' | ||||||
| 		items = [] | 		items = [] | ||||||
| 
 |  | ||||||
| 		for table in [self.items, self.packed_items]: | 		for table in [self.items, self.packed_items]: | ||||||
| 			for i in table: | 			for i in table: | ||||||
| 				bom = get_default_bom_item(i.item_code) | 				bom = get_default_bom_item(i.item_code) | ||||||
| 				if bom: | 				stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty | ||||||
| 					stock_qty = i.qty if i.doctype == 'Packed Item' else i.stock_qty | 				if not for_raw_material_request: | ||||||
| 					if not for_raw_material_request: | 					total_work_order_qty = flt(frappe.db.sql('''select sum(qty) from `tabWork Order` | ||||||
| 						total_work_order_qty = flt(frappe.db.sql('''select sum(qty) from `tabWork Order` | 						where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2''', (i.item_code, self.name, i.name))[0][0]) | ||||||
| 							where production_item=%s and sales_order=%s and sales_order_item = %s and docstatus<2''', (i.item_code, self.name, i.name))[0][0]) | 					pending_qty = stock_qty - total_work_order_qty | ||||||
| 						pending_qty = stock_qty - total_work_order_qty | 				else: | ||||||
| 					else: | 					pending_qty = stock_qty | ||||||
| 						pending_qty = stock_qty |  | ||||||
| 
 | 
 | ||||||
| 					if pending_qty: | 				if pending_qty: | ||||||
|  | 					if bom: | ||||||
| 						items.append(dict( | 						items.append(dict( | ||||||
| 							name= i.name, | 							name= i.name, | ||||||
| 							item_code= i.item_code, | 							item_code= i.item_code, | ||||||
| @ -395,6 +394,16 @@ class SalesOrder(SellingController): | |||||||
| 							required_qty = pending_qty if for_raw_material_request else 0, | 							required_qty = pending_qty if for_raw_material_request else 0, | ||||||
| 							sales_order_item = i.name | 							sales_order_item = i.name | ||||||
| 						)) | 						)) | ||||||
|  | 					else: | ||||||
|  | 						items.append(dict( | ||||||
|  | 							name= i.name, | ||||||
|  | 							item_code= i.item_code, | ||||||
|  | 							bom = '', | ||||||
|  | 							warehouse = i.warehouse, | ||||||
|  | 							pending_qty = pending_qty, | ||||||
|  | 							required_qty = pending_qty if for_raw_material_request else 0, | ||||||
|  | 							sales_order_item = i.name | ||||||
|  | 						)) | ||||||
| 		return items | 		return items | ||||||
| 
 | 
 | ||||||
| 	def on_recurring(self, reference_doc, auto_repeat_doc): | 	def on_recurring(self, reference_doc, auto_repeat_doc): | ||||||
| @ -923,10 +932,12 @@ def make_raw_material_request(items, company, sales_order, project=None): | |||||||
| 	for item in items.get('items'): | 	for item in items.get('items'): | ||||||
| 		item["include_exploded_items"] = items.get('include_exploded_items') | 		item["include_exploded_items"] = items.get('include_exploded_items') | ||||||
| 		item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty') | 		item["ignore_existing_ordered_qty"] = items.get('ignore_existing_ordered_qty') | ||||||
|  | 		item["include_raw_materials_from_sales_order"] = items.get('include_raw_materials_from_sales_order') | ||||||
| 
 | 
 | ||||||
| 	raw_materials = get_items_for_material_requests(items, company) | 	raw_materials = get_items_for_material_requests(items, company) | ||||||
| 	if not raw_materials: | 	if not raw_materials: | ||||||
| 		frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available.")) | 		frappe.msgprint(_("Material Request not created, as quantity for Raw Materials already available.")) | ||||||
|  | 		return | ||||||
| 
 | 
 | ||||||
| 	material_request = frappe.new_doc('Material Request') | 	material_request = frappe.new_doc('Material Request') | ||||||
| 	material_request.update(dict( | 	material_request.update(dict( | ||||||
| @ -951,4 +962,4 @@ def make_raw_material_request(items, company, sales_order, project=None): | |||||||
| 	material_request.flags.ignore_permissions = 1 | 	material_request.flags.ignore_permissions = 1 | ||||||
| 	material_request.run_method("set_missing_values") | 	material_request.run_method("set_missing_values") | ||||||
| 	material_request.submit() | 	material_request.submit() | ||||||
| 	return material_request | 	return material_request | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user