mirror of
https://github.com/frappe/erpnext.git
synced 2026-06-04 20:59:11 +00:00
style: format code with black
This commit is contained in:
@@ -9,77 +9,40 @@ from frappe.utils import flt
|
||||
|
||||
def execute(filters=None):
|
||||
columns, data = [], []
|
||||
columns=get_columns("Campaign Name")
|
||||
data=get_lead_data(filters or {}, "Campaign Name")
|
||||
columns = get_columns("Campaign Name")
|
||||
data = get_lead_data(filters or {}, "Campaign Name")
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns(based_on):
|
||||
return [
|
||||
{
|
||||
"fieldname": frappe.scrub(based_on),
|
||||
"label": _(based_on),
|
||||
"fieldtype": "Data",
|
||||
"width": 150
|
||||
},
|
||||
{
|
||||
"fieldname": "lead_count",
|
||||
"label": _("Lead Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": 80
|
||||
},
|
||||
{
|
||||
"fieldname": "opp_count",
|
||||
"label": _("Opp Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": 80
|
||||
},
|
||||
{
|
||||
"fieldname": "quot_count",
|
||||
"label": _("Quot Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": 80
|
||||
},
|
||||
{
|
||||
"fieldname": "order_count",
|
||||
"label": _("Order Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "order_value",
|
||||
"label": _("Order Value"),
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "opp_lead",
|
||||
"label": _("Opp/Lead %"),
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "quot_lead",
|
||||
"label": _("Quot/Lead %"),
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname": "order_quot",
|
||||
"label": _("Order/Quot %"),
|
||||
"fieldtype": "Float",
|
||||
"width": 100
|
||||
}
|
||||
{"fieldname": frappe.scrub(based_on), "label": _(based_on), "fieldtype": "Data", "width": 150},
|
||||
{"fieldname": "lead_count", "label": _("Lead Count"), "fieldtype": "Int", "width": 80},
|
||||
{"fieldname": "opp_count", "label": _("Opp Count"), "fieldtype": "Int", "width": 80},
|
||||
{"fieldname": "quot_count", "label": _("Quot Count"), "fieldtype": "Int", "width": 80},
|
||||
{"fieldname": "order_count", "label": _("Order Count"), "fieldtype": "Int", "width": 100},
|
||||
{"fieldname": "order_value", "label": _("Order Value"), "fieldtype": "Float", "width": 100},
|
||||
{"fieldname": "opp_lead", "label": _("Opp/Lead %"), "fieldtype": "Float", "width": 100},
|
||||
{"fieldname": "quot_lead", "label": _("Quot/Lead %"), "fieldtype": "Float", "width": 100},
|
||||
{"fieldname": "order_quot", "label": _("Order/Quot %"), "fieldtype": "Float", "width": 100},
|
||||
]
|
||||
|
||||
|
||||
def get_lead_data(filters, based_on):
|
||||
based_on_field = frappe.scrub(based_on)
|
||||
conditions = get_filter_conditions(filters)
|
||||
|
||||
lead_details = frappe.db.sql("""
|
||||
lead_details = frappe.db.sql(
|
||||
"""
|
||||
select {based_on_field}, name
|
||||
from `tabLead`
|
||||
where {based_on_field} is not null and {based_on_field} != '' {conditions}
|
||||
""".format(based_on_field=based_on_field, conditions=conditions), filters, as_dict=1)
|
||||
""".format(
|
||||
based_on_field=based_on_field, conditions=conditions
|
||||
),
|
||||
filters,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
lead_map = frappe._dict()
|
||||
for d in lead_details:
|
||||
@@ -87,11 +50,8 @@ def get_lead_data(filters, based_on):
|
||||
|
||||
data = []
|
||||
for based_on_value, leads in lead_map.items():
|
||||
row = {
|
||||
based_on_field: based_on_value,
|
||||
"lead_count": len(leads)
|
||||
}
|
||||
row["quot_count"]= get_lead_quotation_count(leads)
|
||||
row = {based_on_field: based_on_value, "lead_count": len(leads)}
|
||||
row["quot_count"] = get_lead_quotation_count(leads)
|
||||
row["opp_count"] = get_lead_opp_count(leads)
|
||||
row["order_count"] = get_quotation_ordered_count(leads)
|
||||
row["order_value"] = get_order_amount(leads) or 0
|
||||
@@ -105,8 +65,9 @@ def get_lead_data(filters, based_on):
|
||||
|
||||
return data
|
||||
|
||||
|
||||
def get_filter_conditions(filters):
|
||||
conditions=""
|
||||
conditions = ""
|
||||
if filters.from_date:
|
||||
conditions += " and date(creation) >= %(from_date)s"
|
||||
if filters.to_date:
|
||||
@@ -114,23 +75,45 @@ def get_filter_conditions(filters):
|
||||
|
||||
return conditions
|
||||
|
||||
|
||||
def get_lead_quotation_count(leads):
|
||||
return frappe.db.sql("""select count(name) from `tabQuotation`
|
||||
where quotation_to = 'Lead' and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0] #nosec
|
||||
return frappe.db.sql(
|
||||
"""select count(name) from `tabQuotation`
|
||||
where quotation_to = 'Lead' and party_name in (%s)"""
|
||||
% ", ".join(["%s"] * len(leads)),
|
||||
tuple(leads),
|
||||
)[0][
|
||||
0
|
||||
] # nosec
|
||||
|
||||
|
||||
def get_lead_opp_count(leads):
|
||||
return frappe.db.sql("""select count(name) from `tabOpportunity`
|
||||
where opportunity_from = 'Lead' and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
|
||||
return frappe.db.sql(
|
||||
"""select count(name) from `tabOpportunity`
|
||||
where opportunity_from = 'Lead' and party_name in (%s)"""
|
||||
% ", ".join(["%s"] * len(leads)),
|
||||
tuple(leads),
|
||||
)[0][0]
|
||||
|
||||
|
||||
def get_quotation_ordered_count(leads):
|
||||
return frappe.db.sql("""select count(name)
|
||||
return frappe.db.sql(
|
||||
"""select count(name)
|
||||
from `tabQuotation` where status = 'Ordered' and quotation_to = 'Lead'
|
||||
and party_name in (%s)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
|
||||
and party_name in (%s)"""
|
||||
% ", ".join(["%s"] * len(leads)),
|
||||
tuple(leads),
|
||||
)[0][0]
|
||||
|
||||
|
||||
def get_order_amount(leads):
|
||||
return frappe.db.sql("""select sum(base_net_amount)
|
||||
return frappe.db.sql(
|
||||
"""select sum(base_net_amount)
|
||||
from `tabSales Order Item`
|
||||
where prevdoc_docname in (
|
||||
select name from `tabQuotation` where status = 'Ordered'
|
||||
and quotation_to = 'Lead' and party_name in (%s)
|
||||
)""" % ', '.join(["%s"]*len(leads)), tuple(leads))[0][0]
|
||||
)"""
|
||||
% ", ".join(["%s"] * len(leads)),
|
||||
tuple(leads),
|
||||
)[0][0]
|
||||
|
||||
@@ -7,21 +7,17 @@ import frappe
|
||||
|
||||
def execute(filters=None):
|
||||
columns = [
|
||||
{"fieldname": "creation_date", "label": "Date", "fieldtype": "Date", "width": 300},
|
||||
{
|
||||
'fieldname': 'creation_date',
|
||||
'label': 'Date',
|
||||
'fieldtype': 'Date',
|
||||
'width': 300
|
||||
},
|
||||
{
|
||||
'fieldname': 'first_response_time',
|
||||
'fieldtype': 'Duration',
|
||||
'label': 'First Response Time',
|
||||
'width': 300
|
||||
"fieldname": "first_response_time",
|
||||
"fieldtype": "Duration",
|
||||
"label": "First Response Time",
|
||||
"width": 300,
|
||||
},
|
||||
]
|
||||
|
||||
data = frappe.db.sql('''
|
||||
data = frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
date(creation) as creation_date,
|
||||
avg(first_response_time) as avg_response_time
|
||||
@@ -31,6 +27,8 @@ def execute(filters=None):
|
||||
and first_response_time > 0
|
||||
GROUP BY creation_date
|
||||
ORDER BY creation_date desc
|
||||
''', (filters.from_date, filters.to_date))
|
||||
""",
|
||||
(filters.from_date, filters.to_date),
|
||||
)
|
||||
|
||||
return columns, data
|
||||
|
||||
@@ -8,7 +8,8 @@ from frappe.utils import date_diff, flt
|
||||
|
||||
|
||||
def execute(filters=None):
|
||||
if not filters: filters = {}
|
||||
if not filters:
|
||||
filters = {}
|
||||
|
||||
communication_list = get_communication_details(filters)
|
||||
columns = get_columns()
|
||||
@@ -19,8 +20,12 @@ def execute(filters=None):
|
||||
|
||||
data = []
|
||||
for communication in communication_list:
|
||||
row = [communication.get('customer'), communication.get('interactions'),\
|
||||
communication.get('duration'), communication.get('support_tickets')]
|
||||
row = [
|
||||
communication.get("customer"),
|
||||
communication.get("interactions"),
|
||||
communication.get("duration"),
|
||||
communication.get("support_tickets"),
|
||||
]
|
||||
data.append(row)
|
||||
|
||||
# add the average row
|
||||
@@ -32,9 +37,17 @@ def execute(filters=None):
|
||||
total_interactions += row[1]
|
||||
total_duration += row[2]
|
||||
total_tickets += row[3]
|
||||
data.append(['Average', total_interactions/len(data), total_duration/len(data), total_tickets/len(data)])
|
||||
data.append(
|
||||
[
|
||||
"Average",
|
||||
total_interactions / len(data),
|
||||
total_duration / len(data),
|
||||
total_tickets / len(data),
|
||||
]
|
||||
)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
{
|
||||
@@ -42,36 +55,37 @@ def get_columns():
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"options": "Customer",
|
||||
"width": 120
|
||||
"width": 120,
|
||||
},
|
||||
{
|
||||
"label": _("No of Interactions"),
|
||||
"fieldname": "interactions",
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Duration in Days"),
|
||||
"fieldname": "duration",
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
"width": 120,
|
||||
},
|
||||
{"label": _("Duration in Days"), "fieldname": "duration", "fieldtype": "Float", "width": 120},
|
||||
{
|
||||
"label": _("Support Tickets"),
|
||||
"fieldname": "support_tickets",
|
||||
"fieldtype": "Float",
|
||||
"width": 120
|
||||
}
|
||||
"width": 120,
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def get_communication_details(filters):
|
||||
communication_count = None
|
||||
communication_list = []
|
||||
opportunities = frappe.db.get_values('Opportunity', {'opportunity_from': 'Lead'},\
|
||||
['name', 'customer_name', 'contact_email'], as_dict=1)
|
||||
opportunities = frappe.db.get_values(
|
||||
"Opportunity",
|
||||
{"opportunity_from": "Lead"},
|
||||
["name", "customer_name", "contact_email"],
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
for d in opportunities:
|
||||
invoice = frappe.db.sql('''
|
||||
invoice = frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
date(creation)
|
||||
FROM
|
||||
@@ -81,22 +95,30 @@ def get_communication_details(filters):
|
||||
ORDER BY
|
||||
creation
|
||||
LIMIT 1
|
||||
''', (d.contact_email, filters.from_date, filters.to_date))
|
||||
""",
|
||||
(d.contact_email, filters.from_date, filters.to_date),
|
||||
)
|
||||
|
||||
if not invoice: continue
|
||||
if not invoice:
|
||||
continue
|
||||
|
||||
communication_count = frappe.db.sql('''
|
||||
communication_count = frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
count(*)
|
||||
FROM
|
||||
`tabCommunication`
|
||||
WHERE
|
||||
sender = %s AND date(communication_date) <= %s
|
||||
''', (d.contact_email, invoice))[0][0]
|
||||
""",
|
||||
(d.contact_email, invoice),
|
||||
)[0][0]
|
||||
|
||||
if not communication_count: continue
|
||||
if not communication_count:
|
||||
continue
|
||||
|
||||
first_contact = frappe.db.sql('''
|
||||
first_contact = frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
date(communication_date)
|
||||
FROM
|
||||
@@ -106,10 +128,19 @@ def get_communication_details(filters):
|
||||
ORDER BY
|
||||
communication_date
|
||||
LIMIT 1
|
||||
''', (d.contact_email))[0][0]
|
||||
""",
|
||||
(d.contact_email),
|
||||
)[0][0]
|
||||
|
||||
duration = flt(date_diff(invoice[0][0], first_contact))
|
||||
|
||||
support_tickets = len(frappe.db.get_all('Issue', {'raised_by': d.contact_email}))
|
||||
communication_list.append({'customer': d.customer_name, 'interactions': communication_count, 'duration': duration, 'support_tickets': support_tickets})
|
||||
support_tickets = len(frappe.db.get_all("Issue", {"raised_by": d.contact_email}))
|
||||
communication_list.append(
|
||||
{
|
||||
"customer": d.customer_name,
|
||||
"interactions": communication_count,
|
||||
"duration": duration,
|
||||
"support_tickets": support_tickets,
|
||||
}
|
||||
)
|
||||
return communication_list
|
||||
|
||||
@@ -10,6 +10,7 @@ def execute(filters=None):
|
||||
columns, data = get_columns(), get_data(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
columns = [
|
||||
{
|
||||
@@ -19,101 +20,57 @@ def get_columns():
|
||||
"options": "Lead",
|
||||
"width": 150,
|
||||
},
|
||||
{"label": _("Lead Name"), "fieldname": "lead_name", "fieldtype": "Data", "width": 120},
|
||||
{"fieldname": "status", "label": _("Status"), "fieldtype": "Data", "width": 100},
|
||||
{
|
||||
"label": _("Lead Name"),
|
||||
"fieldname": "lead_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"fieldname":"status",
|
||||
"label": _("Status"),
|
||||
"fieldtype": "Data",
|
||||
"width": 100
|
||||
},
|
||||
{
|
||||
"fieldname":"lead_owner",
|
||||
"fieldname": "lead_owner",
|
||||
"label": _("Lead Owner"),
|
||||
"fieldtype": "Link",
|
||||
"options": "User",
|
||||
"width": 100
|
||||
"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
|
||||
"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
|
||||
"width": 120,
|
||||
},
|
||||
{
|
||||
"label": _("Company"),
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"options": "Company",
|
||||
"width": 120
|
||||
"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":"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",
|
||||
"fieldname": "country",
|
||||
"label": _("Country"),
|
||||
"fieldtype": "Link",
|
||||
"options": "Country",
|
||||
"width": 100
|
||||
"width": 100,
|
||||
},
|
||||
|
||||
]
|
||||
return columns
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
return frappe.db.sql("""
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
`tabLead`.name,
|
||||
`tabLead`.lead_name,
|
||||
@@ -144,9 +101,15 @@ def get_data(filters):
|
||||
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)
|
||||
`tabLead`.creation asc """.format(
|
||||
conditions=get_conditions(filters)
|
||||
),
|
||||
filters,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
def get_conditions(filters) :
|
||||
|
||||
def get_conditions(filters):
|
||||
conditions = []
|
||||
|
||||
if filters.get("territory"):
|
||||
|
||||
@@ -9,10 +9,11 @@ from erpnext.crm.report.campaign_efficiency.campaign_efficiency import get_lead_
|
||||
|
||||
def execute(filters=None):
|
||||
columns, data = [], []
|
||||
columns=get_columns()
|
||||
data=get_lead_data(filters, "Lead Owner")
|
||||
columns = get_columns()
|
||||
data = get_lead_data(filters, "Lead Owner")
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
return [
|
||||
{
|
||||
@@ -20,54 +21,14 @@ def get_columns():
|
||||
"label": _("Lead Owner"),
|
||||
"fieldtype": "Link",
|
||||
"options": "User",
|
||||
"width": "130"
|
||||
"width": "130",
|
||||
},
|
||||
{
|
||||
"fieldname": "lead_count",
|
||||
"label": _("Lead Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": "80"
|
||||
},
|
||||
{
|
||||
"fieldname": "opp_count",
|
||||
"label": _("Opp Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": "80"
|
||||
},
|
||||
{
|
||||
"fieldname": "quot_count",
|
||||
"label": _("Quot Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": "80"
|
||||
},
|
||||
{
|
||||
"fieldname": "order_count",
|
||||
"label": _("Order Count"),
|
||||
"fieldtype": "Int",
|
||||
"width": "100"
|
||||
},
|
||||
{
|
||||
"fieldname": "order_value",
|
||||
"label": _("Order Value"),
|
||||
"fieldtype": "Float",
|
||||
"width": "100"
|
||||
},
|
||||
{
|
||||
"fieldname": "opp_lead",
|
||||
"label": _("Opp/Lead %"),
|
||||
"fieldtype": "Float",
|
||||
"width": "100"
|
||||
},
|
||||
{
|
||||
"fieldname": "quot_lead",
|
||||
"label": _("Quot/Lead %"),
|
||||
"fieldtype": "Float",
|
||||
"width": "100"
|
||||
},
|
||||
{
|
||||
"fieldname": "order_quot",
|
||||
"label": _("Order/Quot %"),
|
||||
"fieldtype": "Float",
|
||||
"width": "100"
|
||||
}
|
||||
{"fieldname": "lead_count", "label": _("Lead Count"), "fieldtype": "Int", "width": "80"},
|
||||
{"fieldname": "opp_count", "label": _("Opp Count"), "fieldtype": "Int", "width": "80"},
|
||||
{"fieldname": "quot_count", "label": _("Quot Count"), "fieldtype": "Int", "width": "80"},
|
||||
{"fieldname": "order_count", "label": _("Order Count"), "fieldtype": "Int", "width": "100"},
|
||||
{"fieldname": "order_value", "label": _("Order Value"), "fieldtype": "Float", "width": "100"},
|
||||
{"fieldname": "opp_lead", "label": _("Opp/Lead %"), "fieldtype": "Float", "width": "100"},
|
||||
{"fieldname": "quot_lead", "label": _("Quot/Lead %"), "fieldtype": "Float", "width": "100"},
|
||||
{"fieldname": "order_quot", "label": _("Order/Quot %"), "fieldtype": "Float", "width": "100"},
|
||||
]
|
||||
|
||||
@@ -10,6 +10,7 @@ def execute(filters=None):
|
||||
columns, data = get_columns(), get_data(filters)
|
||||
return columns, data
|
||||
|
||||
|
||||
def get_columns():
|
||||
columns = [
|
||||
{
|
||||
@@ -24,59 +25,56 @@ def get_columns():
|
||||
"fieldname": "opportunity_from",
|
||||
"fieldtype": "Link",
|
||||
"options": "DocType",
|
||||
"width": 130
|
||||
"width": 130,
|
||||
},
|
||||
{
|
||||
"label": _("Party"),
|
||||
"fieldname":"party_name",
|
||||
"fieldname": "party_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"options": "opportunity_from",
|
||||
"width": 160
|
||||
"width": 160,
|
||||
},
|
||||
{
|
||||
"label": _("Customer/Lead Name"),
|
||||
"fieldname":"customer_name",
|
||||
"fieldname": "customer_name",
|
||||
"fieldtype": "Data",
|
||||
"width": 150
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Opportunity Type"),
|
||||
"fieldname": "opportunity_type",
|
||||
"fieldtype": "Data",
|
||||
"width": 130
|
||||
},
|
||||
{
|
||||
"label": _("Lost Reasons"),
|
||||
"fieldname": "lost_reason",
|
||||
"fieldtype": "Data",
|
||||
"width": 220
|
||||
"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
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Territory"),
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"options": "Territory",
|
||||
"width": 150
|
||||
"width": 150,
|
||||
},
|
||||
{
|
||||
"label": _("Next Contact By"),
|
||||
"fieldname": "contact_by",
|
||||
"fieldtype": "Link",
|
||||
"options": "User",
|
||||
"width": 150
|
||||
}
|
||||
"width": 150,
|
||||
},
|
||||
]
|
||||
return columns
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
return frappe.db.sql("""
|
||||
return frappe.db.sql(
|
||||
"""
|
||||
SELECT
|
||||
`tabOpportunity`.name,
|
||||
`tabOpportunity`.opportunity_from,
|
||||
@@ -97,7 +95,12 @@ def get_data(filters):
|
||||
GROUP BY
|
||||
`tabOpportunity`.name
|
||||
ORDER BY
|
||||
`tabOpportunity`.creation asc """.format(conditions=get_conditions(filters), join=get_join(filters)), filters, as_dict=1)
|
||||
`tabOpportunity`.creation asc """.format(
|
||||
conditions=get_conditions(filters), join=get_join(filters)
|
||||
),
|
||||
filters,
|
||||
as_dict=1,
|
||||
)
|
||||
|
||||
|
||||
def get_conditions(filters):
|
||||
@@ -117,6 +120,7 @@ def get_conditions(filters):
|
||||
|
||||
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
|
||||
@@ -127,6 +131,8 @@ def get_join(filters):
|
||||
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"))
|
||||
""".format(
|
||||
filters.get("lost_reason")
|
||||
)
|
||||
|
||||
return join
|
||||
|
||||
@@ -13,8 +13,9 @@ from erpnext.setup.utils import get_exchange_rate
|
||||
def execute(filters=None):
|
||||
return OpportunitySummaryBySalesStage(filters).run()
|
||||
|
||||
|
||||
class OpportunitySummaryBySalesStage(object):
|
||||
def __init__(self,filters=None):
|
||||
def __init__(self, filters=None):
|
||||
self.filters = frappe._dict(filters or {})
|
||||
|
||||
def run(self):
|
||||
@@ -26,98 +27,94 @@ class OpportunitySummaryBySalesStage(object):
|
||||
def get_columns(self):
|
||||
self.columns = []
|
||||
|
||||
if self.filters.get('based_on') == 'Opportunity Owner':
|
||||
self.columns.append({
|
||||
'label': _('Opportunity Owner'),
|
||||
'fieldname': 'opportunity_owner',
|
||||
'width': 200
|
||||
})
|
||||
if self.filters.get("based_on") == "Opportunity Owner":
|
||||
self.columns.append(
|
||||
{"label": _("Opportunity Owner"), "fieldname": "opportunity_owner", "width": 200}
|
||||
)
|
||||
|
||||
if self.filters.get('based_on') == 'Source':
|
||||
self.columns.append({
|
||||
'label': _('Source'),
|
||||
'fieldname': 'source',
|
||||
'fieldtype': 'Link',
|
||||
'options': 'Lead Source',
|
||||
'width': 200
|
||||
})
|
||||
if self.filters.get("based_on") == "Source":
|
||||
self.columns.append(
|
||||
{
|
||||
"label": _("Source"),
|
||||
"fieldname": "source",
|
||||
"fieldtype": "Link",
|
||||
"options": "Lead Source",
|
||||
"width": 200,
|
||||
}
|
||||
)
|
||||
|
||||
if self.filters.get('based_on') == 'Opportunity Type':
|
||||
self.columns.append({
|
||||
'label': _('Opportunity Type'),
|
||||
'fieldname': 'opportunity_type',
|
||||
'width': 200
|
||||
})
|
||||
if self.filters.get("based_on") == "Opportunity Type":
|
||||
self.columns.append(
|
||||
{"label": _("Opportunity Type"), "fieldname": "opportunity_type", "width": 200}
|
||||
)
|
||||
|
||||
self.set_sales_stage_columns()
|
||||
|
||||
def set_sales_stage_columns(self):
|
||||
self.sales_stage_list = frappe.db.get_list('Sales Stage', pluck='name')
|
||||
self.sales_stage_list = frappe.db.get_list("Sales Stage", pluck="name")
|
||||
|
||||
for sales_stage in self.sales_stage_list:
|
||||
if self.filters.get('data_based_on') == 'Number':
|
||||
self.columns.append({
|
||||
'label': _(sales_stage),
|
||||
'fieldname': sales_stage,
|
||||
'fieldtype': 'Int',
|
||||
'width': 150
|
||||
})
|
||||
if self.filters.get("data_based_on") == "Number":
|
||||
self.columns.append(
|
||||
{"label": _(sales_stage), "fieldname": sales_stage, "fieldtype": "Int", "width": 150}
|
||||
)
|
||||
|
||||
elif self.filters.get('data_based_on') == 'Amount':
|
||||
self.columns.append({
|
||||
'label': _(sales_stage),
|
||||
'fieldname': sales_stage,
|
||||
'fieldtype': 'Currency',
|
||||
'width': 150
|
||||
})
|
||||
elif self.filters.get("data_based_on") == "Amount":
|
||||
self.columns.append(
|
||||
{"label": _(sales_stage), "fieldname": sales_stage, "fieldtype": "Currency", "width": 150}
|
||||
)
|
||||
|
||||
def get_data(self):
|
||||
self.data = []
|
||||
|
||||
based_on = {
|
||||
'Opportunity Owner': '_assign',
|
||||
'Source': 'source',
|
||||
'Opportunity Type': 'opportunity_type'
|
||||
}[self.filters.get('based_on')]
|
||||
"Opportunity Owner": "_assign",
|
||||
"Source": "source",
|
||||
"Opportunity Type": "opportunity_type",
|
||||
}[self.filters.get("based_on")]
|
||||
|
||||
data_based_on = {
|
||||
'Number': 'count(name) as count',
|
||||
'Amount': 'opportunity_amount as amount',
|
||||
}[self.filters.get('data_based_on')]
|
||||
"Number": "count(name) as count",
|
||||
"Amount": "opportunity_amount as amount",
|
||||
}[self.filters.get("data_based_on")]
|
||||
|
||||
self.get_data_query(based_on, data_based_on)
|
||||
|
||||
self.get_rows()
|
||||
|
||||
def get_data_query(self, based_on, data_based_on):
|
||||
if self.filters.get('data_based_on') == 'Number':
|
||||
group_by = '{},{}'.format('sales_stage', based_on)
|
||||
self.query_result = frappe.db.get_list('Opportunity',
|
||||
if self.filters.get("data_based_on") == "Number":
|
||||
group_by = "{},{}".format("sales_stage", based_on)
|
||||
self.query_result = frappe.db.get_list(
|
||||
"Opportunity",
|
||||
filters=self.get_conditions(),
|
||||
fields=['sales_stage', data_based_on, based_on],
|
||||
group_by=group_by
|
||||
fields=["sales_stage", data_based_on, based_on],
|
||||
group_by=group_by,
|
||||
)
|
||||
|
||||
elif self.filters.get('data_based_on') == 'Amount':
|
||||
self.query_result = frappe.db.get_list('Opportunity',
|
||||
elif self.filters.get("data_based_on") == "Amount":
|
||||
self.query_result = frappe.db.get_list(
|
||||
"Opportunity",
|
||||
filters=self.get_conditions(),
|
||||
fields=['sales_stage', based_on, data_based_on, 'currency']
|
||||
fields=["sales_stage", based_on, data_based_on, "currency"],
|
||||
)
|
||||
|
||||
self.convert_to_base_currency()
|
||||
|
||||
dataframe = pandas.DataFrame.from_records(self.query_result)
|
||||
dataframe.replace(to_replace=[None], value='Not Assigned', inplace=True)
|
||||
result = dataframe.groupby(['sales_stage', based_on], as_index=False)['amount'].sum()
|
||||
dataframe.replace(to_replace=[None], value="Not Assigned", inplace=True)
|
||||
result = dataframe.groupby(["sales_stage", based_on], as_index=False)["amount"].sum()
|
||||
|
||||
self.grouped_data = []
|
||||
|
||||
for i in range(len(result['amount'])):
|
||||
self.grouped_data.append({
|
||||
'sales_stage': result['sales_stage'][i],
|
||||
based_on : result[based_on][i],
|
||||
'amount': result['amount'][i]
|
||||
})
|
||||
for i in range(len(result["amount"])):
|
||||
self.grouped_data.append(
|
||||
{
|
||||
"sales_stage": result["sales_stage"][i],
|
||||
based_on: result[based_on][i],
|
||||
"amount": result["amount"][i],
|
||||
}
|
||||
)
|
||||
|
||||
self.query_result = self.grouped_data
|
||||
|
||||
@@ -125,17 +122,17 @@ class OpportunitySummaryBySalesStage(object):
|
||||
self.data = []
|
||||
self.get_formatted_data()
|
||||
|
||||
for based_on,data in self.formatted_data.items():
|
||||
row_based_on={
|
||||
'Opportunity Owner': 'opportunity_owner',
|
||||
'Source': 'source',
|
||||
'Opportunity Type': 'opportunity_type'
|
||||
}[self.filters.get('based_on')]
|
||||
for based_on, data in self.formatted_data.items():
|
||||
row_based_on = {
|
||||
"Opportunity Owner": "opportunity_owner",
|
||||
"Source": "source",
|
||||
"Opportunity Type": "opportunity_type",
|
||||
}[self.filters.get("based_on")]
|
||||
|
||||
row = {row_based_on: based_on}
|
||||
|
||||
for d in self.query_result:
|
||||
sales_stage = d.get('sales_stage')
|
||||
sales_stage = d.get("sales_stage")
|
||||
row[sales_stage] = data.get(sales_stage)
|
||||
|
||||
self.data.append(row)
|
||||
@@ -144,24 +141,21 @@ class OpportunitySummaryBySalesStage(object):
|
||||
self.formatted_data = frappe._dict()
|
||||
|
||||
for d in self.query_result:
|
||||
data_based_on ={
|
||||
'Number': 'count',
|
||||
'Amount': 'amount'
|
||||
}[self.filters.get('data_based_on')]
|
||||
data_based_on = {"Number": "count", "Amount": "amount"}[self.filters.get("data_based_on")]
|
||||
|
||||
based_on ={
|
||||
'Opportunity Owner': '_assign',
|
||||
'Source': 'source',
|
||||
'Opportunity Type': 'opportunity_type'
|
||||
}[self.filters.get('based_on')]
|
||||
based_on = {
|
||||
"Opportunity Owner": "_assign",
|
||||
"Source": "source",
|
||||
"Opportunity Type": "opportunity_type",
|
||||
}[self.filters.get("based_on")]
|
||||
|
||||
if self.filters.get('based_on') == 'Opportunity Owner':
|
||||
if d.get(based_on) == '[]' or d.get(based_on) is None or d.get(based_on) == 'Not Assigned':
|
||||
assignments = ['Not Assigned']
|
||||
if self.filters.get("based_on") == "Opportunity Owner":
|
||||
if d.get(based_on) == "[]" or d.get(based_on) is None or d.get(based_on) == "Not Assigned":
|
||||
assignments = ["Not Assigned"]
|
||||
else:
|
||||
assignments = json.loads(d.get(based_on))
|
||||
|
||||
sales_stage = d.get('sales_stage')
|
||||
sales_stage = d.get("sales_stage")
|
||||
count = d.get(data_based_on)
|
||||
|
||||
if assignments:
|
||||
@@ -173,7 +167,7 @@ class OpportunitySummaryBySalesStage(object):
|
||||
self.set_formatted_data_based_on_sales_stage(assigned_to, sales_stage, count)
|
||||
else:
|
||||
value = d.get(based_on)
|
||||
sales_stage = d.get('sales_stage')
|
||||
sales_stage = d.get("sales_stage")
|
||||
count = d.get(data_based_on)
|
||||
self.set_formatted_data_based_on_sales_stage(value, sales_stage, count)
|
||||
|
||||
@@ -184,20 +178,22 @@ class OpportunitySummaryBySalesStage(object):
|
||||
def get_conditions(self):
|
||||
filters = []
|
||||
|
||||
if self.filters.get('company'):
|
||||
filters.append({'company': self.filters.get('company')})
|
||||
if self.filters.get("company"):
|
||||
filters.append({"company": self.filters.get("company")})
|
||||
|
||||
if self.filters.get('opportunity_type'):
|
||||
filters.append({'opportunity_type': self.filters.get('opportunity_type')})
|
||||
if self.filters.get("opportunity_type"):
|
||||
filters.append({"opportunity_type": self.filters.get("opportunity_type")})
|
||||
|
||||
if self.filters.get('opportunity_source'):
|
||||
filters.append({'source': self.filters.get('opportunity_source')})
|
||||
if self.filters.get("opportunity_source"):
|
||||
filters.append({"source": self.filters.get("opportunity_source")})
|
||||
|
||||
if self.filters.get('status'):
|
||||
filters.append({'status': ('in',self.filters.get('status'))})
|
||||
if self.filters.get("status"):
|
||||
filters.append({"status": ("in", self.filters.get("status"))})
|
||||
|
||||
if self.filters.get('from_date') and self.filters.get('to_date'):
|
||||
filters.append(['transaction_date', 'between', [self.filters.get('from_date'), self.filters.get('to_date')]])
|
||||
if self.filters.get("from_date") and self.filters.get("to_date"):
|
||||
filters.append(
|
||||
["transaction_date", "between", [self.filters.get("from_date"), self.filters.get("to_date")]]
|
||||
)
|
||||
|
||||
return filters
|
||||
|
||||
@@ -209,45 +205,36 @@ class OpportunitySummaryBySalesStage(object):
|
||||
for sales_stage in self.sales_stage_list:
|
||||
labels.append(sales_stage)
|
||||
|
||||
options = {
|
||||
'Number': 'count',
|
||||
'Amount': 'amount'
|
||||
}[self.filters.get('data_based_on')]
|
||||
options = {"Number": "count", "Amount": "amount"}[self.filters.get("data_based_on")]
|
||||
|
||||
for data in self.query_result:
|
||||
for count in range(len(values)):
|
||||
if data['sales_stage'] == labels[count]:
|
||||
if data["sales_stage"] == labels[count]:
|
||||
values[count] = values[count] + data[options]
|
||||
|
||||
datasets.append({'name':options, 'values':values})
|
||||
datasets.append({"name": options, "values": values})
|
||||
|
||||
self.chart = {
|
||||
'data':{
|
||||
'labels': labels,
|
||||
'datasets': datasets
|
||||
},
|
||||
'type':'line'
|
||||
}
|
||||
self.chart = {"data": {"labels": labels, "datasets": datasets}, "type": "line"}
|
||||
|
||||
def currency_conversion(self,from_currency,to_currency):
|
||||
def currency_conversion(self, from_currency, to_currency):
|
||||
cacheobj = frappe.cache()
|
||||
|
||||
if cacheobj.get(from_currency):
|
||||
return flt(str(cacheobj.get(from_currency),'UTF-8'))
|
||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||
|
||||
else:
|
||||
value = get_exchange_rate(from_currency,to_currency)
|
||||
cacheobj.set(from_currency,value)
|
||||
return flt(str(cacheobj.get(from_currency),'UTF-8'))
|
||||
value = get_exchange_rate(from_currency, to_currency)
|
||||
cacheobj.set(from_currency, value)
|
||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||
|
||||
def get_default_currency(self):
|
||||
company = self.filters.get('company')
|
||||
return frappe.db.get_value('Company', company, 'default_currency')
|
||||
company = self.filters.get("company")
|
||||
return frappe.db.get_value("Company", company, "default_currency")
|
||||
|
||||
def convert_to_base_currency(self):
|
||||
default_currency = self.get_default_currency()
|
||||
for data in self.query_result:
|
||||
if data.get('currency') != default_currency:
|
||||
opportunity_currency = data.get('currency')
|
||||
value = self.currency_conversion(opportunity_currency,default_currency)
|
||||
data['amount'] = data['amount'] * value
|
||||
if data.get("currency") != default_currency:
|
||||
opportunity_currency = data.get("currency")
|
||||
value = self.currency_conversion(opportunity_currency, default_currency)
|
||||
data["amount"] = data["amount"] * value
|
||||
|
||||
@@ -27,68 +27,44 @@ class TestOpportunitySummaryBySalesStage(unittest.TestCase):
|
||||
self.check_all_filters()
|
||||
|
||||
def check_for_opportunity_owner(self):
|
||||
filters = {
|
||||
'based_on': "Opportunity Owner",
|
||||
'data_based_on': "Number",
|
||||
'company': "Best Test"
|
||||
}
|
||||
filters = {"based_on": "Opportunity Owner", "data_based_on": "Number", "company": "Best Test"}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [{
|
||||
'opportunity_owner': "Not Assigned",
|
||||
'Prospecting': 1
|
||||
}]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "Prospecting": 1}]
|
||||
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_source(self):
|
||||
filters = {
|
||||
'based_on': "Source",
|
||||
'data_based_on': "Number",
|
||||
'company': "Best Test"
|
||||
}
|
||||
filters = {"based_on": "Source", "data_based_on": "Number", "company": "Best Test"}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [{
|
||||
'source': 'Cold Calling',
|
||||
'Prospecting': 1
|
||||
}]
|
||||
expected_data = [{"source": "Cold Calling", "Prospecting": 1}]
|
||||
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_opportunity_type(self):
|
||||
filters = {
|
||||
'based_on': "Opportunity Type",
|
||||
'data_based_on': "Number",
|
||||
'company': "Best Test"
|
||||
}
|
||||
filters = {"based_on": "Opportunity Type", "data_based_on": "Number", "company": "Best Test"}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [{
|
||||
'opportunity_type': 'Sales',
|
||||
'Prospecting': 1
|
||||
}]
|
||||
expected_data = [{"opportunity_type": "Sales", "Prospecting": 1}]
|
||||
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_all_filters(self):
|
||||
filters = {
|
||||
'based_on': "Opportunity Type",
|
||||
'data_based_on': "Number",
|
||||
'company': "Best Test",
|
||||
'opportunity_source': "Cold Calling",
|
||||
'opportunity_type': "Sales",
|
||||
'status': ["Open"]
|
||||
"based_on": "Opportunity Type",
|
||||
"data_based_on": "Number",
|
||||
"company": "Best Test",
|
||||
"opportunity_source": "Cold Calling",
|
||||
"opportunity_type": "Sales",
|
||||
"status": ["Open"],
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [{
|
||||
'opportunity_type': 'Sales',
|
||||
'Prospecting': 1
|
||||
}]
|
||||
expected_data = [{"opportunity_type": "Sales", "Prospecting": 1}]
|
||||
|
||||
self.assertEqual(expected_data, report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
@@ -15,62 +15,58 @@ def execute(filters=None):
|
||||
|
||||
return columns, data
|
||||
|
||||
|
||||
def set_defaut_value_for_filters(filters):
|
||||
if not filters.get('no_of_interaction'): filters["no_of_interaction"] = 1
|
||||
if not filters.get('lead_age'): filters["lead_age"] = 60
|
||||
if not filters.get("no_of_interaction"):
|
||||
filters["no_of_interaction"] = 1
|
||||
if not filters.get("lead_age"):
|
||||
filters["lead_age"] = 60
|
||||
|
||||
|
||||
def get_columns():
|
||||
columns = [{
|
||||
"label": _("Lead"),
|
||||
"fieldname": "lead",
|
||||
"fieldtype": "Link",
|
||||
"options": "Lead",
|
||||
"width": 130
|
||||
},
|
||||
{
|
||||
"label": _("Name"),
|
||||
"fieldname": "name",
|
||||
"width": 120
|
||||
},
|
||||
{
|
||||
"label": _("Organization"),
|
||||
"fieldname": "organization",
|
||||
"width": 120
|
||||
},
|
||||
columns = [
|
||||
{"label": _("Lead"), "fieldname": "lead", "fieldtype": "Link", "options": "Lead", "width": 130},
|
||||
{"label": _("Name"), "fieldname": "name", "width": 120},
|
||||
{"label": _("Organization"), "fieldname": "organization", "width": 120},
|
||||
{
|
||||
"label": _("Reference Document Type"),
|
||||
"fieldname": "reference_document_type",
|
||||
"fieldtype": "Link",
|
||||
"options": "Doctype",
|
||||
"width": 100
|
||||
"width": 100,
|
||||
},
|
||||
{
|
||||
"label": _("Reference Name"),
|
||||
"fieldname": "reference_name",
|
||||
"fieldtype": "Dynamic Link",
|
||||
"options": "reference_document_type",
|
||||
"width": 140
|
||||
"width": 140,
|
||||
},
|
||||
{
|
||||
"label": _("Last Communication"),
|
||||
"fieldname": "last_communication",
|
||||
"fieldtype": "Data",
|
||||
"width": 200
|
||||
"width": 200,
|
||||
},
|
||||
{
|
||||
"label": _("Last Communication Date"),
|
||||
"fieldname": "last_communication_date",
|
||||
"fieldtype": "Date",
|
||||
"width": 100
|
||||
}]
|
||||
"width": 100,
|
||||
},
|
||||
]
|
||||
return columns
|
||||
|
||||
|
||||
def get_data(filters):
|
||||
lead_details = []
|
||||
lead_filters = get_lead_filters(filters)
|
||||
|
||||
for lead in frappe.get_all('Lead', fields = ['name', 'lead_name', 'company_name'], filters=lead_filters):
|
||||
data = frappe.db.sql("""
|
||||
for lead in frappe.get_all(
|
||||
"Lead", fields=["name", "lead_name", "company_name"], filters=lead_filters
|
||||
):
|
||||
data = frappe.db.sql(
|
||||
"""
|
||||
select
|
||||
`tabCommunication`.reference_doctype, `tabCommunication`.reference_name,
|
||||
`tabCommunication`.content, `tabCommunication`.communication_date
|
||||
@@ -90,7 +86,8 @@ def get_data(filters):
|
||||
`tabCommunication`.sent_or_received = 'Received'
|
||||
order by
|
||||
ref_document.lead, `tabCommunication`.creation desc limit %(limit)s""",
|
||||
{'lead': lead.name, 'limit': filters.get('no_of_interaction')})
|
||||
{"lead": lead.name, "limit": filters.get("no_of_interaction")},
|
||||
)
|
||||
|
||||
for lead_info in data:
|
||||
lead_data = [lead.name, lead.lead_name, lead.company_name] + list(lead_info)
|
||||
@@ -98,13 +95,15 @@ def get_data(filters):
|
||||
|
||||
return lead_details
|
||||
|
||||
|
||||
def get_lead_filters(filters):
|
||||
lead_creation_date = get_creation_date_based_on_lead_age(filters)
|
||||
lead_filters = [["status", "!=", "Converted"], ["creation", ">", lead_creation_date]]
|
||||
|
||||
if filters.get('lead'):
|
||||
lead_filters.append(["name", "=", filters.get('lead')])
|
||||
if filters.get("lead"):
|
||||
lead_filters.append(["name", "=", filters.get("lead")])
|
||||
return lead_filters
|
||||
|
||||
|
||||
def get_creation_date_based_on_lead_age(filters):
|
||||
return add_days(now(), (filters.get('lead_age') * -1))
|
||||
return add_days(now(), (filters.get("lead_age") * -1))
|
||||
|
||||
@@ -16,6 +16,7 @@ from erpnext.setup.utils import get_exchange_rate
|
||||
def execute(filters=None):
|
||||
return SalesPipelineAnalytics(filters).run()
|
||||
|
||||
|
||||
class SalesPipelineAnalytics(object):
|
||||
def __init__(self, filters=None):
|
||||
self.filters = frappe._dict(filters or {})
|
||||
@@ -34,113 +35,94 @@ class SalesPipelineAnalytics(object):
|
||||
self.set_pipeline_based_on_column()
|
||||
|
||||
def set_range_columns(self):
|
||||
based_on = {
|
||||
'Number': 'Int',
|
||||
'Amount': 'Currency'
|
||||
}[self.filters.get('based_on')]
|
||||
based_on = {"Number": "Int", "Amount": "Currency"}[self.filters.get("based_on")]
|
||||
|
||||
if self.filters.get('range') == 'Monthly':
|
||||
if self.filters.get("range") == "Monthly":
|
||||
month_list = self.get_month_list()
|
||||
|
||||
for month in month_list:
|
||||
self.columns.append({
|
||||
'fieldname': month,
|
||||
'fieldtype': based_on,
|
||||
'label': month,
|
||||
'width': 200
|
||||
})
|
||||
self.columns.append({"fieldname": month, "fieldtype": based_on, "label": month, "width": 200})
|
||||
|
||||
elif self.filters.get('range') == 'Quarterly':
|
||||
elif self.filters.get("range") == "Quarterly":
|
||||
for quarter in range(1, 5):
|
||||
self.columns.append({
|
||||
'fieldname': f'Q{quarter}',
|
||||
'fieldtype': based_on,
|
||||
'label': f'Q{quarter}',
|
||||
'width': 200
|
||||
})
|
||||
self.columns.append(
|
||||
{"fieldname": f"Q{quarter}", "fieldtype": based_on, "label": f"Q{quarter}", "width": 200}
|
||||
)
|
||||
|
||||
def set_pipeline_based_on_column(self):
|
||||
if self.filters.get('pipeline_by') == 'Owner':
|
||||
self.columns.insert(0, {
|
||||
'fieldname': 'opportunity_owner',
|
||||
'label': _('Opportunity Owner'),
|
||||
'width': 200
|
||||
})
|
||||
if self.filters.get("pipeline_by") == "Owner":
|
||||
self.columns.insert(
|
||||
0, {"fieldname": "opportunity_owner", "label": _("Opportunity Owner"), "width": 200}
|
||||
)
|
||||
|
||||
elif self.filters.get('pipeline_by') == 'Sales Stage':
|
||||
self.columns.insert(0, {
|
||||
'fieldname': 'sales_stage',
|
||||
'label': _('Sales Stage'),
|
||||
'width': 200
|
||||
})
|
||||
elif self.filters.get("pipeline_by") == "Sales Stage":
|
||||
self.columns.insert(0, {"fieldname": "sales_stage", "label": _("Sales Stage"), "width": 200})
|
||||
|
||||
def get_fields(self):
|
||||
self.based_on ={
|
||||
'Owner': '_assign as opportunity_owner',
|
||||
'Sales Stage': 'sales_stage'
|
||||
}[self.filters.get('pipeline_by')]
|
||||
self.based_on = {"Owner": "_assign as opportunity_owner", "Sales Stage": "sales_stage"}[
|
||||
self.filters.get("pipeline_by")
|
||||
]
|
||||
|
||||
self.data_based_on ={
|
||||
'Number': 'count(name) as count',
|
||||
'Amount': 'opportunity_amount as amount'
|
||||
}[self.filters.get('based_on')]
|
||||
self.data_based_on = {
|
||||
"Number": "count(name) as count",
|
||||
"Amount": "opportunity_amount as amount",
|
||||
}[self.filters.get("based_on")]
|
||||
|
||||
self.group_by_based_on = {
|
||||
'Owner': '_assign',
|
||||
'Sales Stage': 'sales_stage'
|
||||
}[self.filters.get('pipeline_by')]
|
||||
self.group_by_based_on = {"Owner": "_assign", "Sales Stage": "sales_stage"}[
|
||||
self.filters.get("pipeline_by")
|
||||
]
|
||||
|
||||
self.group_by_period = {
|
||||
'Monthly': 'month(expected_closing)',
|
||||
'Quarterly': 'QUARTER(expected_closing)'
|
||||
}[self.filters.get('range')]
|
||||
"Monthly": "month(expected_closing)",
|
||||
"Quarterly": "QUARTER(expected_closing)",
|
||||
}[self.filters.get("range")]
|
||||
|
||||
self.pipeline_by = {
|
||||
'Owner': 'opportunity_owner',
|
||||
'Sales Stage': 'sales_stage'
|
||||
}[self.filters.get('pipeline_by')]
|
||||
self.pipeline_by = {"Owner": "opportunity_owner", "Sales Stage": "sales_stage"}[
|
||||
self.filters.get("pipeline_by")
|
||||
]
|
||||
|
||||
self.duration = {
|
||||
'Monthly': 'monthname(expected_closing) as month',
|
||||
'Quarterly': 'QUARTER(expected_closing) as quarter'
|
||||
}[self.filters.get('range')]
|
||||
"Monthly": "monthname(expected_closing) as month",
|
||||
"Quarterly": "QUARTER(expected_closing) as quarter",
|
||||
}[self.filters.get("range")]
|
||||
|
||||
self.period_by = {
|
||||
'Monthly': 'month',
|
||||
'Quarterly': 'quarter'
|
||||
}[self.filters.get('range')]
|
||||
self.period_by = {"Monthly": "month", "Quarterly": "quarter"}[self.filters.get("range")]
|
||||
|
||||
def get_data(self):
|
||||
self.get_fields()
|
||||
|
||||
if self.filters.get('based_on') == 'Number':
|
||||
self.query_result = frappe.db.get_list('Opportunity',
|
||||
if self.filters.get("based_on") == "Number":
|
||||
self.query_result = frappe.db.get_list(
|
||||
"Opportunity",
|
||||
filters=self.get_conditions(),
|
||||
fields=[self.based_on, self.data_based_on, self.duration],
|
||||
group_by='{},{}'.format(self.group_by_based_on, self.group_by_period),
|
||||
order_by=self.group_by_period
|
||||
group_by="{},{}".format(self.group_by_based_on, self.group_by_period),
|
||||
order_by=self.group_by_period,
|
||||
)
|
||||
|
||||
if self.filters.get('based_on') == 'Amount':
|
||||
self.query_result = frappe.db.get_list('Opportunity',
|
||||
if self.filters.get("based_on") == "Amount":
|
||||
self.query_result = frappe.db.get_list(
|
||||
"Opportunity",
|
||||
filters=self.get_conditions(),
|
||||
fields=[self.based_on, self.data_based_on, self.duration, 'currency']
|
||||
fields=[self.based_on, self.data_based_on, self.duration, "currency"],
|
||||
)
|
||||
|
||||
self.convert_to_base_currency()
|
||||
|
||||
dataframe = pandas.DataFrame.from_records(self.query_result)
|
||||
dataframe.replace(to_replace=[None], value='Not Assigned', inplace=True)
|
||||
result = dataframe.groupby([self.pipeline_by, self.period_by], as_index=False)['amount'].sum()
|
||||
dataframe.replace(to_replace=[None], value="Not Assigned", inplace=True)
|
||||
result = dataframe.groupby([self.pipeline_by, self.period_by], as_index=False)["amount"].sum()
|
||||
|
||||
self.grouped_data = []
|
||||
|
||||
for i in range(len(result['amount'])):
|
||||
self.grouped_data.append({
|
||||
self.pipeline_by : result[self.pipeline_by][i],
|
||||
self.period_by : result[self.period_by][i],
|
||||
'amount': result['amount'][i]
|
||||
})
|
||||
for i in range(len(result["amount"])):
|
||||
self.grouped_data.append(
|
||||
{
|
||||
self.pipeline_by: result[self.pipeline_by][i],
|
||||
self.period_by: result[self.period_by][i],
|
||||
"amount": result["amount"][i],
|
||||
}
|
||||
)
|
||||
|
||||
self.query_result = self.grouped_data
|
||||
|
||||
@@ -150,21 +132,22 @@ class SalesPipelineAnalytics(object):
|
||||
def get_conditions(self):
|
||||
conditions = []
|
||||
|
||||
if self.filters.get('opportunity_source'):
|
||||
conditions.append({'source': self.filters.get('opportunity_source')})
|
||||
if self.filters.get("opportunity_source"):
|
||||
conditions.append({"source": self.filters.get("opportunity_source")})
|
||||
|
||||
if self.filters.get('opportunity_type'):
|
||||
conditions.append({'opportunity_type': self.filters.get('opportunity_type')})
|
||||
if self.filters.get("opportunity_type"):
|
||||
conditions.append({"opportunity_type": self.filters.get("opportunity_type")})
|
||||
|
||||
if self.filters.get('status'):
|
||||
conditions.append({'status': self.filters.get('status')})
|
||||
if self.filters.get("status"):
|
||||
conditions.append({"status": self.filters.get("status")})
|
||||
|
||||
if self.filters.get('company'):
|
||||
conditions.append({'company': self.filters.get('company')})
|
||||
if self.filters.get("company"):
|
||||
conditions.append({"company": self.filters.get("company")})
|
||||
|
||||
if self.filters.get('from_date') and self.filters.get('to_date'):
|
||||
conditions.append(['expected_closing', 'between',
|
||||
[self.filters.get('from_date'), self.filters.get('to_date')]])
|
||||
if self.filters.get("from_date") and self.filters.get("to_date"):
|
||||
conditions.append(
|
||||
["expected_closing", "between", [self.filters.get("from_date"), self.filters.get("to_date")]]
|
||||
)
|
||||
|
||||
return conditions
|
||||
|
||||
@@ -175,49 +158,36 @@ class SalesPipelineAnalytics(object):
|
||||
self.append_to_dataset(datasets)
|
||||
|
||||
for column in self.columns:
|
||||
if column['fieldname'] != 'opportunity_owner' and column['fieldname'] != 'sales_stage':
|
||||
labels.append(column['fieldname'])
|
||||
if column["fieldname"] != "opportunity_owner" and column["fieldname"] != "sales_stage":
|
||||
labels.append(column["fieldname"])
|
||||
|
||||
self.chart = {
|
||||
'data':{
|
||||
'labels': labels,
|
||||
'datasets': datasets
|
||||
},
|
||||
'type':'line'
|
||||
}
|
||||
self.chart = {"data": {"labels": labels, "datasets": datasets}, "type": "line"}
|
||||
|
||||
return self.chart
|
||||
|
||||
def get_periodic_data(self):
|
||||
self.periodic_data = frappe._dict()
|
||||
|
||||
based_on = {
|
||||
'Number': 'count',
|
||||
'Amount': 'amount'
|
||||
}[self.filters.get('based_on')]
|
||||
based_on = {"Number": "count", "Amount": "amount"}[self.filters.get("based_on")]
|
||||
|
||||
pipeline_by = {
|
||||
'Owner': 'opportunity_owner',
|
||||
'Sales Stage': 'sales_stage'
|
||||
}[self.filters.get('pipeline_by')]
|
||||
pipeline_by = {"Owner": "opportunity_owner", "Sales Stage": "sales_stage"}[
|
||||
self.filters.get("pipeline_by")
|
||||
]
|
||||
|
||||
frequency = {
|
||||
'Monthly': 'month',
|
||||
'Quarterly': 'quarter'
|
||||
}[self.filters.get('range')]
|
||||
frequency = {"Monthly": "month", "Quarterly": "quarter"}[self.filters.get("range")]
|
||||
|
||||
for info in self.query_result:
|
||||
if self.filters.get('range') == 'Monthly':
|
||||
if self.filters.get("range") == "Monthly":
|
||||
period = info.get(frequency)
|
||||
if self.filters.get('range') == 'Quarterly':
|
||||
if self.filters.get("range") == "Quarterly":
|
||||
period = f'Q{cint(info.get("quarter"))}'
|
||||
|
||||
value = info.get(pipeline_by)
|
||||
count_or_amount = info.get(based_on)
|
||||
|
||||
if self.filters.get('pipeline_by') == 'Owner':
|
||||
if value == 'Not Assigned' or value == '[]' or value is None:
|
||||
assigned_to = ['Not Assigned']
|
||||
if self.filters.get("pipeline_by") == "Owner":
|
||||
if value == "Not Assigned" or value == "[]" or value is None:
|
||||
assigned_to = ["Not Assigned"]
|
||||
else:
|
||||
assigned_to = json.loads(value)
|
||||
self.check_for_assigned_to(period, value, count_or_amount, assigned_to, info)
|
||||
@@ -228,9 +198,9 @@ class SalesPipelineAnalytics(object):
|
||||
def set_formatted_data(self, period, value, count_or_amount, assigned_to):
|
||||
if assigned_to:
|
||||
if len(assigned_to) > 1:
|
||||
if self.filters.get('assigned_to'):
|
||||
if self.filters.get("assigned_to"):
|
||||
for user in assigned_to:
|
||||
if self.filters.get('assigned_to') == user:
|
||||
if self.filters.get("assigned_to") == user:
|
||||
value = user
|
||||
self.periodic_data.setdefault(value, frappe._dict()).setdefault(period, 0)
|
||||
self.periodic_data[value][period] += count_or_amount
|
||||
@@ -249,40 +219,34 @@ class SalesPipelineAnalytics(object):
|
||||
self.periodic_data[value][period] += count_or_amount
|
||||
|
||||
def check_for_assigned_to(self, period, value, count_or_amount, assigned_to, info):
|
||||
if self.filters.get('assigned_to'):
|
||||
for data in json.loads(info.get('opportunity_owner')):
|
||||
if data == self.filters.get('assigned_to'):
|
||||
if self.filters.get("assigned_to"):
|
||||
for data in json.loads(info.get("opportunity_owner")):
|
||||
if data == self.filters.get("assigned_to"):
|
||||
self.set_formatted_data(period, data, count_or_amount, assigned_to)
|
||||
else:
|
||||
self.set_formatted_data(period, value, count_or_amount, assigned_to)
|
||||
|
||||
def get_month_list(self):
|
||||
month_list= []
|
||||
month_list = []
|
||||
current_date = date.today()
|
||||
month_number = date.today().month
|
||||
|
||||
for month in range(month_number,13):
|
||||
month_list.append(current_date.strftime('%B'))
|
||||
for month in range(month_number, 13):
|
||||
month_list.append(current_date.strftime("%B"))
|
||||
current_date = current_date + relativedelta(months=1)
|
||||
|
||||
return month_list
|
||||
|
||||
def append_to_dataset(self, datasets):
|
||||
range_by = {
|
||||
'Monthly': 'month',
|
||||
'Quarterly': 'quarter'
|
||||
}[self.filters.get('range')]
|
||||
range_by = {"Monthly": "month", "Quarterly": "quarter"}[self.filters.get("range")]
|
||||
|
||||
based_on = {
|
||||
'Amount': 'amount',
|
||||
'Number': 'count'
|
||||
}[self.filters.get('based_on')]
|
||||
based_on = {"Amount": "amount", "Number": "count"}[self.filters.get("based_on")]
|
||||
|
||||
if self.filters.get('range') == 'Quarterly':
|
||||
frequency_list = [1,2,3,4]
|
||||
if self.filters.get("range") == "Quarterly":
|
||||
frequency_list = [1, 2, 3, 4]
|
||||
count = [0] * 4
|
||||
|
||||
if self.filters.get('range') == 'Monthly':
|
||||
if self.filters.get("range") == "Monthly":
|
||||
frequency_list = self.get_month_list()
|
||||
count = [0] * 12
|
||||
|
||||
@@ -290,43 +254,43 @@ class SalesPipelineAnalytics(object):
|
||||
for i in range(len(frequency_list)):
|
||||
if info[range_by] == frequency_list[i]:
|
||||
count[i] = count[i] + info[based_on]
|
||||
datasets.append({'name': based_on, 'values': count})
|
||||
datasets.append({"name": based_on, "values": count})
|
||||
|
||||
def append_data(self, pipeline_by, period_by):
|
||||
self.data = []
|
||||
for pipeline,period_data in self.periodic_data.items():
|
||||
row = {pipeline_by : pipeline}
|
||||
for pipeline, period_data in self.periodic_data.items():
|
||||
row = {pipeline_by: pipeline}
|
||||
for info in self.query_result:
|
||||
if self.filters.get('range') == 'Monthly':
|
||||
if self.filters.get("range") == "Monthly":
|
||||
period = info.get(period_by)
|
||||
|
||||
if self.filters.get('range') == 'Quarterly':
|
||||
period = f'Q{cint(info.get(period_by))}'
|
||||
if self.filters.get("range") == "Quarterly":
|
||||
period = f"Q{cint(info.get(period_by))}"
|
||||
|
||||
count = period_data.get(period,0.0)
|
||||
count = period_data.get(period, 0.0)
|
||||
row[period] = count
|
||||
|
||||
self.data.append(row)
|
||||
|
||||
def get_default_currency(self):
|
||||
company = self.filters.get('company')
|
||||
return frappe.db.get_value('Company',company,['default_currency'])
|
||||
company = self.filters.get("company")
|
||||
return frappe.db.get_value("Company", company, ["default_currency"])
|
||||
|
||||
def get_currency_rate(self, from_currency, to_currency):
|
||||
cacheobj = frappe.cache()
|
||||
|
||||
if cacheobj.get(from_currency):
|
||||
return flt(str(cacheobj.get(from_currency),'UTF-8'))
|
||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||
|
||||
else:
|
||||
value = get_exchange_rate(from_currency, to_currency)
|
||||
cacheobj.set(from_currency, value)
|
||||
return flt(str(cacheobj.get(from_currency),'UTF-8'))
|
||||
return flt(str(cacheobj.get(from_currency), "UTF-8"))
|
||||
|
||||
def convert_to_base_currency(self):
|
||||
default_currency = self.get_default_currency()
|
||||
for data in self.query_result:
|
||||
if data.get('currency') != default_currency:
|
||||
opportunity_currency = data.get('currency')
|
||||
value = self.get_currency_rate(opportunity_currency,default_currency)
|
||||
data['amount'] = data['amount'] * value
|
||||
if data.get("currency") != default_currency:
|
||||
opportunity_currency = data.get("currency")
|
||||
value = self.get_currency_rate(opportunity_currency, default_currency)
|
||||
data["amount"] = data["amount"] * value
|
||||
|
||||
@@ -22,217 +22,175 @@ class TestSalesPipelineAnalytics(unittest.TestCase):
|
||||
|
||||
def check_for_monthly_and_number(self):
|
||||
filters = {
|
||||
'pipeline_by':"Owner",
|
||||
'range':"Monthly",
|
||||
'based_on':"Number",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Owner",
|
||||
"range": "Monthly",
|
||||
"based_on": "Number",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'opportunity_owner':'Not Assigned',
|
||||
'August':1
|
||||
}
|
||||
]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "August": 1}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
filters = {
|
||||
'pipeline_by':"Sales Stage",
|
||||
'range':"Monthly",
|
||||
'based_on':"Number",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Sales Stage",
|
||||
"range": "Monthly",
|
||||
"based_on": "Number",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'sales_stage':'Prospecting',
|
||||
'August':1
|
||||
}
|
||||
]
|
||||
expected_data = [{"sales_stage": "Prospecting", "August": 1}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_monthly_and_amount(self):
|
||||
filters = {
|
||||
'pipeline_by':"Owner",
|
||||
'range':"Monthly",
|
||||
'based_on':"Amount",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Owner",
|
||||
"range": "Monthly",
|
||||
"based_on": "Amount",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'opportunity_owner':'Not Assigned',
|
||||
'August':150000
|
||||
}
|
||||
]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "August": 150000}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
filters = {
|
||||
'pipeline_by':"Sales Stage",
|
||||
'range':"Monthly",
|
||||
'based_on':"Amount",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Sales Stage",
|
||||
"range": "Monthly",
|
||||
"based_on": "Amount",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'sales_stage':'Prospecting',
|
||||
'August':150000
|
||||
}
|
||||
]
|
||||
expected_data = [{"sales_stage": "Prospecting", "August": 150000}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_quarterly_and_number(self):
|
||||
filters = {
|
||||
'pipeline_by':"Owner",
|
||||
'range':"Quarterly",
|
||||
'based_on':"Number",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Owner",
|
||||
"range": "Quarterly",
|
||||
"based_on": "Number",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'opportunity_owner':'Not Assigned',
|
||||
'Q3':1
|
||||
}
|
||||
]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "Q3": 1}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
filters = {
|
||||
'pipeline_by':"Sales Stage",
|
||||
'range':"Quarterly",
|
||||
'based_on':"Number",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Sales Stage",
|
||||
"range": "Quarterly",
|
||||
"based_on": "Number",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'sales_stage':'Prospecting',
|
||||
'Q3':1
|
||||
}
|
||||
]
|
||||
expected_data = [{"sales_stage": "Prospecting", "Q3": 1}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_quarterly_and_amount(self):
|
||||
filters = {
|
||||
'pipeline_by':"Owner",
|
||||
'range':"Quarterly",
|
||||
'based_on':"Amount",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Owner",
|
||||
"range": "Quarterly",
|
||||
"based_on": "Amount",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'opportunity_owner':'Not Assigned',
|
||||
'Q3':150000
|
||||
}
|
||||
]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "Q3": 150000}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
filters = {
|
||||
'pipeline_by':"Sales Stage",
|
||||
'range':"Quarterly",
|
||||
'based_on':"Amount",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test"
|
||||
"pipeline_by": "Sales Stage",
|
||||
"range": "Quarterly",
|
||||
"based_on": "Amount",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'sales_stage':'Prospecting',
|
||||
'Q3':150000
|
||||
}
|
||||
]
|
||||
expected_data = [{"sales_stage": "Prospecting", "Q3": 150000}]
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
def check_for_all_filters(self):
|
||||
filters = {
|
||||
'pipeline_by':"Owner",
|
||||
'range':"Monthly",
|
||||
'based_on':"Number",
|
||||
'status':"Open",
|
||||
'opportunity_type':"Sales",
|
||||
'company':"Best Test",
|
||||
'opportunity_source':'Cold Calling',
|
||||
'from_date': '2021-08-01',
|
||||
'to_date':'2021-08-31'
|
||||
"pipeline_by": "Owner",
|
||||
"range": "Monthly",
|
||||
"based_on": "Number",
|
||||
"status": "Open",
|
||||
"opportunity_type": "Sales",
|
||||
"company": "Best Test",
|
||||
"opportunity_source": "Cold Calling",
|
||||
"from_date": "2021-08-01",
|
||||
"to_date": "2021-08-31",
|
||||
}
|
||||
|
||||
report = execute(filters)
|
||||
|
||||
expected_data = [
|
||||
{
|
||||
'opportunity_owner':'Not Assigned',
|
||||
'August': 1
|
||||
}
|
||||
]
|
||||
expected_data = [{"opportunity_owner": "Not Assigned", "August": 1}]
|
||||
|
||||
self.assertEqual(expected_data, report[1])
|
||||
|
||||
self.assertEqual(expected_data,report[1])
|
||||
|
||||
def create_company():
|
||||
doc = frappe.db.exists('Company','Best Test')
|
||||
doc = frappe.db.exists("Company", "Best Test")
|
||||
if not doc:
|
||||
doc = frappe.new_doc('Company')
|
||||
doc.company_name = 'Best Test'
|
||||
doc = frappe.new_doc("Company")
|
||||
doc.company_name = "Best Test"
|
||||
doc.default_currency = "INR"
|
||||
doc.insert()
|
||||
|
||||
|
||||
def create_customer():
|
||||
doc = frappe.db.exists("Customer","_Test NC")
|
||||
doc = frappe.db.exists("Customer", "_Test NC")
|
||||
if not doc:
|
||||
doc = frappe.new_doc("Customer")
|
||||
doc.customer_name = '_Test NC'
|
||||
doc.customer_name = "_Test NC"
|
||||
doc.insert()
|
||||
|
||||
|
||||
def create_opportunity():
|
||||
doc = frappe.db.exists({"doctype":"Opportunity","party_name":"_Test NC"})
|
||||
doc = frappe.db.exists({"doctype": "Opportunity", "party_name": "_Test NC"})
|
||||
if not doc:
|
||||
doc = frappe.new_doc("Opportunity")
|
||||
doc.opportunity_from = "Customer"
|
||||
customer_name = frappe.db.get_value("Customer",{"customer_name":'_Test NC'},['customer_name'])
|
||||
customer_name = frappe.db.get_value("Customer", {"customer_name": "_Test NC"}, ["customer_name"])
|
||||
doc.party_name = customer_name
|
||||
doc.opportunity_amount = 150000
|
||||
doc.source = "Cold Calling"
|
||||
doc.currency = "INR"
|
||||
doc.expected_closing = "2021-08-31"
|
||||
doc.company = 'Best Test'
|
||||
doc.insert()
|
||||
doc.company = "Best Test"
|
||||
doc.insert()
|
||||
|
||||
Reference in New Issue
Block a user