From 744ff0010baa3e8e5546240389ffbfd766d71477 Mon Sep 17 00:00:00 2001 From: Prateeksha Singh Date: Fri, 17 Nov 2017 12:00:29 +0530 Subject: [PATCH] Variant report (#11618) * Item Variant Details Report * remove queries from inside for loop * make attribute value map * Update item_variant_details.py --- erpnext/config/stock.py | 6 + erpnext/stock/doctype/item/item.js | 4 + .../report/item_variant_details/__init__.py | 0 .../item_variant_details.js | 21 ++ .../item_variant_details.json | 44 +++++ .../item_variant_details.py | 180 ++++++++++++++++++ 6 files changed, 255 insertions(+) create mode 100644 erpnext/stock/report/item_variant_details/__init__.py create mode 100644 erpnext/stock/report/item_variant_details/item_variant_details.js create mode 100644 erpnext/stock/report/item_variant_details/item_variant_details.json create mode 100644 erpnext/stock/report/item_variant_details/item_variant_details.py diff --git a/erpnext/config/stock.py b/erpnext/config/stock.py index cb17deb9bf..e0207d050d 100644 --- a/erpnext/config/stock.py +++ b/erpnext/config/stock.py @@ -268,6 +268,12 @@ def get_data(): "name": "Itemwise Recommended Reorder Level", "doctype": "Item" }, + { + "type": "report", + "is_query_report": True, + "name": "Item Variant Details", + "doctype": "Item" + } ] }, { diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index a71e1eadbb..f670e946cd 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -57,6 +57,10 @@ frappe.ui.form.on("Item", { frappe.set_route("List", "Item", {"variant_of": frm.doc.name}); }, __("View")); + frm.add_custom_button(__("Variant Details Report"), function() { + frappe.set_route("query-report", "Item Variant Details", {"item": frm.doc.name}); + }, __("View")); + if(frm.doc.variant_based_on==="Item Attribute") { frm.add_custom_button(__("Single Variant"), function() { erpnext.item.show_single_variant_dialog(frm); diff --git a/erpnext/stock/report/item_variant_details/__init__.py b/erpnext/stock/report/item_variant_details/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.js b/erpnext/stock/report/item_variant_details/item_variant_details.js new file mode 100644 index 0000000000..78eab4050c --- /dev/null +++ b/erpnext/stock/report/item_variant_details/item_variant_details.js @@ -0,0 +1,21 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Item Variant Details"] = { + "filters": [ + { + reqd: 1, + default: "", + options: "Item", + label: __("Item"), + fieldname: "item", + fieldtype: "Link", + get_query: () => { + return { + filters: { "has_variants": 1 } + } + } + } + ] +} diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.json b/erpnext/stock/report/item_variant_details/item_variant_details.json new file mode 100644 index 0000000000..1d279039b4 --- /dev/null +++ b/erpnext/stock/report/item_variant_details/item_variant_details.json @@ -0,0 +1,44 @@ +{ + "add_total_row": 0, + "apply_user_permissions": 1, + "creation": "2017-11-16 06:05:36.132547", + "disabled": 0, + "docstatus": 0, + "doctype": "Report", + "idx": 0, + "is_standard": "Yes", + "modified": "2017-11-16 06:24:10.818276", + "modified_by": "Administrator", + "module": "Stock", + "name": "Item Variant Details", + "owner": "Administrator", + "ref_doctype": "Item", + "report_name": "Item Variant Details", + "report_type": "Script Report", + "roles": [ + { + "role": "Maintenance User" + }, + { + "role": "Accounts User" + }, + { + "role": "Stock User" + }, + { + "role": "Stock Manager" + }, + { + "role": "Purchase User" + }, + { + "role": "Sales User" + }, + { + "role": "Manufacturing User" + }, + { + "role": "Item Manager" + } + ] +} \ No newline at end of file diff --git a/erpnext/stock/report/item_variant_details/item_variant_details.py b/erpnext/stock/report/item_variant_details/item_variant_details.py new file mode 100644 index 0000000000..67b6b5f2a0 --- /dev/null +++ b/erpnext/stock/report/item_variant_details/item_variant_details.py @@ -0,0 +1,180 @@ +# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +import frappe +from frappe import _ + +def execute(filters=None): + columns = get_columns(filters.item) + data = get_data(filters.item) + return columns, data + +def get_data(item): + if not item: + return [] + item_dicts = [] + + variant_results = frappe.db.sql("""select name from `tabItem` + where variant_of = %s""", item, as_dict=1) + variants = ",".join(['"' + 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) + + 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))] + + # Prepare dicts + variant_dicts = [{"variant_name": d['name']} for d in variant_results] + for item_dict in variant_dicts: + name = item_dict["variant_name"] + + for d in attribute_list: + item_dict[d] = attr_val_map[name][d] + + 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 + else: + item_dict["Inventory"] = item_dict["In Production"] = item_dict["Available Selling"] = 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) + + return item_dicts + +def get_columns(item): + columns = [{ + "fieldname": "variant_name", + "label": "Variant", + "fieldtype": "Link", + "options": "Item", + "width": 200 + }] + + item_doc = frappe.get_doc("Item", item) + + for d in item_doc.attributes: + columns.append(d.attribute + ":Data: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" + ] + + 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) + + order_count_map = {} + for d in open_sales_orders: + order_count_map[d["item_code"]] = d["count"] + + 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) + + stock_details_map = {} + for d in stock_details: + name = d["item_code"] + stock_details_map[name] = { + "Inventory" :d["actual_qty"], + "In Production" :d["planned_qty"], + "Available Selling" :d["projected_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) + + buying_price_map = {} + for d in buying: + buying_price_map[d["item_code"]] = d["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) + + selling_price_map = {} + for d in selling: + selling_price_map[d["item_code"]] = d["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) + + attr_val_map = {} + for d in list_attr: + name = d["parent"] + if not attr_val_map.get(name): + attr_val_map[name] = {} + + attr_val_map[name][d["attribute"]] = d["attribute_value"] + + return attr_val_map