Skip to main content

Overview

The Production Tracking module provides comprehensive monitoring and reporting across all manufacturing stages. Each production area (Print, Die-cut, Rewind, Packaging) has dedicated tracking interfaces with activity logging and tooling status verification.

Multi-Stage Tracking

Separate interfaces for Print, Die-cut, Rewind, and Packaging operations

Activity Breakdown

Detailed time tracking for setup, production runs, and downtime

Tooling Status

Real-time clise and die condition monitoring

Production Reports

Comprehensive reports with operator notes and quality observations

Production Stages

P.FLEX tracks production across four primary manufacturing stages:
The print module provides the most comprehensive tracking with activity timeline and tooling status.

Report Data Model

// Print Report Interface (production-print.component.ts:9-32)
interface PrintActivity {
  type: string;        // 'Setup', 'Impresión', 'Parada', etc.
  startTime: string;   // HH:mm format
  endTime: string;     // HH:mm format
  meters: number;      // Meters produced (0 for non-production)
  duration?: string;   // Calculated duration
}

interface PrintReport {
  id: string;
  date: Date;
  ot: string;                    // Work order reference
  client: string;
  product: string;
  machine: string;
  operator: string;
  shift: string;                 // 'Día - A' or 'Noche - B'
  activities: PrintActivity[];   // Timeline breakdown
  totalMeters: number;
  clise: { 
    code: string;                // Clisé identifier
    status: string;              // 'OK', 'Desgaste', 'Dañado'
  };
  die: { status: string };
  observations: string;
  productionStatus: 'PARCIAL' | 'TOTAL';
}

Activity Timeline

Production activities are logged chronologically with start/end times:
// Activity Generation Example (production-print.component.ts:383-388)
const activities: PrintActivity[] = [
  { 
    type: 'Setup', 
    startTime: '07:00', 
    endTime: '08:30', 
    meters: 0 
  },
  { 
    type: 'Impresión', 
    startTime: '08:30', 
    endTime: '11:00', 
    meters: Math.floor(totalMeters * 0.4) 
  },
  { 
    type: 'Parada - Cambio Bobina', 
    startTime: '11:00', 
    endTime: '11:15', 
    meters: 0 
  },
  { 
    type: 'Impresión', 
    startTime: '11:15', 
    endTime: '13:00', 
    meters: Math.floor(totalMeters * 0.6) 
  }
];

Duration Calculation

// Calculate Activity Duration (production-print.component.ts:461-470)
calculateDuration(start: string, end: string): string {
  const [h1, m1] = start.split(':').map(Number);
  const [h2, m2] = end.split(':').map(Number);
  let diff = (h2 * 60 + m2) - (h1 * 60 + m1);
  if (diff < 0) diff += 24 * 60; // Handle overnight shifts
  
  const hours = Math.floor(diff / 60);
  const mins = diff % 60;
  return `${hours}h ${mins}m`;
}

KPI Dashboard

Each production module displays aggregated performance metrics.
// KPI Calculations (production-print.component.ts:427-438)
get kpis() {
  const totalMeters = this.reports.reduce((acc, r) => acc + r.totalMeters, 0);
  const totalHours = this.reports.length * 6; // Mock avg hours
  const avgSpeed = totalHours > 0 ? (totalMeters / (totalHours * 60)) : 0;
  
  return {
    totalMeters,
    avgSpeed: avgSpeed * 5,  // Scaling for realistic m/min
    completedOts: this.reports.filter(r => 
      r.productionStatus === 'TOTAL'
    ).length,
    toolingIssues: this.reports.filter(r => 
      r.die.status !== 'OK' || r.clise.status !== 'OK'
    ).length
  };
}

KPI Display

// KPI Cards UI (production-print.component.ts:68-118)
<div class="grid grid-cols-4 gap-6 mb-8">
  <!-- Total Meters -->
  <div class="glass-card p-5 rounded-2xl">
    <p class="text-[10px] text-blue-400 font-bold uppercase">
      <span class="material-icons text-sm">straighten</span> Total Metros (Mes)
    </p>
    <p class="text-3xl font-black text-white">
      {{ kpis.totalMeters | number }} <span class="text-sm">m</span>
    </p>
    <div class="text-xs text-slate-400">+12% vs mes anterior</div>
  </div>
  
  <!-- Average Speed -->
  <div class="glass-card p-5 rounded-2xl">
    <p class="text-[10px] text-emerald-400 font-bold uppercase">
      <span class="material-icons text-sm">speed</span> Velocidad Prom.
    </p>
    <p class="text-3xl font-black text-white">
      {{ kpis.avgSpeed | number:'1.0-0' }} <span class="text-sm">m/min</span>
    </p>
    <div class="w-full bg-slate-700/50 h-1.5 rounded-full mt-3">
      <div class="bg-emerald-500 h-full" style="width: 85%"></div>
    </div>
  </div>
  
  <!-- Completed OTs -->
  <div class="glass-card p-5 rounded-2xl">
    <p class="text-[10px] text-purple-400 font-bold uppercase">
      <span class="material-icons text-sm">assignment_turned_in</span> OTs Completadas
    </p>
    <p class="text-3xl font-black text-white">
      {{ kpis.completedOts }} <span class="text-sm">ordenes</span>
    </p>
  </div>
  
  <!-- Tooling Alerts -->
  <div class="glass-card p-5 rounded-2xl">
    <p class="text-[10px] text-red-400 font-bold uppercase">
      <span class="material-icons text-sm">warning</span> Alertas Herramental
    </p>
    <p class="text-3xl font-black text-white">
      {{ kpis.toolingIssues }} <span class="text-sm">casos</span>
    </p>
    <p class="text-xs text-red-400/80 bg-red-500/10 inline-block px-2 py-0.5 rounded">
      Requiere Atención
    </p>
  </div>
</div>
KPIs are calculated dynamically from the reports array and update in real-time as new reports are added.

Tooling Status Tracking

Critical for quality control, the system tracks condition of clisés (printing plates) and dies.

Status States

Tooling is in good condition and performing within specifications.Visual Indicator: Green badge with checkmark
Showing signs of wear but still usable. Schedule replacement soon.Visual Indicator: Yellow badge with warning iconAction Required: Add to maintenance queue
Damaged and requires immediate replacement or repair.Visual Indicator: Red badge with error iconAction Required: Remove from production, create maintenance ticket

Tooling Status Logic

// Status Assignment (production-print.component.ts:394-396)
const dieStatus = index % 5 === 0 ? 'Desgaste' : 
  (index % 15 === 0 ? 'Dañado' : 'OK');
const cliseStatus = index % 7 === 0 ? 'Desgaste' : 'OK';

Status Display

// Status Badge Helper (production-print.component.ts:452-459)
getStatusClass(status: string) {
  switch(status) {
    case 'OK': 
      return 'bg-emerald-500/10 text-emerald-400 border-emerald-500/20';
    case 'Desgaste': 
      return 'bg-yellow-500/10 text-yellow-400 border-yellow-500/20';
    case 'Dañado': 
      return 'bg-red-500/10 text-red-400 border-red-500/20';
    default: 
      return 'bg-slate-500/10 text-slate-400';
  }
}

Report Detail Modal

Clicking any report row opens a comprehensive detail view.

Product Information

Client, product description, machine, operator details

Tooling Status

Clisé code, die status, condition indicators

Activity Timeline

Full breakdown of setup, production runs, and stoppages

Observations

Operator notes and quality remarks

Activities Table

// Activity Breakdown Table (production-print.component.ts:277-313)
<table class="w-full text-sm">
  <thead class="bg-white/5 text-slate-400">
    <tr>
      <th class="px-5 py-3">Actividad</th>
      <th class="px-5 py-3 text-center">Horario</th>
      <th class="px-5 py-3 text-center">Duración</th>
      <th class="px-5 py-3 text-right">Metros</th>
    </tr>
  </thead>
  <tbody class="divide-y divide-white/5">
    <tr *ngFor="let act of selectedReport.activities">
      <td class="px-5 py-3 font-medium text-white">
        <div class="flex items-center gap-2">
          <div class="w-1.5 h-1.5 rounded-full" 
            [ngClass]="act.meters > 0 ? 'bg-emerald-500' : 'bg-slate-500'">
          </div>
          {{ act.type }}
        </div>
      </td>
      <td class="px-5 py-3 text-center font-mono text-xs">
        {{ act.startTime }} - {{ act.endTime }}
      </td>
      <td class="px-5 py-3 text-center font-mono text-xs text-slate-500">
        {{ calculateDuration(act.startTime, act.endTime) }}
      </td>
      <td class="px-5 py-3 text-right font-mono font-bold" 
        [class.text-emerald-400]="act.meters > 0">
        {{ act.meters > 0 ? (act.meters | number) : '-' }}
      </td>
    </tr>
  </tbody>
  <tfoot class="bg-white/5 border-t border-white/10 font-bold">
    <tr>
      <td colspan="3" class="px-5 py-3 text-right text-xs uppercase">
        Total Producción
      </td>
      <td class="px-5 py-3 text-right font-mono">
        {{ selectedReport.totalMeters | number }}
      </td>
    </tr>
  </tfoot>
</table>

Production Status Classification

Reports are classified as either PARTIAL or TOTAL production:
// Status Badge (production-print.component.ts:162-169)
<span class="px-2 py-1 rounded text-[10px] font-bold uppercase"
  [ngClass]="{
    'bg-emerald-500/10 text-emerald-400 border-emerald-500/20': 
      report.productionStatus === 'TOTAL',
    'bg-amber-500/10 text-amber-400 border-amber-500/20': 
      report.productionStatus === 'PARCIAL'
  }">
  {{ report.productionStatus }}
</span>
Definition: Order completed in full during this production run.Criteria:
  • All planned meters/pieces produced
  • Quality verification passed
  • Ready for next stage or finished goods
Visual: Green badge with “TOTAL”

Report Generation

Reports are generated from active OTs with realistic production data:
// Report Generation Logic (production-print.component.ts:373-415)
generateReports() {
  const ots = this.ordersService.ots.slice(0, 20);
  const machines = this.state.adminMachines()
    .filter(m => m.type === 'Impresión');
  const operators = ['Juan Martinez', 'Carlos Ruiz', 'Miguel Torres', 'Ana Lopez'];
  
  this.reports = ots.map((ot, index) => {
    const isComplete = index % 3 !== 0;
    const totalMeters = Math.floor(Math.random() * 15000) + 2000;
    
    const activities: PrintActivity[] = [
      { type: 'Setup', startTime: '07:00', endTime: '08:30', meters: 0 },
      { type: 'Impresión', startTime: '08:30', endTime: '11:00', 
        meters: Math.floor(totalMeters * 0.4) },
      { type: 'Parada - Cambio Bobina', startTime: '11:00', 
        endTime: '11:15', meters: 0 },
      { type: 'Impresión', startTime: '11:15', endTime: '13:00', 
        meters: Math.floor(totalMeters * 0.6) },
    ];

    const date = new Date();
    date.setDate(date.getDate() - (index % 7));
    date.setHours(7 + (index % 10), 0);

    return {
      id: `REP-${1000 + index}`,
      date: date,
      ot: ot.OT,
      client: ot['Razon Social'],
      product: ot.descripcion || ot.impresion || 'Etiqueta Genérica',
      machine: machines[index % machines.length]?.name || 'Máquina 1',
      operator: operators[index % operators.length],
      shift: index % 2 === 0 ? 'Día - A' : 'Noche - B',
      activities: activities,
      totalMeters: totalMeters,
      clise: { 
        code: `CL-${ot.OT}-01`, 
        status: index % 7 === 0 ? 'Desgaste' : 'OK' 
      },
      die: { 
        status: index % 5 === 0 ? 'Desgaste' : 
          (index % 15 === 0 ? 'Dañado' : 'OK') 
      },
      observations: index % 4 === 0 ? 
        'Leve variación de tono en la segunda bobina. Ajuste de presión realizado.' : '',
      productionStatus: isComplete ? 'TOTAL' : 'PARCIAL'
    };
  });
}

Search and Filtering

Production reports can be searched across multiple fields:
// Search Implementation (production-print.component.ts:417-425)
get filteredReports() {
  const term = this.searchTerm.toLowerCase();
  return this.reports.filter(r => 
    r.ot.toLowerCase().includes(term) ||
    r.machine.toLowerCase().includes(term) ||
    r.operator.toLowerCase().includes(term) ||
    r.client.toLowerCase().includes(term)
  );
}
Search is performed in real-time as the user types, with no debounce delay for immediate feedback.

Operator Information

Each report tracks the responsible operator with avatar initials:
// Operator Display (production-print.component.ts:152-157)
<td class="px-6 py-4 text-slate-400 font-medium text-xs">
  <div class="flex items-center gap-2">
    <div class="w-6 h-6 rounded-full bg-slate-700 flex items-center justify-center text-[10px] font-bold text-white">
      {{ getInitials(report.operator) }}
    </div>
    {{ report.operator }}
  </div>
</td>

// Initials Helper (production-print.component.ts:448-450)
getInitials(name: string) {
  return name.split(' ').map(n => n[0]).join('').substring(0, 2).toUpperCase();
}

PDF Export

Generate printable PDF reports for documentation and quality records.
// Export Button (production-print.component.ts:61-63)
<button class="bg-blue-600 hover:bg-blue-500 text-white px-5 py-2.5 rounded-xl text-sm font-bold flex items-center gap-2">
  <span class="material-icons text-sm">add</span> Nuevo Reporte
</button>
PDF export functionality requires the jspdf library. Ensure it’s installed in your project dependencies.

Integration with Other Modules

Production reports reference work orders from the OT module:
// OT Reference (production-print.component.ts:374)
const ots = this.ordersService.ots.slice(0, 20);
Machine assignments pull from the centralized machine registry:
// Machine Data (production-print.component.ts:375-376)
const machines = this.state.adminMachines()
  .filter(m => m.type === 'Impresión');
Clisé codes and die status connect to the inventory module for tooling lifecycle tracking.

Best Practices

Accurate Time Logging

Record exact start/end times for all activities to enable precise OEE calculations

Tooling Inspections

Inspect and update clisé/die status at every setup and changeover

Detailed Observations

Document any quality issues, adjustments, or anomalies in the observations field

Complete Reports

Mark production status (TOTAL/PARCIAL) accurately for inventory reconciliation

Order Management

View OT specifications and production requirements

Planning & Scheduling

Schedule production runs and assign machines

Inventory - Tooling

Manage clisés, dies, and track tooling lifecycle

Quality Control

Report production incidents and quality issues

Build docs developers (and LLMs) love