diff --git a/westech_r2/doctype/customer_interaction/__init__.py b/westech_r2/doctype/customer_interaction/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/westech_r2/doctype/customer_interaction/customer_interaction.js b/westech_r2/doctype/customer_interaction/customer_interaction.js new file mode 100644 index 0000000..c66bd61 --- /dev/null +++ b/westech_r2/doctype/customer_interaction/customer_interaction.js @@ -0,0 +1,8 @@ +// Copyright (c) 2026, Westech and contributors +// For license information, please see license.txt + +// frappe.ui.form.on("Customer Interaction", { +// refresh(frm) { + +// }, +// }); diff --git a/westech_r2/doctype/customer_interaction/customer_interaction.json b/westech_r2/doctype/customer_interaction/customer_interaction.json new file mode 100644 index 0000000..e1c711d --- /dev/null +++ b/westech_r2/doctype/customer_interaction/customer_interaction.json @@ -0,0 +1,147 @@ +{ + "actions": [], + "autoname": "autoincrement", + "creation": "2026-05-22 11:58:31.649154", + "doctype": "DocType", + "editable_grid": 1, + "engine": "InnoDB", + "field_order": [ + "customer", + "customer_number", + "contact_name", + "phone_1", + "phone_2", + "email_1", + "email_2", + "address", + "city", + "zip", + "hours", + "notes", + "red_r2", + "dnc", + "raw_name", + "raw_phone1", + "raw_phone2", + "raw_email" + ], + "fields": [ + { + "fieldname": "customer", + "fieldtype": "Link", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Customer", + "options": "Customer", + "reqd": 1 + }, + { + "fieldname": "customer_number", + "fieldtype": "Data", + "in_list_view": 1, + "in_standard_filter": 1, + "label": "Customer Number" + }, + { + "fieldname": "contact_name", + "fieldtype": "Data", + "in_list_view": 1, + "label": "Contact Name" + }, + { + "fieldname": "phone_1", + "fieldtype": "Data", + "label": "Phone 1" + }, + { + "fieldname": "phone_2", + "fieldtype": "Data", + "label": "Phone 2" + }, + { + "fieldname": "email_1", + "fieldtype": "Data", + "label": "Email 1" + }, + { + "fieldname": "email_2", + "fieldtype": "Data", + "label": "Email 2" + }, + { + "fieldname": "address", + "fieldtype": "Text", + "label": "Address" + }, + { + "fieldname": "city", + "fieldtype": "Data", + "label": "City" + }, + { + "fieldname": "zip", + "fieldtype": "Data", + "label": "Zip" + }, + { + "fieldname": "hours", + "fieldtype": "Data", + "label": "Hours" + }, + { + "fieldname": "notes", + "fieldtype": "Text", + "label": "Notes" + }, + { + "fieldname": "red_r2", + "fieldtype": "Data", + "in_standard_filter": 1, + "label": "Red R2" + }, + { + "default": "0", + "fieldname": "dnc", + "fieldtype": "Check", + "label": "DNC" + }, + { + "fieldname": "raw_name", + "fieldtype": "Text", + "label": "Raw Name" + }, + { + "fieldname": "raw_phone1", + "fieldtype": "Data", + "label": "Raw Phone 1" + }, + { + "fieldname": "raw_phone2", + "fieldtype": "Data", + "label": "Raw Phone 2" + }, + { + "fieldname": "raw_email", + "fieldtype": "Data", + "label": "Raw Email" + } + ], + "grid_page_length": 50, + "index_web_pages_for_search": 1, + "links": [], + "modified": "2026-05-22 11:58:31.649154", + "modified_by": "Administrator", + "module": "Westech R2", + "name": "Customer Interaction", + "naming_rule": "Autoincrement", + "owner": "Administrator", + "permissions": [], + "row_format": "Dynamic", + "rows_threshold_for_grid_search": 20, + "sort_field": "modified", + "sort_order": "DESC", + "states": [], + "title_field": "contact_name", + "track_changes": 1, + "track_seen": 1 +} \ No newline at end of file diff --git a/westech_r2/doctype/customer_interaction/customer_interaction.py b/westech_r2/doctype/customer_interaction/customer_interaction.py new file mode 100644 index 0000000..162d1a4 --- /dev/null +++ b/westech_r2/doctype/customer_interaction/customer_interaction.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, Westech and contributors +# For license information, please see license.txt + +# import frappe +from frappe.model.document import Document + + +class CustomerInteraction(Document): + pass diff --git a/westech_r2/doctype/customer_interaction/test_customer_interaction.py b/westech_r2/doctype/customer_interaction/test_customer_interaction.py new file mode 100644 index 0000000..41e8f96 --- /dev/null +++ b/westech_r2/doctype/customer_interaction/test_customer_interaction.py @@ -0,0 +1,9 @@ +# Copyright (c) 2026, Westech and Contributors +# See license.txt + +# import frappe +from frappe.tests.utils import FrappeTestCase + + +class TestCustomerInteraction(FrappeTestCase): + pass diff --git a/westech_r2/import_customer_interactions.py b/westech_r2/import_customer_interactions.py new file mode 100644 index 0000000..352687d --- /dev/null +++ b/westech_r2/import_customer_interactions.py @@ -0,0 +1,107 @@ +import frappe +import csv + +def create_customer_interaction_doctype(): + """Create Customer Interaction DocType if it doesn't exist""" + if frappe.db.exists("DocType", "Customer Interaction"): + print("Customer Interaction DocType already exists") + return + + doc = frappe.get_doc({ + "doctype": "DocType", + "module": "Westech R2", + "name": "Customer Interaction", + "title_field": "contact_name", + "autoname": "autoincrement", + "naming_rule": "Autoincrement", + "track_changes": 1, + "track_seen": 1, + "fields": [ + {"label": "Customer", "fieldname": "customer", "fieldtype": "Link", "options": "Customer", "in_list_view": 1, "reqd": 1, "in_standard_filter": 1}, + {"label": "Customer Number", "fieldname": "customer_number", "fieldtype": "Data", "in_list_view": 1, "in_standard_filter": 1}, + {"label": "Contact Name", "fieldname": "contact_name", "fieldtype": "Data", "in_list_view": 1}, + {"label": "Phone 1", "fieldname": "phone_1", "fieldtype": "Data"}, + {"label": "Phone 2", "fieldname": "phone_2", "fieldtype": "Data"}, + {"label": "Email 1", "fieldname": "email_1", "fieldtype": "Data"}, + {"label": "Email 2", "fieldname": "email_2", "fieldtype": "Data"}, + {"label": "Address", "fieldname": "address", "fieldtype": "Text"}, + {"label": "City", "fieldname": "city", "fieldtype": "Data"}, + {"label": "Zip", "fieldname": "zip", "fieldtype": "Data"}, + {"label": "Hours", "fieldname": "hours", "fieldtype": "Data"}, + {"label": "Notes", "fieldname": "notes", "fieldtype": "Text"}, + {"label": "Red R2", "fieldname": "red_r2", "fieldtype": "Data", "in_standard_filter": 1}, + {"label": "DNC", "fieldname": "dnc", "fieldtype": "Check"}, + {"label": "Raw Name", "fieldname": "raw_name", "fieldtype": "Text"}, + {"label": "Raw Phone 1", "fieldname": "raw_phone1", "fieldtype": "Data"}, + {"label": "Raw Phone 2", "fieldname": "raw_phone2", "fieldtype": "Data"}, + {"label": "Raw Email", "fieldname": "raw_email", "fieldtype": "Data"}, + ] + }) + + doc.insert() + frappe.db.commit() + print(f"Created Customer Interaction DocType") + +def import_contacts(csv_path): + """Import contacts from CSV file""" + count = 0 + errors = 0 + + with open(csv_path, 'r', encoding='utf-8') as f: + reader = csv.DictReader(f) + for row in reader: + try: + # Find customer by customer_number + customer = frappe.db.get_value("Customer", {"customer_number": row['customer_number']}, "name") + + if not customer: + # Customer doesn't exist yet, skip or create placeholder + errors += 1 + continue + + interaction = frappe.get_doc({ + "doctype": "Customer Interaction", + "customer": customer, + "customer_number": row['customer_number'], + "contact_name": row.get('contact_name', ''), + "phone_1": row.get('phone_1', ''), + "phone_2": row.get('phone_2', ''), + "email_1": row.get('email_1', ''), + "email_2": row.get('email_2', ''), + "address": row.get('address', ''), + "city": row.get('city', ''), + "zip": row.get('zip', ''), + "hours": row.get('hours', ''), + "notes": row.get('notes', ''), + "red_r2": row.get('red_r2', ''), + "dnc": 1 if row.get('dnc', '').strip() else 0, + "raw_name": row.get('raw_name', ''), + "raw_phone1": row.get('raw_phone1', ''), + "raw_phone2": row.get('raw_phone2', ''), + "raw_email": row.get('raw_email', '') + }) + + interaction.insert() + count += 1 + + if count % 500 == 0: + frappe.db.commit() + print(f"Imported {count} interactions...") + + except Exception as e: + errors += 1 + if errors < 10: + print(f"Error importing row {count}: {e}") + + frappe.db.commit() + print(f"Import complete: {count} interactions imported, {errors} errors") + +if __name__ == "__main__": + frappe.init(site="erpnext.local") + frappe.connect() + + try: + create_customer_interaction_doctype() + import_contacts("/home/frappe/erpnext-bench/apps/westech_r2/westech_r2/crm_contacts_clean.csv") + finally: + frappe.destroy()