Overview
Manage tolerance limits for scrap quantity and cost. Tolerances define acceptable scrap levels and trigger alerts when exceeded.
Tolerances can be set globally or for specific targets (area, chain, line, category) with different time periods (daily, weekly, monthly).
Authentication
Requires valid JWT token. Creating and editing requires admin or calidad role.
Authorization: Bearer <token>
Endpoints
List All Tolerances
curl -X GET http://localhost:3001/api/tolerances \
-H "Authorization: Bearer YOUR_TOKEN"
Get Tolerance by ID
curl -X GET http://localhost:3001/api/tolerances/1 \
-H "Authorization: Bearer YOUR_TOKEN"
Create Tolerance
curl -X POST http://localhost:3001/api/tolerances \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"nombre": "Límite Mensual Ensamble",
"tipo_objetivo": "area",
"objetivo_id": "Ensamble",
"tipo_periodo": "mensual",
"cantidad_max": 10000,
"costo_max": 25000,
"porcentaje_alerta": 80
}'
Update Tolerance
curl -X PUT http://localhost:3001/api/tolerances/1 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{"cantidad_max": 12000, "costo_max": 30000}'
Delete Tolerance
curl -X DELETE http://localhost:3001/api/tolerances/1 \
-H "Authorization: Bearer YOUR_TOKEN"
Get Tolerance Status
This endpoint calculates current usage vs. limits for all active tolerances.
curl -X GET http://localhost:3001/api/tolerances/status/all \
-H "Authorization: Bearer YOUR_TOKEN"
Data Structure
Unique tolerance identifier
Tolerance name/description
Target type: global, cadena, linea, area, categoria
Target identifier (e.g., area name, chain ID). NULL for global tolerances.
Time period: diario, semanal, mensual
Maximum acceptable quantity (pieces)
Maximum acceptable cost (USD)
Alert threshold percentage (0-100)
Status: 1 = active, 0 = inactive
Response Example
[
{
"id": 1,
"nombre": "Límite Global Mensual",
"tipo_objetivo": "global",
"objetivo_id": null,
"tipo_periodo": "mensual",
"cantidad_max": 50000,
"costo_max": 100000,
"porcentaje_alerta": 80,
"activo": 1
},
{
"id": 2,
"nombre": "Límite Diario Ensamble",
"tipo_objetivo": "area",
"objetivo_id": "Ensamble",
"tipo_periodo": "diario",
"cantidad_max": 500,
"costo_max": 1200,
"porcentaje_alerta": 75,
"activo": 1
}
]
Tolerance Status Response
[
{
"id": 2,
"nombre": "Límite Diario Ensamble",
"tipo_objetivo": "area",
"objetivo_id": "Ensamble",
"tipo_periodo": "diario",
"cantidad_max": 500,
"costo_max": 1200,
"porcentaje_alerta": 75,
"activo": 1,
"totalQty": 420,
"totalCost": 1050.50,
"qtyPct": 84.0,
"costPct": 87.5,
"maxPct": 87.5,
"status": "yellow"
}
]
Current quantity in this period
Current cost in this period
Percentage of quantity limit reached
Percentage of cost limit reached
Maximum of qtyPct and costPct
Status: green (< alert %), yellow (>= alert %), red (>= 100%)
Dashboard Integration
const ToleranceMonitor: React.FC = () => {
const [tolerances, setTolerances] = useState([]);
useEffect(() => {
const fetchStatus = async () => {
const response = await fetch(
'http://localhost:3001/api/tolerances/status/all',
{
headers: { 'Authorization': `Bearer ${getToken()}` }
}
);
const data = await response.json();
setTolerances(data);
};
fetchStatus();
const interval = setInterval(fetchStatus, 60000); // Refresh every minute
return () => clearInterval(interval);
}, []);
return (
<div className="tolerance-grid">
{tolerances.map(t => (
<ToleranceCard key={t.id} tolerance={t} />
))}
</div>
);
};
const ToleranceCard: React.FC<{ tolerance: any }> = ({ tolerance }) => {
const getStatusColor = (status: string) => {
switch (status) {
case 'green': return '#22c55e';
case 'yellow': return '#eab308';
case 'red': return '#ef4444';
default: return '#6b7280';
}
};
return (
<div className="card" style={{ borderLeft: `4px solid ${getStatusColor(tolerance.status)}` }}>
<h3>{tolerance.nombre}</h3>
<p>Target: {tolerance.tipo_objetivo} - {tolerance.objetivo_id || 'Global'}</p>
<p>Period: {tolerance.tipo_periodo}</p>
<div className="progress-bar">
<div
className="progress-fill"
style={{
width: `${Math.min(tolerance.maxPct, 100)}%`,
backgroundColor: getStatusColor(tolerance.status)
}}
/>
</div>
<p>{tolerance.maxPct.toFixed(1)}% of limit</p>
<p>Cost: ${tolerance.totalCost.toFixed(2)} / ${tolerance.costo_max}</p>
<p>Qty: {tolerance.totalQty} / {tolerance.cantidad_max}</p>
</div>
);
};
Alert System
const checkToleranceAlerts = async () => {
const response = await fetch(
'http://localhost:3001/api/tolerances/status/all',
{
headers: { 'Authorization': `Bearer ${getToken()}` }
}
);
const tolerances = await response.json();
const alerts = tolerances.filter(t =>
t.status === 'yellow' || t.status === 'red'
);
if (alerts.length > 0) {
alerts.forEach(alert => {
const severity = alert.status === 'red' ? '🚨 CRITICAL' : '⚠️ WARNING';
console.warn(
`${severity}: ${alert.nombre} is at ${alert.maxPct.toFixed(1)}%`
);
// Send notification
notifyUser({
title: `Tolerance Alert: ${alert.nombre}`,
message: `Current usage is at ${alert.maxPct.toFixed(1)}% of the limit`,
severity: alert.status
});
});
}
return alerts;
};
// Run every 5 minutes
setInterval(checkToleranceAlerts, 5 * 60 * 1000);
TypeScript Interface
export interface Tolerancia {
id: number;
nombre: string;
tipo_objetivo: 'global' | 'cadena' | 'linea' | 'area' | 'categoria';
objetivo_id: string;
tipo_periodo: 'diario' | 'semanal' | 'mensual';
cantidad_max: number;
costo_max: number;
porcentaje_alerta: number;
activo: number;
}