From 96a667351055ebf27e68913981798ff42e2ea491 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 29 Jun 2024 00:45:39 +0200 Subject: [PATCH] feat(analytics): comply erpnext with utm methodology --- .../doctype/campaign_item/campaign_item.json | 6 +- .../doctype/pos_invoice/pos_invoice.json | 57 ++++--- .../doctype/pos_invoice/pos_invoice.py | 9 +- .../doctype/pos_profile/pos_profile.json | 35 +++- .../doctype/pos_profile/pos_profile.py | 4 +- .../doctype/pricing_rule/pricing_rule.json | 6 +- .../doctype/pricing_rule/test_pricing_rule.py | 6 +- .../doctype/sales_invoice/sales_invoice.js | 4 +- .../doctype/sales_invoice/sales_invoice.json | 70 +++++--- .../doctype/sales_invoice/sales_invoice.py | 11 +- .../lead_source/lead_source.json | 7 +- .../opportunities_via_campaigns.json | 7 +- erpnext/crm/doctype/campaign/campaign.js | 2 +- erpnext/crm/doctype/campaign/campaign.py | 20 +++ erpnext/crm/doctype/lead/lead.json | 70 +++++--- erpnext/crm/doctype/lead/lead.py | 9 +- erpnext/crm/doctype/lead_source/__init__.py | 0 .../crm/doctype/lead_source/lead_source.js | 7 - .../crm/doctype/lead_source/lead_source.json | 65 ------- .../crm/doctype/lead_source/lead_source.py | 22 --- .../doctype/lead_source/test_lead_source.py | 9 - .../crm/doctype/opportunity/opportunity.json | 73 +++++--- .../crm/doctype/opportunity/opportunity.py | 6 +- .../campaign_efficiency.py | 4 +- .../opportunity_summary_by_sales_stage.js | 2 +- .../opportunity_summary_by_sales_stage.py | 12 +- ...test_opportunity_summary_by_sales_stage.py | 2 +- .../sales_pipeline_analytics.js | 2 +- .../sales_pipeline_analytics.py | 2 +- .../test_sales_pipeline_analytics.py | 2 +- erpnext/crm/workspace/crm/crm.json | 159 +++++++++--------- erpnext/patches.txt | 1 + .../patches/v15_0/migrate_to_utm_analytics.py | 64 +++++++ .../selling/doctype/quotation/quotation.json | 59 ++++--- .../selling/doctype/quotation/quotation.py | 6 +- .../doctype/sales_order/sales_order.json | 72 +++++--- .../doctype/sales_order/sales_order.py | 6 +- .../selling/page/sales_funnel/sales_funnel.js | 14 +- .../selling/page/sales_funnel/sales_funnel.py | 26 ++- .../selling/workspace/selling/selling.json | 10 +- erpnext/setup/install.py | 17 ++ .../{lead_source.txt => marketing_source.txt} | 0 .../operations/install_fixtures.py | 2 +- .../doctype/delivery_note/delivery_note.json | 62 ++++--- .../doctype/delivery_note/delivery_note.py | 8 +- .../test_service_level_agreement.py | 10 +- 46 files changed, 631 insertions(+), 416 deletions(-) delete mode 100644 erpnext/crm/doctype/lead_source/__init__.py delete mode 100644 erpnext/crm/doctype/lead_source/lead_source.js delete mode 100644 erpnext/crm/doctype/lead_source/lead_source.json delete mode 100644 erpnext/crm/doctype/lead_source/lead_source.py delete mode 100644 erpnext/crm/doctype/lead_source/test_lead_source.py create mode 100644 erpnext/patches/v15_0/migrate_to_utm_analytics.py rename erpnext/setup/setup_wizard/data/{lead_source.txt => marketing_source.txt} (100%) diff --git a/erpnext/accounts/doctype/campaign_item/campaign_item.json b/erpnext/accounts/doctype/campaign_item/campaign_item.json index b592088079a..9b6ca4172de 100644 --- a/erpnext/accounts/doctype/campaign_item/campaign_item.json +++ b/erpnext/accounts/doctype/campaign_item/campaign_item.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json index c0934b0a052..c52bb917be3 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.json +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py index 40c99bd07a6..3d683cd1050 100644 --- a/erpnext/accounts/doctype/pos_invoice/pos_invoice.py +++ b/erpnext/accounts/doctype/pos_invoice/pos_invoice.py @@ -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"), } diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.json b/erpnext/accounts/doctype/pos_profile/pos_profile.json index 5a0f82500a7..b8a0460ee81 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.json +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.json @@ -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": [] -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/pos_profile/pos_profile.py b/erpnext/accounts/doctype/pos_profile/pos_profile.py index 29403ab493f..ad06cdbb8bc 100644 --- a/erpnext/accounts/doctype/pos_profile/pos_profile.py +++ b/erpnext/accounts/doctype/pos_profile/pos_profile.py @@ -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 diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index d138ff85897..47ddcd7e444 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -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" -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 235fddf3ab3..3299f02e2eb 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -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() diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index df6f3b563c6..32b184f3d1a 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -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", diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json index 405ec6d57b6..7bfefad54f5 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.json +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index ad149f91882..6d2e3b57365 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -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"), } diff --git a/erpnext/crm/dashboard_chart/lead_source/lead_source.json b/erpnext/crm/dashboard_chart/lead_source/lead_source.json index f25fea5751e..9c90be821ea 100644 --- a/erpnext/crm/dashboard_chart/lead_source/lead_source.json +++ b/erpnext/crm/dashboard_chart/lead_source/lead_source.json @@ -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, diff --git a/erpnext/crm/dashboard_chart/opportunities_via_campaigns/opportunities_via_campaigns.json b/erpnext/crm/dashboard_chart/opportunities_via_campaigns/opportunities_via_campaigns.json index 4adda9a1c5c..0f0c3acbc4b 100644 --- a/erpnext/crm/dashboard_chart/opportunities_via_campaigns/opportunities_via_campaigns.json +++ b/erpnext/crm/dashboard_chart/opportunities_via_campaigns/opportunities_via_campaigns.json @@ -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, diff --git a/erpnext/crm/doctype/campaign/campaign.js b/erpnext/crm/doctype/campaign/campaign.js index 219e8cf3e4f..933bd2dfd70 100644 --- a/erpnext/crm/doctype/campaign/campaign.js +++ b/erpnext/crm/doctype/campaign/campaign.js @@ -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", diff --git a/erpnext/crm/doctype/campaign/campaign.py b/erpnext/crm/doctype/campaign/campaign.py index 5e14b0e758b..f9834d2ccef 100644 --- a/erpnext/crm/doctype/campaign/campaign.py +++ b/erpnext/crm/doctype/campaign/campaign.py @@ -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 diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index 84f6903bd93..2b3367a73bd 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -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" -} \ No newline at end of file +} diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index c65fbf9f8b7..1e9a224d044 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -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", diff --git a/erpnext/crm/doctype/lead_source/__init__.py b/erpnext/crm/doctype/lead_source/__init__.py deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/erpnext/crm/doctype/lead_source/lead_source.js b/erpnext/crm/doctype/lead_source/lead_source.js deleted file mode 100644 index 5efc750601a..00000000000 --- a/erpnext/crm/doctype/lead_source/lead_source.js +++ /dev/null @@ -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) { - // } -}); diff --git a/erpnext/crm/doctype/lead_source/lead_source.json b/erpnext/crm/doctype/lead_source/lead_source.json deleted file mode 100644 index 94ec3b74c54..00000000000 --- a/erpnext/crm/doctype/lead_source/lead_source.json +++ /dev/null @@ -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 -} \ No newline at end of file diff --git a/erpnext/crm/doctype/lead_source/lead_source.py b/erpnext/crm/doctype/lead_source/lead_source.py deleted file mode 100644 index b426a329fa7..00000000000 --- a/erpnext/crm/doctype/lead_source/lead_source.py +++ /dev/null @@ -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 diff --git a/erpnext/crm/doctype/lead_source/test_lead_source.py b/erpnext/crm/doctype/lead_source/test_lead_source.py deleted file mode 100644 index 1363d1f4649..00000000000 --- a/erpnext/crm/doctype/lead_source/test_lead_source.py +++ /dev/null @@ -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 diff --git a/erpnext/crm/doctype/opportunity/opportunity.json b/erpnext/crm/doctype/opportunity/opportunity.json index 497aeb3648e..e75dd9eff4b 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.json +++ b/erpnext/crm/doctype/opportunity/opportunity.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/crm/doctype/opportunity/opportunity.py b/erpnext/crm/doctype/opportunity/opportunity.py index 4a68c73c7ed..538adf3251c 100644 --- a/erpnext/crm/doctype/opportunity/opportunity.py +++ b/erpnext/crm/doctype/opportunity/opportunity.py @@ -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 diff --git a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py index 6d01bd289d3..bf17b2b9ca7 100644 --- a/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py +++ b/erpnext/crm/report/campaign_efficiency/campaign_efficiency.py @@ -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 diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js index 36361e531df..2c4d1ee5ec2 100644 --- a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.js @@ -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", diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py index 2e8ae7e340e..d8562565989 100644 --- a/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/opportunity_summary_by_sales_stage.py @@ -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"))}) diff --git a/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py b/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py index ffc612df64b..d15a80d4aee 100644 --- a/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py +++ b/erpnext/crm/report/opportunity_summary_by_sales_stage/test_opportunity_summary_by_sales_stage.py @@ -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]) diff --git a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js index df035c1a201..bdad6070acd 100644 --- a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js +++ b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.js @@ -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", diff --git a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py index 9c19e9f0148..217d9ca31be 100644 --- a/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py +++ b/erpnext/crm/report/sales_pipeline_analytics/sales_pipeline_analytics.py @@ -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")}) diff --git a/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py b/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py index bf3f946d6ab..39d16a09cab 100644 --- a/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py +++ b/erpnext/crm/report/sales_pipeline_analytics/test_sales_pipeline_analytics.py @@ -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" diff --git a/erpnext/crm/workspace/crm/crm.json b/erpnext/crm/workspace/crm/crm.json index 4b5b9af714b..15db21446b2 100644 --- a/erpnext/crm/workspace/crm/crm.json +++ b/erpnext/crm/workspace/crm/crm.json @@ -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", diff --git a/erpnext/patches.txt b/erpnext/patches.txt index a1a33197abd..3cd33380430 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -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 diff --git a/erpnext/patches/v15_0/migrate_to_utm_analytics.py b/erpnext/patches/v15_0/migrate_to_utm_analytics.py new file mode 100644 index 00000000000..c8a1d6fc5b4 --- /dev/null +++ b/erpnext/patches/v15_0/migrate_to_utm_analytics.py @@ -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", + ) diff --git a/erpnext/selling/doctype/quotation/quotation.json b/erpnext/selling/doctype/quotation/quotation.json index 548e645acdf..885675a3257 100644 --- a/erpnext/selling/doctype/quotation/quotation.json +++ b/erpnext/selling/doctype/quotation/quotation.json @@ -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" -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/quotation/quotation.py b/erpnext/selling/doctype/quotation/quotation.py index 2e861bcbec4..c7b3247b8bc 100644 --- a/erpnext/selling/doctype/quotation/quotation.py +++ b/erpnext/selling/doctype/quotation/quotation.py @@ -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 diff --git a/erpnext/selling/doctype/sales_order/sales_order.json b/erpnext/selling/doctype/sales_order/sales_order.json index 7bf0858001e..4ff503111e4 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.json +++ b/erpnext/selling/doctype/sales_order/sales_order.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 8bfada101ee..c9a3aa2f83c 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -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): diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.js b/erpnext/selling/page/sales_funnel/sales_funnel.js index 6b59301c400..75bbdf862c0 100644 --- a/erpnext/selling/page/sales_funnel/sales_funnel.js +++ b/erpnext/selling/page/sales_funnel/sales_funnel.js @@ -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")); } diff --git a/erpnext/selling/page/sales_funnel/sales_funnel.py b/erpnext/selling/page/sales_funnel/sales_funnel.py index 73deb8fe66b..3c979a60367 100644 --- a/erpnext/selling/page/sales_funnel/sales_funnel.py +++ b/erpnext/selling/page/sales_funnel/sales_funnel.py @@ -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 = [] diff --git a/erpnext/selling/workspace/selling/selling.json b/erpnext/selling/workspace/selling/selling.json index e13bdec11fb..b10a99544af 100644 --- a/erpnext/selling/workspace/selling/selling.json +++ b/erpnext/selling/workspace/selling/selling.json @@ -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\":\"Quick Access\",\"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\":\"Reports & Masters\",\"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\":\"Quick Access\",\"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\":\"Reports & Masters\",\"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" -} \ No newline at end of file +} diff --git a/erpnext/setup/install.py b/erpnext/setup/install.py index 88adbfb8c2e..4acd13e7300 100644 --- a/erpnext/setup/install.py +++ b/erpnext/setup/install.py @@ -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")): diff --git a/erpnext/setup/setup_wizard/data/lead_source.txt b/erpnext/setup/setup_wizard/data/marketing_source.txt similarity index 100% rename from erpnext/setup/setup_wizard/data/lead_source.txt rename to erpnext/setup/setup_wizard/data/marketing_source.txt diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index ef484551271..84cf05f128e 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -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)] diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.json b/erpnext/stock/doctype/delivery_note/delivery_note.json index fab0670eb75..39b863c45e4 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.json +++ b/erpnext/stock/doctype/delivery_note/delivery_note.json @@ -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 -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/delivery_note/delivery_note.py b/erpnext/stock/doctype/delivery_note/delivery_note.py index 9b0c3218add..2ddd99c3a0f 100644 --- a/erpnext/stock/doctype/delivery_note/delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/delivery_note.py @@ -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 diff --git a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py index 47ea251b0fe..2f9df8970c4 100644 --- a/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py +++ b/erpnext/support/doctype/service_level_agreement/test_service_level_agreement.py @@ -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)