Overview
Work Orders (OTE - Órdenes de Trabajo de Ejecución) represent the execution phase of approved PTEs. This guide covers creating, tracking, and completing work orders.
Understanding Work Orders
What is an OTE? A work order is an executable document that includes:
Work scope and location
Timeline and schedule
Resource allocation
Progress tracking by steps
Production tracking
Financial information
Work Order Types
Initial OT Type ID : 4Original work order created from a completed PTE
Reprogramming Type ID : 5Extension or modification of an existing work order
Creating Work Orders
Option 1: From Completed PTE
See Managing Proposals - Creating Work Orders from PTEs
Option 2: Manual Creation
Navigate to OT Module
Go to Operaciones > Órdenes de Trabajo > Nuevo
Fill Basic Information
Required fields: @require_http_methods ([ "POST" ])
@login_required
def crear_ot ( request ):
orden_trabajo = request. POST .get( 'orden_trabajo' ) # Required
oficio_ot = request. POST .get( 'oficio_ot' )
id_tipo_id = request. POST .get( 'id_tipo' ) # 4 or 5
descripcion_trabajo = request. POST .get( 'descripcion_trabajo' )
ot = OTE .objects.create(
orden_trabajo = orden_trabajo,
oficio_ot = oficio_ot,
id_tipo_id = id_tipo_id,
descripcion_trabajo = descripcion_trabajo,
estatus = 1 , # Active
id_estatus_ot_id = 5 # ASIGNADA
)
Set Work Site
Configure location based on frente (work front):
Tierra / Patio Frente 1, 3: Select patio
Embarcaciones Frente 2, 6: Select vessel
Plataformas Frente 4, 7: Select platform
Intercom Frente 5: Select intercom site
Configure Dates
Set timeline:
Fecha Inicio Programado : Planned start date
Fecha Término Programado : Planned end date
Plazo Días : Duration in days
Financial Information
Enter amounts:
Monto MXN : Amount in Mexican Pesos
Monto USD : Amount in US Dollars
For Reprogramming Only
If creating a reprogramming (Tipo 5):
Select OT Principal : Parent work order
Enter Número de Reprogramación : Sequence number
Submit
Click Guardar to create the work order Steps are automatically created based on work order type and client
Work Order Status Management
Status Types
Status ID Description Use When ASIGNADA 5 Assigned to team Initial status EN PROCESO 6 Work started Execution begins PAUSADA 7 Temporarily paused Work stopped COMPLETADA 10 Finished All work done CANCELADA 11 Cancelled OT terminated
Changing Status
Open OT Details
Click on work order in the list
Click 'Cambiar Estatus'
Status change button in actions menu
Select New Status
Choose from dropdown
Add Comment
Explain reason for change
Set Completion Date
For COMPLETADA status, system auto-sets fecha_termino_real @registrar_actividad
def cambiar_estatus_ot ( request ):
ot_id = request. POST .get( 'ot_id' )
nuevo_estatus_id = request. POST .get( 'nuevo_estatus_id' )
ot = OTE .objects.get( id = ot_id)
ot.id_estatus_ot_id = nuevo_estatus_id
# Auto-set completion date
if int (nuevo_estatus_id) == 10 : # COMPLETADA
ot.fecha_termino_real = datetime.now()
ot.save()
Managing Work Order Steps
Step Status Flow
PENDIENTE (1)
Initial status - not started
EN PROCESO (2)
Work in progress
COMPLETADO (3)
Step finished successfully
Updating Step Progress
@require_http_methods ([ "POST" ])
@login_required
@registrar_actividad
def cambiar_estatus_paso_ot ( request ):
paso_id = request. POST .get( 'paso_id' )
nuevo_estatus = request. POST .get( 'nuevo_estatus' )
comentario = request. POST .get( 'comentario' , '' )
detalle = OTDetalle.objects.get( id = paso_id)
detalle.estatus_paso_id = int (nuevo_estatus)
detalle.comentario = comentario
# Auto-set completion date
if int (nuevo_estatus) == 3 :
detalle.fecha_entrega = timezone.now()
detalle.save()
Each step completion date is automatically recorded for tracking purposes.
Attaching Files to Steps
Click File Icon
On the step you want to attach evidence to
Paste File URL
Enter the URL of uploaded document (Google Drive, SharePoint, etc.)
Save
File link is stored with the step @registrar_actividad
def guardar_archivo_ot ( request ):
paso_id = request. POST .get( 'paso_id' )
url = request. POST .get( 'archivo' )
paso = OTDetalle.objects.get( id = paso_id)
paso.archivo = url
paso.save()
Progress Tracking
Progress Calculation
Work order progress combines time and step completion:
# Step progress (30% weight)
detalles = ot.detalles.all()
total_pasos = detalles.count()
pasos_completados = detalles.filter( estatus_paso_id = 3 ).count()
progreso_pasos = (pasos_completados / total_pasos) * 100
# Time progress (70% weight)
today = date.today()
if ot.fecha_inicio_programado and ot.fecha_termino_programado:
plazo_total = (ot.fecha_termino_programado - ot.fecha_inicio_programado).days
dias_transcurridos = (today - ot.fecha_inicio_programado).days
progreso_tiempo = (dias_transcurridos / plazo_total) * 100
# Combined progress
progreso_final = (progreso_tiempo * 0.7 ) + (progreso_pasos * 0.3 )
Progress Formula Final Progress = (Time Progress × 70%) + (Step Progress × 30%)This weighted formula ensures realistic progress tracking even if steps are completed early or late.
Viewing Progress
Progress Bar Visual indicator in OT list
Percentage Numeric value displayed
Days Remaining Countdown to deadline
Reprogramming Work Orders
When to Reprogram
Original deadline cannot be met - extend the work period
Additional work identified that wasn’t in original OT
Different resources or site configuration needed
Creating a Reprogramming
Create New OT
Go to Operaciones > OT > Nuevo
Select Type 5
Choose “Reprogramación” as the OT type
Link to Parent OT
if str (ot.id_tipo_id) == '5' : # Reprogramming
ot_principal_id = request. POST .get( 'ot_principal' )
num_reprogramacion = request. POST .get( 'num_reprogramacion' )
if not ot_principal_id:
return JsonResponse({
'exito' : False ,
'detalles' : 'Must select parent OT'
})
ot.ot_principal = ot_principal_id
ot.num_reprogramacion = num_reprogramacion
Set New Dates
Enter extended timeline
Submit
Reprogramming is created and linked to original OT
Progress tracking automatically includes all reprogramming in the OT family.
Work Site Management
Primary Work Site
Based on the Frente selection:
# User selects frente (work front)
id_frente_input = request. POST .get( 'id_frente' )
if id_frente_input == 1 : # Tierra
ot.id_patio = request. POST .get( 'id_patio' )
else :
# Set appropriate site field
ot.id_embarcacion = request. POST .get( 'id_embarcacion' )
ot.id_plataforma = request. POST .get( 'id_plataforma' )
ot.id_intercom = request. POST .get( 'id_intercom' )
Yard Phase Configuration
For offshore work requiring yard preparation:
Enable Yard Phase
Check “Requiere Fase de Patio”
Select Yard
Choose patio for preparation work
Set Yard Dates
ot.requiere_patio = True
ot.id_patio = request. POST .get( 'id_patio_fase' )
ot.fecha_inicio_patio = request. POST .get( 'fecha_inicio_patio' )
ot.fecha_fin_patio = request. POST .get( 'fecha_fin_patio' )
When yard phase is active, production tracking requires selecting the specific site (yard or final location).
Importing Annex Data
Excel Import Process
Prepare Excel File
Format must include columns:
ANEXO
PARTIDA
CONCEPTO
UNIDAD
VOLUMEN PTE
P.U. M.N.
P.U. USD (optional)
Upload File
Click Importar Anexo button on OT details page
System Validation
# Validate units exist
unidad_id_resuelto = unidades_lookup.get(norm_unidad_txt)
if not unidad_id_resuelto:
errores_validacion.append({
'OBSERVACIONES_SISTEMA' : f "Unidad ' { raw_unidad } ' no existe"
})
# Validate concepts in catalog
key_busqueda = (norm_codigo, norm_concepto, unidad_id_resuelto)
producto_encontrado = catalogo_map.get(key_busqueda)
if not producto_encontrado:
errores_validacion.append({
'OBSERVACIONES_SISTEMA' : 'NO ENCONTRADO en catálogo'
})
Review Errors
If validation fails:
Download error report
Fix issues in Excel
Re-upload
Confirm Import
Valid records are imported as PartidaAnexoImportada
Only one active import per OT. New imports replace previous ones (es_activo flag).
Adding Individual Items
To add concepts not in the Excel import:
Search Master Catalog
Use the search function to find concepts
Select Concept
Click to add to OT annex
System Creates Link
operaciones/views/produccion.py
@require_http_methods ([ "POST" ])
def vincular_partida_ot ( request ):
id_ot = request. POST .get( 'id_ot' )
id_concepto = request. POST .get( 'id_producto' )
importacion = ImportacionAnexo.objects.filter(
ot_id = id_ot, es_activo = True
).first()
concepto = ConceptoMaestro.objects.get( id = id_concepto)
PartidaAnexoImportada.objects.create(
importacion_anexo = importacion,
id_partida = codigo_partida,
descripcion_concepto = concepto.descripcion,
volumen_proyectado = 0 , # To be updated
precio_unitario_mn = concepto.precio_unitario_mn,
precio_unitario_usd = concepto.precio_unitario_usd
)
Filtering and Searching Work Orders
By Type Filter Initial OTs (4) or Reprogramming (5)
By Status ASIGNADA, EN PROCESO, COMPLETADA, etc.
By Site Filter by work location
By Year Filter by year from oficio or start date
By Client Filter by client organization
By Responsible Filter by project manager
Best Practices
Update Progress Daily Keep step status current for accurate tracking
Document Changes Use comments to explain status changes
Attach Evidence Link all deliverables and documentation
Monitor Deadlines Check dias_restantes regularly
Validate Imports Always review Excel import errors
Plan Reprogramming Create reprogramming early if deadlines at risk
Recording Production Track production volumes for work orders
Managing Proposals Create PTEs that generate work orders