From b0019bcf5be87ddb88846af76baf018ae532d7aa Mon Sep 17 00:00:00 2001 From: marination Date: Fri, 21 May 2021 21:27:55 +0530 Subject: [PATCH] fix: Item Variant Details Report Co-authored-by: gavindsouza - Handling of variants with special characters - Set data in appropriately named columns - Code cleanup --- .../item_variant_details.py | 262 +++++++++++------- 1 file changed, 157 insertions(+), 105 deletions(-) diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.py b/erpnext/stock/report/item_variant_details/item_variant_details.py index e8449cc33e..d8563d7927 100644 --- a/erpnext/stock/report/item_variant_details/item_variant_details.py +++ b/erpnext/stock/report/item_variant_details/item_variant_details.py @@ -14,47 +14,58 @@ def get_data(item): if not item: return [] item_dicts = [] - variants = None - variant_results = frappe.db.sql("""select name from `tabItem` - where variant_of = %s""", item, as_dict=1) + variant_results = frappe.db.get_all( + "Item", + fields=["name"], + filters={ + "variant_of": ["=", item], + "disabled": 0 + } + ) + if not variant_results: - frappe.msgprint(_("There isn't any item variant for the selected item")) + frappe.msgprint(_("There aren't any item variants for the selected item")) return [] else: - variants = ", ".join([frappe.db.escape(variant['name']) for variant in variant_results]) + variant_list = [variant['name'] for variant in variant_results] - order_count_map = get_open_sales_orders_map(variants) - stock_details_map = get_stock_details_map(variants) - buying_price_map = get_buying_price_map(variants) - selling_price_map = get_selling_price_map(variants) - attr_val_map = get_attribute_values_map(variants) + order_count_map = get_open_sales_orders_count(variant_list) + stock_details_map = get_stock_details_map(variant_list) + buying_price_map = get_buying_price_map(variant_list) + selling_price_map = get_selling_price_map(variant_list) + attr_val_map = get_attribute_values_map(variant_list) - attribute_list = [d[0] for d in frappe.db.sql("""select attribute - from `tabItem Variant Attribute` - where parent in ({variants}) group by attribute""".format(variants=variants))] + attributes = frappe.db.get_all( + "Item Variant Attribute", + fields=["attribute"], + filters={ + "parent": ["in", variant_list] + }, + group_by="attribute" + ) + attribute_list = [row.get("attribute") for row in attributes] # Prepare dicts variant_dicts = [{"variant_name": d['name']} for d in variant_results] for item_dict in variant_dicts: - name = item_dict["variant_name"] + name = item_dict.get("variant_name") - for d in attribute_list: - attr_dict = attr_val_map[name] - if attr_dict and attr_dict.get(d): - item_dict[d] = attr_val_map[name][d] + for attribute in attribute_list: + attr_dict = attr_val_map.get(name) + if attr_dict and attr_dict.get(attribute): + item_dict[frappe.scrub(attribute)] = attr_val_map.get(name).get(attribute) - item_dict["Open Orders"] = order_count_map.get(name) or 0 + item_dict["open_orders"] = order_count_map.get(name) or 0 if stock_details_map.get(name): - item_dict["Inventory"] = stock_details_map.get(name)["Inventory"] or 0 - item_dict["In Production"] = stock_details_map.get(name)["In Production"] or 0 - item_dict["Available Selling"] = stock_details_map.get(name)["Available Selling"] or 0 + item_dict["current_stock"] = stock_details_map.get(name)["Inventory"] or 0 + item_dict["in_production"] = stock_details_map.get(name)["In Production"] or 0 else: - item_dict["Inventory"] = item_dict["In Production"] = item_dict["Available Selling"] = 0 + item_dict["current_stock"] = item_dict["in_production"] = 0 - item_dict["Avg. Buying Price List Rate"] = buying_price_map.get(name) or 0 - item_dict["Avg. Selling Price List Rate"] = selling_price_map.get(name) or 0 + item_dict["avg_buying_price_list_rate"] = buying_price_map.get(name) or 0 + item_dict["avg_selling_price_list_rate"] = selling_price_map.get(name) or 0 item_dicts.append(item_dict) @@ -71,117 +82,158 @@ def get_columns(item): item_doc = frappe.get_doc("Item", item) - for d in item_doc.attributes: - columns.append(d.attribute + ":Data:100") + for entry in item_doc.attributes: + columns.append({ + "fieldname": frappe.scrub(entry.attribute), + "label": entry.attribute, + "fieldtype": "Data", + "width": 100 + }) - columns += [_("Avg. Buying Price List Rate") + ":Currency:110", _("Avg. Selling Price List Rate") + ":Currency:110", - _("Inventory") + ":Float:100", _("In Production") + ":Float:100", - _("Open Orders") + ":Float:100", _("Available Selling") + ":Float:100" + additional_columns = [ + { + "fieldname": "avg_buying_price_list_rate", + "label": _("Avg. Buying Price List Rate"), + "fieldtype": "Currency", + "width": 150 + }, + { + "fieldname": "avg_selling_price_list_rate", + "label": _("Avg. Selling Price List Rate"), + "fieldtype": "Currency", + "width": 150 + }, + { + "fieldname": "current_stock", + "label": _("Current Stock"), + "fieldtype": "Float", + "width": 120 + }, + { + "fieldname": "in_production", + "label": _("In Production"), + "fieldtype": "Float", + "width": 150 + }, + { + "fieldname": "open_orders", + "label": _("Open Sales Orders"), + "fieldtype": "Float", + "width": 150 + } ] + columns.extend(additional_columns) return columns -def get_open_sales_orders_map(variants): - open_sales_orders = frappe.db.sql(""" - select - count(*) as count, - item_code - from - `tabSales Order Item` - where - docstatus = 1 and - qty > ifnull(delivered_qty, 0) and - item_code in ({variants}) - group by - item_code - """.format(variants=variants), as_dict=1) +def get_open_sales_orders_count(variants_list): + open_sales_orders = frappe.db.get_list( + "Sales Order", + fields=[ + "name", + "`tabSales Order Item`.item_code" + ], + filters=[ + ["Sales Order", "docstatus", "=", 1], + ["Sales Order Item", "item_code", "in", variants_list] + ], + distinct=1 + ) order_count_map = {} - for d in open_sales_orders: - order_count_map[d["item_code"]] = d["count"] + for row in open_sales_orders: + item_code = row.get("item_code") + if order_count_map.get(item_code) is None: + order_count_map[item_code] = 1 + else: + order_count_map[item_code] += 1 return order_count_map -def get_stock_details_map(variants): - stock_details = frappe.db.sql(""" - select - sum(planned_qty) as planned_qty, - sum(actual_qty) as actual_qty, - sum(projected_qty) as projected_qty, - item_code - from - `tabBin` - where - item_code in ({variants}) - group by - item_code - """.format(variants=variants), as_dict=1) +def get_stock_details_map(variant_list): + stock_details = frappe.db.get_all( + "Bin", + fields=[ + "sum(planned_qty) as planned_qty", + "sum(actual_qty) as actual_qty", + "sum(projected_qty) as projected_qty", + "item_code", + ], + filters={ + "item_code": ["in", variant_list] + }, + group_by="item_code" + ) stock_details_map = {} - for d in stock_details: - name = d["item_code"] + for row in stock_details: + name = row.get("item_code") stock_details_map[name] = { - "Inventory" :d["actual_qty"], - "In Production" :d["planned_qty"], - "Available Selling" :d["projected_qty"] + "Inventory": row.get("actual_qty"), + "In Production": row.get("planned_qty") } return stock_details_map -def get_buying_price_map(variants): - buying = frappe.db.sql(""" - select - avg(price_list_rate) as avg_rate, - item_code - from - `tabItem Price` - where - item_code in ({variants}) and buying=1 - group by - item_code - """.format(variants=variants), as_dict=1) +def get_buying_price_map(variant_list): + buying = frappe.db.get_all( + "Item Price", + fields=[ + "avg(price_list_rate) as avg_rate", + "item_code", + ], + filters={ + "item_code": ["in", variant_list], + "buying": 1 + }, + group_by="item_code" + ) buying_price_map = {} - for d in buying: - buying_price_map[d["item_code"]] = d["avg_rate"] + for row in buying: + buying_price_map[row.get("item_code")] = row.get("avg_rate") return buying_price_map -def get_selling_price_map(variants): - selling = frappe.db.sql(""" - select - avg(price_list_rate) as avg_rate, - item_code - from - `tabItem Price` - where - item_code in ({variants}) and selling=1 - group by - item_code - """.format(variants=variants), as_dict=1) +def get_selling_price_map(variant_list): + selling = frappe.db.get_all( + "Item Price", + fields=[ + "avg(price_list_rate) as avg_rate", + "item_code", + ], + filters={ + "item_code": ["in", variant_list], + "selling": 1 + }, + group_by="item_code" + ) selling_price_map = {} - for d in selling: - selling_price_map[d["item_code"]] = d["avg_rate"] + for row in selling: + selling_price_map[row.get("item_code")] = row.get("avg_rate") return selling_price_map -def get_attribute_values_map(variants): - list_attr = frappe.db.sql(""" - select - attribute, attribute_value, parent - from - `tabItem Variant Attribute` - where - parent in ({variants}) - """.format(variants=variants), as_dict=1) +def get_attribute_values_map(variant_list): + attribute_list = frappe.db.get_all( + "Item Variant Attribute", + fields=[ + "attribute", + "attribute_value", + "parent" + ], + filters={ + "parent": ["in", variant_list] + } + ) attr_val_map = {} - for d in list_attr: - name = d["parent"] + for row in attribute_list: + name = row.get("parent") if not attr_val_map.get(name): attr_val_map[name] = {} - attr_val_map[name][d["attribute"]] = d["attribute_value"] + attr_val_map[name][row.get("attribute")] = row.get("attribute_value") return attr_val_map