Skip to content

Commit 8a0e149

Browse files
committed
init
1 parent e67513c commit 8a0e149

File tree

16 files changed

+274
-231
lines changed

16 files changed

+274
-231
lines changed
File renamed without changes.
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"custom_fields": [
3+
{
4+
"dt": "Address",
5+
"fieldname": "geolocation",
6+
"fieldtype": "Section Break",
7+
"insert_after": "links",
8+
"label": "Location"
9+
},
10+
{
11+
"dt": "Address",
12+
"fieldname": "location",
13+
"fieldtype": "Geolocation",
14+
"insert_after": "geolocation",
15+
"label": "Map"
16+
},
17+
{
18+
"dt": "Address",
19+
"fieldname": "latitude",
20+
"fieldtype": "Float",
21+
"hidden": 1,
22+
"insert_after": "location",
23+
"label": "Latitude",
24+
"precision": "6"
25+
},
26+
{
27+
"dt": "Address",
28+
"fieldname": "longitude",
29+
"fieldtype": "Float",
30+
"hidden": 1,
31+
"insert_after": "latitude",
32+
"label": "Longitude",
33+
"precision": "6"
34+
}
35+
],
36+
"property_setters": [],
37+
"sync_on_migrate": 1,
38+
"doctype": "Address"
39+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
{
2+
"custom_fields": [
3+
{
4+
"dt": "Customer",
5+
"depends_on": "eval:doc.customer_primary_contact",
6+
"fetch_from": "customer_primary_contact.phone",
7+
"fetch_if_empty": 1,
8+
"fieldname": "contact_phone",
9+
"fieldtype": "Read Only",
10+
"insert_after": "customer_primary_contact",
11+
"label": "Phone",
12+
"module": "erpnext_cis_plus"
13+
},
14+
{
15+
"dt": "Customer",
16+
"depends_on": "eval:doc.customer_primary_address",
17+
"fetch_from": "customer_primary_address.email_id",
18+
"fetch_if_empty": 1,
19+
"fieldname": "customer_email_address",
20+
"fieldtype": "Read Only",
21+
"insert_after": "primary_address",
22+
"label": "Customer Email Address",
23+
"module": "erpnext_cis_plus"
24+
},
25+
{
26+
"dt": "Customer",
27+
"depends_on": "eval:doc.customer_primary_address",
28+
"fetch_from": "customer_primary_address.phone",
29+
"fetch_if_empty": 1,
30+
"fieldname": "customer_phone",
31+
"fieldtype": "Read Only",
32+
"insert_after": "customer_email_address",
33+
"label": "Customer Phone",
34+
"module": "erpnext_cis_plus"
35+
},
36+
{
37+
"dt": "Customer",
38+
"depends_on": "eval:doc.customer_primary_address",
39+
"fetch_from": "customer_primary_address.fax",
40+
"fetch_if_empty": 1,
41+
"fieldname": "customer_fax",
42+
"fieldtype": "Read Only",
43+
"insert_after": "customer_fax",
44+
"label": "Customer Fax",
45+
"module": "erpnext_cis_plus"
46+
},
47+
{
48+
"dt": "Customer",
49+
"depends_on": "eval:doc.customer_primary_address",
50+
"fieldname": "geolocation",
51+
"fieldtype": "Section Break",
52+
"insert_after": "email_id",
53+
"label": "Location",
54+
"module": "erpnext_cis_plus"
55+
},
56+
{
57+
"dt": "Customer",
58+
"fetch_from": "customer_primary_address.latitude",
59+
"fetch_if_empty": 1,
60+
"fieldname": "latitude",
61+
"fieldtype": "Float",
62+
"hidden": 1,
63+
"insert_after": "geolocation",
64+
"label": "Latitude",
65+
"module": "erpnext_cis_plus",
66+
"precision": "6",
67+
"read_only": 1
68+
},
69+
{
70+
"dt": "Customer",
71+
"fetch_from": "customer_primary_address.longitude",
72+
"fetch_if_empty": 1,
73+
"fieldname": "longitude",
74+
"fieldtype": "Float",
75+
"hidden": 1,
76+
"insert_after": "latitude",
77+
"label": "Longitude",
78+
"module": "erpnext_cis_plus",
79+
"precision": "6",
80+
"read_only": 1
81+
},
82+
{
83+
"dt": "Customer",
84+
"fetch_from": "customer_primary_address.location",
85+
"fetch_if_empty": 1,
86+
"fieldname": "location",
87+
"fieldtype": "Geolocation",
88+
"insert_after": "longitude",
89+
"label": "Map",
90+
"module": "erpnext_cis_plus",
91+
"read_only": 1
92+
}
93+
],
94+
"property_setters": [],
95+
"sync_on_migrate": 1,
96+
"doctype": "Customer"
97+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# Copyright (c) 2024, Avunu LLC and contributors
2+
# For license information, please see license.txt
3+
4+
import frappe
5+
import json
6+
from nominatim import Nominatim
7+
8+
@frappe.whitelist()
9+
def geolocate_address(doc, method=None):
10+
"""
11+
Get coordinates from address
12+
"""
13+
# check if address is already geocoded
14+
if doc.latitude and doc.longitude and doc.pincode:
15+
return doc
16+
fields = ["address_line1", "city", "state", "country"]
17+
# check if address is empty
18+
if not any([doc.get(f) for f in fields]):
19+
return doc
20+
address_string = ", ".join([doc.get(f) for f in fields if doc.get(f)])
21+
try:
22+
geolocator = Nominatim()
23+
geolocation = geolocator.query(address_string)
24+
except Exception as e:
25+
frappe.throw(e)
26+
# check if geolocation contains a result
27+
if not geolocation:
28+
frappe.log_error("Geolocation Error", "No geolocation found for address: {0}".format(address_string))
29+
return doc
30+
geolocation = geolocation[0]
31+
if geolocation:
32+
lat = geolocation['lat']
33+
lng = geolocation['lon']
34+
if lat and lng:
35+
doc.latitude = lat
36+
doc.longitude = lng
37+
# parse address components
38+
components = geolocation['display_name'].split(', ')
39+
doc.pincode = components[-2]
40+
doc.state = components[-3]
41+
if not doc.country:
42+
doc.country = components[-1]
43+
if not doc.county:
44+
doc.county = components[-4]
45+
return doc
46+
47+
@frappe.whitelist()
48+
def generate_point(doc, method=None):
49+
if doc.latitude and doc.longitude:
50+
doc.location = json.dumps({
51+
"type": "FeatureCollection",
52+
"features": [{
53+
"type": "Feature",
54+
"properties": {
55+
"point_type": "Point"
56+
},
57+
"geometry": {
58+
"type": "Point",
59+
"coordinates": [doc.longitude, doc.latitude]
60+
}
61+
}]
62+
})
63+
return doc
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Copyright (c) 2024, Avunu LLC and contributors
2+
# For license information, please see license.txt
3+
4+
import frappe
5+
6+
# Get a list of coordinates for the map view
7+
@frappe.whitelist()
8+
def get_coords(filters):
9+
popup_template = """
10+
<div class="map-popup">
11+
<strong>{{ frappe.utils.get_link_to_form('Customer', name, customer_name) }}</strong>
12+
{% if customer_primary_contact %}
13+
<p>{{ frappe.utils.get_link_to_form('Contact', customer_primary_contact) }}</p>
14+
{% endif %}
15+
<p>{{ primary_address }}</p>
16+
</div>
17+
"""
18+
filters = frappe.parse_json(filters)
19+
doctype = "Customer"
20+
customers = frappe.get_all(doctype, filters=filters, fields=["name", "customer_name", "customer_primary_contact", "primary_address", "latitude", "longitude"])
21+
geojson = {"type": "FeatureCollection", "features": None}
22+
features = []
23+
for customer in customers:
24+
if customer.latitude and customer.longitude:
25+
popup_contents = frappe.render_template(popup_template, customer)
26+
features.append({
27+
"type": "Feature",
28+
"properties": {
29+
"name": popup_contents
30+
},
31+
"geometry": {
32+
"type": "Point",
33+
"coordinates": [customer.longitude, customer.latitude]
34+
}
35+
})
36+
geojson["features"] = features
37+
return geojson
38+

erpnext_cis_plus/hooks.py

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
app_name = "erpnext_cis_plus"
2+
app_title = "ERPNext Customer Plus"
3+
app_publisher = "Avunu LLC"
4+
app_description = "Various enhancements to the customer, contact, and address management for ERPNext."
5+
app_email = "[email protected]"
6+
app_license = "mit"
7+
required_apps = ["erpnext"]
8+
9+
# Includes in <head>
10+
# ------------------
11+
12+
# include js in doctype views
13+
doctype_js = {"Customer" : "public/js/customer.js"}
14+
doctype_list_js = {"Customer" : "public/js/customer_list.js"}
15+
16+
# Document Events
17+
# ---------------
18+
# Hook on document methods and events
19+
20+
doc_events = {
21+
"Address": {
22+
"before_save": "erpnext_cis_plus.erpnext_cis_plus.hooks.address.generate_point",
23+
"validate": "erpnext_cis_plus.erpnext_cis_plus.hooks.address.geolocate_address"
24+
},
25+
# "Customer": {
26+
# "before_save": "erpnext_cis_plus.erpnext_cis_plus.hooks.customer.validate"
27+
# }
28+
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// Copyright (c) 2023, Avunu LLC and contributors
2+
// For license information, please see license.txt
3+
4+
// add a settings.get_coords_method to this list view
5+
frappe.listview_settings['Customer'] = {
6+
get_coords_method: 'erpnext_cis_plus.erpnext_cis_plus.hooks.customer.get_coords'
7+
};

0 commit comments

Comments
 (0)