Skip to content

MTO Enhancement Hooks

Last Updated: 2026-01-19

Overview

Three specialized hooks that enhance the Material Takeoff (MTO) and Estimation Master experience:

  1. useLaborEnrichment - Enriches MTO items with calculated labor costs
  2. useDataSourceToggle - Manages MTO vs uploaded estimation data
  3. useKpiAggregation - Fetches KPI-based cost aggregation (Q-Flag system)

1. Labor Enrichment Hook

Location: frontend/src/hooks/mto/useLaborEnrichment.ts

Purpose

Fetches labor settings and service crews, provides enrichItem function for calculating labor costs on MTO items.

Usage

const { enrichItem, laborSettings, serviceCrews, isLoading } = useLaborEnrichment({
  serviceId,
  projectId,
  subcontractors,
});

// Enrich items for display
const enrichedData = items.map(item => enrichItem(item));

Enriched Fields

Field Formula
laborProdFactor Lookup by discipline
hourlyCost Lookup by crewCode
totalManhours quantity × manhourPerUnit × laborProdFactor
laborUnitCost manhourPerUnit × laborProdFactor × hourlyCost
totalLaborCost quantity × laborUnitCost
totalEstimationUnitPrice Subcontractor rate OR (labor + material + equipment)
totalCost totalEstimationUnitPrice × quantity

2. Data Source Toggle Hook

Location: frontend/src/hooks/mto/useDataSourceToggle.ts

Purpose

Manages switching between two estimation data sources: - MTO Data - Derived from imported Material Takeoff - Upload Data - Pre-calculated estimation uploaded via Excel

Usage

const {
  dataSource,        // 'mto' | 'upload'
  setDataSource,
  hasMTO,
  hasUpload,
  isLoading,
} = useDataSourceToggle({ serviceId, projectId });

UI Component

import { DataSourceToggle } from '@/components/common/DataSourceToggle';

<DataSourceToggle
  value={dataSource}
  onChange={setDataSource}
  hasMTO={hasMTO}
  hasUpload={hasUpload}
/>

3. KPI Aggregation Hook

Location: frontend/src/hooks/mto/useKpiAggregation.ts

Purpose

Fetches aggregated costs by KPI code using the Q-Flag system for cost-per-unit calculations.

Usage

const { data, loading, error, refetch } = useKpiAggregation({
  projectId,
  serviceId,
  dataSource: 'mto',
});

Response Structure

interface KPIAggregationResponse {
  projectId: string;
  aggregations: KPIAggregation[];
  totalKpiGroups: number;
  kpiGroupsWithQFlag: number;
}

interface KPIAggregation {
  kpiCode: string;
  totalLaborCost: number;
  totalMaterialCost: number;
  totalEquipmentCost: number;
  totalSubcontractorCost: number;
  totalCost: number;
  totalHours: number;
  qFlaggedQuantity?: number;   // From Q-flagged item
  costPerUnit?: number;        // totalCost / qFlaggedQuantity
  hoursPerUnit?: number;
  hasQFlag: boolean;
}

Q-Flag System

Purpose

Designates which item in a KPI group provides the primary quantity for cost-per-unit calculations.

Formula

Cost per Unit = Total Cost (all items in KPI group) / Q-Flagged Quantity

Rules

  1. One Q-Flag per KPI - Only one item per KPI code can have Q-flag
  2. Last One Wins - Enabling Q-flag auto-unflags existing item
  3. API Endpoint - PATCH /mto/{id}/q-flag?projectId={pid}&enable={bool}

Backend Service

Location: backend/app/services/q_flag_aggregation_service.py

Methods: - get_kpi_aggregations(project_id, service_id) - Aggregate costs by KPI - set_q_flag(item_id, project_id, enable) - Toggle Q-flag

Data Flow

Labor Settings API ──┐
                     ├──> useLaborEnrichment ──> Enriched MTO Items
Service Crews API ───┘

Data Sources API ──> useDataSourceToggle ──> DataSourceToggle Component

MTO/Upload API ──> useKpiAggregation ──> KPI Aggregation Table

Component Integration

Component Hooks Used
EstimationMasterTab useLaborEnrichment, useDataSourceToggle
MTODisciplineTab useLaborEnrichment
KPIAggregationTab useKpiAggregation, useDataSourceToggle