From dc448c2f51210e4b7481ad229cf9c339e81ffd69 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 17 Jun 2021 00:28:03 +0530 Subject: [PATCH 01/25] refactor: lead --- erpnext/crm/doctype/lead/lead.js | 5 - erpnext/crm/doctype/lead/lead.json | 186 ++++++++++++++++------------- erpnext/crm/doctype/lead/lead.py | 84 +------------ 3 files changed, 107 insertions(+), 168 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index ebe85241d28..815bb41a76e 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -68,11 +68,6 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller }) } - organization_lead () { - this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead); - this.frm.toggle_reqd("company_name", this.frm.doc.organization_lead); - } - company_name () { if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) { this.frm.set_value("lead_name", this.frm.doc.company_name); diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index 1b33fd73acf..ed33d896f8a 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -9,30 +9,32 @@ "email_append_to": 1, "engine": "InnoDB", "field_order": [ - "organization_lead", "lead_details", "naming_series", - "lead_name", - "company_name", - "email_id", - "col_break123", - "lead_owner", - "status", "salutation", + "first_name", + "middle_name", + "last_name", + "lead_name", + "email_id", + "mobile_no", + "phone", + "col_break123", + "status", + "company_name", "designation", "gender", - "source", - "customer", - "campaign_name", - "image", - "section_break_12", - "contact_by", - "column_break_14", - "contact_date", - "ends_on", - "notes_section", - "notes", - "address_info", + "additional_information_section", + "no_of_employees", + "industry", + "market_segment", + "type", + "request_type", + "column_break_22", + "whatsapp_no", + "fax", + "website", + "address_section", "address_html", "address_type", "address_title", @@ -45,35 +47,33 @@ "state", "country", "pincode", - "contact_section", - "phone", - "mobile_no", - "fax", - "website", - "more_info", - "type", - "market_segment", - "industry", - "request_type", - "column_break3", + "section_break_12", + "lead_owner", + "ends_on", + "column_break_14", + "contact_by", + "contact_date", + "lead_source_details_section", "company", "territory", "language", + "column_break_50", + "source", + "campaign_name", "unsubscribed", "blog_subscriber", + "notes_section", + "notes", + "other_information_section", + "customer", + "image", "title" ], "fields": [ - { - "default": "0", - "fieldname": "organization_lead", - "fieldtype": "Check", - "label": "Lead is an Organization", - "set_only_once": 1 - }, { "fieldname": "lead_details", "fieldtype": "Section Break", + "label": "Lead Details", "options": "fa fa-user" }, { @@ -90,7 +90,8 @@ "fieldname": "lead_name", "fieldtype": "Data", "in_global_search": 1, - "label": "Person Name", + "label": "Full Name", + "mandatory_depends_on": "eval: !(doc.company_name)", "oldfieldname": "lead_name", "oldfieldtype": "Data", "search_index": 1 @@ -99,7 +100,9 @@ "fieldname": "company_name", "fieldtype": "Data", "in_list_view": 1, + "in_standard_filter": 1, "label": "Organization Name", + "mandatory_depends_on": "eval: !(doc.lead_name)", "oldfieldname": "company_name", "oldfieldtype": "Data" }, @@ -121,7 +124,6 @@ "default": "__user", "fieldname": "lead_owner", "fieldtype": "Link", - "in_list_view": 1, "label": "Lead Owner", "oldfieldname": "lead_owner", "oldfieldtype": "Link", @@ -241,46 +243,39 @@ "read_only": 1 }, { - "depends_on": "eval: doc.__islocal", "description": "Home, Work, etc.", "fieldname": "address_title", "fieldtype": "Data", "label": "Address Title" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "address_line1", "fieldtype": "Data", "label": "Address Line 1", "mandatory_depends_on": "eval: doc.address_title && doc.address_type" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "address_line2", "fieldtype": "Data", "label": "Address Line 2" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "city", "fieldtype": "Data", "label": "City/Town", "mandatory_depends_on": "eval: doc.address_title && doc.address_type" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "county", "fieldtype": "Data", "label": "County" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "state", "fieldtype": "Data", "label": "State" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "country", "fieldtype": "Link", "label": "Country", @@ -288,7 +283,7 @@ "options": "Country" }, { - "depends_on": "eval: doc.__islocal", + "collapsible_depends_on": "eval: doc.__islocal", "fieldname": "pincode", "fieldtype": "Data", "label": "Postal Code" @@ -329,14 +324,6 @@ "oldfieldname": "fax", "oldfieldtype": "Data" }, - { - "collapsible": 1, - "fieldname": "more_info", - "fieldtype": "Section Break", - "label": "More Information", - "oldfieldtype": "Section Break", - "options": "fa fa-file-text" - }, { "fieldname": "type", "fieldtype": "Select", @@ -369,12 +356,6 @@ "oldfieldtype": "Select", "options": "\nProduct Enquiry\nRequest for Information\nSuggestions\nOther" }, - { - "fieldname": "column_break3", - "fieldtype": "Column Break", - "oldfieldtype": "Column Break", - "width": "50%" - }, { "fieldname": "company", "fieldtype": "Link", @@ -389,11 +370,14 @@ "fieldtype": "Data", "label": "Website", "oldfieldname": "website", - "oldfieldtype": "Data" + "oldfieldtype": "Data", + "options": "URL" }, { "fieldname": "territory", "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, "label": "Territory", "oldfieldname": "territory", "oldfieldtype": "Link", @@ -422,28 +406,13 @@ { "fieldname": "designation", "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, "label": "Designation", "options": "Designation" }, - { - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "fieldname": "address_info", - "fieldtype": "Section Break", - "label": "Address & Contact", - "oldfieldtype": "Column Break", - "options": "fa fa-map-marker" - }, - { - "collapsible": 1, - "collapsible_depends_on": "eval: doc.__islocal", - "fieldname": "contact_section", - "fieldtype": "Section Break", - "label": "Contact" - }, { "default": "Billing", - "depends_on": "eval: doc.__islocal", "fieldname": "address_type", "fieldtype": "Select", "label": "Address Type", @@ -454,13 +423,70 @@ "fieldtype": "Link", "label": "Print Language", "options": "Language" + }, + { + "fieldname": "first_name", + "fieldtype": "Data", + "label": "First Name" + }, + { + "fieldname": "middle_name", + "fieldtype": "Data", + "label": "Middle Name" + }, + { + "fieldname": "last_name", + "fieldtype": "Data", + "label": "Last Name" + }, + { + "collapsible": 1, + "fieldname": "additional_information_section", + "fieldtype": "Section Break", + "label": "Additional Information" + }, + { + "fieldname": "no_of_employees", + "fieldtype": "Int", + "label": "No. of Employees" + }, + { + "fieldname": "column_break_22", + "fieldtype": "Column Break" + }, + { + "fieldname": "whatsapp_no", + "fieldtype": "Data", + "label": "WhatsApp No.", + "options": "Phone" + }, + { + "collapsible": 1, + "depends_on": "eval:!doc.__islocal", + "fieldname": "address_section", + "fieldtype": "Section Break", + "label": "Address" + }, + { + "fieldname": "lead_source_details_section", + "fieldtype": "Section Break", + "label": "Lead Source Details" + }, + { + "fieldname": "column_break_50", + "fieldtype": "Column Break" + }, + { + "fieldname": "other_information_section", + "fieldtype": "Section Break", + "label": "Other Information" } ], "icon": "fa fa-user", "idx": 5, "image_field": "image", "links": [], - "modified": "2021-01-06 19:39:58.748978", + "modified": "2021-06-17 00:20:37.768449", "modified_by": "Administrator", "module": "CRM", "name": "Lead", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index d1d096843bf..b18129b14fc 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -21,14 +21,6 @@ class Lead(SellingController): self.get("__onload").is_customer = customer load_address_and_contact(self) - def before_insert(self): - if self.address_title and self.address_type: - self.address_doc = self.create_address() - self.contact_doc = self.create_contact() - - def after_insert(self): - self.update_links() - def validate(self): self.set_lead_name() self.set_title() @@ -120,85 +112,11 @@ class Lead(SellingController): self.lead_name = self.email_id.split("@")[0] def set_title(self): - if self.organization_lead: + if self.company_name: self.title = self.company_name else: self.title = self.lead_name - def create_address(self): - address_fields = ["address_type", "address_title", "address_line1", "address_line2", - "city", "county", "state", "country", "pincode"] - info_fields = ["email_id", "phone", "fax"] - - # do not create an address if no fields are available, - # skipping country since the system auto-sets it from system defaults - address = frappe.new_doc("Address") - - address.update({addr_field: self.get(addr_field) for addr_field in address_fields}) - address.update({info_field: self.get(info_field) for info_field in info_fields}) - address.insert() - - return address - - def create_contact(self): - if not self.lead_name: - self.set_lead_name() - - names = self.lead_name.strip().split(" ") - if len(names) > 1: - first_name, last_name = names[0], " ".join(names[1:]) - else: - first_name, last_name = self.lead_name, None - - contact = frappe.new_doc("Contact") - contact.update({ - "first_name": first_name, - "last_name": last_name, - "salutation": self.salutation, - "gender": self.gender, - "designation": self.designation, - }) - - if self.email_id: - contact.append("email_ids", { - "email_id": self.email_id, - "is_primary": 1 - }) - - if self.phone: - contact.append("phone_nos", { - "phone": self.phone, - "is_primary": 1 - }) - - if self.mobile_no: - contact.append("phone_nos", { - "phone": self.mobile_no - }) - - contact.insert(ignore_permissions=True) - - return contact - - def update_links(self): - # update address links - if hasattr(self, 'address_doc'): - self.address_doc.append("links", { - "link_doctype": "Lead", - "link_name": self.name, - "link_title": self.lead_name - }) - self.address_doc.save() - - # update contact links - if self.contact_doc: - self.contact_doc.append("links", { - "link_doctype": "Lead", - "link_name": self.name, - "link_title": self.lead_name - }) - self.contact_doc.save() - @frappe.whitelist() def make_customer(source_name, target_doc=None): return _make_customer(source_name, target_doc) From 49cfac0ef0eb2333e5ff6291a60550d26faf3930 Mon Sep 17 00:00:00 2001 From: Anupam Date: Wed, 28 Jul 2021 17:51:35 +0530 Subject: [PATCH 02/25] feat: added basic info. of lead in header part --- erpnext/crm/doctype/lead/lead.js | 40 ++++++++++++++++++++++++++++++ erpnext/crm/doctype/lead/lead.json | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 815bb41a76e..bd1639bb12f 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -42,6 +42,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller if (!this.frm.is_new()) { frappe.contacts.render_address_and_contact(this.frm); + cur_frm.trigger('render_basic_info_html'); } else { frappe.contacts.clear_address_and_contact(this.frm); } @@ -81,6 +82,45 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller this.frm.set_value("ends_on", d.format(frappe.defaultDatetimeFormat)); } } + + render_basic_info_html() { + let html=''; + if (cur_frm.doc.lead_owner){ + html += `
+ Lead Owner +
+
+ ${cur_frm.doc.lead_owner} +
` ; + } + + if (cur_frm.doc.email_id){ + html += `
+ Email +
+
+ ${cur_frm.doc.email_id} +
` ; + } + + if (cur_frm.doc.mobile_no){ + html += `
+ Mobile +
+
+ ${cur_frm.doc.mobile_no} +
` ; + } + + html += `
+ Status +
+
+ ${cur_frm.doc.status} +
` ; + html = `
${html}
`; + cur_frm.dashboard.set_headline_alert(html); + } }; extend_cscript(cur_frm.cscript, new erpnext.LeadController({ frm: cur_frm })); diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index ed33d896f8a..dc030fe8197 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -486,7 +486,7 @@ "idx": 5, "image_field": "image", "links": [], - "modified": "2021-06-17 00:20:37.768449", + "modified": "2021-07-28 00:20:37.768449", "modified_by": "Administrator", "module": "CRM", "name": "Lead", From 47a651a80fe5be8ec9100b68f33097f2e349a086 Mon Sep 17 00:00:00 2001 From: Anupam Date: Wed, 28 Jul 2021 18:21:19 +0530 Subject: [PATCH 03/25] fix: removing depends_on for contact fields --- erpnext/crm/doctype/lead/lead.json | 5 ----- 1 file changed, 5 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index dc030fe8197..f9a500fa974 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -145,7 +145,6 @@ "search_index": 1 }, { - "depends_on": "eval: doc.__islocal", "fieldname": "salutation", "fieldtype": "Link", "label": "Salutation", @@ -283,7 +282,6 @@ "options": "Country" }, { - "collapsible_depends_on": "eval: doc.__islocal", "fieldname": "pincode", "fieldtype": "Data", "label": "Postal Code" @@ -299,7 +297,6 @@ "read_only": 1 }, { - "depends_on": "eval: doc.__islocal", "fieldname": "phone", "fieldtype": "Data", "label": "Phone", @@ -308,7 +305,6 @@ "options": "Phone" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "mobile_no", "fieldtype": "Data", "label": "Mobile No.", @@ -317,7 +313,6 @@ "options": "Phone" }, { - "depends_on": "eval: doc.__islocal", "fieldname": "fax", "fieldtype": "Data", "label": "Fax", From a6ce1244a07279d601702ece31243d9d6e857557 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 29 Jul 2021 10:43:21 +0530 Subject: [PATCH 04/25] fix: sider issues --- erpnext/crm/doctype/lead/lead.js | 6 +++--- erpnext/crm/doctype/lead/lead.py | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index bd1639bb12f..ad24a6e2225 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -85,7 +85,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller render_basic_info_html() { let html=''; - if (cur_frm.doc.lead_owner){ + if (cur_frm.doc.lead_owner) { html += `
Lead Owner
@@ -94,7 +94,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller ` ; } - if (cur_frm.doc.email_id){ + if (cur_frm.doc.email_id) { html += `
Email
@@ -103,7 +103,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller ` ; } - if (cur_frm.doc.mobile_no){ + if (cur_frm.doc.mobile_no) { html += `
Mobile
diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index ce36069052e..f09a8145401 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -95,7 +95,7 @@ class Lead(SellingController): if d.link_doctype == self.doctype and d.link_name == self.name: to_remove = d if to_remove: - link_doctype.remove(to_remove) + linked_doc.remove(to_remove) def has_customer(self): return frappe.db.get_value("Customer", {"lead_name": self.name}) From 2732490cbefd0e8af56ae4e473e6a2fb9c72b1a3 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Aug 2021 00:30:01 +0530 Subject: [PATCH 05/25] fix: review changes --- erpnext/crm/doctype/lead/lead.js | 47 +++++--------------- erpnext/crm/doctype/lead/lead.json | 70 +++++++++++++----------------- erpnext/crm/doctype/lead/lead.py | 18 +++++--- 3 files changed, 54 insertions(+), 81 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index ad24a6e2225..10e3f7da6be 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -12,7 +12,8 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller 'Opportunity': this.make_opportunity }; - this.frm.toggle_reqd("lead_name", !this.frm.doc.organization_lead); + // For avoiding integration issues. + this.frm.set_df_property('first_name', 'reqd', true); } onload () { @@ -84,42 +85,16 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller } render_basic_info_html() { - let html=''; - if (cur_frm.doc.lead_owner) { - html += `
- Lead Owner -
-
- ${cur_frm.doc.lead_owner} -
` ; + if (cur_frm.doc.contact_date) { + let contact_date = frappe.datetime.obj_to_str(cur_frm.doc.contact_date) + let diff_days = frappe.datetime.get_day_diff(contact_date, frappe.datetime.get_today()); + let color = diff_days > 0 ? "orange" : "green"; + let message = diff_days > 0 ? __("Next Contact Date") : __("Last Contact Date"); + let html = `
+ ${message} : ${contact_date} +
` ; + cur_frm.dashboard.set_headline_alert(html); } - - if (cur_frm.doc.email_id) { - html += `
- Email -
-
- ${cur_frm.doc.email_id} -
` ; - } - - if (cur_frm.doc.mobile_no) { - html += `
- Mobile -
-
- ${cur_frm.doc.mobile_no} -
` ; - } - - html += `
- Status -
-
- ${cur_frm.doc.status} -
` ; - html = `
${html}
`; - cur_frm.dashboard.set_headline_alert(html); } }; diff --git a/erpnext/crm/doctype/lead/lead.json b/erpnext/crm/doctype/lead/lead.json index f9a500fa974..542977e689b 100644 --- a/erpnext/crm/doctype/lead/lead.json +++ b/erpnext/crm/doctype/lead/lead.json @@ -16,37 +16,36 @@ "middle_name", "last_name", "lead_name", - "email_id", - "mobile_no", - "phone", "col_break123", "status", "company_name", "designation", "gender", + "contact_details_section", + "email_id", + "mobile_no", + "whatsapp_no", + "column_break_16", + "phone", + "phone_ext", "additional_information_section", "no_of_employees", "industry", "market_segment", - "type", - "request_type", "column_break_22", - "whatsapp_no", "fax", "website", + "type", + "request_type", "address_section", "address_html", - "address_type", - "address_title", - "address_line1", - "address_line2", "city", + "pincode", "county", "column_break2", "contact_html", "state", "country", - "pincode", "section_break_12", "lead_owner", "ends_on", @@ -91,9 +90,9 @@ "fieldtype": "Data", "in_global_search": 1, "label": "Full Name", - "mandatory_depends_on": "eval: !(doc.company_name)", "oldfieldname": "lead_name", "oldfieldtype": "Data", + "read_only": 1, "search_index": 1 }, { @@ -102,7 +101,7 @@ "in_list_view": 1, "in_standard_filter": 1, "label": "Organization Name", - "mandatory_depends_on": "eval: !(doc.lead_name)", + "mandatory_depends_on": "eval: !(doc.first_name)", "oldfieldname": "company_name", "oldfieldtype": "Data" }, @@ -241,23 +240,6 @@ "label": "Address HTML", "read_only": 1 }, - { - "description": "Home, Work, etc.", - "fieldname": "address_title", - "fieldtype": "Data", - "label": "Address Title" - }, - { - "fieldname": "address_line1", - "fieldtype": "Data", - "label": "Address Line 1", - "mandatory_depends_on": "eval: doc.address_title && doc.address_type" - }, - { - "fieldname": "address_line2", - "fieldtype": "Data", - "label": "Address Line 2" - }, { "fieldname": "city", "fieldtype": "Data", @@ -406,13 +388,6 @@ "label": "Designation", "options": "Designation" }, - { - "default": "Billing", - "fieldname": "address_type", - "fieldtype": "Select", - "label": "Address Type", - "options": "Billing\nShipping\nOffice\nPersonal\nPlant\nPostal\nShop\nSubsidiary\nWarehouse\nCurrent\nPermanent\nOther" - }, { "fieldname": "language", "fieldtype": "Link", @@ -422,7 +397,8 @@ { "fieldname": "first_name", "fieldtype": "Data", - "label": "First Name" + "label": "First Name", + "mandatory_depends_on": "eval: !(doc.company_name)" }, { "fieldname": "middle_name", @@ -457,7 +433,7 @@ }, { "collapsible": 1, - "depends_on": "eval:!doc.__islocal", + "depends_on": "eval: !doc.__islocal", "fieldname": "address_section", "fieldtype": "Section Break", "label": "Address" @@ -475,13 +451,27 @@ "fieldname": "other_information_section", "fieldtype": "Section Break", "label": "Other Information" + }, + { + "fieldname": "contact_details_section", + "fieldtype": "Section Break", + "label": "Contact Details" + }, + { + "fieldname": "column_break_16", + "fieldtype": "Column Break" + }, + { + "fieldname": "phone_ext", + "fieldtype": "Data", + "label": "Phone Ext." } ], "icon": "fa fa-user", "idx": 5, "image_field": "image", "links": [], - "modified": "2021-07-28 00:20:37.768449", + "modified": "2021-08-04 00:24:57.208590", "modified_by": "Administrator", "module": "CRM", "name": "Lead", diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index f09a8145401..33fda89f28b 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -21,18 +21,24 @@ class Lead(SellingController): self.get("__onload").is_customer = customer load_address_and_contact(self) + def set_full_name(self): + self.lead_name = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) + def validate(self): + self.set_full_name() self.set_lead_name() self.set_title() + self.set_status() + self.check_email_id_is_unique() + self.validate_email_id() + self.validate_contact_date() self._prev = frappe._dict({ "contact_date": frappe.db.get_value("Lead", self.name, "contact_date") if (not cint(self.is_new())) else None, "ends_on": frappe.db.get_value("Lead", self.name, "ends_on") if (not cint(self.is_new())) else None, "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None, }) - - self.set_status() - self.check_email_id_is_unique() - + + def validate_email_id(self): if self.email_id: if not self.flags.ignore_email_validation: validate_email_address(self.email_id, throw=True) @@ -46,6 +52,7 @@ class Lead(SellingController): if self.is_new() or not self.image: self.image = has_gravatar(self.email_id) + def validate_contact_date(self): if self.contact_date and getdate(self.contact_date) < getdate(nowdate()): frappe.throw(_("Next Contact Date cannot be in the past")) @@ -88,7 +95,7 @@ class Lead(SellingController): linked_doc = frappe.get_doc(link['parenttype'], link['parent']) if len(linked_doc.get('links')) == 1: - linked_doc.delete() + linked_doc.delete(ignore_permissions=True) else: to_remove = None for d in linked_doc.get('links'): @@ -96,6 +103,7 @@ class Lead(SellingController): to_remove = d if to_remove: linked_doc.remove(to_remove) + linked_doc.save(ignore_permissions=True) def has_customer(self): return frappe.db.get_value("Customer", {"lead_name": self.name}) From c35a526dd826e91e764194ad45a1b6ac52b98b2a Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Aug 2021 14:42:15 +0530 Subject: [PATCH 06/25] fix: adding test cases --- erpnext/crm/doctype/lead/lead.js | 6 ++-- erpnext/crm/doctype/lead/lead.py | 6 ++-- erpnext/crm/doctype/lead/test_lead.py | 49 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 6 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 10e3f7da6be..3363d8c0232 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -43,7 +43,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller if (!this.frm.is_new()) { frappe.contacts.render_address_and_contact(this.frm); - cur_frm.trigger('render_basic_info_html'); + cur_frm.trigger('render_contact_day_html'); } else { frappe.contacts.clear_address_and_contact(this.frm); } @@ -84,14 +84,14 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller } } - render_basic_info_html() { + render_contact_day_html() { if (cur_frm.doc.contact_date) { let contact_date = frappe.datetime.obj_to_str(cur_frm.doc.contact_date) let diff_days = frappe.datetime.get_day_diff(contact_date, frappe.datetime.get_today()); let color = diff_days > 0 ? "orange" : "green"; let message = diff_days > 0 ? __("Next Contact Date") : __("Last Contact Date"); let html = `
- ${message} : ${contact_date} + ${message} : ${frappe.datetime.global_date_format(contact_date)}
` ; cur_frm.dashboard.set_headline_alert(html); } diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 33fda89f28b..49b682c12fd 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -21,9 +21,6 @@ class Lead(SellingController): self.get("__onload").is_customer = customer load_address_and_contact(self) - def set_full_name(self): - self.lead_name = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) - def validate(self): self.set_full_name() self.set_lead_name() @@ -38,6 +35,9 @@ class Lead(SellingController): "contact_by": frappe.db.get_value("Lead", self.name, "contact_by") if (not cint(self.is_new())) else None, }) + def set_full_name(self): + self.lead_name = " ".join(filter(None, [self.first_name, self.middle_name, self.last_name])) + def validate_email_id(self): if self.email_id: if not self.flags.ignore_email_validation: diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index d428a453f9f..174b1c98bd4 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -4,6 +4,7 @@ from __future__ import unicode_literals import frappe +from frappe.utils import random_string import unittest test_records = frappe.get_test_records('Lead') @@ -32,3 +33,51 @@ class TestLead(unittest.TestCase): customer.company = "_Test Company" customer.customer_group = "_Test Customer Group" customer.insert() + + def test_create_lead_and_unlinking_dynamic_links(self): + lead_doc = make_lead(first_name = "Lorem", last_name="Ipsum") + lead_doc_1 = make_lead() + address = frappe.get_doc({ + "doctype": "Address", + "address_type": "Billing", + "city": "Mumbai", + "address_line1": "Vidya Vihar West", + "country": "India", + "links": [{ + "link_doctype": "Lead", + "link_name": lead_doc.name + }] + }).insert() + + address_1 = frappe.get_doc({ + "doctype": "Address", + "address_type": "Billing", + "address_line1": "Baner", + "city": "Pune", + "country": "India", + "links": [{ + "link_doctype": "Lead", + "link_name": lead_doc.name + }, + { + "link_doctype": "Lead", + "link_name": lead_doc_1.name + }] + }).insert() + + lead_doc.delete() + address_1.reload() + self.assertEqual(frappe.db.exists("Lead",lead_doc.name), None) + self.assertEqual(len(address_1.get('links')), 1) + +def make_lead(**args): + args = frappe._dict(args) + + lead_doc = frappe.get_doc({ + "doctype": "Lead", + "first_name": args.first_name or "Test", + "last_name": args.last_name or "Lead", + "email_id": args.email_id or "new_lead{}@example.com".format(random_string(5)), + }).insert() + + return lead_doc \ No newline at end of file From 4723e18f9e3dec0846fd13240dd7594095b7cbc4 Mon Sep 17 00:00:00 2001 From: Anupam Date: Thu, 5 Aug 2021 19:44:00 +0530 Subject: [PATCH 07/25] fix: sider issue --- erpnext/crm/doctype/lead/lead.js | 2 +- erpnext/crm/doctype/lead/test_lead.py | 20 +++++++++++--------- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 3363d8c0232..97e6315eff5 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -86,7 +86,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller render_contact_day_html() { if (cur_frm.doc.contact_date) { - let contact_date = frappe.datetime.obj_to_str(cur_frm.doc.contact_date) + let contact_date = frappe.datetime.obj_to_str(cur_frm.doc.contact_date); let diff_days = frappe.datetime.get_day_diff(contact_date, frappe.datetime.get_today()); let color = diff_days > 0 ? "orange" : "green"; let message = diff_days > 0 ? __("Next Contact Date") : __("Last Contact Date"); diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index 174b1c98bd4..18e0692c5e9 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -37,7 +37,7 @@ class TestLead(unittest.TestCase): def test_create_lead_and_unlinking_dynamic_links(self): lead_doc = make_lead(first_name = "Lorem", last_name="Ipsum") lead_doc_1 = make_lead() - address = frappe.get_doc({ + frappe.get_doc({ "doctype": "Address", "address_type": "Billing", "city": "Mumbai", @@ -55,14 +55,16 @@ class TestLead(unittest.TestCase): "address_line1": "Baner", "city": "Pune", "country": "India", - "links": [{ - "link_doctype": "Lead", - "link_name": lead_doc.name - }, - { - "link_doctype": "Lead", - "link_name": lead_doc_1.name - }] + "links": [ + { + "link_doctype": "Lead", + "link_name": lead_doc.name + }, + { + "link_doctype": "Lead", + "link_name": lead_doc_1.name + } + ] }).insert() lead_doc.delete() From 01a0585ba0bbfe68b650a1090edb20f6071bfaf0 Mon Sep 17 00:00:00 2001 From: Anupam Date: Fri, 6 Aug 2021 11:47:07 +0530 Subject: [PATCH 08/25] fix: removing organization_lead traceback --- erpnext/crm/doctype/lead/lead.js | 2 +- erpnext/crm/doctype/lead/test_lead.py | 4 ++-- erpnext/crm/doctype/lead/test_records.json | 1 - erpnext/crm/doctype/lead/tests/test_lead_organization.js | 1 - erpnext/selling/doctype/customer/customer.py | 4 ++-- 5 files changed, 5 insertions(+), 7 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.js b/erpnext/crm/doctype/lead/lead.js index 97e6315eff5..75af9379900 100644 --- a/erpnext/crm/doctype/lead/lead.js +++ b/erpnext/crm/doctype/lead/lead.js @@ -71,7 +71,7 @@ erpnext.LeadController = class LeadController extends frappe.ui.form.Controller } company_name () { - if (this.frm.doc.organization_lead && !this.frm.doc.lead_name) { + if (!this.frm.doc.lead_name) { this.frm.set_value("lead_name", this.frm.doc.company_name); } } diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index 18e0692c5e9..cadc1a28a0e 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -35,7 +35,7 @@ class TestLead(unittest.TestCase): customer.insert() def test_create_lead_and_unlinking_dynamic_links(self): - lead_doc = make_lead(first_name = "Lorem", last_name="Ipsum") + lead_doc = make_lead(first_name = "Lorem", last_name="Ipsum", email_id="lorem_ipsum@example.com") lead_doc_1 = make_lead() frappe.get_doc({ "doctype": "Address", @@ -79,7 +79,7 @@ def make_lead(**args): "doctype": "Lead", "first_name": args.first_name or "Test", "last_name": args.last_name or "Lead", - "email_id": args.email_id or "new_lead{}@example.com".format(random_string(5)), + "email_id": args.email_id or "new_lead_{}@example.com".format(random_string(5)), }).insert() return lead_doc \ No newline at end of file diff --git a/erpnext/crm/doctype/lead/test_records.json b/erpnext/crm/doctype/lead/test_records.json index 39864e2e3e2..3158add0f23 100644 --- a/erpnext/crm/doctype/lead/test_records.json +++ b/erpnext/crm/doctype/lead/test_records.json @@ -27,7 +27,6 @@ { "doctype": "Lead", "email_id": "test_lead4@example.com", - "organization_lead": 1, "lead_name": "_Test Lead 4", "company_name": "_Test Lead 4", "status": "Open" diff --git a/erpnext/crm/doctype/lead/tests/test_lead_organization.js b/erpnext/crm/doctype/lead/tests/test_lead_organization.js index 43959356b14..7fb957370b0 100644 --- a/erpnext/crm/doctype/lead/tests/test_lead_organization.js +++ b/erpnext/crm/doctype/lead/tests/test_lead_organization.js @@ -9,7 +9,6 @@ QUnit.test("test: lead", function (assert) { () => frappe.set_route("List", "Lead"), () => frappe.new_doc("Lead"), () => frappe.timeout(1), - () => cur_frm.set_value("organization_lead", "1"), () => cur_frm.set_value("company_name", lead_name), () => cur_frm.save(), () => frappe.timeout(1), diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 3b62081e24c..66edcd01886 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -176,12 +176,12 @@ class Customer(TransactionBase): address.append('links', dict(link_doctype='Customer', link_name=self.name)) address.save(ignore_permissions=self.flags.ignore_permissions) - lead = frappe.db.get_value("Lead", self.lead_name, ["organization_lead", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True) + lead = frappe.db.get_value("Lead", self.lead_name, ["company_name", "lead_name", "email_id", "phone", "mobile_no", "gender", "salutation"], as_dict=True) if not lead.lead_name: frappe.throw(_("Please mention the Lead Name in Lead {0}").format(self.lead_name)) - if lead.organization_lead: + if lead.company_name: contact_names = frappe.get_all('Dynamic Link', filters={ "parenttype":"Contact", "link_doctype":"Lead", From 59c971015abf1e90452da2e8752d47b34ed76ee4 Mon Sep 17 00:00:00 2001 From: Anupam Date: Fri, 6 Aug 2021 14:02:57 +0530 Subject: [PATCH 09/25] fix: test case --- erpnext/crm/doctype/lead/test_lead.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/lead/test_lead.py b/erpnext/crm/doctype/lead/test_lead.py index cadc1a28a0e..d4886d35067 100644 --- a/erpnext/crm/doctype/lead/test_lead.py +++ b/erpnext/crm/doctype/lead/test_lead.py @@ -77,7 +77,7 @@ def make_lead(**args): lead_doc = frappe.get_doc({ "doctype": "Lead", - "first_name": args.first_name or "Test", + "first_name": args.first_name or "_Test", "last_name": args.last_name or "Lead", "email_id": args.email_id or "new_lead_{}@example.com".format(random_string(5)), }).insert() From b4e720f8ecd8ad5966fb8c7f399c1347f11a84d2 Mon Sep 17 00:00:00 2001 From: Anupam Date: Fri, 6 Aug 2021 14:39:13 +0530 Subject: [PATCH 10/25] fix: test case --- erpnext/crm/doctype/appointment/test_appointment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py index 50c98c59de6..bcab7bd7081 100644 --- a/erpnext/crm/doctype/appointment/test_appointment.py +++ b/erpnext/crm/doctype/appointment/test_appointment.py @@ -9,7 +9,7 @@ import datetime def create_test_lead(): - test_lead = frappe.db.exists({'doctype': 'Lead', 'lead_name': 'Test Lead'}) + test_lead = frappe.db.exists({'doctype': 'Lead', 'email':'test@example.com'}) if test_lead: return frappe.get_doc('Lead', test_lead[0][0]) test_lead = frappe.get_doc({ From ab8f0cab4d0a934c200665a6916ecb7de032519b Mon Sep 17 00:00:00 2001 From: Marica Date: Mon, 9 Aug 2021 12:24:04 +0530 Subject: [PATCH 11/25] fix: Faulty Gl Entry for Asset LCVs (#26803) * fix: Faulty Gl Entry for Asset LCVs - Both Gl entries were crediting in their respective accounts - Asset Account must be debited into * fix: Use keyword arguments instead of positional for better readability * chore: Test for LCV for draft asset created via Purchase Receipt --- .../test_landed_cost_voucher.py | 35 +++- .../purchase_receipt/purchase_receipt.py | 179 ++++++++++++++---- 2 files changed, 181 insertions(+), 33 deletions(-) diff --git a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py index 32b08f60c4a..128a2ab62ff 100644 --- a/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py +++ b/erpnext/stock/doctype/landed_cost_voucher/test_landed_cost_voucher.py @@ -11,6 +11,7 @@ from erpnext.stock.doctype.purchase_receipt.test_purchase_receipt \ from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice from erpnext.accounts.doctype.account.test_account import get_inventory_account from erpnext.accounts.doctype.account.test_account import create_account +from erpnext.assets.doctype.asset.test_asset import create_asset_category, create_fixed_asset_item class TestLandedCostVoucher(unittest.TestCase): def test_landed_cost_voucher(self): @@ -250,6 +251,38 @@ class TestLandedCostVoucher(unittest.TestCase): self.assertEqual(entry.credit, amounts[0]) self.assertEqual(entry.credit_in_account_currency, amounts[1]) + def test_asset_lcv(self): + "Check if LCV for an Asset updates the Assets Gross Purchase Amount correctly." + if not frappe.db.exists("Asset Category", "Computers"): + create_asset_category() + + if not frappe.db.exists("Item", "Macbook Pro"): + create_fixed_asset_item() + + pr = make_purchase_receipt(item_code="Macbook Pro", qty=1, rate=50000) + + # check if draft asset was created + assets = frappe.db.get_all('Asset', filters={'purchase_receipt': pr.name}) + self.assertEqual(len(assets), 1) + + frappe.db.set_value("Company", pr.company, "capital_work_in_progress_account", "CWIP Account - _TC") + lcv = make_landed_cost_voucher( + company = pr.company, + receipt_document_type = "Purchase Receipt", + receipt_document=pr.name, + charges=80, + expense_account="Expenses Included In Valuation - _TC") + + lcv.save() + lcv.submit() + + # lcv updates amount in draft asset + self.assertEqual(frappe.db.get_value("Asset", assets[0].name, "gross_purchase_amount"), 50080) + + # tear down + lcv.cancel() + pr.cancel() + def make_landed_cost_voucher(** args): args = frappe._dict(args) ref_doc = frappe.get_doc(args.receipt_document_type, args.receipt_document) @@ -268,7 +301,7 @@ def make_landed_cost_voucher(** args): lcv.set("taxes", [{ "description": "Shipping Charges", - "expense_account": "Expenses Included In Valuation - TCP1", + "expense_account": args.expense_account or "Expenses Included In Valuation - TCP1", "amount": args.charges }]) diff --git a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py index 899d7e8e666..bcf605288f6 100644 --- a/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/purchase_receipt.py @@ -290,8 +290,16 @@ class PurchaseReceipt(BuyingController): and warehouse_account_name == supplier_warehouse_account: continue - self.add_gl_entry(gl_entries, warehouse_account_name, d.cost_center, stock_value_diff, 0.0, remarks, - stock_rbnb, account_currency=warehouse_account_currency, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=warehouse_account_name, + cost_center=d.cost_center, + debit=stock_value_diff, + credit=0.0, + remarks=remarks, + against_account=stock_rbnb, + account_currency=warehouse_account_currency, + item=d) # GL Entry for from warehouse or Stock Received but not billed # Intentionally passed negative debit amount to avoid incorrect GL Entry validation @@ -304,9 +312,17 @@ class PurchaseReceipt(BuyingController): account = warehouse_account[d.from_warehouse]['account'] \ if d.from_warehouse else stock_rbnb - self.add_gl_entry(gl_entries, account, d.cost_center, - -1 * flt(d.base_net_amount, d.precision("base_net_amount")), 0.0, remarks, warehouse_account_name, - debit_in_account_currency=-1 * credit_amount, account_currency=credit_currency, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=d.cost_center, + debit=-1 * flt(d.base_net_amount, d.precision("base_net_amount")), + credit=0.0, + remarks=remarks, + against_account=warehouse_account_name, + debit_in_account_currency=-1 * credit_amount, + account_currency=credit_currency, + item=d) # check if the exchange rate has changed if d.get('purchase_invoice'): @@ -317,13 +333,29 @@ class PurchaseReceipt(BuyingController): discrepancy_caused_by_exchange_rate_difference = (d.qty * d.net_rate) * \ (exchange_rate_map[d.purchase_invoice] - self.conversion_rate) - self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, discrepancy_caused_by_exchange_rate_difference, - remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, - account_currency=credit_currency, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=d.cost_center, + debit=0.0, + credit=discrepancy_caused_by_exchange_rate_difference, + remarks=remarks, + against_account=self.supplier, + debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=credit_currency, + item=d) - self.add_gl_entry(gl_entries, self.get_company_default("exchange_gain_loss_account"), d.cost_center, discrepancy_caused_by_exchange_rate_difference, 0.0, - remarks, self.supplier, debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, - account_currency=credit_currency, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=self.get_company_default("exchange_gain_loss_account"), + cost_center=d.cost_center, + debit=discrepancy_caused_by_exchange_rate_difference, + credit=0.0, + remarks=remarks, + against_account=self.supplier, + debit_in_account_currency=-1 * discrepancy_caused_by_exchange_rate_difference, + account_currency=credit_currency, + item=d) # Amount added through landed-cos-voucher if d.landed_cost_voucher_amount and landed_cost_entries: @@ -332,14 +364,31 @@ class PurchaseReceipt(BuyingController): credit_amount = (flt(amount["base_amount"]) if (amount["base_amount"] or account_currency!=self.company_currency) else flt(amount["amount"])) - self.add_gl_entry(gl_entries, account, d.cost_center, 0.0, credit_amount, remarks, - warehouse_account_name, credit_in_account_currency=flt(amount["amount"]), - account_currency=account_currency, project=d.project, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=d.cost_center, + debit=0.0, + credit=credit_amount, + remarks=remarks, + against_account=warehouse_account_name, + credit_in_account_currency=flt(amount["amount"]), + account_currency=account_currency, + project=d.project, + item=d) # sub-contracting warehouse if flt(d.rm_supp_cost) and warehouse_account.get(self.supplier_warehouse): - self.add_gl_entry(gl_entries, supplier_warehouse_account, d.cost_center, 0.0, flt(d.rm_supp_cost), - remarks, warehouse_account_name, account_currency=supplier_warehouse_account_currency, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=supplier_warehouse_account, + cost_center=d.cost_center, + debit=0.0, + credit=flt(d.rm_supp_cost), + remarks=remarks, + against_account=warehouse_account_name, + account_currency=supplier_warehouse_account_currency, + item=d) # divisional loss adjustment valuation_amount_as_per_doc = flt(d.base_net_amount, d.precision("base_net_amount")) + \ @@ -356,8 +405,17 @@ class PurchaseReceipt(BuyingController): cost_center = d.cost_center or frappe.get_cached_value("Company", self.company, "cost_center") - self.add_gl_entry(gl_entries, loss_account, cost_center, divisional_loss, 0.0, remarks, - warehouse_account_name, account_currency=credit_currency, project=d.project, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=loss_account, + cost_center=cost_center, + debit=divisional_loss, + credit=0.0, + remarks=remarks, + against_account=warehouse_account_name, + account_currency=credit_currency, + project=d.project, + item=d) elif d.warehouse not in warehouse_with_no_account or \ d.rejected_warehouse not in warehouse_with_no_account: @@ -368,12 +426,30 @@ class PurchaseReceipt(BuyingController): debit_currency = get_account_currency(d.expense_account) remarks = self.get("remarks") or _("Accounting Entry for Service") - self.add_gl_entry(gl_entries, service_received_but_not_billed_account, d.cost_center, 0.0, d.amount, - remarks, d.expense_account, account_currency=credit_currency, project=d.project, + self.add_gl_entry( + gl_entries=gl_entries, + account=service_received_but_not_billed_account, + cost_center=d.cost_center, + debit=0.0, + credit=d.amount, + remarks=remarks, + against_account=d.expense_account, + account_currency=credit_currency, + project=d.project, voucher_detail_no=d.name, item=d) - self.add_gl_entry(gl_entries, d.expense_account, d.cost_center, d.amount, 0.0, remarks, service_received_but_not_billed_account, - account_currency = debit_currency, project=d.project, voucher_detail_no=d.name, item=d) + self.add_gl_entry( + gl_entries=gl_entries, + account=d.expense_account, + cost_center=d.cost_center, + debit=d.amount, + credit=0.0, + remarks=remarks, + against_account=service_received_but_not_billed_account, + account_currency = debit_currency, + project=d.project, + voucher_detail_no=d.name, + item=d) if warehouse_with_no_account: frappe.msgprint(_("No accounting entries for the following warehouses") + ": \n" + @@ -423,8 +499,15 @@ class PurchaseReceipt(BuyingController): applicable_amount = negative_expense_to_be_booked * (valuation_tax[tax.name] / total_valuation_amount) amount_including_divisional_loss -= applicable_amount - self.add_gl_entry(gl_entries, account, tax.cost_center, 0.0, applicable_amount, self.remarks or _("Accounting Entry for Stock"), - against_account, item=tax) + self.add_gl_entry( + gl_entries=gl_entries, + account=account, + cost_center=tax.cost_center, + debit=0.0, + credit=applicable_amount, + remarks=self.remarks or _("Accounting Entry for Stock"), + against_account=against_account, + item=tax) i += 1 @@ -477,15 +560,31 @@ class PurchaseReceipt(BuyingController): # debit cwip account debit_in_account_currency = (base_asset_amount if cwip_account_currency == self.company_currency else asset_amount) - self.add_gl_entry(gl_entries, cwip_account, item.cost_center, base_asset_amount, 0.0, remarks, - arbnb_account, debit_in_account_currency=debit_in_account_currency, item=item) + self.add_gl_entry( + gl_entries=gl_entries, + account=cwip_account, + cost_center=item.cost_center, + debit=base_asset_amount, + credit=0.0, + remarks=remarks, + against_account=arbnb_account, + debit_in_account_currency=debit_in_account_currency, + item=item) asset_rbnb_currency = get_account_currency(arbnb_account) # credit arbnb account credit_in_account_currency = (base_asset_amount if asset_rbnb_currency == self.company_currency else asset_amount) - self.add_gl_entry(gl_entries, arbnb_account, item.cost_center, 0.0, base_asset_amount, remarks, - cwip_account, credit_in_account_currency=credit_in_account_currency, item=item) + self.add_gl_entry( + gl_entries=gl_entries, + account=arbnb_account, + cost_center=item.cost_center, + debit=0.0, + credit=base_asset_amount, + remarks=remarks, + against_account=cwip_account, + credit_in_account_currency=credit_in_account_currency, + item=item) def add_lcv_gl_entries(self, item, gl_entries): expenses_included_in_asset_valuation = self.get_company_default("expenses_included_in_asset_valuation") @@ -498,11 +597,27 @@ class PurchaseReceipt(BuyingController): remarks = self.get("remarks") or _("Accounting Entry for Stock") - self.add_gl_entry(gl_entries, expenses_included_in_asset_valuation, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount), - remarks, asset_account, project=item.project, item=item) + self.add_gl_entry( + gl_entries=gl_entries, + account=expenses_included_in_asset_valuation, + cost_center=item.cost_center, + debit=0.0, + credit=flt(item.landed_cost_voucher_amount), + remarks=remarks, + against_account=asset_account, + project=item.project, + item=item) - self.add_gl_entry(gl_entries, asset_account, item.cost_center, 0.0, flt(item.landed_cost_voucher_amount), - remarks, expenses_included_in_asset_valuation, project=item.project, item=item) + self.add_gl_entry( + gl_entries=gl_entries, + account=asset_account, + cost_center=item.cost_center, + debit=flt(item.landed_cost_voucher_amount), + credit=0.0, + remarks=remarks, + against_account=expenses_included_in_asset_valuation, + project=item.project, + item=item) def update_assets(self, item, valuation_rate): assets = frappe.db.get_all('Asset', From ef8539fd606b1fc00b0d5b3ea124b11df765e32e Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Mon, 9 Aug 2021 12:38:14 +0530 Subject: [PATCH 12/25] refactor: Selling Settings form cleanup (#26841) --- .../selling_settings/selling_settings.json | 61 +++++++++++++++---- 1 file changed, 50 insertions(+), 11 deletions(-) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index f01934b7e6b..717fd9b92e3 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -6,24 +6,31 @@ "document_type": "Other", "engine": "InnoDB", "field_order": [ + "customer_defaults_section", "cust_master_name", - "campaign_naming_by", "customer_group", + "column_break_4", "territory", - "selling_price_list", - "close_opportunity_after_days", + "crm_settings_section", + "campaign_naming_by", "default_valid_till", - "column_break_5", + "column_break_9", + "close_opportunity_after_days", + "item_price_settings_section", + "selling_price_list", + "column_break_15", + "maintain_same_sales_rate", + "maintain_same_rate_action", + "editable_price_list_rate", + "validate_selling_price", + "sales_transactions_settings_section", "so_required", "dn_required", "sales_update_frequency", - "maintain_same_sales_rate", - "maintain_same_rate_action", + "column_break_5", "role_to_override_stop_action", - "editable_price_list_rate", "allow_multiple_items", "allow_against_multiple_purchase_orders", - "validate_selling_price", "hide_tax_id" ], "fields": [ @@ -116,7 +123,7 @@ "default": "0", "fieldname": "allow_multiple_items", "fieldtype": "Check", - "label": "Allow Item to Be Added Multiple Times in a Transaction" + "label": "Allow Item to be Added Multiple Times in a Transaction" }, { "default": "0", @@ -142,7 +149,7 @@ "description": "Configure the action to stop the transaction or just warn if the same rate is not maintained.", "fieldname": "maintain_same_rate_action", "fieldtype": "Select", - "label": "Action If Same Rate is Not Maintained", + "label": "Action if Same Rate is Not Maintained", "mandatory_depends_on": "maintain_same_sales_rate", "options": "Stop\nWarn" }, @@ -152,6 +159,38 @@ "fieldtype": "Link", "label": "Role Allowed to Override Stop Action", "options": "Role" + }, + { + "fieldname": "customer_defaults_section", + "fieldtype": "Section Break", + "label": "Customer Defaults" + }, + { + "fieldname": "column_break_4", + "fieldtype": "Column Break" + }, + { + "fieldname": "crm_settings_section", + "fieldtype": "Section Break", + "label": "CRM Settings" + }, + { + "fieldname": "column_break_9", + "fieldtype": "Column Break" + }, + { + "fieldname": "item_price_settings_section", + "fieldtype": "Section Break", + "label": "Item Price Settings" + }, + { + "fieldname": "column_break_15", + "fieldtype": "Column Break" + }, + { + "fieldname": "sales_transactions_settings_section", + "fieldtype": "Section Break", + "label": "Transaction Settings" } ], "icon": "fa fa-cog", @@ -159,7 +198,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-04-04 20:18:12.814624", + "modified": "2021-08-06 22:25:50.119458", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", From 07337d5c78c14119ae9fc5d010080a1db61d0bdd Mon Sep 17 00:00:00 2001 From: Ankush Date: Mon, 9 Aug 2021 12:38:40 +0530 Subject: [PATCH 13/25] fix: validate python expressions (#26835) --- erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 5 +++-- .../item_quality_inspection_parameter.json | 5 +++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 428989aa965..0be41b40635 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -558,7 +558,8 @@ "description": "Simple Python Expression, Example: territory != 'All Territories'", "fieldname": "condition", "fieldtype": "Code", - "label": "Condition" + "label": "Condition", + "options": "PythonExpression" }, { "fieldname": "column_break_42", @@ -575,7 +576,7 @@ "icon": "fa fa-gift", "idx": 1, "links": [], - "modified": "2021-03-06 22:01:24.840422", + "modified": "2021-08-06 15:10:04.219321", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json index 9b1a47eed6c..5de45cbcad9 100644 --- a/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json +++ b/erpnext/stock/doctype/item_quality_inspection_parameter/item_quality_inspection_parameter.json @@ -47,7 +47,8 @@ "description": "Simple Python formula applied on Reading fields.
Numeric eg. 1: reading_1 > 0.2 and reading_1 < 0.5
\nNumeric eg. 2: mean > 3.5 (mean of populated fields)
\nValue based eg.: reading_value in (\"A\", \"B\", \"C\")", "fieldname": "acceptance_formula", "fieldtype": "Code", - "label": "Acceptance Criteria Formula" + "label": "Acceptance Criteria Formula", + "options": "PythonExpression" }, { "default": "0", @@ -89,7 +90,7 @@ "idx": 1, "istable": 1, "links": [], - "modified": "2021-02-04 18:50:02.056173", + "modified": "2021-08-06 15:08:20.911338", "modified_by": "Administrator", "module": "Stock", "name": "Item Quality Inspection Parameter", From b0f3c0f3fd86ed6d75e0234075402362b1941681 Mon Sep 17 00:00:00 2001 From: harshpwctech <84438948+harshpwctech@users.noreply.github.com> Date: Mon, 9 Aug 2021 13:42:05 +0530 Subject: [PATCH 14/25] fix: JWT decoding error (#26624) --- erpnext/regional/india/e_invoice/utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/regional/india/e_invoice/utils.py b/erpnext/regional/india/e_invoice/utils.py index f4976138ac8..4276946ebb3 100644 --- a/erpnext/regional/india/e_invoice/utils.py +++ b/erpnext/regional/india/e_invoice/utils.py @@ -928,7 +928,7 @@ class GSPConnector(): def set_einvoice_data(self, res): enc_signed_invoice = res.get('SignedInvoice') - dec_signed_invoice = jwt.decode(enc_signed_invoice, verify=False)['data'] + dec_signed_invoice = jwt.decode(enc_signed_invoice, options={"verify_signature": False})['data'] self.invoice.irn = res.get('Irn') self.invoice.ewaybill = res.get('EwbNo') @@ -1126,4 +1126,4 @@ def check_scheduler_status(): def job_already_enqueued(job_name): enqueued_jobs = [d.get("job_name") for d in get_info()] if job_name in enqueued_jobs: - return True \ No newline at end of file + return True From 9c04c297b8906978c5931223f1f56c75246e7709 Mon Sep 17 00:00:00 2001 From: Anupam Kumar Date: Mon, 9 Aug 2021 14:01:02 +0530 Subject: [PATCH 15/25] refactor: Accounts Settings form cleanup (#26842) --- .../doctype/accounts_settings/accounts_settings.json | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json index 703e93c0757..7bcc6ee53b3 100644 --- a/erpnext/accounts/doctype/accounts_settings/accounts_settings.json +++ b/erpnext/accounts/doctype/accounts_settings/accounts_settings.json @@ -10,6 +10,7 @@ "accounts_transactions_settings_section", "over_billing_allowance", "role_allowed_to_over_bill", + "credit_controller", "make_payment_via_journal_entry", "column_break_11", "check_supplier_invoice_uniqueness", @@ -27,7 +28,6 @@ "acc_frozen_upto", "frozen_accounts_modifier", "column_break_4", - "credit_controller", "deferred_accounting_settings_section", "book_deferred_entries_based_on", "column_break_18", @@ -73,11 +73,10 @@ "fieldtype": "Column Break" }, { - "description": "This role is allowed to submit transactions that exceed credit limits", "fieldname": "credit_controller", "fieldtype": "Link", "in_list_view": 1, - "label": "Credit Controller", + "label": "Role allowed to bypass Credit Limit", "options": "Role" }, { @@ -268,7 +267,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2021-06-17 20:26:03.721202", + "modified": "2021-08-09 13:08:01.335416", "modified_by": "Administrator", "module": "Accounts", "name": "Accounts Settings", From b3bbebd27c73827d5a88ff47d0d16fb73dcf6de2 Mon Sep 17 00:00:00 2001 From: Afshan <33727827+AfshanKhan@users.noreply.github.com> Date: Mon, 9 Aug 2021 14:39:32 +0530 Subject: [PATCH 16/25] fix: add parameter for db insert while adding item tax (#26855) --- erpnext/controllers/accounts_controller.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index bf4ab1a848f..9e2e5968c6d 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -1507,7 +1507,7 @@ def set_child_tax_template_and_map(item, child_item, parent_doc): if child_item.get("item_tax_template"): child_item.item_tax_rate = get_item_tax_map(parent_doc.get('company'), child_item.item_tax_template, as_json=True) -def add_taxes_from_tax_template(child_item, parent_doc): +def add_taxes_from_tax_template(child_item, parent_doc, db_insert=True): add_taxes_from_item_tax_template = frappe.db.get_single_value("Accounts Settings", "add_taxes_from_item_tax_template") if child_item.get("item_tax_rate") and add_taxes_from_item_tax_template: @@ -1530,7 +1530,8 @@ def add_taxes_from_tax_template(child_item, parent_doc): "category" : "Total", "add_deduct_tax" : "Add" }) - tax_row.db_insert() + if db_insert: + tax_row.db_insert() def set_order_defaults(parent_doctype, parent_doctype_name, child_doctype, child_docname, trans_item): """ From 42bb77bf80a494e6ed4fae35e1e283dbadf2c581 Mon Sep 17 00:00:00 2001 From: Anupam Date: Mon, 9 Aug 2021 15:11:13 +0530 Subject: [PATCH 17/25] fix: creating contact on creation of lead --- erpnext/crm/doctype/lead/lead.py | 58 +++++++++++++++++++++++++++++--- 1 file changed, 53 insertions(+), 5 deletions(-) diff --git a/erpnext/crm/doctype/lead/lead.py b/erpnext/crm/doctype/lead/lead.py index 49b682c12fd..7f028cb3160 100644 --- a/erpnext/crm/doctype/lead/lead.py +++ b/erpnext/crm/doctype/lead/lead.py @@ -63,6 +63,22 @@ class Lead(SellingController): def on_update(self): self.add_calendar_event() + def before_insert(self): + self.contact_doc = self.create_contact() + + def after_insert(self): + self.update_links() + + def update_links(self): + # update contact links + if self.contact_doc: + self.contact_doc.append("links", { + "link_doctype": "Lead", + "link_name": self.name, + "link_title": self.lead_name + }) + self.contact_doc.save() + def add_calendar_event(self, opts=None, force=False): super(Lead, self).add_calendar_event({ "owner": self.lead_owner, @@ -116,7 +132,6 @@ class Lead(SellingController): "party_name": self.name, "docstatus": 1, "status": ["!=", "Lost"] - }) def has_lost_quotation(self): @@ -137,10 +152,43 @@ class Lead(SellingController): self.lead_name = self.email_id.split("@")[0] def set_title(self): - if self.company_name: - self.title = self.company_name - else: - self.title = self.lead_name + self.title = self.company_name or self.lead_name + + def create_contact(self): + if not self.lead_name: + self.set_full_name() + self.set_lead_name() + + contact = frappe.new_doc("Contact") + contact.update({ + "first_name": self.first_name or self.lead_name, + "last_name": self.last_name, + "salutation": self.salutation, + "gender": self.gender, + "designation": self.designation, + }) + + if self.email_id: + contact.append("email_ids", { + "email_id": self.email_id, + "is_primary": 1 + }) + + if self.phone: + contact.append("phone_nos", { + "phone": self.phone, + "is_primary_phone": 1 + }) + + if self.mobile_no: + contact.append("phone_nos", { + "phone": self.mobile_no, + "is_primary_mobile_no":1 + }) + + contact.insert(ignore_permissions=True) + + return contact @frappe.whitelist() def make_customer(source_name, target_doc=None): From 7ba8c821a1659185df524c466fd8906d44649876 Mon Sep 17 00:00:00 2001 From: Ankush Date: Mon, 9 Aug 2021 15:14:26 +0530 Subject: [PATCH 18/25] test: fix flaky purchase receipt test (#26859) --- .../purchase_receipt/test_purchase_receipt.py | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py index bb4a710a046..d40d78184d5 100644 --- a/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py +++ b/erpnext/stock/doctype/purchase_receipt/test_purchase_receipt.py @@ -324,21 +324,8 @@ class TestPurchaseReceipt(unittest.TestCase): pr1.submit() self.assertRaises(frappe.ValidationError, pr2.submit) + frappe.db.rollback() - pr1.cancel() - se.cancel() - se1.cancel() - se2.cancel() - se3.cancel() - po.reload() - pr2.load_from_db() - - if pr2.docstatus == 1 and frappe.db.get_value('Stock Ledger Entry', - {'voucher_no': pr2.name, 'is_cancelled': 0}, 'name'): - pr2.cancel() - - po.load_from_db() - po.cancel() def test_serial_no_supplier(self): pr = make_purchase_receipt(item_code="_Test Serialized Item With Series", qty=1) From db3ee314138ee40653c562d89d5aff0764a03ad7 Mon Sep 17 00:00:00 2001 From: Anupam Date: Mon, 9 Aug 2021 15:34:50 +0530 Subject: [PATCH 19/25] fix: test case --- erpnext/crm/doctype/appointment/test_appointment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/crm/doctype/appointment/test_appointment.py b/erpnext/crm/doctype/appointment/test_appointment.py index bcab7bd7081..c7563e9d15b 100644 --- a/erpnext/crm/doctype/appointment/test_appointment.py +++ b/erpnext/crm/doctype/appointment/test_appointment.py @@ -9,7 +9,7 @@ import datetime def create_test_lead(): - test_lead = frappe.db.exists({'doctype': 'Lead', 'email':'test@example.com'}) + test_lead = frappe.db.exists({'doctype': 'Lead', 'email_id':'test@example.com'}) if test_lead: return frappe.get_doc('Lead', test_lead[0][0]) test_lead = frappe.get_doc({ From 458f7f119416d380a63fe69e8a2d74b25234c468 Mon Sep 17 00:00:00 2001 From: Ganga Manoj Date: Mon, 9 Aug 2021 17:16:48 +0530 Subject: [PATCH 20/25] patch: delete all orphaned tables docs (#26743) --- erpnext/patches.txt | 1 + .../patches/v13_0/delete_orphaned_tables.py | 69 +++++++++++++++++++ 2 files changed, 70 insertions(+) create mode 100644 erpnext/patches/v13_0/delete_orphaned_tables.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 04f05eda13d..30486242c1b 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -294,6 +294,7 @@ erpnext.patches.v13_0.update_level_in_bom #1234sswef erpnext.patches.v13_0.add_missing_fg_item_for_stock_entry erpnext.patches.v13_0.update_subscription_status_in_memberships erpnext.patches.v13_0.update_amt_in_work_order_required_items +erpnext.patches.v13_0.delete_orphaned_tables erpnext.patches.v13_0.update_export_type_for_gst erpnext.patches.v13_0.update_tds_check_field #3 erpnext.patches.v13_0.add_custom_field_for_south_africa diff --git a/erpnext/patches/v13_0/delete_orphaned_tables.py b/erpnext/patches/v13_0/delete_orphaned_tables.py new file mode 100644 index 00000000000..1d6eebe0398 --- /dev/null +++ b/erpnext/patches/v13_0/delete_orphaned_tables.py @@ -0,0 +1,69 @@ +# Copyright (c) 2019, Frappe and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from frappe.utils import getdate + +def execute(): + frappe.reload_doc('setup', 'doctype', 'transaction_deletion_record') + + if has_deleted_company_transactions(): + child_doctypes = get_child_doctypes_whose_parent_doctypes_were_affected() + + for doctype in child_doctypes: + docs = frappe.get_all(doctype, fields=['name', 'parent', 'parenttype', 'creation']) + + for doc in docs: + if not frappe.db.exists(doc['parenttype'], doc['parent']): + frappe.db.delete(doctype, {'name': doc['name']}) + + elif check_for_new_doc_with_same_name_as_deleted_parent(doc): + frappe.db.delete(doctype, {'name': doc['name']}) + +def has_deleted_company_transactions(): + return frappe.get_all('Transaction Deletion Record') + +def get_child_doctypes_whose_parent_doctypes_were_affected(): + parent_doctypes = get_affected_doctypes() + child_doctypes = frappe.get_all( + 'DocField', + filters={ + 'fieldtype': 'Table', + 'parent':['in', parent_doctypes] + }, pluck='options') + + return child_doctypes + +def get_affected_doctypes(): + affected_doctypes = [] + tdr_docs = frappe.get_all('Transaction Deletion Record', pluck="name") + + for tdr in tdr_docs: + tdr_doc = frappe.get_doc("Transaction Deletion Record", tdr) + + for doctype in tdr_doc.doctypes: + if is_not_child_table(doctype.doctype_name): + affected_doctypes.append(doctype.doctype_name) + + affected_doctypes = remove_duplicate_items(affected_doctypes) + return affected_doctypes + +def is_not_child_table(doctype): + return not bool(frappe.get_value('DocType', doctype, 'istable')) + +def remove_duplicate_items(affected_doctypes): + return list(set(affected_doctypes)) + +def check_for_new_doc_with_same_name_as_deleted_parent(doc): + """ + Compares creation times of parent and child docs. + Since Transaction Deletion Record resets the naming series after deletion, + it allows the creation of new docs with the same names as the deleted ones. + """ + + parent_creation_time = frappe.db.get_value(doc['parenttype'], doc['parent'], 'creation') + child_creation_time = doc['creation'] + + return getdate(parent_creation_time) > getdate(child_creation_time) \ No newline at end of file From 08ae49cd118bf24beff9908c162ae2abcb544337 Mon Sep 17 00:00:00 2001 From: Anuja Pawar <60467153+Anuja-pawar@users.noreply.github.com> Date: Mon, 9 Aug 2021 17:58:52 +0530 Subject: [PATCH 21/25] fix(regional): add permissions for VAT Audit report (#26851) fix(regional): add permissions for VAT Audit report --- erpnext/patches.txt | 2 +- .../add_custom_field_for_south_africa.py | 3 ++- .../vat_audit_report/vat_audit_report.json | 12 +--------- .../vat_audit_report/vat_audit_report.py | 22 ++++++++++++++++--- erpnext/regional/south_africa/setup.py | 20 ++++++++++++++--- 5 files changed, 40 insertions(+), 19 deletions(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 30486242c1b..35b248c08ed 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -297,5 +297,5 @@ erpnext.patches.v13_0.update_amt_in_work_order_required_items erpnext.patches.v13_0.delete_orphaned_tables erpnext.patches.v13_0.update_export_type_for_gst erpnext.patches.v13_0.update_tds_check_field #3 -erpnext.patches.v13_0.add_custom_field_for_south_africa +erpnext.patches.v13_0.add_custom_field_for_south_africa #2 erpnext.patches.v13_0.shopify_deprecation_warning diff --git a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py index f882fdedf38..73ff1cad5b6 100644 --- a/erpnext/patches/v13_0/add_custom_field_for_south_africa.py +++ b/erpnext/patches/v13_0/add_custom_field_for_south_africa.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from erpnext.regional.south_africa.setup import make_custom_fields +from erpnext.regional.south_africa.setup import make_custom_fields, add_permissions def execute(): company = frappe.get_all('Company', filters = {'country': 'South Africa'}) @@ -11,3 +11,4 @@ def execute(): return make_custom_fields() + add_permissions() diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.json b/erpnext/regional/report/vat_audit_report/vat_audit_report.json index 8917e8f3c7e..a8be7bf64c0 100644 --- a/erpnext/regional/report/vat_audit_report/vat_audit_report.json +++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.json @@ -18,15 +18,5 @@ "ref_doctype": "GL Entry", "report_name": "VAT Audit Report", "report_type": "Script Report", - "roles": [ - { - "role": "Accounts User" - }, - { - "role": "Accounts Manager" - }, - { - "role": "Auditor" - } - ] + "roles": [] } \ No newline at end of file diff --git a/erpnext/regional/report/vat_audit_report/vat_audit_report.py b/erpnext/regional/report/vat_audit_report/vat_audit_report.py index f45ba01dea5..292605ef13d 100644 --- a/erpnext/regional/report/vat_audit_report/vat_audit_report.py +++ b/erpnext/regional/report/vat_audit_report/vat_audit_report.py @@ -189,6 +189,8 @@ class VATAuditReport(object): row["posting_date"] = formatdate(inv_data.get("posting_date"), "dd-mm-yyyy") row["voucher_type"] = doctype row["voucher_no"] = inv + row["party_type"] = "Customer" if doctype == "Sales Invoice" else "Supplier" + row["party"] = inv_data.get("party") row["remarks"] = inv_data.get("remarks") row["gross_amount"]= item_details[0].get("gross_amount") row["tax_amount"]= item_details[0].get("tax_amount") @@ -226,6 +228,20 @@ class VATAuditReport(object): "options": "voucher_type", "width": 150 }, + { + "fieldname": "party_type", + "label": "Party Type", + "fieldtype": "Data", + "width": 140, + "hidden": 1 + }, + { + "fieldname": "party", + "label": "Party", + "fieldtype": "Dynamic Link", + "options": "party_type", + "width": 150 + }, { "fieldname": "remarks", "label": "Details", @@ -236,18 +252,18 @@ class VATAuditReport(object): "fieldname": "net_amount", "label": "Net Amount", "fieldtype": "Currency", - "width": 150 + "width": 130 }, { "fieldname": "tax_amount", "label": "Tax Amount", "fieldtype": "Currency", - "width": 150 + "width": 130 }, { "fieldname": "gross_amount", "label": "Gross Amount", "fieldtype": "Currency", - "width": 150 + "width": 130 }, ] diff --git a/erpnext/regional/south_africa/setup.py b/erpnext/regional/south_africa/setup.py index ac783b84884..4657ff833dd 100644 --- a/erpnext/regional/south_africa/setup.py +++ b/erpnext/regional/south_africa/setup.py @@ -3,11 +3,12 @@ from __future__ import unicode_literals -# import frappe, os, json +import frappe from frappe.custom.doctype.custom_field.custom_field import create_custom_fields from frappe.permissions import add_permission, update_permission_property def setup(company=None, patch=True): + make_custom_fields() add_permissions() def make_custom_fields(update=True): @@ -27,10 +28,23 @@ def make_custom_fields(update=True): create_custom_fields(custom_fields, update=update) def add_permissions(): - """Add Permissions for South Africa VAT Settings and South Africa VAT Account""" + """Add Permissions for South Africa VAT Settings and South Africa VAT Account + and VAT Audit Report""" for doctype in ('South Africa VAT Settings', 'South Africa VAT Account'): add_permission(doctype, 'All', 0) for role in ('Accounts Manager', 'Accounts User', 'System Manager'): add_permission(doctype, role, 0) update_permission_property(doctype, role, 0, 'write', 1) - update_permission_property(doctype, role, 0, 'create', 1) \ No newline at end of file + update_permission_property(doctype, role, 0, 'create', 1) + + + if not frappe.db.get_value('Custom Role', dict(report="VAT Audit Report")): + frappe.get_doc(dict( + doctype='Custom Role', + report="VAT Audit Report", + roles= [ + dict(role='Accounts User'), + dict(role='Accounts Manager'), + dict(role='Auditor') + ] + )).insert() \ No newline at end of file From 7e3dd9e8ee05611f5192a674a8ed6f87545ad389 Mon Sep 17 00:00:00 2001 From: Francisco Roldan Date: Mon, 9 Aug 2021 11:21:41 -0300 Subject: [PATCH 22/25] fix: depends_on in price list field --- .../accounts/doctype/subscription_plan/subscription_plan.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json index 46ce0939e4f..771611a7860 100644 --- a/erpnext/accounts/doctype/subscription_plan/subscription_plan.json +++ b/erpnext/accounts/doctype/subscription_plan/subscription_plan.json @@ -78,7 +78,7 @@ "label": "Cost" }, { - "depends_on": "eval:doc.price_determination==\"Based on price list\"", + "depends_on": "eval:doc.price_determination==\"Based On Price List\"", "fieldname": "price_list", "fieldtype": "Link", "label": "Price List", @@ -147,7 +147,7 @@ } ], "links": [], - "modified": "2020-06-25 10:53:44.205774", + "modified": "2021-08-09 10:53:44.205774", "modified_by": "Administrator", "module": "Accounts", "name": "Subscription Plan", From 5e428f0447e2b0de930efe0f7924090e54543045 Mon Sep 17 00:00:00 2001 From: Ankush Date: Mon, 9 Aug 2021 22:15:49 +0530 Subject: [PATCH 23/25] perf(cache): fix active SLA doctype caching (#26861) If no SLA is configured then this query runs on EVERY `validate` call. Root cause: if not active SLA doctypes exist then `not []` evalutes to true and causes query to run again. --- .../service_level_agreement/service_level_agreement.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py index 8739cb2364c..cfa264feb54 100644 --- a/erpnext/support/doctype/service_level_agreement/service_level_agreement.py +++ b/erpnext/support/doctype/service_level_agreement/service_level_agreement.py @@ -281,15 +281,18 @@ def get_repeated(values): def get_documents_with_active_service_level_agreement(): - if not frappe.cache().hget("service_level_agreement", "active"): - set_documents_with_active_service_level_agreement() + sla_doctypes = frappe.cache().hget("service_level_agreement", "active") - return frappe.cache().hget("service_level_agreement", "active") + if sla_doctypes is None: + return set_documents_with_active_service_level_agreement() + + return sla_doctypes def set_documents_with_active_service_level_agreement(): active = [sla.document_type for sla in frappe.get_all("Service Level Agreement", fields=["document_type"])] frappe.cache().hset("service_level_agreement", "active", active) + return active def apply(doc, method=None): From 8db0f07115676c63c40c38d092ca352a794d0f67 Mon Sep 17 00:00:00 2001 From: Subin Tom <36098155+nemesis189@users.noreply.github.com> Date: Tue, 10 Aug 2021 11:43:43 +0530 Subject: [PATCH 24/25] fix: Missing method reset_issue_metrics added back to Issue doctype (#26573) --- erpnext/support/doctype/issue/issue.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/support/doctype/issue/issue.py b/erpnext/support/doctype/issue/issue.py index b9a65b6749e..24dadd5a8c6 100644 --- a/erpnext/support/doctype/issue/issue.py +++ b/erpnext/support/doctype/issue/issue.py @@ -116,6 +116,10 @@ class Issue(Document): }).insert(ignore_permissions=True) return replicated_issue.name + + def reset_issue_metrics(self): + self.db_set("resolution_time", None) + self.db_set("user_resolution_time", None) def get_list_context(context=None): return { From 94beda65ca01724fb3d0d2b57190672083740c61 Mon Sep 17 00:00:00 2001 From: Anurag Mishra <32095923+Anurag810@users.noreply.github.com> Date: Tue, 10 Aug 2021 13:16:46 +0530 Subject: [PATCH 25/25] fix: updating lead status while customer creation (#26606) * fix: updating lead status while customer creation * fix: changes requested --- erpnext/selling/doctype/customer/customer.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 66edcd01886..abf146c43f4 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -157,9 +157,7 @@ class Customer(TransactionBase): '''If Customer created from Lead, update lead status to "Converted" update Customer link in Quotation, Opportunity''' if self.lead_name: - lead = frappe.get_doc('Lead', self.lead_name) - lead.status = 'Converted' - lead.save() + frappe.db.set_value("Lead", self.lead_name, "status", "Converted") def create_lead_address_contact(self): if self.lead_name: