New Report Address and Contacts (#14307)
* New Report Address and Contacts
* Fix codacy
* Add links to report in module pages
diff --git a/erpnext/config/accounts.py b/erpnext/config/accounts.py
index 636c160..a534421 100644
--- a/erpnext/config/accounts.py
+++ b/erpnext/config/accounts.py
@@ -459,6 +459,12 @@
"is_query_report": True,
"name": "Sales Payment Summary",
"doctype": "Sales Invoice"
+ },
+ {
+ "type": "report",
+ "is_query_report": True,
+ "name": "Address And Contacts",
+ "doctype": "Address"
}
]
},
diff --git a/erpnext/config/buying.py b/erpnext/config/buying.py
index e20d514..270519e 100644
--- a/erpnext/config/buying.py
+++ b/erpnext/config/buying.py
@@ -198,13 +198,13 @@
{
"type": "report",
"is_query_report": True,
- "name": "Addresses And Contacts",
+ "name": "Address And Contacts",
"label": "Supplier Addresses And Contacts",
"doctype": "Address",
"route_options": {
"party_type": "Supplier"
}
- },
+ }
]
},
{
diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py
index 496617a..029fdac 100644
--- a/erpnext/config/selling.py
+++ b/erpnext/config/selling.py
@@ -120,7 +120,7 @@
{
"type": "report",
"is_query_report": True,
- "name": "Addresses And Contacts",
+ "name": "Address And Contacts",
"label": _("Sales Partner Addresses And Contacts"),
"doctype": "Address",
"route_options": {
@@ -230,7 +230,7 @@
{
"type": "report",
"is_query_report": True,
- "name": "Addresses And Contacts",
+ "name": "Address And Contacts",
"label": _("Customer Addresses And Contacts"),
"doctype": "Address",
"route_options": {
diff --git a/erpnext/selling/report/address_and_contacts/__init__.py b/erpnext/selling/report/address_and_contacts/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/erpnext/selling/report/address_and_contacts/__init__.py
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.js b/erpnext/selling/report/address_and_contacts/address_and_contacts.js
new file mode 100644
index 0000000..383f18b
--- /dev/null
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.js
@@ -0,0 +1,34 @@
+// Copyright (c) 2016, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+/* eslint-disable */
+
+frappe.query_reports["Address And Contacts"] = {
+ "filters": [
+ {
+ "reqd": 1,
+ "fieldname":"party_type",
+ "label": __("Party Type"),
+ "fieldtype": "Link",
+ "options": "DocType",
+ "get_query": function() {
+ return {
+ "filters": {
+ "name": ["in","Customer,Supplier,Sales Partner"],
+ }
+ }
+ }
+ },
+ {
+ "fieldname":"party_name",
+ "label": __("Party Name"),
+ "fieldtype": "Dynamic Link",
+ "get_options": function() {
+ let party_type = frappe.query_report_filters_by_name.party_type.get_value();
+ if(!party_type) {
+ frappe.throw(__("Please select Party Type first"));
+ }
+ return party_type;
+ }
+ }
+ ]
+}
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.json b/erpnext/selling/report/address_and_contacts/address_and_contacts.json
new file mode 100644
index 0000000..da38bab
--- /dev/null
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.json
@@ -0,0 +1,33 @@
+{
+ "add_total_row": 0,
+ "apply_user_permissions": 1,
+ "creation": "2018-06-01 09:32:13.088771",
+ "disabled": 0,
+ "docstatus": 0,
+ "doctype": "Report",
+ "idx": 0,
+ "is_standard": "Yes",
+ "letter_head": "Test",
+ "modified": "2018-06-01 09:39:39.604944",
+ "modified_by": "Administrator",
+ "module": "Selling",
+ "name": "Address And Contacts",
+ "owner": "Administrator",
+ "ref_doctype": "Address",
+ "report_name": "Address And Contacts",
+ "report_type": "Script Report",
+ "roles": [
+ {
+ "role": "Sales User"
+ },
+ {
+ "role": "Purchase User"
+ },
+ {
+ "role": "Maintenance User"
+ },
+ {
+ "role": "Accounts User"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/erpnext/selling/report/address_and_contacts/address_and_contacts.py b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
new file mode 100644
index 0000000..0a46d2c
--- /dev/null
+++ b/erpnext/selling/report/address_and_contacts/address_and_contacts.py
@@ -0,0 +1,120 @@
+# Copyright (c) 2013, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from six.moves import range
+from six import iteritems
+import frappe
+
+
+field_map = {
+ "Contact": [ "first_name", "last_name", "phone", "mobile_no", "email_id", "is_primary_contact" ],
+ "Address": [ "address_line1", "address_line2", "city", "state", "pincode", "country", "is_primary_address" ]
+}
+
+def execute(filters=None):
+ columns, data = get_columns(filters), get_data(filters)
+ return columns, data
+
+def get_columns(filters):
+ party_type = filters.get("party_type")
+ party_type_value = get_party_group(party_type)
+ return [
+ "{party_type}:Link/{party_type}".format(party_type=party_type),
+ "{party_value_type}::150".format(party_value_type = frappe.unscrub(str(party_type_value))),
+ "Address Line 1",
+ "Address Line 2",
+ "City",
+ "State",
+ "Postal Code",
+ "Country",
+ "Is Primary Address:Check",
+ "First Name",
+ "Last Name",
+ "Phone",
+ "Mobile No",
+ "Email Id",
+ "Is Primary Contact:Check"
+ ]
+
+def get_data(filters):
+ party_type = filters.get("party_type")
+ party = filters.get("party_name")
+ party_group = get_party_group(party_type)
+
+ return get_party_addresses_and_contact(party_type, party, party_group)
+
+def get_party_addresses_and_contact(party_type, party, party_group):
+ data = []
+ filters = None
+ party_details = frappe._dict()
+
+ if not party_type:
+ return []
+
+ if party:
+ filters = { "name": party }
+
+ fetch_party_list = frappe.get_list(party_type, filters=filters, fields=["name", party_group], as_list=True)
+ party_list = [d[0] for d in fetch_party_list]
+ party_groups = {}
+ for d in fetch_party_list:
+ party_groups[d[0]] = d[1]
+
+ for d in party_list:
+ party_details.setdefault(d, frappe._dict())
+
+ party_details = get_party_details(party_type, party_list, "Address", party_details)
+ party_details = get_party_details(party_type, party_list, "Contact", party_details)
+
+ for party, details in iteritems(party_details):
+ addresses = details.get("address", [])
+ contacts = details.get("contact", [])
+ if not any([addresses, contacts]):
+ result = [party]
+ result.append(party_groups[party])
+ result.extend(add_blank_columns_for("Contact"))
+ result.extend(add_blank_columns_for("Address"))
+ data.append(result)
+ else:
+ addresses = map(list, addresses)
+ contacts = map(list, contacts)
+
+ max_length = max(len(addresses), len(contacts))
+ for idx in range(0, max_length):
+ result = [party]
+ result.append(party_groups[party])
+ address = addresses[idx] if idx < len(addresses) else add_blank_columns_for("Address")
+ contact = contacts[idx] if idx < len(contacts) else add_blank_columns_for("Contact")
+ result.extend(address)
+ result.extend(contact)
+
+ data.append(result)
+ return data
+
+def get_party_details(party_type, party_list, doctype, party_details):
+ filters = [
+ ["Dynamic Link", "link_doctype", "=", party_type],
+ ["Dynamic Link", "link_name", "in", party_list]
+ ]
+ fields = ["`tabDynamic Link`.link_name"] + field_map.get(doctype, [])
+
+ records = frappe.get_list(doctype, filters=filters, fields=fields, as_list=True)
+ for d in records:
+ details = party_details.get(d[0])
+ details.setdefault(frappe.scrub(doctype), []).append(d[1:])
+
+ return party_details
+
+def add_blank_columns_for(doctype):
+ return ["" for field in field_map.get(doctype, [])]
+
+def get_party_group(party_type):
+ if not party_type: return
+ group = {
+ "Customer": "customer_group",
+ "Supplier": "supplier_group",
+ "Sales Partner": "partner_type"
+ }
+
+ return group[party_type]
\ No newline at end of file