feat(analytics): comply erpnext with utm methodology

This commit is contained in:
David
2024-06-29 00:45:39 +02:00
parent 7a21574cfb
commit 96a6673510
46 changed files with 631 additions and 416 deletions

View File

@@ -13,13 +13,13 @@
"fieldtype": "Link",
"in_list_view": 1,
"label": "Campaign",
"options": "Campaign"
"options": "UTM Campaign"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-03-27 13:06:44.142625",
"modified": "2024-06-28 11:04:09.815940",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Campaign Item",
@@ -29,4 +29,4 @@
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@@ -156,11 +156,13 @@
"more_information",
"inter_company_invoice_reference",
"customer_group",
"campaign",
"is_discounted",
"col_break23",
"utm_source",
"utm_campaign",
"utm_medium",
"column_break_gpiw",
"status",
"source",
"more_info",
"debit_to",
"party_account_currency",
@@ -1318,15 +1320,6 @@
"options": "Customer Group",
"print_hide": 1
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
"print_hide": 1
},
{
"default": "0",
"fieldname": "is_discounted",
@@ -1351,15 +1344,6 @@
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
"print_hide": 1
},
{
"collapsible": 1,
"fieldname": "more_info",
@@ -1558,12 +1542,41 @@
"fieldname": "update_billed_amount_in_delivery_note",
"fieldtype": "Check",
"label": "Update Billed Amount in Delivery Note"
},
{
"fieldname": "column_break_gpiw",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign",
"print_hide": 1
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source",
"print_hide": 1
}
],
"icon": "fa fa-file-text",
"is_submittable": 1,
"links": [],
"modified": "2024-03-27 13:10:14.787999",
"modified": "2024-06-28 10:55:34.941200",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Invoice",
@@ -1617,4 +1630,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -66,7 +66,6 @@ class POSInvoice(SalesInvoice):
base_total: DF.Currency
base_total_taxes_and_charges: DF.Currency
base_write_off_amount: DF.Currency
campaign: DF.Link | None
cash_bank_account: DF.Link | None
change_amount: DF.Currency
commission_rate: DF.Float
@@ -141,7 +140,6 @@ class POSInvoice(SalesInvoice):
shipping_address: DF.TextEditor | None
shipping_address_name: DF.Link | None
shipping_rule: DF.Link | None
source: DF.Link | None
status: DF.Literal[
"",
"Draft",
@@ -176,6 +174,9 @@ class POSInvoice(SalesInvoice):
update_billed_amount_in_delivery_note: DF.Check
update_billed_amount_in_sales_order: DF.Check
update_stock: DF.Check
utm_campaign: DF.Link | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
write_off_account: DF.Link | None
write_off_amount: DF.Currency
write_off_cost_center: DF.Link | None
@@ -642,7 +643,9 @@ class POSInvoice(SalesInvoice):
if profile:
return {
"print_format": print_format,
"campaign": profile.get("campaign"),
"utm_source": profile.get("utm_source"),
"utm_campaign": profile.get("utm_campaign"),
"utm_medium": profile.get("utm_medium"),
"allow_print_before_pay": profile.get("allow_print_before_pay"),
}

View File

@@ -12,7 +12,9 @@
"disabled",
"column_break_9",
"warehouse",
"campaign",
"utm_source",
"utm_campaign",
"utm_medium",
"company_address",
"section_break_15",
"applicable_for_users",
@@ -88,12 +90,6 @@
"fieldtype": "Read Only",
"label": "Country"
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"options": "Campaign"
},
{
"fieldname": "company_address",
"fieldtype": "Link",
@@ -375,6 +371,27 @@
"fieldname": "disable_rounded_total",
"fieldtype": "Check",
"label": "Disable Rounded Total"
},
{
"fieldname": "utm_campaign",
"print_hide": 1,
"fieldtype": "Link",
"label": "Campaign",
"options": "UTM Campaign"
},
{
"fieldname": "utm_source",
"print_hide": 1,
"fieldtype": "Link",
"label": "Source",
"options": "UTM Source"
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Campaign"
}
],
"icon": "icon-cog",
@@ -402,7 +419,7 @@
"link_fieldname": "pos_profile"
}
],
"modified": "2024-03-27 13:10:16.476972",
"modified": "2024-06-28 10:51:48.543766",
"modified_by": "Administrator",
"module": "Accounts",
"name": "POS Profile",
@@ -431,4 +448,4 @@
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}
}

View File

@@ -28,7 +28,6 @@ class POSProfile(Document):
applicable_for_users: DF.Table[POSProfileUser]
apply_discount_on: DF.Literal["Grand Total", "Net Total"]
auto_add_item_to_cart: DF.Check
campaign: DF.Link | None
company: DF.Link
company_address: DF.Link | None
cost_center: DF.Link | None
@@ -53,6 +52,9 @@ class POSProfile(Document):
taxes_and_charges: DF.Link | None
tc_name: DF.Link | None
update_stock: DF.Check
utm_campaign: DF.Link | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
validate_stock_on_save: DF.Check
warehouse: DF.Link
write_off_account: DF.Link

View File

@@ -282,7 +282,7 @@
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"options": "Campaign"
"options": "UTM Campaign"
},
{
"depends_on": "eval:doc.applicable_for==\"Supplier\"",
@@ -647,7 +647,7 @@
"icon": "fa fa-gift",
"idx": 1,
"links": [],
"modified": "2024-05-17 13:16:34.496704",
"modified": "2024-06-28 11:03:15.252701",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Pricing Rule",
@@ -709,4 +709,4 @@
"sort_order": "DESC",
"states": [],
"title_field": "title"
}
}

View File

@@ -1377,7 +1377,7 @@ class TestPricingRule(unittest.TestCase):
pi.cancel()
test_dependencies = ["Campaign"]
test_dependencies = ["UTM Campaign"]
def make_pricing_rule(**args):
@@ -1437,9 +1437,9 @@ def make_pricing_rule(**args):
def setup_pricing_rule_data():
if not frappe.db.exists("Campaign", "_Test Campaign"):
if not frappe.db.exists("UTM Campaign", "_Test Campaign"):
frappe.get_doc(
{"doctype": "Campaign", "campaign_name": "_Test Campaign", "name": "_Test Campaign"}
{"doctype": "UTM Campaign", "description": "_Test Campaign", "name": "_Test Campaign"}
).insert()

View File

@@ -838,7 +838,9 @@ frappe.ui.form.on("Sales Invoice", {
"project",
"due_date",
"is_opening",
"source",
"utm_source",
"utm_campaign",
"utm_medium",
"total_advance",
"get_advances",
"advances",

View File

@@ -207,10 +207,13 @@
"more_information",
"status",
"inter_company_invoice_reference",
"campaign",
"represents_company",
"source",
"customer_group",
"column_break_imbx",
"utm_source",
"utm_campaign",
"utm_medium",
"utm_content",
"col_break23",
"is_internal_customer",
"is_discounted",
@@ -1634,17 +1637,6 @@
"options": "Customer Group",
"print_hide": 1
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
"print_hide": 1
},
{
"default": "0",
"fieldname": "is_discounted",
@@ -1676,17 +1668,6 @@
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "source",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
"print_hide": 1
},
{
"collapsible": 1,
"fieldname": "more_info",
@@ -2183,6 +2164,45 @@
"label": "Update Outstanding for Self",
"no_copy": 1,
"print_hide": 1
},
{
"fieldname": "column_break_imbx",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_medium",
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium",
"print_hide": 1
},
{
"fieldname": "utm_content",
"fieldtype": "Data",
"label": "Content",
"print_hide": 1
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign",
"print_hide": 1
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source",
"print_hide": 1
}
],
"icon": "fa fa-file-text",
@@ -2250,4 +2270,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -92,7 +92,6 @@ class SalesInvoice(SellingController):
base_total: DF.Currency
base_total_taxes_and_charges: DF.Currency
base_write_off_amount: DF.Currency
campaign: DF.Link | None
cash_bank_account: DF.Link | None
change_amount: DF.Currency
commission_rate: DF.Float
@@ -154,6 +153,7 @@ class SalesInvoice(SellingController):
party_account_currency: DF.Link | None
payment_schedule: DF.Table[PaymentSchedule]
payment_terms_template: DF.Link | None
payment_url: DF.Data | None
payments: DF.Table[SalesInvoicePayment]
plc_conversion_rate: DF.Float
po_date: DF.Date | None
@@ -181,7 +181,6 @@ class SalesInvoice(SellingController):
shipping_address: DF.TextEditor | None
shipping_address_name: DF.Link | None
shipping_rule: DF.Link | None
source: DF.Link | None
status: DF.Literal[
"",
"Draft",
@@ -223,6 +222,10 @@ class SalesInvoice(SellingController):
update_outstanding_for_self: DF.Check
update_stock: DF.Check
use_company_roundoff_cost_center: DF.Check
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
write_off_account: DF.Link | None
write_off_amount: DF.Currency
write_off_cost_center: DF.Link | None
@@ -681,7 +684,9 @@ class SalesInvoice(SellingController):
"print_format": print_format,
"allow_edit_rate": pos.get("allow_user_to_edit_rate"),
"allow_edit_discount": pos.get("allow_user_to_edit_discount"),
"campaign": pos.get("campaign"),
"utm_source": pos.get("utm_source"),
"utm_campaign": pos.get("utm_campaign"),
"utm_medium": pos.get("utm_medium"),
"allow_print_before_pay": pos.get("allow_print_before_pay"),
}

View File

@@ -8,18 +8,19 @@
"document_type": "Lead",
"dynamic_filters_json": "[[\"Lead\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[]",
"group_by_based_on": "source",
"group_by_based_on": "utm_source",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-22 16:11:14.170636",
"modified": "2020-07-22 16:13:38.696710",
"last_synced_on": "2023-10-09 17:32:34.504416",
"modified": "2024-06-28 12:18:19.477467",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Source",
"number_of_groups": 0,
"owner": "Administrator",
"roles": [],
"timeseries": 0,
"type": "Donut",
"use_report_chart": 0,

View File

@@ -8,18 +8,19 @@
"document_type": "Opportunity",
"dynamic_filters_json": "[[\"Opportunity\",\"company\",\"=\",\"frappe.defaults.get_user_default(\\\"Company\\\")\"]]",
"filters_json": "[]",
"group_by_based_on": "campaign",
"group_by_based_on": "utm_campaign",
"group_by_type": "Count",
"idx": 0,
"is_public": 1,
"is_standard": 1,
"last_synced_on": "2020-07-22 15:45:32.572011",
"modified": "2020-07-22 16:10:02.497726",
"last_synced_on": "2024-06-28 12:17:20.081440",
"modified": "2024-06-28 12:17:53.934536",
"modified_by": "Administrator",
"module": "CRM",
"name": "Opportunities via Campaigns",
"number_of_groups": 0,
"owner": "Administrator",
"roles": [],
"timeseries": 0,
"type": "Pie",
"use_report_chart": 0,

View File

@@ -14,7 +14,7 @@ frappe.ui.form.on("Campaign", {
frm.add_custom_button(
__("View Leads"),
function () {
frappe.route_options = { source: "Campaign", campaign_name: frm.doc.name };
frappe.route_options = { utm_source: "Campaign", utm_campaign: frm.doc.name };
frappe.set_route("List", "Lead");
},
"fa fa-list",

View File

@@ -25,6 +25,26 @@ class Campaign(Document):
naming_series: DF.Literal["SAL-CAM-.YYYY.-"]
# end: auto-generated types
def after_insert(self):
try:
mc = frappe.get_doc("UTM Campaign", self.campaign_name)
except frappe.DoesNotExistError:
mc = frappe.new_doc("UTM Campaign")
mc.name = self.campaign_name
mc.campaign_description = self.description
mc.crm_campaign = self.campaign_name
mc.save(ignore_permissions=True)
def on_change(self):
try:
mc = frappe.get_doc("UTM Campaign", self.campaign_name)
except frappe.DoesNotExistError:
mc = frappe.new_doc("UTM Campaign")
mc.name = self.campaign_name
mc.campaign_description = self.description
mc.crm_campaign = self.campaign_name
mc.save(ignore_permissions=True)
def autoname(self):
if frappe.defaults.get_global_default("campaign_naming_by") != "Naming Series":
self.name = self.campaign_name

View File

@@ -19,7 +19,6 @@
"lead_name",
"job_title",
"gender",
"source",
"col_break123",
"lead_owner",
"status",
@@ -53,13 +52,19 @@
"country",
"column_break2",
"contact_html",
"section_break_analytics",
"utm_source",
"utm_content",
"column_break_gkxo",
"utm_campaign",
"column_break_gqka",
"utm_medium",
"qualification_tab",
"qualification_status",
"column_break_64",
"qualified_by",
"qualified_on",
"other_info_tab",
"campaign_name",
"company",
"column_break_22",
"language",
@@ -160,14 +165,6 @@
"label": "Gender",
"options": "Gender"
},
{
"fieldname": "source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source"
},
{
"depends_on": "eval:doc.source == 'Existing Customer'",
"fieldname": "customer",
@@ -178,14 +175,6 @@
"oldfieldtype": "Link",
"options": "Customer"
},
{
"fieldname": "campaign_name",
"fieldtype": "Link",
"label": "Campaign Name",
"oldfieldname": "campaign_name",
"oldfieldtype": "Link",
"options": "Campaign"
},
{
"fieldname": "image",
"fieldtype": "Attach Image",
@@ -510,13 +499,54 @@
"fieldtype": "Tab Break",
"label": "Connections",
"show_dashboard": 1
},
{
"fieldname": "column_break_gkxo",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_gqka",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_content",
"print_hide": 1,
"fieldtype": "Data",
"label": "Content"
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source"
},
{
"fieldname": "utm_medium",
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign_name",
"oldfieldtype": "Link",
"options": "UTM Campaign"
},
{
"fieldname": "section_break_analytics",
"fieldtype": "Section Break",
"label": "Analytics"
}
],
"icon": "fa fa-user",
"idx": 5,
"image_field": "image",
"links": [],
"modified": "2024-03-27 13:09:59.818450",
"modified": "2024-06-28 10:29:32.676323",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead",
@@ -584,4 +614,4 @@
"states": [],
"subject_field": "title",
"title_field": "title"
}
}

View File

@@ -32,7 +32,6 @@ class Lead(SellingController, CRMNote):
annual_revenue: DF.Currency
blog_subscriber: DF.Check
campaign_name: DF.Link | None
city: DF.Data | None
company: DF.Link | None
company_name: DF.Data | None
@@ -63,7 +62,6 @@ class Lead(SellingController, CRMNote):
qualified_on: DF.Date | None
request_type: DF.Literal["", "Product Enquiry", "Request for Information", "Suggestions", "Other"]
salutation: DF.Link | None
source: DF.Link | None
state: DF.Data | None
status: DF.Literal[
"Lead",
@@ -80,6 +78,10 @@ class Lead(SellingController, CRMNote):
title: DF.Data | None
type: DF.Literal["", "Client", "Channel Partner", "Consultant"]
unsubscribed: DF.Check
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
website: DF.Data | None
whatsapp_no: DF.Data | None
# end: auto-generated types
@@ -101,7 +103,7 @@ class Lead(SellingController, CRMNote):
def before_insert(self):
self.contact_doc = None
if frappe.db.get_single_value("CRM Settings", "auto_creation_of_contact"):
if self.source == "Existing Customer" and self.customer:
if self.utm_source == "Existing Customer" and self.customer:
contact = frappe.db.get_value(
"Dynamic Link",
{"link_doctype": "Customer", "parenttype": "Contact", "link_name": self.customer},
@@ -369,7 +371,6 @@ def make_opportunity(source_name, target_doc=None):
"Lead": {
"doctype": "Opportunity",
"field_map": {
"campaign_name": "campaign",
"doctype": "opportunity_from",
"name": "party_name",
"lead_name": "contact_display",

View File

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

View File

@@ -1,65 +0,0 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:source_name",
"creation": "2016-09-16 01:47:47.382372",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"source_name",
"details"
],
"fields": [
{
"fieldname": "source_name",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Source Name",
"reqd": 1,
"unique": 1
},
{
"fieldname": "details",
"fieldtype": "Text Editor",
"label": "Details"
}
],
"links": [],
"modified": "2024-03-27 13:10:00.097850",
"modified_by": "Administrator",
"module": "CRM",
"name": "Lead Source",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales 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": "creation",
"sort_order": "DESC",
"states": [],
"translated_doctype": 1
}

View File

@@ -1,22 +0,0 @@
# 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 LeadSource(Document):
# begin: auto-generated types
# This code is auto-generated. Do not modify anything in this block.
from typing import TYPE_CHECKING
if TYPE_CHECKING:
from frappe.types import DF
details: DF.TextEditor | None
source_name: DF.Data
# end: auto-generated types
pass

View File

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

View File

@@ -19,7 +19,6 @@
"status",
"column_break0",
"opportunity_type",
"source",
"opportunity_owner",
"column_break_10",
"sales_stage",
@@ -45,9 +44,15 @@
"column_break_17",
"opportunity_amount",
"base_opportunity_amount",
"section_break_analytics",
"utm_source",
"utm_content",
"column_break_emai",
"utm_campaign",
"column_break_whcu",
"utm_medium",
"more_info",
"company",
"campaign",
"transaction_date",
"column_break1",
"language",
@@ -317,24 +322,6 @@
"oldfieldtype": "Section Break",
"options": "fa fa-file-text"
},
{
"fieldname": "source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source"
},
{
"depends_on": "eval: doc.source==\"Campaign\"",
"description": "Enter name of campaign if source of enquiry is campaign",
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign"
},
{
"fieldname": "column_break1",
"fieldtype": "Column Break",
@@ -620,6 +607,50 @@
"fieldtype": "Link",
"label": "Country",
"options": "Country"
},
{
"fieldname": "column_break_emai",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_source",
"print_hide": 1,
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source"
},
{
"fieldname": "utm_campaign",
"print_hide": 1,
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign"
},
{
"fieldname": "section_break_analytics",
"fieldtype": "Section Break",
"label": "Analytics"
},
{
"fieldname": "column_break_whcu",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_content",
"print_hide": 1,
"fieldtype": "Data",
"label": "Content"
}
],
"icon": "fa fa-info-sign",
@@ -668,4 +699,4 @@
"title_field": "title",
"track_seen": 1,
"track_views": 1
}
}

View File

@@ -45,7 +45,6 @@ class Opportunity(TransactionBase, CRMNote):
annual_revenue: DF.Currency
base_opportunity_amount: DF.Currency
base_total: DF.Currency
campaign: DF.Link | None
city: DF.Data | None
company: DF.Link
competitors: DF.TableMultiSelect[CompetitorDetail]
@@ -80,13 +79,16 @@ class Opportunity(TransactionBase, CRMNote):
phone_ext: DF.Data | None
probability: DF.Percent
sales_stage: DF.Link | None
source: DF.Link | None
state: DF.Data | None
status: DF.Literal["Open", "Quotation", "Converted", "Lost", "Replied", "Closed"]
territory: DF.Link | None
title: DF.Data | None
total: DF.Currency
transaction_date: DF.Date
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
website: DF.Data | None
whatsapp: DF.Data | None
# end: auto-generated types

View File

@@ -9,8 +9,8 @@ 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("utm_campaign")
data = get_lead_data(filters or {}, "utm_campaign")
return columns, data

View File

@@ -44,7 +44,7 @@ frappe.query_reports["Opportunity Summary by Sales Stage"] = {
fieldname: "opportunity_source",
label: __("Opportunity Source"),
fieldtype: "Link",
options: "Lead Source",
options: "UTM Source",
},
{
fieldname: "opportunity_type",

View File

@@ -36,9 +36,9 @@ class OpportunitySummaryBySalesStage:
self.columns.append(
{
"label": _("Source"),
"fieldname": "source",
"fieldname": "utm_source",
"fieldtype": "Link",
"options": "Lead Source",
"options": "UTM Source",
"width": 200,
}
)
@@ -69,7 +69,7 @@ class OpportunitySummaryBySalesStage:
based_on = {
"Opportunity Owner": "_assign",
"Source": "source",
"Source": "utm_source",
"Opportunity Type": "opportunity_type",
}[self.filters.get("based_on")]
@@ -128,7 +128,7 @@ class OpportunitySummaryBySalesStage:
for based_on, data in self.formatted_data.items():
row_based_on = {
"Opportunity Owner": "opportunity_owner",
"Source": "source",
"Source": "utm_source",
"Opportunity Type": "opportunity_type",
}[self.filters.get("based_on")]
@@ -148,7 +148,7 @@ class OpportunitySummaryBySalesStage:
based_on = {
"Opportunity Owner": "_assign",
"Source": "source",
"Source": "utm_source",
"Opportunity Type": "opportunity_type",
}[self.filters.get("based_on")]
@@ -188,7 +188,7 @@ class OpportunitySummaryBySalesStage:
filters.append({"opportunity_type": self.filters.get("opportunity_type")})
if self.filters.get("opportunity_source"):
filters.append({"source": self.filters.get("opportunity_source")})
filters.append({"utm_source": self.filters.get("opportunity_source")})
if self.filters.get("status"):
filters.append({"status": ("in", self.filters.get("status"))})

View File

@@ -40,7 +40,7 @@ class TestOpportunitySummaryBySalesStage(unittest.TestCase):
report = execute(filters)
expected_data = [{"source": "Cold Calling", "Prospecting": 1}]
expected_data = [{"utm_source": "Cold Calling", "Prospecting": 1}]
self.assertEqual(expected_data, report[1])

View File

@@ -57,7 +57,7 @@ frappe.query_reports["Sales Pipeline Analytics"] = {
fieldname: "opportunity_source",
label: __("Opportunity Source"),
fieldtype: "Link",
options: "Lead Source",
options: "UTM Source",
},
{
fieldname: "opportunity_type",

View File

@@ -142,7 +142,7 @@ class SalesPipelineAnalytics:
conditions = []
if self.filters.get("opportunity_source"):
conditions.append({"source": self.filters.get("opportunity_source")})
conditions.append({"utm_source": self.filters.get("opportunity_source")})
if self.filters.get("opportunity_type"):
conditions.append({"opportunity_type": self.filters.get("opportunity_type")})

View File

@@ -207,7 +207,7 @@ def create_opportunity():
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.utm_source = "Cold Calling"
doc.currency = "INR"
doc.expected_closing = "2021-08-31"
doc.company = "Best Test"

View File

@@ -163,84 +163,6 @@
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Masters",
"link_count": 7,
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Territory",
"link_count": 0,
"link_to": "Territory",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Customer Group",
"link_count": 0,
"link_to": "Customer Group",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Contact",
"link_count": 0,
"link_to": "Contact",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Prospect",
"link_count": 0,
"link_to": "Prospect",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Person",
"link_count": 0,
"link_to": "Sales Person",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Stage",
"link_count": 0,
"link_to": "Sales Stage",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Lead Source",
"link_count": 0,
"link_to": "Lead Source",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
@@ -417,9 +339,88 @@
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Masters",
"link_count": 7,
"link_type": "DocType",
"onboard": 0,
"type": "Card Break"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Territory",
"link_count": 0,
"link_to": "Territory",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Customer Group",
"link_count": 0,
"link_to": "Customer Group",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Contact",
"link_count": 0,
"link_to": "Contact",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Prospect",
"link_count": 0,
"link_to": "Prospect",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Person",
"link_count": 0,
"link_to": "Sales Person",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Sales Stage",
"link_count": 0,
"link_to": "Sales Stage",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
},
{
"hidden": 0,
"is_query_report": 0,
"label": "Lead Source",
"link_count": 0,
"link_to": "UTM Source",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
}
],
"modified": "2023-09-14 12:11:03.968048",
"modified": "2024-09-12 04:43:41.406488",
"modified_by": "Administrator",
"module": "CRM",
"name": "CRM",

View File

@@ -382,3 +382,4 @@ erpnext.patches.v15_0.add_disassembly_order_stock_entry_type #1
erpnext.patches.v15_0.set_standard_stock_entry_type
erpnext.patches.v15_0.set_difference_amount_in_asset_value_adjustment
erpnext.patches.v15_0.link_purchase_item_to_asset_doc
erpnext.patches.v15_0.migrate_to_utm_analytics

View File

@@ -0,0 +1,64 @@
import click
import frappe
from frappe.query_builder.functions import Coalesce
from erpnext.setup.install import create_marketgin_campagin_custom_fields
def execute():
"""
Remove Lead Source doctype and use UTM Source Instead
Ensure that for each Campaign, a UTM Campaign is also set
"""
ls = frappe.qb.DocType("Lead Source")
ms = frappe.qb.DocType("UTM Source")
# Fetch all Lead Sources
if lead_sources := frappe.qb.from_(ls).select(ls.source_name, ls.details).run(as_dict=True):
# Prepare the insert query with IGNORE
insert_query = frappe.qb.into(ms).ignore().columns(ms.name, ms.description)
# Add values for each Lead Source
for source in lead_sources:
insert_query = insert_query.insert(source.source_name, Coalesce(source.details, ""))
# Execute the insert query
insert_query.run()
frappe.delete_doc("DocType", "Lead Source", ignore_missing=True)
campaign = frappe.qb.DocType("Campaign")
create_marketgin_campagin_custom_fields()
marketing_campaign = frappe.qb.DocType("UTM Campaign")
# Fetch all Campaigns
if campaigns := (
frappe.qb.from_(campaign).select(campaign.campaign_name, campaign.description).run(as_dict=True)
):
# Prepare the insert query with IGNORE
insert_query = (
frappe.qb.into(marketing_campaign)
.ignore()
.columns(
marketing_campaign.name,
marketing_campaign.campaign_description,
marketing_campaign.crm_campaign,
)
)
# Add values for each Campaign
for camp in campaigns:
insert_query = insert_query.insert(
camp.campaign_name, Coalesce(camp.description, ""), camp.campaign_name
)
# Execute the insert query
insert_query.run()
click.secho(
f"Inserted {len(lead_sources)} Lead Sources into UTM Sources and deleted Lead Source.\n"
f"Inserted {len(campaigns)} Campaigns into UTM Campaigns.\n"
"You can also make use of the new UTM Medium for analytics, now.",
fg="green",
)

View File

@@ -124,8 +124,10 @@
"customer_group",
"territory",
"column_break_108",
"campaign",
"source",
"utm_source",
"utm_campaign",
"utm_medium",
"utm_content",
"column_break4",
"opportunity",
"supplier_quotation",
@@ -853,24 +855,6 @@
"fieldtype": "Button",
"label": "Update Auto Repeat Reference"
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
"print_hide": 1
},
{
"fieldname": "source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
"print_hide": 1
},
{
"allow_on_submit": 1,
"depends_on": "eval:doc.status=='Lost'",
@@ -1068,13 +1052,44 @@
"fieldname": "named_place",
"fieldtype": "Data",
"label": "Named Place"
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign",
"print_hide": 1
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source",
"print_hide": 1
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_content",
"print_hide": 1,
"fieldtype": "Data",
"label": "Content"
}
],
"icon": "fa fa-shopping-cart",
"idx": 82,
"is_submittable": 1,
"links": [],
"modified": "2024-04-20 01:15:19.171383",
"modified": "2024-06-28 10:32:47.638342",
"modified_by": "Administrator",
"module": "Selling",
"name": "Quotation",
@@ -1172,4 +1187,4 @@
"states": [],
"timeline_field": "party_name",
"title_field": "title"
}
}

View File

@@ -46,7 +46,6 @@ class Quotation(SellingController):
base_rounding_adjustment: DF.Currency
base_total: DF.Currency
base_total_taxes_and_charges: DF.Currency
campaign: DF.Link | None
company: DF.Link
company_address: DF.Link | None
company_address_display: DF.TextEditor | None
@@ -96,7 +95,6 @@ class Quotation(SellingController):
shipping_address: DF.TextEditor | None
shipping_address_name: DF.Link | None
shipping_rule: DF.Link | None
source: DF.Link | None
status: DF.Literal[
"Draft", "Open", "Replied", "Partially Ordered", "Ordered", "Lost", "Cancelled", "Expired"
]
@@ -113,6 +111,10 @@ class Quotation(SellingController):
total_qty: DF.Float
total_taxes_and_charges: DF.Currency
transaction_date: DF.Date
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
valid_till: DF.Date | None
# end: auto-generated types

View File

@@ -159,10 +159,13 @@
"additional_info_section",
"is_internal_customer",
"represents_company",
"column_break_yvzv",
"utm_source",
"utm_campaign",
"utm_medium",
"utm_content",
"column_break_152",
"source",
"inter_company_order_reference",
"campaign",
"party_account_currency",
"connections_tab"
],
@@ -1165,28 +1168,6 @@
"print_hide": 1,
"read_only": 1
},
{
"fieldname": "source",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
"print_hide": 1
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
"print_hide": 1
},
{
"collapsible": 1,
"fieldname": "printing_details",
@@ -1656,13 +1637,52 @@
"no_copy": 1,
"options": "Not Requested\nRequested\nPartially Paid\nFully Paid",
"print_hide": 1
},
{
"fieldname": "column_break_yvzv",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_content",
"print_hide": 1,
"fieldtype": "Data",
"label": "Content"
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source",
"print_hide": 1
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"hide_days": 1,
"hide_seconds": 1,
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign",
"print_hide": 1
}
],
"icon": "fa fa-file-text",
"idx": 105,
"is_submittable": 1,
"links": [],
"modified": "2024-05-27 18:51:54.905804",
"modified": "2024-06-28 10:36:23.824623",
"modified_by": "Administrator",
"module": "Selling",
"name": "Sales Order",
@@ -1740,4 +1760,4 @@
"title_field": "customer_name",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -80,7 +80,6 @@ class SalesOrder(SellingController):
base_total: DF.Currency
base_total_taxes_and_charges: DF.Currency
billing_status: DF.Literal["Not Billed", "Fully Billed", "Partly Billed", "Closed"]
campaign: DF.Link | None
commission_rate: DF.Float
company: DF.Link
company_address: DF.Link | None
@@ -151,7 +150,6 @@ class SalesOrder(SellingController):
shipping_address_name: DF.Link | None
shipping_rule: DF.Link | None
skip_delivery_note: DF.Check
source: DF.Link | None
status: DF.Literal[
"",
"Draft",
@@ -179,6 +177,10 @@ class SalesOrder(SellingController):
total_qty: DF.Float
total_taxes_and_charges: DF.Currency
transaction_date: DF.Date
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
# end: auto-generated types
def __init__(self, *args, **kwargs):

View File

@@ -45,7 +45,9 @@ erpnext.SalesFunnel = class SalesFunnel {
chart: wrapper.page.add_select(__("Chart"), [
{ value: "sales_funnel", label: __("Sales Funnel") },
{ value: "sales_pipeline", label: __("Sales Pipeline") },
{ value: "opp_by_lead_source", label: __("Opportunities by lead source") },
{ value: "opp_by_utm_source", label: __("Opportunities by Source") },
{ value: "opp_by_utm_campaign", label: __("Opportunities by Campaign") },
{ value: "opp_by_utm_medium", label: __("Opportunities by Medium") },
]),
refresh_btn: wrapper.page.set_primary_action(
__("Refresh"),
@@ -111,7 +113,9 @@ erpnext.SalesFunnel = class SalesFunnel {
const method_map = {
sales_funnel: "erpnext.selling.page.sales_funnel.sales_funnel.get_funnel_data",
opp_by_lead_source: "erpnext.selling.page.sales_funnel.sales_funnel.get_opp_by_lead_source",
opp_by_utm_source: "erpnext.selling.page.sales_funnel.sales_funnel.get_opp_by_utm_source",
opp_by_utm_campaign: "erpnext.selling.page.sales_funnel.sales_funnel.get_opp_by_utm_campaign",
opp_by_utm_medium: "erpnext.selling.page.sales_funnel.sales_funnel.get_opp_by_utm_medium",
sales_pipeline: "erpnext.selling.page.sales_funnel.sales_funnel.get_pipeline_data",
};
frappe.call({
@@ -140,8 +144,12 @@ erpnext.SalesFunnel = class SalesFunnel {
let me = this;
if (me.options.chart == "sales_funnel") {
me.render_funnel();
} else if (me.options.chart == "opp_by_lead_source") {
} else if (me.options.chart == "opp_by_utm_source") {
me.render_chart(__("Sales Opportunities by Source"));
} else if (me.options.chart == "opp_by_utm_campaign") {
me.render_chart(__("Sales Opportunities by Campaign"));
} else if (me.options.chart == "opp_by_utm_medium") {
me.render_chart(__("Sales Opportunities by Medium"));
} else if (me.options.chart == "sales_pipeline") {
me.render_chart(__("Sales Pipeline by Stage"));
}

View File

@@ -60,7 +60,21 @@ def get_funnel_data(from_date, to_date, company):
@frappe.whitelist()
def get_opp_by_lead_source(from_date, to_date, company):
def get_opp_by_utm_source(from_date, to_date, company):
return get_opp_by("utm_source", from_date, to_date, company)
@frappe.whitelist()
def get_opp_by_utm_campaign(from_date, to_date, company):
return get_opp_by("utm_campaign", from_date, to_date, company)
@frappe.whitelist()
def get_opp_by_utm_medium(from_date, to_date, company):
return get_opp_by("utm_medium", from_date, to_date, company)
def get_opp_by(by_field, from_date, to_date, company):
validate_filters(from_date, to_date, company)
opportunities = frappe.get_all(
@@ -70,7 +84,7 @@ def get_opp_by_lead_source(from_date, to_date, company):
["company", "=", company],
["transaction_date", "Between", [from_date, to_date]],
],
fields=["currency", "sales_stage", "opportunity_amount", "probability", "source"],
fields=["currency", "sales_stage", "opportunity_amount", "probability", by_field],
)
if opportunities:
@@ -92,9 +106,11 @@ def get_opp_by_lead_source(from_date, to_date, company):
summary = {}
sales_stages = set()
group_key = lambda o: (o["source"], o["sales_stage"]) # noqa
for (source, sales_stage), rows in groupby(sorted(cp_opportunities, key=group_key), group_key):
summary.setdefault(source, {})[sales_stage] = sum(r["compound_amount"] for r in rows)
group_key = lambda o: (o[by_field], o["sales_stage"]) # noqa
for (by_field_group, sales_stage), rows in groupby(
sorted(cp_opportunities, key=group_key), group_key
):
summary.setdefault(by_field_group, {})[sales_stage] = sum(r["compound_amount"] for r in rows)
sales_stages.add(sales_stage)
pivot_table = []

View File

@@ -5,7 +5,7 @@
"label": "Sales Order Trends"
}
],
"content": "[{\"id\":\"ow595dYDrI\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Selling\",\"col\":12}},{\"id\":\"vBSf8Vi9U8\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Sales Order Trends\",\"col\":12}},{\"id\":\"aW2i5R5GRP\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"1it3dCOnm6\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Quick Access</b></span>\",\"col\":12}},{\"id\":\"x7pLl-spS4\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":3}},{\"id\":\"SSGrXWmY-H\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order\",\"col\":3}},{\"id\":\"-5J_yLxDaS\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"id\":\"6YEYpnIBKV\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Point of Sale\",\"col\":3}},{\"id\":\"c_GjZuZ2oN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"mX-9DJSyT2\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Sales Management\",\"col\":3}},{\"id\":\"oNjjNbnUHp\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"0BcePLg0g1\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"uze5dJ1ipL\",\"type\":\"card\",\"data\":{\"card_name\":\"Selling\",\"col\":4}},{\"id\":\"3j2fYwMAkq\",\"type\":\"card\",\"data\":{\"card_name\":\"Point of Sale\",\"col\":4}},{\"id\":\"xImm8NepFt\",\"type\":\"card\",\"data\":{\"card_name\":\"Items and Pricing\",\"col\":4}},{\"id\":\"6MjIe7KCQo\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"id\":\"lBu2EKgmJF\",\"type\":\"card\",\"data\":{\"card_name\":\"Key Reports\",\"col\":4}},{\"id\":\"1ARHrjg4kI\",\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"content": "[{\"id\":\"vBSf8Vi9U8\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Sales Order Trends\",\"col\":12}},{\"id\":\"aW2i5R5GRP\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"1it3dCOnm6\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Quick Access</b></span>\",\"col\":12}},{\"id\":\"x7pLl-spS4\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Item\",\"col\":3}},{\"id\":\"SSGrXWmY-H\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Order\",\"col\":3}},{\"id\":\"-5J_yLxDaS\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Analytics\",\"col\":3}},{\"id\":\"6YEYpnIBKV\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Point of Sale\",\"col\":3}},{\"id\":\"c_GjZuZ2oN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"mX-9DJSyT2\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Sales Management\",\"col\":3}},{\"id\":\"oNjjNbnUHp\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"0BcePLg0g1\",\"type\":\"header\",\"data\":{\"text\":\"<span class=\\\"h4\\\"><b>Reports &amp; Masters</b></span>\",\"col\":12}},{\"id\":\"uze5dJ1ipL\",\"type\":\"card\",\"data\":{\"card_name\":\"Selling\",\"col\":4}},{\"id\":\"3j2fYwMAkq\",\"type\":\"card\",\"data\":{\"card_name\":\"Point of Sale\",\"col\":4}},{\"id\":\"xImm8NepFt\",\"type\":\"card\",\"data\":{\"card_name\":\"Items and Pricing\",\"col\":4}},{\"id\":\"6MjIe7KCQo\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}},{\"id\":\"lBu2EKgmJF\",\"type\":\"card\",\"data\":{\"card_name\":\"Key Reports\",\"col\":4}},{\"id\":\"1ARHrjg4kI\",\"type\":\"card\",\"data\":{\"card_name\":\"Other Reports\",\"col\":4}}]",
"creation": "2020-01-28 11:49:12.092882",
"custom_blocks": [],
"docstatus": 0,
@@ -254,9 +254,9 @@
"dependencies": "",
"hidden": 0,
"is_query_report": 0,
"label": "Lead Source",
"label": "UTM Source",
"link_count": 0,
"link_to": "Lead Source",
"link_to": "UTM Source",
"link_type": "DocType",
"onboard": 0,
"type": "Link"
@@ -621,7 +621,7 @@
"type": "Link"
}
],
"modified": "2023-07-04 14:35:58.204465",
"modified": "2024-07-18 04:16:18.176054",
"modified_by": "Administrator",
"module": "Selling",
"name": "Selling",
@@ -677,4 +677,4 @@
}
],
"title": "Selling"
}
}

View File

@@ -23,6 +23,7 @@ def after_install():
set_single_defaults()
create_print_setting_custom_fields()
create_marketgin_campagin_custom_fields()
add_all_roles_to("Administrator")
create_default_success_action()
create_default_energy_point_rules()
@@ -123,6 +124,22 @@ def create_print_setting_custom_fields():
)
def create_marketgin_campagin_custom_fields():
create_custom_fields(
{
"UTM Campaign": [
{
"label": _("Messaging CRM Campagin"),
"fieldname": "crm_campaign",
"fieldtype": "Link",
"options": "Campaign",
"insert_after": "campaign_decription",
},
]
}
)
def create_default_success_action():
for success_action in get_default_success_action():
if not frappe.db.exists("Success Action", success_action.get("ref_doctype")):

View File

@@ -302,7 +302,7 @@ def install(country=None):
("Designation", "designation_name", "designation.txt"),
("Sales Stage", "stage_name", "sales_stage.txt"),
("Industry Type", "industry", "industry_type.txt"),
("Lead Source", "source_name", "lead_source.txt"),
("UTM Source", "name", "marketing_source.txt"),
("Sales Partner Type", "sales_partner_type", "sales_partner_type.txt"),
):
records += [{"doctype": doctype, title_field: title} for title in read_lines(filename)]

View File

@@ -159,8 +159,11 @@
"inter_company_reference",
"customer_group",
"territory",
"source",
"campaign",
"column_break_pxls",
"utm_source",
"utm_campaign",
"utm_medium",
"utm_content",
"column_break5",
"excise_page",
"instructions",
@@ -969,24 +972,6 @@
"oldfieldtype": "Link",
"options": "Project"
},
{
"fieldname": "campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "Campaign",
"print_hide": 1
},
{
"fieldname": "source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "Lead Source",
"print_hide": 1
},
{
"fieldname": "column_break5",
"fieldtype": "Column Break",
@@ -1402,6 +1387,41 @@
"label": "Delivery Trip",
"options": "Delivery Trip",
"print_hide": 1
},
{
"fieldname": "column_break_pxls",
"fieldtype": "Column Break"
},
{
"fieldname": "utm_medium",
"print_hide": 1,
"fieldtype": "Link",
"label": "Medium",
"options": "UTM Medium"
},
{
"fieldname": "utm_content",
"print_hide": 1,
"fieldtype": "Data",
"label": "Content"
},
{
"fieldname": "utm_source",
"fieldtype": "Link",
"label": "Source",
"oldfieldname": "source",
"oldfieldtype": "Select",
"options": "UTM Source",
"print_hide": 1
},
{
"fieldname": "utm_campaign",
"fieldtype": "Link",
"label": "Campaign",
"oldfieldname": "campaign",
"oldfieldtype": "Link",
"options": "UTM Campaign",
"print_hide": 1
}
],
"icon": "fa fa-truck",
@@ -1508,4 +1528,4 @@
"title_field": "title",
"track_changes": 1,
"track_seen": 1
}
}

View File

@@ -48,14 +48,13 @@ class DeliveryNote(SellingController):
base_rounding_adjustment: DF.Currency
base_total: DF.Currency
base_total_taxes_and_charges: DF.Currency
campaign: DF.Link | None
commission_rate: DF.Float
company: DF.Link
company_address: DF.Link | None
company_address_display: DF.TextEditor | None
contact_display: DF.SmallText | None
contact_email: DF.Data | None
contact_mobile: DF.SmallText | None
contact_mobile: DF.Data | None
contact_person: DF.Link | None
conversion_rate: DF.Float
cost_center: DF.Link | None
@@ -121,7 +120,6 @@ class DeliveryNote(SellingController):
shipping_address: DF.TextEditor | None
shipping_address_name: DF.Link | None
shipping_rule: DF.Link | None
source: DF.Link | None
status: DF.Literal["", "Draft", "To Bill", "Completed", "Return Issued", "Cancelled", "Closed"]
tax_category: DF.Link | None
tax_id: DF.Data | None
@@ -138,6 +136,10 @@ class DeliveryNote(SellingController):
total_taxes_and_charges: DF.Currency
transporter: DF.Link | None
transporter_name: DF.Data | None
utm_campaign: DF.Link | None
utm_content: DF.Data | None
utm_medium: DF.Link | None
utm_source: DF.Link | None
vehicle_no: DF.Data | None
# end: auto-generated types

View File

@@ -333,7 +333,7 @@ class TestServiceLevelAgreement(unittest.TestCase):
holiday_list="__Test Holiday List",
entity_type=None,
entity=None,
condition='doc.source == "Test Source"',
condition='doc.utm_source == "Test Source"',
response_time=14400,
sla_fulfilled_on=[{"status": "Replied"}],
apply_sla_for_resolution=0,
@@ -343,16 +343,18 @@ class TestServiceLevelAgreement(unittest.TestCase):
applied_sla = frappe.db.get_value("Lead", lead.name, "service_level_agreement")
self.assertFalse(applied_sla)
source = frappe.get_doc(doctype="Lead Source", source_name="Test Source")
source = frappe.new_doc(doctype="UTM Source")
source.name = "Test Source"
source.flags.name_set = True
source.insert(ignore_if_duplicate=True)
lead.source = "Test Source"
lead.utm_source = "Test Source"
lead.save()
applied_sla = frappe.db.get_value("Lead", lead.name, "service_level_agreement")
self.assertEqual(applied_sla, lead_sla.name)
# check if SLA is removed if condition fails
lead.reload()
lead.source = None
lead.utm_source = None
lead.save()
applied_sla = frappe.db.get_value("Lead", lead.name, "service_level_agreement")
self.assertFalse(applied_sla)