Skip to main content

Company Completion Score System

Ruby-based completion score calculation with tiered field weighting for company profile completeness.

Overview

The completion score measures how complete a company's profile is, based on presence of key fields across three importance tiers. Score ranges from 0.00 (empty) to 1.00 (complete).

Architecture

Location: app/models/concerns/completable.rb Storage: companies_infos.completion_score (decimal) Triggers: Automatic via model callbacks on Company and Companies::Info

Tiered Field Weighting

Tier 1: Critical Identity (weight: 3)

Essential for company identification and classification:

  • name - Legal company name
  • legal_status_id - Legal form (SA, SARL, etc.)
  • naf_id - NAF activity code
  • start_date - Operations start date
  • description_id - Activity description

Tier 2: Important Business Data (weight: 2)

Key operational and legal information:

  • date_registered - Official registration date
  • capital_amount - Company capital
  • main_activity - Primary activity text
  • rep_type_id - Representative type
  • commercial_name - Trading name
  • company_rep - Representative info

Tier 3: Supplementary Details (weight: 1)

Additional profile enhancements:

  • currency_code - Capital currency
  • duration - Company duration
  • end_date - End date (if applicable)
  • tax_year_date - Fiscal year end
  • subsidiary_id - Branch type
  • updated - Last update timestamp

Score Calculation

total_points = (critical_filled * 3) + (important_filled * 2) + (supplementary_filled * 1)
max_points = (5 * 3) + (6 * 2) + (6 * 1) # = 33
score = total_points / max_points

Example: Company with name, NAF, legal_status, capital_amount

  • Critical: 3 fields × 3 = 9 points
  • Important: 1 field × 2 = 2 points
  • Score: 11 / 33 = 0.33 (33%)

Usage

Automatic Updates

Scores update automatically when relevant fields change:

company.update(commercial_name: "New Name")
# → completion score automatically recalculated

Manual Calculation

# Calculate without saving
score = company.calculate_completion_score
# => 0.67

# Update stored score
company.update_completion_score
# => true

# Get tier breakdown
company.completion_breakdown
# => { critical: {...}, important: {...}, supplementary: {...}, overall: {...} }

Rake Tasks

# Recalculate all companies
rake completion_scores:recalculate

# Recalculate since date
rake completion_scores:recalculate_since[2025-01-01]

# View statistics
rake completion_scores:stats

Background Job

Scheduled daily at 2 AM via UpdateCompletionScoresJob:

# Manual trigger
UpdateCompletionScoresJob.perform_later

# Force full update
UpdateCompletionScoresJob.perform_later(force_full_update: true)

Integration Points

Elasticsearch

Score indexed as integer (0-100):

# In ElasticSearch::CompanySearch concern
completion_score: (company.infos&.completion_score || 0) * 100

API Serialization

Exposed in API as percentage:

# CompanySerializer
completion_score: (company.infos&.completion_score || 0.0) * 100
# => Returns 0-100

Admin Filters

Range filtering in admin interface:

# API params
filters: {
completion_score_min: 50, # 50%
completion_score_max: 100 # 100%
}

Performance

  • Conditional Triggers: Only recalculates when tracked fields change
  • Batch Processing: find_in_batches for large updates
  • No N+1 Queries: Direct field access, no joins required
  • Synchronous: Runs in-process (sub-millisecond per company)

Migration from SQL Function

Previous implementation used companies_completion_score_optimized() SQL function. New Ruby implementation provides:

✅ Maintainable Ruby code vs complex SQL ✅ Tiered importance vs equal weighting ✅ Testable via RSpec ✅ Better performance (no SQL function calls) ✅ Conditional triggers (only when needed)

Testing

bundle exec rspec spec/models/concerns/completable_spec.rb

Tests cover:

  • Score calculation logic for each tier
  • Automatic hook triggers
  • Edge cases (empty, partial, full profiles)
  • Breakdown reporting

Troubleshooting

Score not updating

Check if companies_infos record exists:

company.infos.present? # Should be true

Incorrect scores

Verify field values:

company.completion_breakdown
# Shows exactly which fields are counted

Bulk recalculation needed

After schema changes or migrations:

rake completion_scores:recalculate