feat: Competitor Tagging in Opportunity and Quotation (#28050)

* feat: Competitor Tagging in Opportunity and Quotation

* fix: review changes

* fix: linter issue

* fix: section label

Co-authored-by: Rucha Mahabal <ruchamahabal2@gmail.com>
This commit is contained in:
Anupam Kumar 2021-11-09 19:36:27 +05:30 committed by GitHub
parent ccf84ae88a
commit 6954dd6329
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 197 additions and 18 deletions

View File

@ -0,0 +1,8 @@
// Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on('Competitor', {
// refresh: function(frm) {
// }
});

View File

@ -0,0 +1,68 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:competitor_name",
"creation": "2021-10-21 10:28:52.071316",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"competitor_name",
"website"
],
"fields": [
{
"fieldname": "competitor_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Competitor Name",
"reqd": 1,
"unique": 1
},
{
"allow_in_quick_entry": 1,
"fieldname": "website",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Website",
"options": "URL"
}
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2021-10-21 12:43:59.106807",
"modified_by": "Administrator",
"module": "CRM",
"name": "Competitor",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,9 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class Competitor(Document):
pass

View File

@ -0,0 +1,9 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
import unittest
class TestCompetitor(unittest.TestCase):
pass

View File

@ -0,0 +1,33 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2021-10-21 10:34:58.841689",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"competitor"
],
"fields": [
{
"fieldname": "competitor",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Competitor",
"options": "Competitor",
"reqd": 1
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2021-10-21 10:34:58.841689",
"modified_by": "Administrator",
"module": "CRM",
"name": "Competitor Detail",
"owner": "Administrator",
"permissions": [],
"sort_field": "modified",
"sort_order": "DESC",
"track_changes": 1
}

View File

@ -0,0 +1,9 @@
# Copyright (c) 2021, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class CompetitorDetail(Document):
pass

View File

@ -23,7 +23,6 @@
"status", "status",
"converted_by", "converted_by",
"sales_stage", "sales_stage",
"order_lost_reason",
"first_response_time", "first_response_time",
"expected_closing", "expected_closing",
"next_contact", "next_contact",
@ -64,7 +63,11 @@
"transaction_date", "transaction_date",
"language", "language",
"amended_from", "amended_from",
"lost_reasons" "lost_detail_section",
"lost_reasons",
"order_lost_reason",
"column_break_56",
"competitors"
], ],
"fields": [ "fields": [
{ {
@ -154,10 +157,9 @@
"reqd": 1 "reqd": 1
}, },
{ {
"depends_on": "eval:doc.status===\"Lost\"",
"fieldname": "order_lost_reason", "fieldname": "order_lost_reason",
"fieldtype": "Small Text", "fieldtype": "Small Text",
"label": "Lost Reason", "label": "Detailed Reason",
"no_copy": 1, "no_copy": 1,
"read_only": 1 "read_only": 1
}, },
@ -409,6 +411,7 @@
"width": "150px" "width": "150px"
}, },
{ {
"depends_on": "eval:doc.status===\"Lost\"",
"fieldname": "lost_reasons", "fieldname": "lost_reasons",
"fieldtype": "Table MultiSelect", "fieldtype": "Table MultiSelect",
"label": "Lost Reasons", "label": "Lost Reasons",
@ -486,15 +489,33 @@
"label": "Grand Total", "label": "Grand Total",
"options": "currency", "options": "currency",
"read_only": 1 "read_only": 1
},
{
"fieldname": "lost_detail_section",
"fieldtype": "Section Break",
"label": "Lost Reasons"
},
{
"fieldname": "column_break_56",
"fieldtype": "Column Break"
},
{
"fieldname": "competitors",
"fieldtype": "Table MultiSelect",
"label": "Competitors",
"options": "Competitor Detail",
"read_only": 1
} }
], ],
"icon": "fa fa-info-sign", "icon": "fa fa-info-sign",
"idx": 195, "idx": 195,
"links": [], "links": [],
"modified": "2021-09-06 10:02:18.609136", "migration_hash": "d87c646ea2579b6900197fd41e6c5c5a",
"modified": "2021-10-21 11:04:30.151379",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "CRM", "module": "CRM",
"name": "Opportunity", "name": "Opportunity",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@ -116,16 +116,20 @@ class Opportunity(TransactionBase):
self.party_name = lead_name self.party_name = lead_name
@frappe.whitelist() @frappe.whitelist()
def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None): def declare_enquiry_lost(self, lost_reasons_list, competitors, detailed_reason=None):
if not self.has_active_quotation(): if not self.has_active_quotation():
frappe.db.set(self, 'status', 'Lost') self.status = 'Lost'
self.lost_reasons = self.competitors = []
if detailed_reason: if detailed_reason:
frappe.db.set(self, 'order_lost_reason', detailed_reason) self.order_lost_reason = detailed_reason
for reason in lost_reasons_list: for reason in lost_reasons_list:
self.append('lost_reasons', reason) self.append('lost_reasons', reason)
for competitor in competitors:
self.append('competitors', competitor)
self.save() self.save()
else: else:

View File

@ -110,7 +110,8 @@
"enq_det", "enq_det",
"supplier_quotation", "supplier_quotation",
"opportunity", "opportunity",
"lost_reasons" "lost_reasons",
"competitors"
], ],
"fields": [ "fields": [
{ {
@ -946,6 +947,14 @@
"label": "Bundle Items", "label": "Bundle Items",
"options": "fa fa-suitcase", "options": "fa fa-suitcase",
"print_hide": 1 "print_hide": 1
},
{
"allow_on_submit": 1,
"fieldname": "competitors",
"fieldtype": "Table MultiSelect",
"label": "Competitors",
"options": "Competitor Detail",
"read_only": 1
} }
], ],
"icon": "fa fa-shopping-cart", "icon": "fa fa-shopping-cart",
@ -953,10 +962,12 @@
"is_submittable": 1, "is_submittable": 1,
"links": [], "links": [],
"max_attachments": 1, "max_attachments": 1,
"modified": "2021-08-27 20:10:07.864951", "migration_hash": "75a86a19f062c2257bcbc8e6e31c7f1e",
"modified": "2021-10-21 12:58:55.514512",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Selling", "module": "Selling",
"name": "Quotation", "name": "Quotation",
"naming_rule": "By \"Naming Series\" field",
"owner": "Administrator", "owner": "Administrator",
"permissions": [ "permissions": [
{ {

View File

@ -68,7 +68,7 @@ class Quotation(SellingController):
opp.set_status(status=status, update=True) opp.set_status(status=status, update=True)
@frappe.whitelist() @frappe.whitelist()
def declare_enquiry_lost(self, lost_reasons_list, detailed_reason=None): def declare_enquiry_lost(self, lost_reasons_list, competitors, detailed_reason=None):
if not self.has_sales_order(): if not self.has_sales_order():
get_lost_reasons = frappe.get_list('Quotation Lost Reason', get_lost_reasons = frappe.get_list('Quotation Lost Reason',
fields = ["name"]) fields = ["name"])
@ -84,6 +84,9 @@ class Quotation(SellingController):
else: else:
frappe.throw(_("Invalid lost reason {0}, please create a new lost reason").format(frappe.bold(reason.get('lost_reason')))) frappe.throw(_("Invalid lost reason {0}, please create a new lost reason").format(frappe.bold(reason.get('lost_reason'))))
for competitor in competitors:
self.append('competitors', competitor)
self.update_opportunity('Lost') self.update_opportunity('Lost')
self.update_lead() self.update_lead()
self.save() self.save()

View File

@ -473,6 +473,12 @@ frappe.ui.form.on(cur_frm.doctype, {
"options": frm.doctype === 'Opportunity' ? 'Opportunity Lost Reason Detail': 'Quotation Lost Reason Detail', "options": frm.doctype === 'Opportunity' ? 'Opportunity Lost Reason Detail': 'Quotation Lost Reason Detail',
"reqd": 1 "reqd": 1
}, },
{
"fieldtype": "Table MultiSelect",
"label": __("Competitors"),
"fieldname": "competitors",
"options": "Competitor Detail"
},
{ {
"fieldtype": "Text", "fieldtype": "Text",
"label": __("Detailed Reason"), "label": __("Detailed Reason"),
@ -480,27 +486,25 @@ frappe.ui.form.on(cur_frm.doctype, {
}, },
], ],
primary_action: function() { primary_action: function() {
var values = dialog.get_values(); let values = dialog.get_values();
var reasons = values["lost_reason"];
var detailed_reason = values["detailed_reason"];
frm.call({ frm.call({
doc: frm.doc, doc: frm.doc,
method: 'declare_enquiry_lost', method: 'declare_enquiry_lost',
args: { args: {
'lost_reasons_list': reasons, 'lost_reasons_list': values.lost_reason,
'detailed_reason': detailed_reason 'competitors': values.competitors,
'detailed_reason': values.detailed_reason
}, },
callback: function(r) { callback: function(r) {
dialog.hide(); dialog.hide();
frm.reload_doc(); frm.reload_doc();
}, },
}); });
refresh_field("lost_reason");
}, },
primary_action_label: __('Declare Lost') primary_action_label: __('Declare Lost')
}); });
dialog.show(); dialog.show();
} }
}) })