feat: address autocomplete (first draft)
This commit is contained in:
parent
bef9bdc5ee
commit
57d7b9ca40
8 changed files with 183 additions and 0 deletions
|
|
@ -0,0 +1,8 @@
|
|||
// Copyright (c) 2024, Frappe Technologies and contributors
|
||||
// For license information, please see license.txt
|
||||
|
||||
// frappe.ui.form.on("Address Autocomplete Settings", {
|
||||
// refresh(frm) {
|
||||
|
||||
// },
|
||||
// });
|
||||
|
|
@ -0,0 +1,52 @@
|
|||
{
|
||||
"actions": [],
|
||||
"creation": "2024-04-09 23:41:49.747820",
|
||||
"doctype": "DocType",
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"enabled",
|
||||
"provider",
|
||||
"api_key"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "provider",
|
||||
"fieldtype": "Select",
|
||||
"label": "Provider",
|
||||
"options": "Geoapify"
|
||||
},
|
||||
{
|
||||
"fieldname": "api_key",
|
||||
"fieldtype": "Password",
|
||||
"label": "Api Key"
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"fieldname": "enabled",
|
||||
"fieldtype": "Check",
|
||||
"label": "Enabled"
|
||||
}
|
||||
],
|
||||
"issingle": 1,
|
||||
"links": [],
|
||||
"modified": "2024-04-09 23:43:27.454479",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Integrations",
|
||||
"name": "Address Autocomplete Settings",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"email": 1,
|
||||
"print": 1,
|
||||
"read": 1,
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
# Copyright (c) 2024, Frappe Technologies and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
import frappe
|
||||
from frappe.model.document import Document
|
||||
|
||||
from .providers.geoapify import GeoapifyProvider
|
||||
|
||||
|
||||
class AddressAutocompleteSettings(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
api_key: DF.Password | None
|
||||
enabled: DF.Check
|
||||
provider: DF.Literal["Geoapify"]
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
|
||||
|
||||
@frappe.whitelist()
|
||||
def autocomplete(txt: str) -> list[dict]:
|
||||
if not txt:
|
||||
return []
|
||||
|
||||
settings = frappe.get_single("Address Autocomplete Settings")
|
||||
if not settings.enabled:
|
||||
return []
|
||||
|
||||
if settings.provider == "Geoapify":
|
||||
provider = GeoapifyProvider(settings.get_password("api_key"), frappe.local.lang)
|
||||
return provider.autocomplete(txt)
|
||||
|
||||
frappe.throw("Invalid provider")
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
import requests
|
||||
|
||||
|
||||
class GeoapifyProvider:
|
||||
def __init__(self, api_key: str, lang: str | None = None):
|
||||
self.api_key = api_key
|
||||
self.lang = lang
|
||||
self.base_url = "https://api.geoapify.com"
|
||||
|
||||
def autocomplete(self, query: str) -> list[dict]:
|
||||
params = {
|
||||
"text": query,
|
||||
"apiKey": self.api_key,
|
||||
"limit": 20,
|
||||
"format": "json",
|
||||
"lang": self.lang,
|
||||
}
|
||||
response = requests.get(f"{self.base_url}/v1/geocode/autocomplete", params=params)
|
||||
response.raise_for_status()
|
||||
|
||||
results = response.json()["results"]
|
||||
# TODO: need to return the full address data here, as value or extra data
|
||||
return [
|
||||
{
|
||||
"label": result["formatted"],
|
||||
"value": result["place_id"],
|
||||
}
|
||||
for result in results
|
||||
]
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
# Copyright (c) 2024, Frappe Technologies and Contributors
|
||||
# See license.txt
|
||||
|
||||
# import frappe
|
||||
from frappe.tests.utils import FrappeTestCase
|
||||
|
||||
|
||||
class TestAddressAutocompleteSettings(FrappeTestCase):
|
||||
pass
|
||||
|
|
@ -108,3 +108,5 @@ import "./frappe/ui/chart.js";
|
|||
import "./frappe/ui/datatable.js";
|
||||
import "./frappe/ui/driver.js";
|
||||
import "./frappe/scanner";
|
||||
|
||||
import "./frappe/ui/address_autocomplete/autocomplete_dialog.js";
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
frappe.provide("frappe.ui");
|
||||
|
||||
frappe.ui.AddressAutocompleteDialog = class AddressAutocompleteDialog {
|
||||
constructor(opts) {
|
||||
this.title = opts?.title || __("New Address");
|
||||
this.link_doctype = opts?.link_doctype;
|
||||
this.link_name = opts?.link_name;
|
||||
this.dialog = this._get_dialog();
|
||||
}
|
||||
|
||||
_get_dialog() {
|
||||
// sourcery skip: inline-immediately-returned-variable
|
||||
const dialog = new frappe.ui.Dialog({
|
||||
title: this.title,
|
||||
fields: [
|
||||
{
|
||||
fieldname: "search",
|
||||
fieldtype: "Autocomplete",
|
||||
label: __("Search"),
|
||||
reqd: 1,
|
||||
get_query:
|
||||
"frappe.integrations.doctype.address_autocomplete_settings.address_autocomplete_settings.autocomplete",
|
||||
},
|
||||
],
|
||||
primary_action_label: __("Save Address"),
|
||||
primary_action: () => {
|
||||
dialog.hide();
|
||||
// TODO: save the selected address to the database
|
||||
},
|
||||
secondary_action_label: __("Edit Address"),
|
||||
secondary_action: () => {
|
||||
dialog.hide();
|
||||
// TODO: open the selected address in the address form
|
||||
},
|
||||
});
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
show() {
|
||||
this.dialog.show();
|
||||
}
|
||||
};
|
||||
Loading…
Add table
Reference in a new issue