# ShiftOps Components Documentation


**Last Updated:** 2025-11-20

Complete reference for all PHP classes, methods, and their responsibilities in the ShiftOps tool.

## Table of Contents

- [ShiftOpsAnalyzer](#shiftopsanalyzer)
- [ShiftOpsCustomerMatcher](#shiftopscustomermatcher)
- [ShiftOpsCostCalculator](#shiftopscostcalculator)
- [ShiftOpsCompetitiveAnalyzer](#shiftopscompetitiveanalyzer)
- [ShiftOpsRecommendationsEngine](#shiftopsrecommendationsengine)
- [ShiftOpsUserExplanations](#shiftopsuserexplanations)

## ShiftOpsAnalyzer

**File:** `v2/api/shiftops.php`  
**Lines:** 708-6084  
**Purpose:** Main analyzer class that orchestrates business analysis and scoring

### Properties

```php
private $googleApiKey = 'AIzaSyAcmDVIEYDtmeXjKfIsqYxbNy2FFsluCdo';
private $benchmarks;  // Industry benchmarks array
private $customerMatcher;  // ShiftOpsCustomerMatcher instance
private $costCalculator;  // ShiftOpsCostCalculator instance
private $competitiveAnalyzer;  // ShiftOpsCompetitiveAnalyzer instance
private $recommendationsEngine;  // ShiftOpsRecommendationsEngine instance
private $userExplanations;  // ShiftOpsUserExplanations instance
private $requestId;  // Unique request ID for logging
```

### Public Methods

#### `__construct($requestId = null)`

Initializes the analyzer, loads benchmarks, and initializes all component classes.

**Parameters:**

- `$requestId` (string|null): Optional request ID for logging traceability

**Behavior:**

- Loads industry benchmarks from `v2/data/industry_benchmarks.php`
- Attempts to load all component classes (cost calculator, competitive analyzer, recommendations engine, user explanations, customer matcher)
- All components are optional with graceful fallbacks
- Logs initialization status for each component

#### `analyzeBusiness($businessData)`

Main analysis method that processes business data and returns complete analysis.

**Parameters:**

- `$businessData` (array): Business data from Google Places API

**Returns:** `array` - Complete ShiftOps analysis including scores, cost savings, recommendations

**Process:**

1. Checks if business is Ordio customer (via customer matcher)
2. Analyzes location
3. Analyzes online presence
4. Calculates ShiftOps score (5 pillars)
5. Calculates cost savings (if cost calculator available)
6. Gets context data (holidays, weather, seasonal trends)
7. Generates competitive analysis (enhanced mode only)
8. Generates recommendations
9. Returns complete analysis

**Error Handling:**

- Wraps each analysis step in try-catch
- Returns fallback data if components fail
- Logs all errors with request ID

#### `getFallbackAnalysis($businessData)`

Generates fallback analysis when main analysis fails.

**Parameters:**

- `$businessData` (array): Business data

**Returns:** `array` - Basic analysis with default scores

### Private Methods - Scoring

#### `calculateShiftOpsScore($businessData, $isOrdioCustomer = false)`

Calculates the complete ShiftOps score across 5 pillars.

**Process:**

1. Calculate raw pillar scores (floats, 0.00-20.00)
2. Sum raw scores
3. Apply data completeness multiplier (0.50-1.0)

**For complete scoring documentation, see [Scoring System Documentation](SHIFTOPS_SCORING_SYSTEM.md)**

4. Apply customer cap (max 95 for customers)
5. Round total score (up for customers, down for non-customers)
6. Adjust pillar scores proportionally to match total
7. Assign grade (A+, A, A-, B+, B, B-, C+, C, C-, D+, D, D-, F)

**Returns:** `array` - Score structure with total_score, pillar_scores, grade, metadata

#### `calculateSchedulingScoreRaw($businessData, $isOrdioCustomer = false)`

Calculates scheduling efficiency score (0-20).

**Factors:**

- Digital maturity (0-5 points): Website, online features, Google Business activity
- Operational complexity (0-7 points): Weekly hours, service types, multi-location
- Team scale indicators (0-3 points): Review count, rating

**Customer Boost:**

- Baseline bonus: +3 points
- Percentage boost: +35%
- Maximum: 18 points

**Returns:** `float` - Raw score before rounding

#### `calculateAbsenceScoreRaw($businessData, $isOrdioCustomer = false)`

Calculates absence stability score (0-20).

**Factors:**

- Review sentiment analysis
- Seasonal factors
- Weather risk assessment
- Industry baseline

**Customer Boost:**

- Baseline bonus: +3 points
- Percentage boost: +25%
- Maximum: 20 points

**Returns:** `float` - Raw score before rounding

#### `calculateTimeTrackingScoreRaw($businessData, $isOrdioCustomer = false)`

Calculates time tracking hygiene score (0-20).

**Factors:**

- Hours complexity analysis
- Standard vs irregular hours
- Consistency of hours

**Customer Boost:**

- Baseline bonus: +3 points
- Percentage boost: +35%
- Maximum: 18 points

**Returns:** `float` - Raw score before rounding

#### `calculateComplianceScoreRaw($businessData, $isOrdioCustomer = false)`

Calculates compliance documentation score (0-20).

**Factors:**

- Industry-specific requirements
- Documentation completeness indicators
- Digital presence indicators

**Customer Boost:**

- Baseline bonus: +3 points
- Percentage boost: +30%
- Maximum: 19 points

**Returns:** `float` - Raw score before rounding

#### `calculatePayrollScoreRaw($businessData, $isOrdioCustomer = false)`

Calculates payroll readiness score (0-20).

**Factors:**

- DATEV integration indicators
- Data structure quality
- Digital maturity

**Customer Boost:**

- Baseline bonus: +3 points
- Percentage boost: +30%
- Maximum: 18 points

**Returns:** `float` - Raw score before rounding

#### `adjustPillarScoresToMatchTotal($rawScores, $targetTotal, $isCustomer = false)`

Adjusts pillar scores proportionally so their rounded sum equals the target total.

**Algorithm:**

1. Calculate adjustment ratio: `targetTotal / rawSum`
2. Apply ratio to each pillar score
3. Floor all scores initially
4. Round up pillars with highest fractional parts until sum matches
5. Handle edge cases (zero sum, over/under adjustments)

**Returns:** `array` - Adjusted pillar scores (integers)

#### `applyCustomerBoostRaw($score, $boostPercent, $maxScore, $minScore = null)`

Applies customer boost to a raw score without rounding.

**Parameters:**

- `$score` (float): Original score
- `$boostPercent` (float): Boost percentage (e.g., 35 for +35%)
- `$maxScore` (float): Maximum allowed score
- `$minScore` (float|null): Optional minimum floor

**Returns:** `float` - Boosted score (not rounded)

#### `calculateDataCompleteness($businessData)`

Calculates data completeness percentage and multiplier.

**Fields Checked:**

- Website
- Opening hours
- Reviews
- Photos

**Multiplier:**

- 4 fields: 1.0 (no penalty)
- 3 fields: 0.95
- 2 fields: 0.90
- 1 field: 0.85
- 0 fields: 0.50

**Returns:** `array` - Completeness data with percentage, multiplier, confidence, impact

### Private Methods - Analysis

#### `analyzeLocation($businessData)`

Analyzes business location and competitor density.

**Returns:** `array` - Location analysis with address, country, urban/suburban flags, competitor density, location score

#### `analyzeOnlinePresence($businessData)`

Analyzes online presence indicators.

**Returns:** `array` - Online presence data with rating, photo count, review count, team size estimate, service complexity, review sentiment, online presence score

#### `getContextData($businessData, $mode = 'enhanced')`

Fetches context data (holidays, weather, seasonal trends).

**Parameters:**

- `$mode` (string): 'essential' or 'enhanced' (affects weather forecast length)

**Returns:** `array` - Context data with holidays, weather, seasonal trends, business hours analysis

#### `getUpcomingHolidays($country, $state = null, $city = null)`

Fetches upcoming holidays from Nager.Date API.

**Returns:** `array` - Array of holiday objects

#### `getWeatherForecast($businessData)`

Fetches weather forecast from Open-Meteo API.

**Returns:** `array` - Weather data with current conditions and forecast

### Private Methods - Competitive Analysis

#### `analyzeCompetitivePosition($businessData, $shiftopsScores)`

Analyzes competitive positioning (enhanced mode only).

**Returns:** `array` - Competitive positioning data

#### `getCompetitorAnalysis($businessData)`

Gets competitor analysis using Google Places Nearby Search.

**Returns:** `array` - Competitor analysis data

### Private Methods - Recommendations

#### `generateQuickRecommendations($businessData, $shiftopsScores)`

Generates quick recommendations based on scores.

**Returns:** `array` - Array of recommendation objects

#### `generateEnhancedRecommendations($businessData, $shiftopsScores, $costSavings, $competitivePositioning)`

Generates enhanced recommendations (enhanced mode only).

**Returns:** `array` - Structured recommendations with quick_wins, high_value, strategic

### Private Methods - Utilities

#### `getPrimaryBusinessType($types)`

Gets primary business type from Google Places types array.

**Priority:** restaurant > hospital > store > cafe > pharmacy > bar > general

**Returns:** `string` - Primary business type

#### `getCountryFromAddress($businessData)`

Extracts country code from address components.

**Returns:** `string` - ISO 3166-1 alpha-2 country code (default: 'DE')

#### `getGradeFromScore($score)`

Converts numeric score to letter grade.

**Mapping:**

- 90-100: A+
- 80-89: A
- 70-79: B
- 60-69: C
- 40-59: D
- 0-39: F

**Returns:** `string` - Letter grade

## ShiftOpsCustomerMatcher

**File:** `v2/api/shiftops-customer-matcher.php`  
**Lines:** 87-918  
**Purpose:** Matches businesses to Ordio customers using fuzzy name matching and domain matching

### Properties

```php
private $customers = null;  // Customer list array
private $customersLoaded = false;  // Loading flag
private $customersFile;  // Path to customers JSON file
private $requestId;  // Request ID for logging
private $fileLoadTime;  // File load time in milliseconds
private $fileLoadMemoryBefore;  // Memory before load
private $fileLoadMemoryAfter;  // Memory after load
```

### Public Methods

#### `__construct($customersFile = null, $requestId = null)`

Initializes customer matcher with path resolution.

**Path Resolution Strategy:**

1. Explicitly provided path
2. From ORDIO_CUSTOMERS_FILE constant
3. Relative to current file (`__DIR__ . '/../data/ordio-customers.json'`)
4. Absolute path using realpath()
5. DOCUMENT_ROOT based path

**Logging:**

- Logs all path attempts
- Logs file existence, readability, size, permissions
- Logs PHP memory limits and current usage

#### `isOrdioCustomer($businessData)`

Checks if a business is an Ordio customer.

**Parameters:**

- `$businessData` (array): Business data from Google Places

**Returns:** `array|null` - Customer match info if found, null otherwise

**Process:**

1. Loads customer list (lazy loading)
2. Extracts business name, website, address
3. Calls `matchBusinessToCustomer()` with extracted data
4. Returns match result with confidence score

#### `matchBusinessToCustomer($businessName, $businessWebsite = '', $businessAddress = '')`

Matches business to customer using multiple strategies.

**Matching Strategies (in order):**

1. **Domain Match** (95% confidence): Exact domain match
2. **Exact Name Match** (100% confidence): Normalized name exact match
3. **Prefix Match** (75-90% confidence): One name starts with another (≥5 chars)
4. **Fuzzy Match** (75-95% confidence): Levenshtein distance similarity (≥85%)
5. **Address Match** (+5% boost): Additional validation if name matches

**Returns:** `array|null` - Match result with confidence, match_type, matched customer info

#### `getCustomerCount()`

Returns the number of customers loaded.

**Returns:** `int` - Customer count

#### `getCustomerInfo($businessData)`

Gets customer information if matched.

**Returns:** `array|null` - Customer info or null

### Private Methods

#### `loadCustomerList()`

Loads customer list from JSON file (lazy loading).

**Process:**

1. Checks if already loaded and not empty
2. Validates file exists and is readable
3. Reads JSON file
4. Parses JSON with error handling
5. Validates structure (must have 'customers' key)
6. Stores in memory
7. Logs performance metrics (load time, memory usage)

**Returns:** `bool` - Success status

**Error Handling:**

- Handles file not found
- Handles JSON parsing errors
- Handles invalid structure
- Returns false on any error

#### `normalizeCompanyName($name)`

Normalizes company name for matching.

**Process:**

1. Converts to lowercase (using safeStrToLower)
2. Removes special characters
3. Removes common suffixes (GmbH, AG, etc.)
4. Trims whitespace

**Returns:** `string` - Normalized name

#### `extractDomain($website)`

Extracts domain from website URL.

**Process:**

1. Removes protocol (http://, https://)
2. Removes www. prefix
3. Removes trailing slash
4. Extracts domain (handles unusual TLDs like .koeln, .berlin)

**Returns:** `string` - Extracted domain

#### `calculateSimilarity($str1, $str2)`

Calculates similarity percentage using Levenshtein distance.

**Returns:** `float` - Similarity percentage (0-100)

#### `matchAddress($address1, $address2)`

Matches addresses for additional validation.

**Returns:** `bool` - True if addresses match

#### `safeStrToLower($str, $encoding = 'UTF-8')`

Safe lowercase conversion with mbstring fallback.

**Fallback:** Uses `strtolower()` if `mb_strtolower()` not available

**Returns:** `string` - Lowercase string

## ShiftOpsCostCalculator

**File:** `v2/api/shiftops-cost-calculator.php`  
**Lines:** 1-922  
**Purpose:** Calculates potential cost savings based on ShiftOps scores

### Properties

```php
private $benchmarks;  // Industry benchmarks array
```

### Public Methods

#### `__construct()`

Initializes cost calculator and loads benchmarks.

**Fallback:** Uses fallback benchmarks if file not found

#### `calculateCostSavings($businessData, $shiftopsScores)`

Calculates complete cost savings analysis.

**Process:**

1. Estimates team size (multi-factor approach)
2. Gets wage data by industry and country
3. Calculates monthly/annual labor cost
4. Calculates potential savings for each category:
   - Overtime reduction
   - Absence cost reduction
   - Compliance avoidance
   - Turnover reduction
   - Scheduling optimization
5. Calculates ROI analysis
6. Calculates break-even analysis

**Returns:** `array` - Complete cost savings structure

### Private Methods

#### `estimateTeamSize($businessData)`

Estimates team size using multi-factor weighted approach.

**Factors:**

1. Customer Volume Proxy (35% weight): Reviews per employee per month calculation
   - Volume factor cap: 4.0x for restaurants with 2000+ reviews, 6.0x otherwise
2. Operating Hours (25% weight): Weekly hours / 40 (standard FTE)
3. Service Complexity (20% weight): Number of service types (+12% per service type)
4. Quality/Scale Indicator (15% weight): Rating + price level combination
5. Review Velocity (5% weight): Review velocity factor

**Validation Bounds:**

- Restaurant: Min 5, Max 25 (capped at 25)
- Cafe: Min 3, Max 15 (capped at 15)
- Bar: Min 3, Max 25 (capped at 25)
- Store: Min 2, Max 30 (capped at 30)
- Hospital: Min 8, Max 60 (capped at 60)
- Pharmacy: Min 3, Max 20 (capped at 20)
- General: Min 3, Max 30 (capped at 30)

**Safety Checks:**

- Additional validation after location multipliers to ensure restaurants don't exceed 25
- Applied in all implementations to prevent unrealistic values

**Returns:** `array` - Team size estimate with confidence level, factors used, validation metadata

**Code Locations:**

- PHP Backend: `v2/api/shiftops-cost-calculator.php` line 110
- PHP API: `v2/api/shiftops.php` line 2047
- JavaScript Report: `v2/pages/shiftops-report.php` line 7288
- JavaScript Loading: `v2/pages/shiftops.php` line 1949

#### `calculateOvertimeSavings($shiftopsScores, $monthlyLaborCost, $industry)`

Calculates potential overtime reduction savings.

**Returns:** `array` - Savings detail with current cost, potential savings, percentage, explanation

#### `calculateAbsenceSavings($shiftopsScores, $monthlyLaborCost, $industry)`

Calculates potential absence cost reduction savings.

**Returns:** `array` - Savings detail

#### `calculateComplianceSavings($shiftopsScores, $monthlyLaborCost, $industry)`

Calculates potential compliance avoidance savings.

**Returns:** `array` - Savings detail

#### `calculateTurnoverSavings($shiftopsScores, $monthlyLaborCost, $industry, $teamSize)`

Calculates potential turnover reduction savings.

**Returns:** `array` - Savings detail

#### `calculateSchedulingSavings($shiftopsScores, $monthlyLaborCost, $industry)`

Calculates potential scheduling optimization savings.

**Returns:** `array` - Savings detail

#### `calculateROI($businessData, $shiftopsScores, $teamSize, $industry, $monthlyLaborCost)`

Calculates ROI analysis.

**Returns:** `array` - ROI data with percentage, payback period, savings per employee

#### `calculateBreakEven($monthlyLaborCost, $shiftopsScores, $industry, $teamSize, $businessData)`

Calculates break-even analysis.

**Returns:** `array` - Break-even data with team size, monthly savings, months to break even

## ShiftOpsCompetitiveAnalyzer

**File:** `v2/api/shiftops-competitive-analyzer.php`  
**Lines:** 1-910  
**Purpose:** Analyzes competitive positioning and market position

### Public Methods

#### `analyzeCompetitivePosition($businessData, $shiftopsScores)`

Analyzes complete competitive positioning.

**Returns:** `array` - Competitive positioning data with competitor analysis, market position, growth potential, competitive advantages

### Private Methods

#### `getDetailedCompetitorAnalysis($businessData)`

Gets detailed competitor analysis using Google Places Nearby Search.

**Process:**

1. Uses business location and types
2. Searches for nearby competitors
3. Calculates averages (rating, review count, price level)
4. Determines market position
5. Categorizes competition density

**Returns:** `array` - Competitor analysis data

#### `calculateMarketPosition($businessData, $competitorAnalysis)`

Calculates market position relative to competitors.

**Returns:** `array` - Market position data

#### `assessGrowthPotential($businessData, $competitorAnalysis, $shiftopsScores)`

Assesses growth potential.

**Returns:** `array` - Growth potential data

## ShiftOpsRecommendationsEngine

**File:** `v2/api/shiftops-recommendations-engine.php`  
**Lines:** 1-947  
**Purpose:** Generates priority-ranked recommendations

### Public Methods

#### `generateRecommendations($businessData, $shiftopsScores, $costSavings = null, $competitiveAnalysis = null)`

Generates complete recommendations structure.

**Process:**

1. Generates recommendations for each pillar
2. Adds cost-based recommendations (if available)
3. Adds competitive recommendations (if available)
4. Adds general business recommendations
5. Adds ROI estimates
6. Prioritizes recommendations
7. Creates implementation roadmap

**Returns:** `array` - Structured recommendations with quick_wins, high_value, strategic, all_recommendations, implementation_roadmap

### Private Methods

#### `generateSchedulingRecommendations($businessData, $scores, $businessName, $industry)`

Generates scheduling efficiency recommendations.

**Returns:** `array` - Array of recommendation objects

#### `generateAbsenceRecommendations($businessData, $scores, $businessName, $industry)`

Generates absence stability recommendations.

**Returns:** `array` - Array of recommendation objects

#### `generateTimeTrackingRecommendations($businessData, $scores, $businessName, $industry)`

Generates time tracking recommendations.

**Returns:** `array` - Array of recommendation objects

#### `generateComplianceRecommendations($businessData, $scores, $businessName, $industry)`

Generates compliance recommendations.

**Returns:** `array` - Array of recommendation objects

#### `generatePayrollRecommendations($businessData, $scores, $businessName, $industry)`

Generates payroll recommendations.

**Returns:** `array` - Array of recommendation objects

#### `prioritizeRecommendations($recommendations)`

Sorts recommendations by priority and impact.

**Returns:** `array` - Sorted recommendations

#### `createImplementationRoadmap($recommendations)`

Creates implementation roadmap with phases.

**Returns:** `array` - Roadmap with phase_1, phase_2, phase_3

## ShiftOpsUserExplanations

**File:** `v2/api/shiftops-user-explanations.php`  
**Lines:** 1-126  
**Purpose:** Generates user-friendly explanations for scores

### Public Methods

#### `generateScoreExplanations($businessData, $shiftopsScores)`

Generates explanations for total score and all pillar scores.

**Returns:** `array` - Explanations structure

### Private Methods

#### `explainTotalScore($score)`

Explains total score with details and recommendations.

**Returns:** `array` - Explanation with explanation, details, recommendation

#### `explainSchedulingScore($score)`

Explains scheduling efficiency score.

**Returns:** `string` - User-friendly explanation

#### `explainAbsenceScore($score)`

Explains absence stability score.

**Returns:** `string` - User-friendly explanation

#### `explainTimeTrackingScore($score)`

Explains time tracking hygiene score.

**Returns:** `string` - User-friendly explanation

#### `explainComplianceScore($score)`

Explains compliance documentation score.

**Returns:** `string` - User-friendly explanation

#### `explainPayrollScore($score)`

Explains payroll readiness score.

**Returns:** `string` - User-friendly explanation

#### `explainGrade($grade)`

Explains letter grade.

**Returns:** `string` - User-friendly explanation

## Component Dependencies

```
ShiftOpsAnalyzer
├── ShiftOpsCustomerMatcher (optional)
├── ShiftOpsCostCalculator (optional)
├── ShiftOpsCompetitiveAnalyzer (optional)
├── ShiftOpsRecommendationsEngine (optional)
└── ShiftOpsUserExplanations (optional)
```

All components are optional with graceful fallbacks. The analyzer will work even if components fail to load.

## Error Handling Pattern

All components follow this error handling pattern:

```php
try {
    // Component operation
} catch (Exception $e) {
    error_log("Error: " . $e->getMessage());
    // Return fallback or null
    return null; // or fallback data
}
```

## Logging Pattern

All components use request IDs for traceability:

```php
error_log("[{$this->requestId}] Component operation: result");
```

This allows tracking all operations for a single request across all components.
