refactor: simplify CRM MCP architecture
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from .crm_mixin import CrmMixin
|
||||
from .crm_schema_helpers import (
|
||||
_configured_or_search_fields,
|
||||
_date_field,
|
||||
_existing_field_names,
|
||||
_field_list,
|
||||
_field_names,
|
||||
_find_field,
|
||||
_find_named_field,
|
||||
_metadata_error,
|
||||
_relation_field,
|
||||
_template_sort,
|
||||
)
|
||||
from .crm_shared import Any
|
||||
|
||||
|
||||
class CrmMetadataMixin(CrmMixin):
|
||||
def crm_health(self) -> dict[str, Any]:
|
||||
health = self.client.health(self.config.customer.resource, self.config.customer.id_field)
|
||||
configured = {
|
||||
"env": self.config.env_name,
|
||||
"data_source": self.config.data_source,
|
||||
"collections": {
|
||||
"customers": self.config.customer.resource,
|
||||
"contacts": self.config.contact.resource,
|
||||
"followups": self.config.followup.resource,
|
||||
"teams": self.config.team.resource,
|
||||
"projects": self.config.project.resource,
|
||||
"project_updates": self.config.project.update_resource,
|
||||
},
|
||||
}
|
||||
return {"ok": bool(health.get("ok")), "nb": health, "configured": configured}
|
||||
|
||||
def crm_schema(self, include_fields: bool = False) -> dict[str, Any]:
|
||||
schema: dict[str, Any] = {
|
||||
"env": self.config.env_name,
|
||||
"data_source": self.config.data_source,
|
||||
"collections": {
|
||||
"customers": self.config.customer.__dict__,
|
||||
"contacts": self.config.contact.__dict__,
|
||||
"followups": self.config.followup.__dict__,
|
||||
"users": self.config.user.__dict__,
|
||||
"teams": self.config.team.__dict__,
|
||||
"projects": self.config.project.__dict__,
|
||||
},
|
||||
}
|
||||
if include_fields:
|
||||
schema["metadata"] = self._safe_metadata()
|
||||
return schema
|
||||
|
||||
def crm_config_template(self) -> dict[str, Any]:
|
||||
metadata = self._safe_metadata()
|
||||
fields_by_kind = metadata.get("fields", {}) if isinstance(metadata, dict) else {}
|
||||
customer_fields = _field_list(fields_by_kind.get("customers"))
|
||||
contact_fields = _field_list(fields_by_kind.get("contacts"))
|
||||
followup_fields = _field_list(fields_by_kind.get("followups"))
|
||||
customer_resource = self.config.customer.resource
|
||||
contact_resource = self.config.contact.resource
|
||||
return {
|
||||
"env": self.config.env_name,
|
||||
"dataSource": self.config.data_source,
|
||||
"users": {
|
||||
"resource": self.config.user.resource,
|
||||
"fields": self.config.user.fields,
|
||||
"matchFields": self.config.user.match_fields,
|
||||
"labelFields": self.config.user.label_fields,
|
||||
},
|
||||
"collections": {
|
||||
"customers": {
|
||||
"resource": customer_resource,
|
||||
"fields": _field_names(customer_fields),
|
||||
"searchFields": _configured_or_search_fields(
|
||||
customer_fields,
|
||||
["f_q2q60q7bqbg", "f_kh_english_name", "f_territorial_name"],
|
||||
),
|
||||
# Ordered: the first non-empty one becomes the customer's
|
||||
# displayed name everywhere it is referenced.
|
||||
"nameFields": _existing_field_names(
|
||||
customer_fields,
|
||||
["f_q2q60q7bqbg", "f_kh_english_name", "f_territorial_name"],
|
||||
)
|
||||
or self.config.customer.name_fields,
|
||||
"managerField": _find_named_field(customer_fields, ["kehu_manage_person"])
|
||||
or self.config.customer.manager_field,
|
||||
"detailFields": {
|
||||
key: value
|
||||
for key, value in self.config.customer.detail_fields.items()
|
||||
if _find_named_field(customer_fields, [value])
|
||||
},
|
||||
"statusField": _find_named_field(customer_fields, ["kh_progress"])
|
||||
or _find_field(customer_fields, ["进度", "状态", "status"]),
|
||||
"sourceField": _find_named_field(customer_fields, ["f_225h6n6v654"])
|
||||
or _find_field(customer_fields, ["客户来源", "来源", "source"]),
|
||||
"ownerField": _find_named_field(customer_fields, ["kehu_followup_person"])
|
||||
or self.config.customer.owner_field,
|
||||
"sort": self.config.customer.sort,
|
||||
},
|
||||
"contacts": {
|
||||
"resource": contact_resource,
|
||||
"fields": _field_names(contact_fields),
|
||||
"searchFields": _configured_or_search_fields(
|
||||
contact_fields,
|
||||
["f_2zpg91gtmwp", "khlxr_phone_number", "khlxr_email"],
|
||||
),
|
||||
"nameFields": _existing_field_names(contact_fields, ["f_2zpg91gtmwp"])
|
||||
or self.config.contact.name_fields,
|
||||
"titleField": _find_named_field(contact_fields, ["f_tn8zdm2f938"])
|
||||
or self.config.contact.title_field,
|
||||
"phoneField": _find_named_field(contact_fields, ["khlxr_phone_number"])
|
||||
or self.config.contact.phone_field,
|
||||
"emailField": _find_named_field(contact_fields, ["khlxr_email"]) or self.config.contact.email_field,
|
||||
"customerField": _find_named_field(contact_fields, ["kehulianxiren_client"])
|
||||
or _relation_field(contact_fields, ["公司", "客户"])
|
||||
or self.config.contact.customer_field,
|
||||
"sort": self.config.contact.sort,
|
||||
},
|
||||
"followups": {
|
||||
"resource": self.config.followup.resource,
|
||||
"fields": _field_names(followup_fields),
|
||||
"searchFields": _configured_or_search_fields(followup_fields, ["f_19iplxz0nds"]),
|
||||
"customerField": _find_named_field(followup_fields, ["gjjl_client"])
|
||||
or _relation_field(followup_fields, ["客户"])
|
||||
or self.config.followup.customer_field,
|
||||
"contactField": _find_named_field(followup_fields, ["gjjl_client_contacts"])
|
||||
or _relation_field(followup_fields, ["客户联系人", "联系人"])
|
||||
or self.config.followup.contact_field,
|
||||
"ownerField": _find_named_field(followup_fields, ["gjjl_followup_person"])
|
||||
or self.config.followup.owner_field,
|
||||
"ownerFields": _existing_field_names(
|
||||
followup_fields,
|
||||
["gjjl_followup_person", "createdBy"],
|
||||
)
|
||||
or self.config.followup.owner_fields,
|
||||
"dateField": _find_named_field(followup_fields, ["f_srysmjkwfq1"])
|
||||
or _date_field(followup_fields)
|
||||
or self.config.followup.date_field,
|
||||
"contentField": _find_named_field(followup_fields, ["f_19iplxz0nds"])
|
||||
or self.config.followup.content_field,
|
||||
"typeField": _find_named_field(followup_fields, ["gjjl_followup_type"])
|
||||
or self.config.followup.type_field,
|
||||
"statusField": _find_named_field(followup_fields, ["f_hskl7gjvos9"])
|
||||
or self.config.followup.status_field,
|
||||
"projectField": _find_named_field(followup_fields, ["f_gjjl_projects"])
|
||||
or self.config.followup.project_field,
|
||||
"locationField": _find_named_field(followup_fields, ["f_b5c4hfi5og6"])
|
||||
or self.config.followup.location_field,
|
||||
"sort": _template_sort(
|
||||
_find_named_field(followup_fields, ["f_srysmjkwfq1"])
|
||||
or _date_field(followup_fields)
|
||||
or self.config.followup.date_field,
|
||||
self.config.followup.sort,
|
||||
),
|
||||
},
|
||||
},
|
||||
"metadata": {
|
||||
"field_errors": metadata.get("field_errors", {}) if isinstance(metadata, dict) else {},
|
||||
"note": "Review inferred owner/status/source/date fields before using this template in production.",
|
||||
},
|
||||
}
|
||||
|
||||
def _safe_metadata(self) -> dict[str, Any]:
|
||||
collections = {
|
||||
"customers": self.config.customer.resource,
|
||||
"contacts": self.config.contact.resource,
|
||||
"followups": self.config.followup.resource,
|
||||
"teams": self.config.team.resource,
|
||||
"projects": self.config.project.resource,
|
||||
"project_updates": self.config.project.update_resource,
|
||||
}
|
||||
fields: dict[str, list[dict[str, Any]]] = {}
|
||||
field_errors: dict[str, dict[str, str]] = {}
|
||||
for label, collection_name in collections.items():
|
||||
try:
|
||||
response = self.client.list_collection_fields(
|
||||
collection_name,
|
||||
page_size=500,
|
||||
paginate=False,
|
||||
)
|
||||
fields[label] = self._data(response)
|
||||
except Exception as error:
|
||||
field_errors[label] = _metadata_error(error)
|
||||
return {"collections": collections, "fields": fields, "field_errors": field_errors}
|
||||
Reference in New Issue
Block a user