Skip to main content
The Tolerance Management module allows quality engineers and administrators to define acceptable scrap thresholds. When limits are exceeded, visual alerts appear on the dashboard to trigger corrective actions.

Overview

Tolerances define the maximum acceptable quantity and cost of scrap for a specific target (global, area, chain, line, or category) over a time period (daily, weekly, or monthly).

Multi-Level Targets

Set limits globally or for specific areas, chains, lines, or categories

Flexible Periods

Configure daily, weekly, or monthly monitoring windows

Dual Thresholds

Track both quantity (pieces) and cost (USD) limits

Progressive Alerts

Green → Yellow → Red status based on percentage consumed

Tolerance Structure

Each tolerance is defined by:
// From types.ts:119-129
export interface Tolerancia {
  id: number;
  nombre: string;                    // Descriptive name
  tipo_objetivo: 'global' | 'cadena' | 'linea' | 'area' | 'categoria';
  objetivo_id: string;               // Target identifier (e.g., "Assembly" for area)
  tipo_periodo: 'diario' | 'semanal' | 'mensual';
  cantidad_max: number;              // Maximum quantity (pieces)
  costo_max: number;                 // Maximum cost (USD)
  porcentaje_alerta: number;         // Alert threshold percentage (e.g., 80)
  activo: number;                    // Active flag (0/1)
}
Example Tolerance:
{
  "nombre": "Assembly Area Daily Limit",
  "tipo_objetivo": "area",
  "objetivo_id": "Assembly",
  "tipo_periodo": "diario",
  "cantidad_max": 500,
  "costo_max": 1500,
  "porcentaje_alerta": 80,
  "activo": 1
}
This tolerance alerts when Assembly area exceeds 400 pieces (80% of 500) or 1200(801200 (80% of 1500) in a single day.

Tolerance Types

Target: Entire operationUse Case: Company-wide scrap reduction goalsExample: “Total scrap must not exceed 5000 pieces/month”
// From TolerancesPage.tsx:108
if (t.tipo_objetivo === 'area') rr = rr.filter(p => p.AREA === t.objetivo_id);
No filtering applied — all records counted.

Time Periods

Tolerances can monitor daily, weekly, or monthly windows:

Daily Tolerance

// From TolerancesPage.tsx:35
if (t.tipo_periodo === 'diario') 
  recs = recs.filter(p => isWithinInterval(new Date(p.FECHA_REGISTRO), { 
    start: startOfDay(now), 
    end: endOfDay(now) 
  }));
  • Window: Midnight to midnight
  • Reset: Automatically at 00:00
  • Use: Short-cycle production

Weekly Tolerance

// From TolerancesPage.tsx:36
else if (t.tipo_periodo === 'semanal') 
  recs = recs.filter(p => isWithinInterval(new Date(p.FECHA_REGISTRO), { 
    start: startOfWeek(now, { weekStartsOn: 1 }), 
    end: endOfDay(now) 
  }));
  • Window: Monday 00:00 to current time
  • Reset: Every Monday
  • Use: Weekly production planning

Monthly Tolerance

// From TolerancesPage.tsx:37
else { 
  const ms = new Date(now.getFullYear(), now.getMonth(), 1); 
  recs = recs.filter(p => new Date(p.FECHA_REGISTRO) >= ms && new Date(p.FECHA_REGISTRO) <= now);
}
  • Window: 1st of month 00:00 to current time
  • Reset: 1st of each month
  • Use: Monthly KPI tracking

Status Calculation

Tolerances have three status levels based on percentage consumed:
// From TolerancesPage.tsx:38-44
const qty = recs.reduce((s, r) => s + Number(r.TOTAL_PZAS || 0), 0);
const cost = recs.reduce((s, r) => s + (r.COSTO || 0), 0);
const qPct = t.cantidad_max > 0 ? (qty / t.cantidad_max) * 100 : 0;
const cPct = t.costo_max > 0 ? (cost / t.costo_max) * 100 : 0;
const maxPct = Math.max(qPct, cPct);
const status = maxPct >= 100 ? 'red' : maxPct >= t.porcentaje_alerta ? 'yellow' : 'green';
return { qty, cost, qPct, cPct, maxPct, status };

Status Levels

1

🟢 Green (Within Meta)

Condition: maxPct < porcentaje_alertaMeaning: Scrap is below alert thresholdExample: 65% of limit consumedAction: Normal operation, no concern
2

🟡 Yellow (Warning)

Condition: porcentaje_alerta <= maxPct < 100Meaning: Approaching limitExample: 85% of limit consumed (alert set at 80%)Action: Review processes, prepare corrective action
3

🔴 Red (Exceeded)

Condition: maxPct >= 100Meaning: Limit has been exceededExample: 110% of limit consumedAction: Immediate investigation, 8D report, CAPA
Red status triggers animated pulse effect to grab attention.

Dual-Threshold Logic

The status uses the higher of quantity or cost percentage:
const maxPct = Math.max(qPct, cPct);
Example Scenario:
  • Quantity: 400 / 500 = 80% ✅
  • Cost: 1400/1400 / 1500 = 93% ⚠️
  • Overall Status: 🟡 Yellow (93% is higher)
This ensures alerts trigger if either quantity or cost exceeds the threshold, providing comprehensive monitoring.

Tolerance Configuration

1

Navigate to Tolerances

Click Pérdida Tolerable in the admin menu (requires manage_tolerances permission).
2

Click 'Nueva Tolerancia'

The configuration modal appears with the following fields:
// From TolerancesPage.tsx:157-226
<form>
  <input name="nombre" placeholder="Tolerance name" />
  <select name="tipo_objetivo">
    <option value="global">Global</option>
    <option value="cadena">Por Cadena</option>
    <option value="linea">Por Línea</option>
    <option value="area">Por Área</option>
    <option value="categoria">Por Categoría</option>
  </select>
  <select name="tipo_periodo">
    <option value="diario">Diario</option>
    <option value="semanal">Semanal</option>
    <option value="mensual">Mensual</option>
  </select>
  <select name="objetivo_id">{/* Dynamic options */}</select>
  <input name="cantidad_max" type="number" placeholder="Max quantity" />
  <input name="costo_max" type="number" placeholder="Max cost $" />
  <input name="porcentaje_alerta" type="number" placeholder="Alert %" />
</form>
3

Fill Configuration

Example Configuration:
  • Name: “Assembly Area Weekly Limit”
  • Target Type: Por Área
  • Target: Assembly (dropdown auto-populates with active areas)
  • Period: Semanal
  • Max Quantity: 2000 pieces
  • Max Cost: $5000 USD
  • Alert %: 80
4

Save

Click Guardar. The tolerance immediately becomes active and starts monitoring.
// From TolerancesPage.tsx:56-60
const handleSave = (t: Tolerancia) => {
  if (editItem) store.updateItem('tolerancias', t.id, t as unknown as Record<string, unknown>);
  else store.addItem('tolerancias', { ...t, id: 0 } as unknown as Record<string, unknown>);
  setShowModal(false); setEditItem(null);
};

Tolerance Display

Tolerances appear in two places:

1. Tolerances Page

// From TolerancesPage.tsx:104-150
{filtered.map(t => {
  const s = getStatus(t);
  return (
    <div key={t.id} style={cardStyle}>
      <div style={{ display: 'flex', justifyContent: 'space-between' }}>
        <div>
          <h3>{t.nombre}</h3>
          <p>{t.tipo_periodo} | {t.objetivo_id || 'Global'} | Alerta al {t.porcentaje_alerta}%</p>
        </div>
        <span style={{ color: statusColor(s.status) }}>
          {s.status === 'green' ? '🟢 Dentro de meta' : s.status === 'yellow' ? '🟡 Advertencia' : '🔴 Excedido'}
        </span>
      </div>
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '12px' }}>
        {/* Quantity bar */}
        <div>
          <span>Cantidad: {s.qty} / {t.cantidad_max} pzas</span>
          <div style={{ width: '100%', height: '12px', background: 'var(--border-color)' }}>
            <div style={{ width: `${Math.min(s.qPct, 100)}%`, background: statusColor(s.status) }} />
          </div>
        </div>
        {/* Cost bar */}
        <div>
          <span>Costo: ${s.cost.toFixed(0)} / ${t.costo_max} USD</span>
          <div style={{ width: '100%', height: '12px', background: 'var(--border-color)' }}>
            <div style={{ width: `${Math.min(s.cPct, 100)}%`, background: statusColor(s.status) }} />
          </div>
        </div>
      </div>
    </div>
  );
})}
Features:
  • Grouped by tabs (Global, Cadena, Línea, Área, Categoría)
  • Progress bars for quantity and cost
  • Status badge with color coding
  • Edit/Delete buttons

2. Dashboard Widget

// From Dashboard.tsx:154-190
{toleranceStatus.length > 0 && (
  <div style={cardStyle}>
    <h3>Estado de Tolerancias</h3>
    <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(260px, 1fr))', gap: '12px' }}>
      {toleranceStatus.map(t => (
        <div key={t.id}>
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <span>{t.nombre}</span>
            <span style={{ color: statusColor(t.status) }}>
              {t.status === 'green' ? '🟢 OK' : t.status === 'yellow' ? '🟡 Alerta' : '🔴 Excedido'}
            </span>
          </div>
          <div style={{ width: '100%', height: '8px', background: 'var(--border-color)' }}>
            <div className={t.status === 'red' ? 'animate-pulse-red' : ''} style={{ width: `${Math.min(t.maxPct, 100)}%`, background: statusColor(t.status) }} />
          </div>
          <div style={{ display: 'flex', justifyContent: 'space-between' }}>
            <span>{t.totalQty}/{t.cantidad_max} pzas</span>
            <span>${t.totalCost.toFixed(0)}/${t.costo_max} USD</span>
          </div>
        </div>
      ))}
    </div>
  </div>
)}
Features:
  • Compact card layout
  • Responsive grid (auto-fit)
  • Animated pulse on exceeded status
  • Quick at-a-glance monitoring

Summary Statistics

The Tolerances page displays an overview:
// From TolerancesPage.tsx:48-53
const summary = useMemo(() => {
  const all = state.tolerancias.filter(t => t.activo);
  let inMeta = 0, inWarn = 0, exceeded = 0;
  all.forEach(t => { 
    const s = getStatus(t); 
    if (s.status === 'green') inMeta++; 
    else if (s.status === 'yellow') inWarn++; 
    else exceeded++;
  });
  return { total: all.length, inMeta, inWarn, exceeded };
}, [state.tolerancias, pesajes]);

Total Configured

Number of active tolerances

Within Meta

Count of green tolerances

In Warning

Count of yellow tolerances

Exceeded

Count of red tolerances — requires immediate action

Edit & Delete

  1. Click the Edit (pencil) icon on a tolerance card
  2. Modal opens with pre-filled values
  3. Modify any field
  4. Click Guardar
// From TolerancesPage.tsx:124
<button onClick={() => { setEditItem(t); setShowModal(true); }}>
  <Edit3 size={16} />
</button>
Changes take effect immediately. The status recalculates with current data.

Dynamic Target Selection

The “Objetivo” dropdown dynamically populates based on target type:
// From TolerancesPage.tsx:161-169
const objetivoOptions = () => {
  switch (form.tipo_objetivo) {
    case 'cadena': return state.cadenas.filter(c => c.activo).map(c => c.nombre);
    case 'linea': return state.lineas.filter(l => l.activo).map(l => l.nombre);
    case 'area': return state.areas.filter(a => a.activo).map(a => a.AREA);
    case 'categoria': return state.categorias.filter(c => c.activo).map(c => c.nombre);
    default: return [];
  }
};
Example Flow:
  1. Select “Por Área” → Dropdown shows: Assembly, Paint, Welding, etc.
  2. Select “Por Categoría” → Dropdown shows: Material, Process, Quality, etc.
  3. Select “Global” → No dropdown (applies to all)

Permissions

Only users with manage_tolerances permission can access:
// From TolerancesPage.tsx:23
if (!can('manage_tolerances')) 
  return <div>Sin permisos.</div>;
Default Roles:
  • Operator — No access
  • Supervisor — No access
  • Quality — Can configure tolerances
  • Admin — Full access
All users can view tolerance status on the dashboard, but only Quality/Admin can configure them.

Best Practices

  • Analyze historical data (3-6 months)
  • Set quantity max at 80th percentile of historical highs
  • Set cost max based on budget allocation
  • Start with 80% alert threshold, adjust based on team response
  • Daily: Fast-paced production, high-volume lines
  • Weekly: Standard manufacturing cycles
  • Monthly: Strategic planning, budgeting
Avoid overly short periods (causes alert fatigue) or too long (delays corrective action).
Start broad, then narrow:
  1. Set global monthly tolerance
  2. Add area-level weekly tolerances
  3. Add problematic line daily tolerances
  4. Add category-specific limits for high-cost defects
Too many tolerances = alert fatigue.
Common values:
  • 70% — Very aggressive, early warning
  • 80% — Standard, balanced approach
  • 90% — Conservative, late warning
Adjust based on:
  • Team response time
  • Corrective action effectiveness
  • Historical alert accuracy

Troubleshooting

Causes:
  1. Max limits set too low (unrealistic targets)
  2. Historical data skews calculation
  3. Wrong target selected (e.g., filtering by wrong area)
Solution:
  • Review last period’s actual scrap
  • Increase max quantity/cost
  • Verify target ID matches intended area/chain
Causes:
  1. activo flag is 0 (inactive)
  2. Target type mismatch (e.g., selected area that doesn’t exist)
  3. No scrap data matches the filter
Solution:
  • Check tolerance is marked active
  • Verify target ID exists in catalog
  • Register some scrap to test
Check:
  • Both quantity AND cost are tracked — status uses the higher percentage
  • Time period window (daily resets at midnight, weekly on Monday)
  • Soft-deleted records are excluded (ELIMINADO = 1)
Debug:
console.log('Quantity:', s.qty, '/', t.cantidad_max, '=', s.qPct + '%');
console.log('Cost:', s.cost, '/', t.costo_max, '=', s.cPct + '%');
console.log('Max:', s.maxPct, '→', s.status);

Dashboard

View live tolerance status with visual alerts

Reports

Analyze scrap trends to inform tolerance limits

Catalog Management

Manage areas, chains, and categories used in tolerances

Build docs developers (and LLMs) love