diff --git a/app/modules/prospecting/schemas/score.py b/app/modules/prospecting/schemas/score.py index 6e16d8cf..8e4f20e3 100644 --- a/app/modules/prospecting/schemas/score.py +++ b/app/modules/prospecting/schemas/score.py @@ -18,7 +18,7 @@ class ProspectScoreResponse(BaseModel): business_value_score: int engagement_score: int reason_flags: list[str] = [] - score_breakdown: dict[str, int] | None = None + score_breakdown: dict[str, dict[str, int]] | None = None lead_tier: str | None = None notes: str | None = None created_at: datetime diff --git a/app/modules/prospecting/services/scoring_service.py b/app/modules/prospecting/services/scoring_service.py index d350ad6e..7ba02b9f 100644 --- a/app/modules/prospecting/services/scoring_service.py +++ b/app/modules/prospecting/services/scoring_service.py @@ -103,33 +103,38 @@ class ScoringService: business_value = 0 engagement = 0 flags = [] - breakdown = {} + breakdown = { + "technical_health": {}, + "modernity": {}, + "business_value": {}, + "engagement": {}, + } # === TECHNICAL HEALTH (max 40) === if not prospect.uses_https: tech_health += 15 flags.append("no_ssl") - breakdown["no_ssl"] = 15 + breakdown["technical_health"]["no_ssl"] = 15 perf = prospect.performance_profile if perf and perf.performance_score is not None: if perf.performance_score < 30: tech_health += 15 flags.append("very_slow") - breakdown["very_slow"] = 15 + breakdown["technical_health"]["very_slow"] = 15 elif perf.performance_score < 50: tech_health += 10 flags.append("slow") - breakdown["slow"] = 10 + breakdown["technical_health"]["slow"] = 10 elif perf.performance_score < 70: tech_health += 5 flags.append("moderate_speed") - breakdown["moderate_speed"] = 5 + breakdown["technical_health"]["moderate_speed"] = 5 if perf.is_mobile_friendly is False: tech_health += 10 flags.append("not_mobile_friendly") - breakdown["not_mobile_friendly"] = 10 + breakdown["technical_health"]["not_mobile_friendly"] = 10 tech_health = min(tech_health, 40) @@ -139,36 +144,36 @@ class ScoringService: if tp.cms and tp.cms.lower() in OUTDATED_CMS: modernity += 15 flags.append("outdated_cms") - breakdown["outdated_cms"] = 15 + breakdown["modernity"]["outdated_cms"] = 15 elif tp.cms is None and prospect.has_website: modernity += 5 flags.append("unknown_cms") - breakdown["unknown_cms"] = 5 + breakdown["modernity"]["unknown_cms"] = 5 if tp.js_framework and tp.js_framework.lower() == "jquery": modernity += 5 flags.append("legacy_js") - breakdown["legacy_js"] = 5 + breakdown["modernity"]["legacy_js"] = 5 if not tp.analytics: modernity += 5 flags.append("no_analytics") - breakdown["no_analytics"] = 5 + breakdown["modernity"]["no_analytics"] = 5 modernity = min(modernity, 25) # === BUSINESS VALUE (max 25) === if prospect.has_website: business_value += 10 - breakdown["has_website"] = 10 + breakdown["business_value"]["has_website"] = 10 if tp and tp.ecommerce_platform: business_value += 10 - breakdown["has_ecommerce"] = 10 + breakdown["business_value"]["has_ecommerce"] = 10 if prospect.domain_name and len(prospect.domain_name) <= 15: business_value += 5 - breakdown["short_domain"] = 5 + breakdown["business_value"]["short_domain"] = 5 business_value = min(business_value, 25) @@ -177,7 +182,7 @@ class ScoringService: if contacts: engagement += 5 flags.append("has_contacts") - breakdown["has_contacts"] = 5 + breakdown["engagement"]["has_contacts"] = 5 has_email = any(c.contact_type == "email" for c in contacts) has_phone = any(c.contact_type == "phone" for c in contacts) @@ -185,11 +190,11 @@ class ScoringService: if has_email: engagement += 3 flags.append("has_email") - breakdown["has_email"] = 3 + breakdown["engagement"]["has_email"] = 3 if has_phone: engagement += 2 flags.append("has_phone") - breakdown["has_phone"] = 2 + breakdown["engagement"]["has_phone"] = 2 engagement = min(engagement, 10) @@ -202,7 +207,12 @@ class ScoringService: business_value = 0 engagement = 0 flags = [] - breakdown = {} + breakdown = { + "technical_health": {}, + "modernity": {}, + "business_value": {}, + "engagement": {}, + } # Offline prospects without a website are high opportunity if not prospect.has_website: @@ -210,9 +220,9 @@ class ScoringService: modernity = 20 business_value = 20 flags.extend(["no_website"]) - breakdown["no_website_tech"] = 30 - breakdown["no_website_mod"] = 20 - breakdown["no_website_biz"] = 20 + breakdown["technical_health"]["no_website"] = 30 + breakdown["modernity"]["no_website"] = 20 + breakdown["business_value"]["no_website"] = 20 # Check for gmail usage (from contacts) contacts = prospect.contacts or [] @@ -223,7 +233,7 @@ class ScoringService: if has_gmail: modernity += 10 flags.append("uses_gmail") - breakdown["uses_gmail"] = 10 + breakdown["modernity"]["uses_gmail"] = 10 modernity = min(modernity, 25) @@ -231,7 +241,7 @@ class ScoringService: if prospect.source in ("street", "networking_event", "referral"): engagement += 5 flags.append("met_in_person") - breakdown["met_in_person"] = 5 + breakdown["engagement"]["met_in_person"] = 5 if contacts: has_email = any(c.contact_type == "email" for c in contacts) @@ -239,11 +249,11 @@ class ScoringService: if has_email: engagement += 3 flags.append("has_email") - breakdown["has_email"] = 3 + breakdown["engagement"]["has_email"] = 3 if has_phone: engagement += 2 flags.append("has_phone") - breakdown["has_phone"] = 2 + breakdown["engagement"]["has_phone"] = 2 engagement = min(engagement, 10) diff --git a/app/modules/prospecting/static/admin/js/prospect-detail.js b/app/modules/prospecting/static/admin/js/prospect-detail.js index 9a73997b..4c25789a 100644 --- a/app/modules/prospecting/static/admin/js/prospect-detail.js +++ b/app/modules/prospecting/static/admin/js/prospect-detail.js @@ -123,9 +123,17 @@ function prospectDetail(prospectId) { return 'text-gray-600'; }, - isPositiveFlag(flag) { - var positive = ['has_website', 'has_contacts', 'has_email', 'has_phone', 'has_ssl', 'modern_cms', 'fast_site', 'mobile_friendly']; - return positive.indexOf(flag) !== -1; + scoreCategories() { + var s = this.prospect?.score; + if (!s) return []; + var bd = s.score_breakdown || {}; + var positive = ['has_website', 'has_contacts', 'has_email', 'has_phone', 'has_ssl', 'modern_cms', 'fast_site', 'mobile_friendly', 'has_ecommerce', 'short_domain', 'met_in_person']; + return [ + { key: 'technical_health', label: 'Technical Health', score: s.technical_health_score, max: 40, flags: Object.entries(bd.technical_health || {}), positive: positive }, + { key: 'modernity', label: 'Modernity', score: s.modernity_score, max: 25, flags: Object.entries(bd.modernity || {}), positive: positive }, + { key: 'business_value', label: 'Business Value', score: s.business_value_score, max: 25, flags: Object.entries(bd.business_value || {}), positive: positive }, + { key: 'engagement', label: 'Engagement', score: s.engagement_score, max: 10, flags: Object.entries(bd.engagement || {}), positive: positive }, + ]; }, techProfileEntries() { diff --git a/app/modules/prospecting/templates/prospecting/admin/prospect-detail.html b/app/modules/prospecting/templates/prospecting/admin/prospect-detail.html index 7c533316..1b1287e9 100644 --- a/app/modules/prospecting/templates/prospecting/admin/prospect-detail.html +++ b/app/modules/prospecting/templates/prospecting/admin/prospect-detail.html @@ -93,39 +93,34 @@
No issues detected