#!/usr/bin/env python3
"""Append an interaction event and update related entities."""
from __future__ import annotations
import argparse
import sys
from pathlib import Path
sys.path.insert(0, str(Path(__file__).resolve().parent))
from common import ( # noqa: E402
COMPANIES_DIR,
CONTACTS_DIR,
INTERACTION_TYPES,
LEADS_DIR,
append_interaction,
load_entities,
positive_reply,
run_sync_indexes,
today_str,
write_markdown,
die,
)
CONTACT_EVENT_TYPES = {"message", "email", "followup", "reply"}
LEAD_STATUS_BY_TYPE = {
"message": "messaged",
"email": "messaged",
"application": "applied",
"followup": "followed_up",
}
def resolve_entity(entity_type: str, entity_id: str):
directories = {
"lead": LEADS_DIR,
"contact": CONTACTS_DIR,
"company": COMPANIES_DIR,
}
directory = directories.get(entity_type)
if not directory:
die(f"Invalid entity type: {entity_type}")
entities = load_entities(directory)
if entity_id not in entities:
die(f"Unknown {entity_type} id: {entity_id}")
return entities[entity_id]
def infer_company_id(
contact_id: str | None,
lead_id: str | None,
company_id: str | None,
) -> str:
if company_id:
resolve_entity("company", company_id)
return company_id
if lead_id:
_, lead_meta, _ = resolve_entity("lead", lead_id)
lead_company = str(lead_meta.get("company_id", "")).strip()
if lead_company:
return lead_company
if contact_id:
_, contact_meta, _ = resolve_entity("contact", contact_id)
contact_company = str(contact_meta.get("company_id", "")).strip()
if contact_company:
return contact_company
return ""
def update_contact(
contact_id: str,
event_date: str,
event_type: str,
next_followup: str,
) -> None:
if event_type not in CONTACT_EVENT_TYPES:
return
path, meta, body = resolve_entity("contact", contact_id)
meta["last_contacted"] = event_date
if next_followup:
meta["next_followup"] = next_followup
meta["date_updated"] = today_str()
write_markdown(path, meta, body)
def update_lead(lead_id: str, event_type: str, summary: str) -> None:
path, meta, body = resolve_entity("lead", lead_id)
changed = False
if event_type in LEAD_STATUS_BY_TYPE:
meta["status"] = LEAD_STATUS_BY_TYPE[event_type]
changed = True
elif event_type == "reply" and positive_reply(summary):
meta["status"] = "interviewing"
changed = True
if changed:
meta["date_updated"] = today_str()
write_markdown(path, meta, body)
def main() -> None:
parser = argparse.ArgumentParser(description="Log an interaction event.")
parser.add_argument(
"--type",
required=True,
choices=sorted(INTERACTION_TYPES),
help="Interaction type",
)
parser.add_argument("--date", default=today_str(), help="Event date (YYYY-MM-DD)")
parser.add_argument("--entity-type", default="", help="Primary entity type")
parser.add_argument("--entity-id", default="", help="Primary entity id")
parser.add_argument("--contact", default="", help="Contact id")
parser.add_argument("--lead", default="", help="Lead id")
parser.add_argument("--company", default="", help="Company id")
parser.add_argument("--summary", required=True, help="Event summary")
parser.add_argument("--next-followup", default="", help="Next follow-up date")
args = parser.parse_args()
contact_id = args.contact.strip()
lead_id = args.lead.strip()
company_id = args.company.strip()
if contact_id:
resolve_entity("contact", contact_id)
if lead_id:
resolve_entity("lead", lead_id)
company_id = infer_company_id(contact_id or None, lead_id or None, company_id or None)
entity_type = args.entity_type.strip()
entity_id = args.entity_id.strip()
if not entity_type or not entity_id:
if contact_id:
entity_type, entity_id = "contact", contact_id
elif lead_id:
entity_type, entity_id = "lead", lead_id
elif company_id:
entity_type, entity_id = "company", company_id
else:
die("Provide --contact, --lead, or --company")
resolve_entity(entity_type, entity_id)
append_interaction(
{
"date": args.date,
"type": args.type,
"entity_type": entity_type,
"entity_id": entity_id,
"contact_id": contact_id,
"lead_id": lead_id,
"company_id": company_id,
"summary": args.summary,
"next_followup": args.next_followup,
}
)
if contact_id:
update_contact(contact_id, args.date, args.type, args.next_followup)
if lead_id:
update_lead(lead_id, args.type, args.summary)
print("Logged interaction")
run_sync_indexes()
if __name__ == "__main__":
main()