From b53203e14c7cc57ba2914d99b0257931c75b2761 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Sun, 16 Jun 2024 17:49:16 +0200 Subject: [PATCH] feat: download Contact as vCard --- frappe/contacts/doctype/contact/contact.js | 11 +++++ frappe/contacts/doctype/contact/contact.py | 50 ++++++++++++++++++++++ pyproject.toml | 1 + 3 files changed, 62 insertions(+) diff --git a/frappe/contacts/doctype/contact/contact.js b/frappe/contacts/doctype/contact/contact.js index f1a40e106f..71571c79e5 100644 --- a/frappe/contacts/doctype/contact/contact.js +++ b/frappe/contacts/doctype/contact/contact.js @@ -88,6 +88,17 @@ frappe.ui.form.on("Contact", { ); } } + + if (!frm.is_dirty()) { + frm.page.add_menu_item(__("Download vCard"), function () { + window.open( + `/api/method/frappe.contacts.doctype.contact.contact.download_vcard?contact=${encodeURIComponent( + frm.doc.name + )}`, + "_blank" + ); + }); + } }, validate: function (frm) { // clear linked customer / supplier / sales partner on saving... diff --git a/frappe/contacts/doctype/contact/contact.py b/frappe/contacts/doctype/contact/contact.py index 2aa497b6b4..7564de029d 100644 --- a/frappe/contacts/doctype/contact/contact.py +++ b/frappe/contacts/doctype/contact/contact.py @@ -167,6 +167,56 @@ class Contact(Document): def _get_full_name(self) -> str: return get_full_name(self.first_name, self.middle_name, self.last_name, self.company_name) + def get_vcard(self): + from vobject import vCard + from vobject.vcard import Name + + vcard = vCard() + vcard.add("fn").value = self.full_name + + name = Name() + if self.first_name: + name.given = self.first_name + + if self.last_name: + name.family = self.last_name + + if self.middle_name: + name.additional = self.middle_name + + vcard.add("n").value = name + + if self.designation: + vcard.add("title").value = self.designation + + for row in self.email_ids: + email = vcard.add("email") + email.value = row.email_id + if row.is_primary: + email.type_param = "pref" + + for row in self.phone_nos: + tel = vcard.add("tel") + tel.value = row.phone + if row.is_primary_phone: + tel.type_param = "home" + + if row.is_primary_mobile_no: + tel.type_param = "cell" + + return vcard + + +@frappe.whitelist() +def download_vcard(contact: str): + """Download vCard for the contact""" + contact = frappe.get_doc("Contact", contact) + vcard = contact.get_vcard() + + frappe.response["filename"] = f"{contact.name}.vcf" + frappe.response["filecontent"] = vcard.serialize().encode("utf-8") + frappe.response["type"] = "binary" + def get_default_contact(doctype, name): """Return default contact for the given doctype, name.""" diff --git a/pyproject.toml b/pyproject.toml index 67d98546e1..79c4d519b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -86,6 +86,7 @@ dependencies = [ "google-auth-oauthlib~=0.4.4", "google-auth~=1.29.0", "posthog~=3.0.1", + "vobject~=0.9.7", ] [project.urls]