From 5d591ebe83517fce195b3e883140249bd3b206bf Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 18 Apr 2014 16:15:31 +0530 Subject: [PATCH] Item, Item Group and Partner Web Page generators moved from Shopping Cart to ERPNext --- .../selling/doctype/lead/test_records.json | 2 +- .../setup/doctype/item_group/item_group.py | 20 ++++- erpnext/stock/doctype/item/item.py | 11 +++ erpnext/templates/generators/__init__.py | 0 erpnext/templates/generators/item.html | 84 +++++++++++++++++++ erpnext/templates/generators/item.py | 20 +++++ erpnext/templates/generators/item_group.html | 58 +++++++++++++ erpnext/templates/generators/item_group.py | 64 ++++++++++++++ erpnext/templates/generators/partner.html | 29 +++++++ erpnext/templates/generators/partner.py | 28 +++++++ erpnext/templates/includes/__init__.py | 0 .../includes/product_breadcrumbs.html | 10 +++ .../templates/includes/product_in_grid.html | 14 ++++ .../templates/includes/product_in_list.html | 15 ++++ erpnext/templates/includes/product_list.js | 52 ++++++++++++ .../includes/product_missing_image.html | 1 + erpnext/templates/includes/product_page.js | 78 +++++++++++++++++ .../includes/product_search_box.html | 28 +++++++ erpnext/templates/pages/__init__.py | 0 erpnext/templates/pages/partners.html | 30 +++++++ erpnext/templates/pages/partners.py | 13 +++ erpnext/templates/pages/product_search.html | 33 ++++++++ erpnext/templates/pages/product_search.py | 33 ++++++++ erpnext/templates/utils.py | 8 +- 24 files changed, 625 insertions(+), 6 deletions(-) create mode 100644 erpnext/templates/generators/__init__.py create mode 100644 erpnext/templates/generators/item.html create mode 100644 erpnext/templates/generators/item.py create mode 100644 erpnext/templates/generators/item_group.html create mode 100644 erpnext/templates/generators/item_group.py create mode 100644 erpnext/templates/generators/partner.html create mode 100644 erpnext/templates/generators/partner.py create mode 100644 erpnext/templates/includes/__init__.py create mode 100644 erpnext/templates/includes/product_breadcrumbs.html create mode 100644 erpnext/templates/includes/product_in_grid.html create mode 100644 erpnext/templates/includes/product_in_list.html create mode 100644 erpnext/templates/includes/product_list.js create mode 100644 erpnext/templates/includes/product_missing_image.html create mode 100644 erpnext/templates/includes/product_page.js create mode 100644 erpnext/templates/includes/product_search_box.html create mode 100644 erpnext/templates/pages/__init__.py create mode 100644 erpnext/templates/pages/partners.html create mode 100644 erpnext/templates/pages/partners.py create mode 100644 erpnext/templates/pages/product_search.html create mode 100644 erpnext/templates/pages/product_search.py diff --git a/erpnext/selling/doctype/lead/test_records.json b/erpnext/selling/doctype/lead/test_records.json index c286a12b28..ce9460489c 100644 --- a/erpnext/selling/doctype/lead/test_records.json +++ b/erpnext/selling/doctype/lead/test_records.json @@ -4,7 +4,7 @@ "email_id": "test_lead@example.com", "lead_name": "_Test Lead", "status": "Open", - "territory": "_Test Territory Rest Of The World" + "territory": "_Test Territory" }, { "doctype": "Lead", diff --git a/erpnext/setup/doctype/item_group/item_group.py b/erpnext/setup/doctype/item_group/item_group.py index 91a5efc1ba..fcdd4b2a01 100644 --- a/erpnext/setup/doctype/item_group/item_group.py +++ b/erpnext/setup/doctype/item_group/item_group.py @@ -6,6 +6,7 @@ import frappe from frappe.utils.nestedset import NestedSet from frappe.website.website_generator import WebsiteGenerator +from frappe.website.render import clear_cache class ItemGroup(NestedSet, WebsiteGenerator): nsm_parent_field = 'parent_item_group' @@ -19,7 +20,9 @@ class ItemGroup(NestedSet, WebsiteGenerator): self.parent_item_group) def on_update(self): - super(ItemGroup, self).on_update() + NestedSet.on_update(self) + WebsiteGenerator.on_update(self) + invalidate_cache_for(self) self.validate_name_with_item() self.validate_one_root() @@ -32,3 +35,18 @@ class ItemGroup(NestedSet, WebsiteGenerator): def validate_name_with_item(self): if frappe.db.exists("Item", self.name): frappe.throw(frappe._("An item exists with same name ({0}), please change the item group name or rename the item").format(self.name)) + +def get_parent_item_groups(item_group_name): + item_group = frappe.get_doc("Item Group", item_group_name) + return frappe.db.sql("""select name, page_name from `tabItem Group` + where lft <= %s and rgt >= %s + and ifnull(show_in_website,0)=1 + order by lft asc""", (item_group.lft, item_group.rgt), as_dict=True) + +def invalidate_cache_for(doc, item_group=None): + if not item_group: + item_group = doc.name + + for i in get_parent_item_groups(item_group): + if i.page_name: + clear_cache(i.page_name) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index b945309bdf..26d827f8c9 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -6,6 +6,8 @@ import frappe from frappe import msgprint, _ from frappe.utils import cstr, flt, getdate, now_datetime, formatdate from frappe.website.website_generator import WebsiteGenerator +from erpnext.setup.doctype.item_group.item_group import invalidate_cache_for +from frappe.website.render import clear_cache class WarehouseNotSet(frappe.ValidationError): pass @@ -46,6 +48,7 @@ class Item(WebsiteGenerator): def on_update(self): super(Item, self).on_update() + invalidate_cache_for_item(self) self.validate_name_with_item_group() self.update_item_price() @@ -230,6 +233,9 @@ class Item(WebsiteGenerator): def after_rename(self, olddn, newdn, merge): super(Item, self).after_rename(olddn, newdn, merge) + if self.page_name: + invalidate_cache_for_item(self) + clear_cache(self.page_name) frappe.db.set_value("Item", newdn, "item_code", newdn) if merge: @@ -344,3 +350,8 @@ def get_last_purchase_details(item_code, doc_name=None, conversion_rate=1.0): }) return out + +def invalidate_cache_for_item(doc): + invalidate_cache_for(doc, doc.item_group) + for d in doc.get({"doctype":"Website Item Group"}): + invalidate_cache_for(doc, d.item_group) diff --git a/erpnext/templates/generators/__init__.py b/erpnext/templates/generators/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/templates/generators/item.html b/erpnext/templates/generators/item.html new file mode 100644 index 0000000000..4d4f5d4469 --- /dev/null +++ b/erpnext/templates/generators/item.html @@ -0,0 +1,84 @@ +{% block title %} {{ title }} {% endblock %} + +{% block header %}

{{ title }}

{% endblock %} + +{% block content %} +
+ {% include 'templates/includes/product_search_box.html' %} + {% include 'templates/includes/product_breadcrumbs.html' %} +
+
+
+ {% if slideshow %} + {% include "templates/includes/slideshow.html" %} + {% else %} + {% if website_image %} + + {% else %} +
+ {% include 'templates/includes/product_missing_image.html' %} +
+ {% endif %} + {% endif %} +
+
+

{{ item_name }}

+

Item Code: {{ name }}

+

Product Description

+
+ {{ web_long_description or description or "[No description given]" }} +
+
+ +
+
+
+ {% if doc.get({"doctype":"Item Website Specification"}) -%} +
+
+

Specifications

+ + {% for d in doc.get( + {"doctype":"Item Website Specification"}) -%} + + + + + {%- endfor %} +
{{ d.label }}{{ d.description }}
+
+
+ {%- endif %} +
+
+ +{% endblock %} + +{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} diff --git a/erpnext/templates/generators/item.py b/erpnext/templates/generators/item.py new file mode 100644 index 0000000000..1ad070ef87 --- /dev/null +++ b/erpnext/templates/generators/item.py @@ -0,0 +1,20 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups +from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow + +doctype = "Item" +condition_field = "show_in_website" + +def get_context(context): + item_context = context.doc.as_dict() + item_context["parent_groups"] = get_parent_item_groups(context.doc.item_group) + \ + [{"name":context.doc.name}] + if context.doc.slideshow: + item_context.update(get_slideshow(context.doc)) + + return item_context diff --git a/erpnext/templates/generators/item_group.html b/erpnext/templates/generators/item_group.html new file mode 100644 index 0000000000..ae0cd22c86 --- /dev/null +++ b/erpnext/templates/generators/item_group.html @@ -0,0 +1,58 @@ +{% block title %} {{ title }} {% endblock %} + +{% block header %}

{{ title }}

{% endblock %} + +{% block content %} +
+ {% include 'templates/includes/product_search_box.html' %} + {% include 'templates/includes/product_breadcrumbs.html' %} +
+ {% if slideshow %} + {% include "templates/includes/slideshow.html" %} + {% endif %} + {% if description %} +
{{ description or ""}}
+ {% else %} +

{{ name }}

+ {% endif %} +
+
+ {% if sub_groups %} +
+
+ {% for d in sub_groups %} + + {% endfor %} +
+
+ {% endif %} + {% if items %} +
+ {% for item in items %} + {{ item }} + {% endfor %} +
+ {% if (items|length)==100 %} +
Showing top 100 items.
+ {% endif %} + {% else %} +
No items listed.
+ {% endif %} +
+
+ + +{% endblock %} + +{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/generators/item_group.py b/erpnext/templates/generators/item_group.py new file mode 100644 index 0000000000..774301888d --- /dev/null +++ b/erpnext/templates/generators/item_group.py @@ -0,0 +1,64 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from frappe.website.doctype.website_slideshow.website_slideshow import get_slideshow +from erpnext.setup.doctype.item_group.item_group import get_parent_item_groups + +doctype = "Item Group" +condition_field = "show_in_website" + +def get_context(context): + item_group_context = context.doc.as_dict() + item_group_context.update({ + "sub_groups": frappe.db.sql("""select name, page_name + from `tabItem Group` where parent_item_group=%s + and ifnull(show_in_website,0)=1""", context.docname, as_dict=1), + "items": get_product_list_for_group(product_group = context.docname, limit=100), + "parent_groups": get_parent_item_groups(context.docname), + "title": context.docname + }) + + if context.doc.slideshow: + item_group_context.update(get_slideshow(context.doc)) + + for d in item_group_context.sub_groups: + d.count = get_group_item_count(d.name) + + return item_group_context + +def get_product_list_for_group(product_group=None, start=0, limit=10): + child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(product_group)]) + + # base query + query = """select name, item_name, page_name, website_image, item_group, + web_long_description as website_description + from `tabItem` where docstatus = 0 and show_in_website = 1 + and (item_group in (%s) + or name in (select parent from `tabWebsite Item Group` where item_group in (%s))) """ % (child_groups, child_groups) + + query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit) + + data = frappe.db.sql(query, {"product_group": product_group}, as_dict=1) + + return [get_item_for_list_in_html(r) for r in data] + +def get_child_groups(item_group_name): + item_group = frappe.get_doc("Item Group", item_group_name) + return frappe.db.sql("""select name + from `tabItem Group` where lft>=%(lft)s and rgt<=%(rgt)s + and show_in_website = 1""", item_group.as_dict()) + +def get_item_for_list_in_html(context): + return frappe.get_template("templates/includes/product_in_grid.html").render(context) + +def get_group_item_count(item_group): + child_groups = ", ".join(['"' + i[0] + '"' for i in get_child_groups(item_group)]) + return frappe.db.sql("""select count(*) from `tabItem` + where docstatus = 0 and show_in_website = 1 + and (item_group in (%s) + or name in (select parent from `tabWebsite Item Group` + where item_group in (%s))) """ % (child_groups, child_groups))[0][0] + diff --git a/erpnext/templates/generators/partner.html b/erpnext/templates/generators/partner.html new file mode 100644 index 0000000000..6a869a1207 --- /dev/null +++ b/erpnext/templates/generators/partner.html @@ -0,0 +1,29 @@ +{% block title %} {{ title }} {% endblock %} + +{% block header %}

{{ title }}

{% endblock %} + +{% block content %} +
+
+
+ {% if logo -%} + +

+ {%- endif %} +
+ {% if partner_website -%}

{{ partner_website }}

{%- endif %} + {% if partner_address -%}

{{ partner_address }}

{%- endif %} + {% if phone -%}

{{ phone }}

{%- endif %} + {% if email -%}

{{ email }}

{%- endif %} +
+
+
+

{{ description }}

+
+
+
+{% endblock %} + +{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/generators/partner.py b/erpnext/templates/generators/partner.py new file mode 100644 index 0000000000..2079309747 --- /dev/null +++ b/erpnext/templates/generators/partner.py @@ -0,0 +1,28 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import filter_strip_join + +doctype = "Sales Partner" +condition_field = "show_in_website" + +def get_context(context): + partner_context = context.doc.as_dict() + + address = frappe.db.get_value("Address", + {"sales_partner": context.doc.name, "is_primary_address": 1}, + "*", as_dict=True) + if address: + city_state = ", ".join(filter(None, [address.city, address.state])) + address_rows = [address.address_line1, address.address_line2, + city_state, address.pincode, address.country] + + partner_context.update({ + "email": address.email_id, + "partner_address": filter_strip_join(address_rows, "\n
"), + "phone": filter_strip_join(cstr(address.phone).split(","), "\n
") + }) + + return partner_context diff --git a/erpnext/templates/includes/__init__.py b/erpnext/templates/includes/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/templates/includes/product_breadcrumbs.html b/erpnext/templates/includes/product_breadcrumbs.html new file mode 100644 index 0000000000..b126847ff1 --- /dev/null +++ b/erpnext/templates/includes/product_breadcrumbs.html @@ -0,0 +1,10 @@ +{% if parent_groups and (parent_groups|length) > 1 %} +
+ +
+{% endif %} \ No newline at end of file diff --git a/erpnext/templates/includes/product_in_grid.html b/erpnext/templates/includes/product_in_grid.html new file mode 100644 index 0000000000..9ef4bbd9b1 --- /dev/null +++ b/erpnext/templates/includes/product_in_grid.html @@ -0,0 +1,14 @@ +
+
+ + {%- if website_image -%} + + {%- else -%} + {% include 'templates/includes/product_missing_image.html' %} + {%- endif -%} + +
+
+

{{ item_name }}

+
+
\ No newline at end of file diff --git a/erpnext/templates/includes/product_in_list.html b/erpnext/templates/includes/product_in_list.html new file mode 100644 index 0000000000..116124a78b --- /dev/null +++ b/erpnext/templates/includes/product_in_list.html @@ -0,0 +1,15 @@ + +
+
+ + {%- if website_image -%} + + {%- else -%} + {% include 'templates/includes/product_missing_image.html' %} + {%- endif -%} + +
+
+

{{ item_name }}

+
+
\ No newline at end of file diff --git a/erpnext/templates/includes/product_list.js b/erpnext/templates/includes/product_list.js new file mode 100644 index 0000000000..3d19d5a0c1 --- /dev/null +++ b/erpnext/templates/includes/product_list.js @@ -0,0 +1,52 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +window.get_product_list = function() { + $(".more-btn .btn").click(function() { + window.get_product_list() + }); + + if(window.start==undefined) { + throw "product list not initialized (no start)" + } + + $.ajax({ + method: "GET", + url: "/", + dataType: "json", + data: { + cmd: "erpnext.templates.pages.product_search.get_product_list", + start: window.start, + search: window.search, + product_group: window.product_group + }, + dataType: "json", + success: function(data) { + window.render_product_list(data.message); + } + }) +} + +window.render_product_list = function(data) { + if(data.length) { + var table = $("#search-list .table"); + if(!table.length) + var table = $("").appendTo("#search-list"); + + $.each(data, function(i, d) { + $(d).appendTo(table); + }); + } + if(data.length < 10) { + if(!table) { + $(".more-btn") + .replaceWith("
No products found.
"); + } else { + $(".more-btn") + .replaceWith("
Nothing more to show.
"); + } + } else { + $(".more-btn").toggle(true) + } + window.start += (data.length || 0); +} diff --git a/erpnext/templates/includes/product_missing_image.html b/erpnext/templates/includes/product_missing_image.html new file mode 100644 index 0000000000..81b893533f --- /dev/null +++ b/erpnext/templates/includes/product_missing_image.html @@ -0,0 +1 @@ +
\ No newline at end of file diff --git a/erpnext/templates/includes/product_page.js b/erpnext/templates/includes/product_page.js new file mode 100644 index 0000000000..42d4ae7ca5 --- /dev/null +++ b/erpnext/templates/includes/product_page.js @@ -0,0 +1,78 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +$(document).ready(function() { + var item_code = $('[itemscope] [itemprop="productID"]').text().trim(); + var qty = 0; + + frappe.call({ + type: "POST", + method: "shopping_cart.shopping_cart.product.get_product_info", + args: { + item_code: "{{ name }}" + }, + callback: function(r) { + if(r.message && r.message.price) { + $(".item-price") + .html(r.message.price.formatted_price + " per " + r.message.uom); + + if(r.message.stock==0) { + $(".item-stock").html("
Not in stock
"); + } + else if(r.message.stock==1) { + $(".item-stock").html("
\ + Available (in stock)
"); + } + + $(".item-price-info").toggle(true); + + if(r.message.qty) { + qty = r.message.qty; + toggle_update_cart(qty); + $("#item-update-cart input").val(qty); + } + } + } + }) + + $("#item-add-to-cart button").on("click", function() { + shopping_cart.update_cart({ + item_code: item_code, + qty: 1, + callback: function(r) { + if(!r.exc) { + toggle_update_cart(1); + qty = 1; + } + }, + btn: this, + }); + }); + + $("#item-update-cart button").on("click", function() { + shopping_cart.update_cart({ + item_code: item_code, + qty: $("#item-update-cart input").val(), + btn: this, + callback: function(r) { + if(r.exc) { + $("#item-update-cart input").val(qty); + } else { + qty = $("#item-update-cart input").val(); + } + }, + }); + }); + + if(localStorage && localStorage.getItem("pending_add_to_cart") && full_name) { + localStorage.removeItem("pending_add_to_cart"); + $("#item-add-to-cart button").trigger("click"); + } +}); + +var toggle_update_cart = function(qty) { + $("#item-add-to-cart").toggle(qty ? false : true); + $("#item-update-cart") + .toggle(qty ? true : false) + .find("input").val(qty); +} \ No newline at end of file diff --git a/erpnext/templates/includes/product_search_box.html b/erpnext/templates/includes/product_search_box.html new file mode 100644 index 0000000000..0f44eea72e --- /dev/null +++ b/erpnext/templates/includes/product_search_box.html @@ -0,0 +1,28 @@ +
+ +
+ + + + +
+ + +
\ No newline at end of file diff --git a/erpnext/templates/pages/__init__.py b/erpnext/templates/pages/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/erpnext/templates/pages/partners.html b/erpnext/templates/pages/partners.html new file mode 100644 index 0000000000..089c15b68f --- /dev/null +++ b/erpnext/templates/pages/partners.html @@ -0,0 +1,30 @@ +{% block title %} {{ title }} {% endblock %} + +{% block header %}

{{ title }}

{% endblock %} + +{% block content %} +
+ {% for partner_info in partners %} +
+
+ {% if partner_info.logo -%} + + + + {%- endif %} +
+
+ +

{{ partner_info.partner_name }}

+
+

{{ partner_info.territory }} - {{ partner_info.partner_type }}

+

{{ partner_info.introduction }}

+
+
+
+ {% endfor %} +
+{% endblock %} + +{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/partners.py b/erpnext/templates/pages/partners.py new file mode 100644 index 0000000000..94b553c2b2 --- /dev/null +++ b/erpnext/templates/pages/partners.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.website.render + +def get_context(context): + return { + "partners": frappe.db.sql("""select * from `tabSales Partner` + where show_in_website=1 order by name asc""", as_dict=True), + "title": "Partners" + } diff --git a/erpnext/templates/pages/product_search.html b/erpnext/templates/pages/product_search.html new file mode 100644 index 0000000000..8e57cb5c0e --- /dev/null +++ b/erpnext/templates/pages/product_search.html @@ -0,0 +1,33 @@ +{% block title %} {{ "Product Search" }} {% endblock %} + +{% block header %}

Product Search

{% endblock %} + +{% block content %} + + + + +{% include "templates/includes/product_search_box.html" %} +
+

Search Results

+
+ +
+
+ +
+
+{% endblock %} + +{% block sidebar %}{% include "templates/includes/sidebar.html" %}{% endblock %} \ No newline at end of file diff --git a/erpnext/templates/pages/product_search.py b/erpnext/templates/pages/product_search.py new file mode 100644 index 0000000000..8d4a8f6425 --- /dev/null +++ b/erpnext/templates/pages/product_search.py @@ -0,0 +1,33 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import cstr +from erpnext.templates.generators.item_group import get_item_for_list_in_html + +no_cache = 1 +no_sitemap = 1 + +@frappe.whitelist(allow_guest=True) +def get_product_list(search=None, start=0, limit=10): + # base query + query = """select name, item_name, page_name, website_image, item_group, + web_long_description as website_description + from `tabItem` where docstatus = 0 and show_in_website = 1 """ + + # search term condition + if search: + query += """and (web_long_description like %(search)s or + item_name like %(search)s or name like %(search)s)""" + search = "%" + cstr(search) + "%" + + # order by + query += """order by weightage desc, modified desc limit %s, %s""" % (start, limit) + + data = frappe.db.sql(query, { + "search": search, + }, as_dict=1) + + return [get_item_for_list_in_html(r) for r in data] + diff --git a/erpnext/templates/utils.py b/erpnext/templates/utils.py index e98a5c046b..7ba4a9d911 100644 --- a/erpnext/templates/utils.py +++ b/erpnext/templates/utils.py @@ -7,10 +7,10 @@ import frappe @frappe.whitelist(allow_guest=True) def send_message(subject="Website Query", message="", sender="", status="Open"): from frappe.templates.pages.contact import send_message as website_send_message - + if not website_send_message(subject, message, sender): return - + if subject=="Support": # create support ticket from erpnext.support.doctype.support_ticket.get_support_mails import add_support_communication @@ -18,6 +18,6 @@ def send_message(subject="Website Query", message="", sender="", status="Open"): else: # make lead / communication from erpnext.selling.doctype.lead.get_leads import add_sales_communication - add_sales_communication(subject or "Website Query", message, sender, sender, + add_sales_communication(subject or "Website Query", message, sender, sender, mail=None, status=status) - \ No newline at end of file +