refactor: BOM Stock Calculated report
This commit is contained in:
		
							parent
							
								
									659d007bf0
								
							
						
					
					
						commit
						723fa9eebc
					
				| @ -4,29 +4,31 @@ | ||||
| 
 | ||||
| import frappe | ||||
| from frappe import _ | ||||
| from frappe.query_builder.functions import Floor, IfNull, Sum | ||||
| from frappe.utils.data import comma_and | ||||
| from pypika.terms import ExistsCriterion | ||||
| 
 | ||||
| 
 | ||||
| def execute(filters=None): | ||||
| 	# if not filters: filters = {} | ||||
| 	columns = get_columns() | ||||
| 	summ_data = [] | ||||
| 	data = [] | ||||
| 
 | ||||
| 	data = get_bom_stock(filters) | ||||
| 	bom_data = get_bom_data(filters) | ||||
| 	qty_to_make = filters.get("qty_to_make") | ||||
| 
 | ||||
| 	manufacture_details = get_manufacturer_records() | ||||
| 	for row in data: | ||||
| 		reqd_qty = qty_to_make * row.actual_qty | ||||
| 		last_pur_price = frappe.db.get_value("Item", row.item_code, "last_purchase_rate") | ||||
| 
 | ||||
| 		summ_data.append(get_report_data(last_pur_price, reqd_qty, row, manufacture_details)) | ||||
| 	return columns, summ_data | ||||
| 	for row in bom_data: | ||||
| 		required_qty = qty_to_make * row.actual_qty | ||||
| 		last_purchase_rate = frappe.db.get_value("Item", row.item_code, "last_purchase_rate") | ||||
| 
 | ||||
| 		data.append(get_report_data(last_purchase_rate, required_qty, row, manufacture_details)) | ||||
| 
 | ||||
| 	return columns, data | ||||
| 
 | ||||
| 
 | ||||
| def get_report_data(last_pur_price, reqd_qty, row, manufacture_details): | ||||
| def get_report_data(last_purchase_rate, required_qty, row, manufacture_details): | ||||
| 	to_build = row.to_build if row.to_build > 0 else 0 | ||||
| 	diff_qty = to_build - reqd_qty | ||||
| 	difference_qty = to_build - required_qty | ||||
| 	return [ | ||||
| 		row.item_code, | ||||
| 		row.description, | ||||
| @ -36,83 +38,127 @@ def get_report_data(last_pur_price, reqd_qty, row, manufacture_details): | ||||
| 		), | ||||
| 		row.actual_qty, | ||||
| 		str(to_build), | ||||
| 		reqd_qty, | ||||
| 		diff_qty, | ||||
| 		last_pur_price, | ||||
| 		required_qty, | ||||
| 		difference_qty, | ||||
| 		last_purchase_rate, | ||||
| 	] | ||||
| 
 | ||||
| 
 | ||||
| def get_columns(): | ||||
| 	"""return columns""" | ||||
| 	columns = [ | ||||
| 		_("Item") + ":Link/Item:100", | ||||
| 		_("Description") + "::150", | ||||
| 		_("Manufacturer") + "::250", | ||||
| 		_("Manufacturer Part Number") + "::250", | ||||
| 		_("Qty") + ":Float:50", | ||||
| 		_("Stock Qty") + ":Float:100", | ||||
| 		_("Reqd Qty") + ":Float:100", | ||||
| 		_("Diff Qty") + ":Float:100", | ||||
| 		_("Last Purchase Price") + ":Float:100", | ||||
| 	return [ | ||||
| 		{ | ||||
| 			"fieldname": "item", | ||||
| 			"label": _("Item"), | ||||
| 			"fieldtype": "Link", | ||||
| 			"options": "Item", | ||||
| 			"width": 120, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "description", | ||||
| 			"label": _("Description"), | ||||
| 			"fieldtype": "Data", | ||||
| 			"width": 150, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "manufacturer", | ||||
| 			"label": _("Manufacturer"), | ||||
| 			"fieldtype": "Data", | ||||
| 			"width": 120, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "manufacturer_part_number", | ||||
| 			"label": _("Manufacturer Part Number"), | ||||
| 			"fieldtype": "Data", | ||||
| 			"width": 150, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "available_qty", | ||||
| 			"label": _("Available Qty"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 120, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "qty_per_unit", | ||||
| 			"label": _("Qty Per Unit"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 110, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "required_qty", | ||||
| 			"label": _("Required Qty"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 120, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "difference_qty", | ||||
| 			"label": _("Difference Qty"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 130, | ||||
| 		}, | ||||
| 		{ | ||||
| 			"fieldname": "last_purchase_rate", | ||||
| 			"label": _("Last Purchase Rate"), | ||||
| 			"fieldtype": "Float", | ||||
| 			"width": 160, | ||||
| 		}, | ||||
| 	] | ||||
| 	return columns | ||||
| 
 | ||||
| 
 | ||||
| def get_bom_stock(filters): | ||||
| 	conditions = "" | ||||
| 	bom = filters.get("bom") | ||||
| 
 | ||||
| 	table = "`tabBOM Item`" | ||||
| 	qty_field = "qty" | ||||
| 
 | ||||
| def get_bom_data(filters): | ||||
| 	if filters.get("show_exploded_view"): | ||||
| 		table = "`tabBOM Explosion Item`" | ||||
| 		qty_field = "stock_qty" | ||||
| 		bom_item_table = "BOM Explosion Item" | ||||
| 	else: | ||||
| 		qty_field = "qty" | ||||
| 		bom_item_table = "BOM Item" | ||||
| 
 | ||||
| 	bom_item = frappe.qb.DocType(bom_item_table) | ||||
| 	bin = frappe.qb.DocType("Bin") | ||||
| 
 | ||||
| 	query = ( | ||||
| 		frappe.qb.from_(bom_item) | ||||
| 		.left_join(bin) | ||||
| 		.on(bom_item.item_code == bin.item_code) | ||||
| 		.select( | ||||
| 			bom_item.item_code, | ||||
| 			bom_item.description, | ||||
| 			bom_item[qty_field], | ||||
| 			IfNull(Sum(bin.actual_qty), 0).as_("actual_qty"), | ||||
| 			IfNull(Sum(Floor(bin.actual_qty / bom_item[qty_field])), 0).as_("to_build"), | ||||
| 		) | ||||
| 		.where((bom_item.parent == filters.get("bom")) & (bom_item.parenttype == "BOM")) | ||||
| 		.groupby(bom_item.item_code) | ||||
| 	) | ||||
| 
 | ||||
| 	if filters.get("warehouse"): | ||||
| 		warehouse_details = frappe.db.get_value( | ||||
| 			"Warehouse", filters.get("warehouse"), ["lft", "rgt"], as_dict=1 | ||||
| 		) | ||||
| 
 | ||||
| 		if warehouse_details: | ||||
| 			conditions += ( | ||||
| 				" and exists (select name from `tabWarehouse` wh \ | ||||
| 				where wh.lft >= %s and wh.rgt <= %s and ledger.warehouse = wh.name)" | ||||
| 				% (warehouse_details.lft, warehouse_details.rgt) | ||||
| 			wh = frappe.qb.DocType("Warehouse") | ||||
| 			query = query.where( | ||||
| 				ExistsCriterion( | ||||
| 					frappe.qb.from_(wh) | ||||
| 					.select(wh.name) | ||||
| 					.where( | ||||
| 						(wh.lft >= warehouse_details.lft) | ||||
| 						& (wh.rgt <= warehouse_details.rgt) | ||||
| 						& (bin.warehouse == wh.name) | ||||
| 					) | ||||
| 				) | ||||
| 			) | ||||
| 		else: | ||||
| 			conditions += " and ledger.warehouse = %s" % frappe.db.escape(filters.get("warehouse")) | ||||
| 			query = query.where(bin.warehouse == frappe.db.escape(filters.get("warehouse"))) | ||||
| 
 | ||||
| 	else: | ||||
| 		conditions += "" | ||||
| 
 | ||||
| 	return frappe.db.sql( | ||||
| 		""" | ||||
| 			SELECT | ||||
| 				bom_item.item_code, | ||||
| 				bom_item.description, | ||||
| 				bom_item.{qty_field}, | ||||
| 				ifnull(sum(ledger.actual_qty), 0) as actual_qty, | ||||
| 				ifnull(sum(FLOOR(ledger.actual_qty / bom_item.{qty_field})), 0) as to_build | ||||
| 			FROM | ||||
| 				{table} AS bom_item | ||||
| 				LEFT JOIN `tabBin` AS ledger | ||||
| 				ON bom_item.item_code = ledger.item_code | ||||
| 				{conditions} | ||||
| 
 | ||||
| 			WHERE | ||||
| 				bom_item.parent = '{bom}' and bom_item.parenttype='BOM' | ||||
| 
 | ||||
| 			GROUP BY bom_item.item_code""".format( | ||||
| 			qty_field=qty_field, table=table, conditions=conditions, bom=bom | ||||
| 		), | ||||
| 		as_dict=1, | ||||
| 	) | ||||
| 	return query.run(as_dict=True) | ||||
| 
 | ||||
| 
 | ||||
| def get_manufacturer_records(): | ||||
| 	details = frappe.get_all( | ||||
| 		"Item Manufacturer", fields=["manufacturer", "manufacturer_part_no", "item_code"] | ||||
| 	) | ||||
| 
 | ||||
| 	manufacture_details = frappe._dict() | ||||
| 	for detail in details: | ||||
| 		dic = manufacture_details.setdefault(detail.get("item_code"), {}) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user