185 lines
9.2 KiB
Python
185 lines
9.2 KiB
Python
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}
|