diff --git a/erpnext/crm/report/lead_details/lead_details.js b/erpnext/crm/report/lead_details/lead_details.js new file mode 100644 index 0000000000..f92070daf3 --- /dev/null +++ b/erpnext/crm/report/lead_details/lead_details.js @@ -0,0 +1,52 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Lead Details"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -12), + "reqd": 1 + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today(), + "reqd": 1 + }, + { + "fieldname":"status", + "label": __("Status"), + "fieldtype": "Select", + options: [ + { "value": "Lead", "label": __("Lead") }, + { "value": "Open", "label": __("Open") }, + { "value": "Replied", "label": __("Replied") }, + { "value": "Opportunity", "label": __("Opportunity") }, + { "value": "Quotation", "label": __("Quotation") }, + { "value": "Lost Quotation", "label": __("Lost Quotation") }, + { "value": "Interested", "label": __("Interested") }, + { "value": "Converted", "label": __("Converted") }, + { "value": "Do Not Contact", "label": __("Do Not Contact") }, + ], + }, + { + "fieldname":"territory", + "label": __("Territory"), + "fieldtype": "Link", + "options": "Territory", + } + ] +}; \ No newline at end of file diff --git a/erpnext/crm/report/lead_details/lead_details.json b/erpnext/crm/report/lead_details/lead_details.json index cdeb6bbe38..7871d0822f 100644 --- a/erpnext/crm/report/lead_details/lead_details.json +++ b/erpnext/crm/report/lead_details/lead_details.json @@ -7,16 +7,15 @@ "doctype": "Report", "idx": 3, "is_standard": "Yes", - "modified": "2020-01-22 16:51:56.591110", + "modified": "2020-07-26 23:59:49.897577", "modified_by": "Administrator", "module": "CRM", "name": "Lead Details", "owner": "Administrator", "prepared_report": 0, - "query": "SELECT\n `tabLead`.name as \"Lead Id:Link/Lead:120\",\n `tabLead`.lead_name as \"Lead Name::120\",\n\t`tabLead`.company_name as \"Company Name::120\",\n\t`tabLead`.status as \"Status::120\",\n\tconcat_ws(', ', \n\t\ttrim(',' from `tabAddress`.address_line1), \n\t\ttrim(',' from tabAddress.address_line2)\n\t) as 'Address::180',\n\t`tabAddress`.state as \"State::100\",\n\t`tabAddress`.pincode as \"Pincode::70\",\n\t`tabAddress`.country as \"Country::100\",\n\t`tabLead`.phone as \"Phone::100\",\n\t`tabLead`.mobile_no as \"Mobile No::100\",\n\t`tabLead`.email_id as \"Email Id::120\",\n\t`tabLead`.lead_owner as \"Lead Owner::120\",\n\t`tabLead`.source as \"Source::120\",\n\t`tabLead`.territory as \"Territory::120\",\n\t`tabLead`.notes as \"Notes::360\",\n `tabLead`.owner as \"Owner:Link/User:120\"\nFROM\n\t`tabLead`\n\tleft join `tabDynamic Link` on (\n\t\t`tabDynamic Link`.link_name=`tabLead`.name \n\t\tand `tabDynamic Link`.parenttype = 'Address'\n\t)\n\tleft join `tabAddress` on (\n\t\t`tabAddress`.name=`tabDynamic Link`.parent\n\t)\nWHERE\n\t`tabLead`.docstatus<2\nORDER BY\n\t`tabLead`.name asc", "ref_doctype": "Lead", "report_name": "Lead Details", - "report_type": "Query Report", + "report_type": "Script Report", "roles": [ { "role": "Sales User" diff --git a/erpnext/crm/report/lead_details/lead_details.py b/erpnext/crm/report/lead_details/lead_details.py new file mode 100644 index 0000000000..eeaaec2bce --- /dev/null +++ b/erpnext/crm/report/lead_details/lead_details.py @@ -0,0 +1,158 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe import _ +import frappe + +def execute(filters=None): + columns, data = get_columns(), get_data(filters) + return columns, data + +def get_columns(): + columns = [ + { + "label": _("Lead"), + "fieldname": "name", + "fieldtype": "Link", + "options": "Lead", + "width": 150, + }, + { + "label": _("Lead Name"), + "fieldname": "lead_name", + "fieldtype": "Data", + "width": 120 + }, + { + "fieldname":"status", + "label": _("Status"), + "fieldtype": "Data", + "width": 100 + }, + { + "fieldname":"lead_owner", + "label": _("Lead Owner"), + "fieldtype": "Link", + "options": "User", + "width": 100 + }, + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "width": 100 + }, + { + "label": _("Source"), + "fieldname": "source", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Email"), + "fieldname": "email_id", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Mobile"), + "fieldname": "mobile_no", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Phone"), + "fieldname": "phone", + "fieldtype": "Data", + "width": 120 + }, + { + "label": _("Owner"), + "fieldname": "owner", + "fieldtype": "Link", + "options": "user", + "width": 120 + }, + { + "label": _("Company"), + "fieldname": "company", + "fieldtype": "Link", + "options": "Company", + "width": 120 + }, + { + "fieldname":"address", + "label": _("Address"), + "fieldtype": "Data", + "width": 130 + }, + { + "fieldname":"state", + "label": _("State"), + "fieldtype": "Data", + "width": 100 + }, + { + "fieldname":"pincode", + "label": _("Postal Code"), + "fieldtype": "Data", + "width": 90 + }, + { + "fieldname":"country", + "label": _("Country"), + "fieldtype": "Link", + "options": "Country", + "width": 100 + }, + + ] + return columns + +def get_data(filters): + return frappe.db.sql(""" + SELECT + `tabLead`.name, + `tabLead`.lead_name, + `tabLead`.status, + `tabLead`.lead_owner, + `tabLead`.territory, + `tabLead`.source, + `tabLead`.email_id, + `tabLead`.mobile_no, + `tabLead`.phone, + `tabLead`.owner, + `tabLead`.company, + concat_ws(', ', + trim(',' from `tabAddress`.address_line1), + trim(',' from tabAddress.address_line2) + ) AS address, + `tabAddress`.state, + `tabAddress`.pincode, + `tabAddress`.country + FROM + `tabLead` left join `tabDynamic Link` on ( + `tabLead`.name = `tabDynamic Link`.link_name and + `tabDynamic Link`.parenttype = 'Address') + left join `tabAddress` on ( + `tabAddress`.name=`tabDynamic Link`.parent) + WHERE + company = %(company)s + AND `tabLead`.creation BETWEEN %(from_date)s AND %(to_date)s + {conditions} + ORDER BY + `tabLead`.creation asc """.format(conditions=get_conditions(filters)), filters, as_dict=1) + +def get_conditions(filters) : + conditions = [] + + if filters.get("territory"): + conditions.append(" and `tabLead`.territory=%(territory)s") + + if filters.get("status"): + conditions.append(" and `tabLead`.status=%(status)s") + + return " ".join(conditions) if conditions else "" + diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.js b/erpnext/crm/report/lost_opportunity/lost_opportunity.js new file mode 100644 index 0000000000..d79f8c8480 --- /dev/null +++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.js @@ -0,0 +1,67 @@ +// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors +// For license information, please see license.txt +/* eslint-disable */ + +frappe.query_reports["Lost Opportunity"] = { + "filters": [ + { + "fieldname":"company", + "label": __("Company"), + "fieldtype": "Link", + "options": "Company", + "default": frappe.defaults.get_user_default("Company"), + "reqd": 1 + }, + { + "fieldname":"from_date", + "label": __("From Date"), + "fieldtype": "Date", + "default": frappe.datetime.add_months(frappe.datetime.get_today(), -12), + "reqd": 1 + }, + { + "fieldname":"to_date", + "label": __("To Date"), + "fieldtype": "Date", + "default": frappe.datetime.get_today(), + "reqd": 1 + }, + { + "fieldname":"lost_reason", + "label": __("Lost Reason"), + "fieldtype": "Link", + "options": "Opportunity Lost Reason" + }, + { + "fieldname":"territory", + "label": __("Territory"), + "fieldtype": "Link", + "options": "Territory" + }, + { + "fieldname":"opportunity_from", + "label": __("Opportunity From"), + "fieldtype": "Link", + "options": "DocType", + "get_query": function() { + return { + "filters": { + "name": ["in", ["Customer", "Lead"]], + } + } + } + }, + { + "fieldname":"party_name", + "label": __("Party"), + "fieldtype": "Dynamic Link", + "options": "opportunity_from" + }, + { + "fieldname":"contact_by", + "label": __("Next Contact By"), + "fieldtype": "Link", + "options": "User" + }, + ] +}; \ No newline at end of file diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.json b/erpnext/crm/report/lost_opportunity/lost_opportunity.json index e7c5068b86..e7a8e12ba7 100644 --- a/erpnext/crm/report/lost_opportunity/lost_opportunity.json +++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.json @@ -1,13 +1,14 @@ { "add_total_row": 0, "creation": "2018-12-31 16:30:57.188837", + "disable_prepared_report": 0, "disabled": 0, "docstatus": 0, "doctype": "Report", "idx": 0, "is_standard": "Yes", "json": "{\"order_by\": \"`tabOpportunity`.`modified` desc\", \"filters\": [[\"Opportunity\", \"status\", \"=\", \"Lost\"]], \"fields\": [[\"name\", \"Opportunity\"], [\"opportunity_from\", \"Opportunity\"], [\"party_name\", \"Opportunity\"], [\"customer_name\", \"Opportunity\"], [\"opportunity_type\", \"Opportunity\"], [\"status\", \"Opportunity\"], [\"contact_by\", \"Opportunity\"], [\"docstatus\", \"Opportunity\"], [\"lost_reason\", \"Lost Reason Detail\"]], \"add_totals_row\": 0, \"add_total_row\": 0, \"page_length\": 20}", - "modified": "2019-06-26 16:33:08.083618", + "modified": "2020-07-29 15:49:02.848845", "modified_by": "Administrator", "module": "CRM", "name": "Lost Opportunity", @@ -15,7 +16,7 @@ "prepared_report": 0, "ref_doctype": "Opportunity", "report_name": "Lost Opportunity", - "report_type": "Report Builder", + "report_type": "Script Report", "roles": [ { "role": "Sales User" diff --git a/erpnext/crm/report/lost_opportunity/lost_opportunity.py b/erpnext/crm/report/lost_opportunity/lost_opportunity.py new file mode 100644 index 0000000000..1aa4afe186 --- /dev/null +++ b/erpnext/crm/report/lost_opportunity/lost_opportunity.py @@ -0,0 +1,131 @@ +# Copyright (c) 2020, Frappe Technologies Pvt. Ltd. and contributors +# For license information, please see license.txt + +from __future__ import unicode_literals +from frappe import _ +import frappe + +def execute(filters=None): + columns, data = get_columns(), get_data(filters) + return columns, data + +def get_columns(): + columns = [ + { + "label": _("Opportunity"), + "fieldname": "name", + "fieldtype": "Link", + "options": "Opportunity", + "width": 170, + }, + { + "label": _("Opportunity From"), + "fieldname": "opportunity_from", + "fieldtype": "Link", + "options": "DocType", + "width": 130 + }, + { + "label": _("Party"), + "fieldname":"party_name", + "fieldtype": "Dynamic Link", + "options": "opportunity_from", + "width": 160 + }, + { + "label": _("Customer/Lead Name"), + "fieldname":"customer_name", + "fieldtype": "Data", + "width": 150 + }, + { + "label": _("Opportunity Type"), + "fieldname": "opportunity_type", + "fieldtype": "Data", + "width": 130 + }, + { + "label": _("Lost Reasons"), + "fieldname": "lost_reason", + "fieldtype": "Data", + "width": 220 + }, + { + "label": _("Sales Stage"), + "fieldname": "sales_stage", + "fieldtype": "Link", + "options": "Sales Stage", + "width": 150 + }, + { + "label": _("Territory"), + "fieldname": "territory", + "fieldtype": "Link", + "options": "Territory", + "width": 150 + }, + { + "label": _("Next Contact By"), + "fieldname": "contact_by", + "fieldtype": "Link", + "options": "User", + "width": 150 + } + ] + return columns + +def get_data(filters): + return frappe.db.sql(""" + SELECT + `tabOpportunity`.name, + `tabOpportunity`.opportunity_from, + `tabOpportunity`.party_name, + `tabOpportunity`.customer_name, + `tabOpportunity`.opportunity_type, + `tabOpportunity`.contact_by, + GROUP_CONCAT(`tabOpportunity Lost Reason Detail`.lost_reason separator ', ') lost_reason, + `tabOpportunity`.sales_stage, + `tabOpportunity`.territory + FROM + `tabOpportunity` + {join} + WHERE + `tabOpportunity`.status = 'Lost' and `tabOpportunity`.company = %(company)s + AND `tabOpportunity`.modified BETWEEN %(from_date)s AND %(to_date)s + {conditions} + GROUP BY + `tabOpportunity`.name + ORDER BY + `tabOpportunity`.creation asc """.format(conditions=get_conditions(filters), join=get_join(filters)), filters, as_dict=1) + + +def get_conditions(filters): + conditions = [] + + if filters.get("territory"): + conditions.append(" and `tabOpportunity`.territory=%(territory)s") + + if filters.get("opportunity_from"): + conditions.append(" and `tabOpportunity`.opportunity_from=%(opportunity_from)s") + + if filters.get("party_name"): + conditions.append(" and `tabOpportunity`.party_name=%(party_name)s") + + if filters.get("contact_by"): + conditions.append(" and `tabOpportunity`.contact_by=%(contact_by)s") + + return " ".join(conditions) if conditions else "" + +def get_join(filters): + join = """LEFT JOIN `tabOpportunity Lost Reason Detail` + ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and + `tabOpportunity Lost Reason Detail`.parent = `tabOpportunity`.name""" + + if filters.get("lost_reason"): + join = """JOIN `tabOpportunity Lost Reason Detail` + ON `tabOpportunity Lost Reason Detail`.parenttype = 'Opportunity' and + `tabOpportunity Lost Reason Detail`.parent = `tabOpportunity`.name and + `tabOpportunity Lost Reason Detail`.lost_reason = '{0}' + """.format(filters.get("lost_reason")) + + return join \ No newline at end of file