Datos del Trabajador
- Nombres mal escritos
- Apellidos incorrectos
- Número de documento errado
- Tipo de documento equivocado
- Dirección incorrecta
La Nota de Ajuste de Reemplazo se utiliza para corregir información NO monetaria de un documento de nómina previamente emitido. Este documento reemplaza completamente al original con datos corregidos.
Datos del Trabajador
Información del Período
Datos del Empleador
Información Adicional
El XML de Reemplazo usa un nodo raíz diferente y estructura especial:
<NominaIndividualDeAjuste xmlns="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd"><!-- OBLIGATORIO: TipoNota = 1 para Reemplazo --><TipoNota>1</TipoNota>| Valor | Tipo de Nota |
|---|---|
| 1 | Reemplazo (corrección informativa) |
| 2 | Eliminación (anular documento) |
<Reemplazar> <!-- Referencia al documento a reemplazar --> <ReemplazandoPredecesor NumeroPred="NOM35921" CUNEPred="a1b2c3d4e5f6..." FechaGenPred="2024-11-20"/>
<!-- TODOS los datos corregidos del documento --> <Periodo ... /> <NumeroSecuenciaXML ... /> <LugarGeneracionXML ... /> <InformacionGeneral ... /> <Empleador ... /> <Trabajador ... /> <Pago ... /> <FechasPagos>...</FechasPagos> <Devengados>...</Devengados> <Deducciones>...</Deducciones> <DevengadosTotal>...</DevengadosTotal> <DeduccionesTotal>...</DeduccionesTotal> <ComprobanteTotal>...</ComprobanteTotal></Reemplazar><?xml version="1.0" encoding="UTF-8"?><NominaIndividualDeAjuste xmlns="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste" xmlns:xs="http://www.w3.org/2001/XMLSchema-instance" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" xmlns:ext="urn:oasis:names:specification:ubl:schema:xsd:CommonExtensionComponents-2" xmlns:xades="http://uri.etsi.org/01903/v1.3.2#" xmlns:xades141="http://uri.etsi.org/01903/v1.4.1#" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" SchemaLocation="" xsi:schemaLocation="dian:gov:co:facturaelectronica:NominaIndividualDeAjuste NominaIndividualDeAjusteElectronicaXSD.xsd">
<ext:UBLExtensions/>
<!-- Tipo de Nota: 1 = Reemplazo --> <TipoNota>1</TipoNota>
<Reemplazar> <!-- Referencia al documento original --> <ReemplazandoPredecesor NumeroPred="NOM35921" CUNEPred="a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2" FechaGenPred="2024-11-20"/>
<!-- Datos corregidos del período --> <Periodo FechaIngreso="2024-01-01" FechaRetiro="" FechaLiquidacionInicio="2024-11-01" FechaLiquidacionFin="2024-11-30" TiempoLaborado="330" FechaGen="2024-11-26"/>
<!-- Nuevo consecutivo para el ajuste --> <NumeroSecuenciaXML CodigoTrabajador="001" Prefijo="ADJ" Consecutivo="00001" Numero="ADJ00001"/>
<LugarGeneracionXML Pais="CO" DepartamentoEstado="68" MunicipioCiudad="68001" Idioma="es"/>
<InformacionGeneral Version="V1.0: Documento Soporte de Pago de Nómina Electrónica" Ambiente="2" TipoXML="103" CUNE="" EncripCUNE="" FechaGen="2024-11-26" HoraGen="10:15:00-05:00" PeriodoNomina="5" TipoMoneda="COP" TRM="1"/>
<Notas>Corrección del segundo apellido del trabajador. Era GOMEZ, se corrige a GONZALEZ.</Notas>
<Empleador RazonSocial="MI EMPRESA SAS" NIT="901143311" DV="8" Pais="CO" DepartamentoEstado="68" MunicipioCiudad="68001" Direccion="Calle 123 # 45-67"/>
<!-- DATOS CORREGIDOS DEL TRABAJADOR --> <Trabajador TipoTrabajador="01" SubTipoTrabajador="00" AltoRiesgoPension="false" TipoDocumento="13" NumeroDocumento="1234567890" PrimerApellido="PEREZ" SegundoApellido="GONZALEZ" PrimerNombre="JUAN" OtrosNombres="CARLOS" LugarTrabajoPais="CO" LugarTrabajoDepartamentoEstado="68" LugarTrabajoMunicipioCiudad="68001" LugarTrabajoDireccion="Carrera 27 # 34-56" SalarioIntegral="false" TipoContrato="1" Sueldo="1300000" CodigoTrabajador="001"/>
<Pago Forma="1" Metodo="10" Banco="BANCOLOMBIA" TipoCuenta="AHORROS" NumeroCuenta="12345678901"/>
<FechasPagos> <FechaPago>2024-11-30</FechaPago> </FechasPagos>
<!-- Mismos valores monetarios del original --> <Devengados> <Basico DiasTrabajados="30" SueldoTrabajado="1300000"/> <Transporte AuxilioTransporte="162000"/> </Devengados>
<Deducciones> <Salud Porcentaje="4.00" Deduccion="52000"/> <FondoPension Porcentaje="4.00" Deduccion="52000"/> </Deducciones>
<Redondeo>0.00</Redondeo> <DevengadosTotal>1462000.00</DevengadosTotal> <DeduccionesTotal>104000.00</DeduccionesTotal> <ComprobanteTotal>1358000.00</ComprobanteTotal> </Reemplazar>
</NominaIndividualDeAjuste>
<?phpclass Nomina_Service_ReemplazoGenerator{ private $xmlGenerator; private $db;
public function __construct() { $this->xmlGenerator = new Nomina_Service_XMLGenerator(); $this->db = Zend_Db_Table::getDefaultAdapter(); }
/** * Genera XML de Nota de Ajuste - Reemplazo * * @param int $nominaOriginalId ID de la nómina a reemplazar * @param array $datosCorregidos Datos no monetarios corregidos * @return string XML de reemplazo */ public function generarReemplazo($nominaOriginalId, $datosCorregidos) { // 1. Obtener nómina original $nominaOriginal = $this->obtenerNomina($nominaOriginalId);
if (!$nominaOriginal) { throw new Exception("Nómina original no encontrada"); }
// 2. Verificar que tiene CUNE if (empty($nominaOriginal['cune'])) { throw new Exception("La nómina original debe estar autorizada"); }
// 3. Validar que solo se corrigen datos NO monetarios $this->validarDatosNoMonetarios($datosCorregidos);
// 4. Preparar datos de reemplazo $datosReemplazo = $this->prepararDatosReemplazo( $nominaOriginal, $datosCorregidos );
// 5. Generar XML con estructura de ajuste $xml = $this->generarXMLAjuste($datosReemplazo, $nominaOriginal);
// 6. Validar $validator = new Nomina_Service_XMLValidator(); if (!$validator->validar($xml)) { throw new Exception( 'XML de reemplazo inválido: ' . implode(', ', $validator->getErrores()) ); }
return $xml; }
private function validarDatosNoMonetarios($datos) { $camposMonetarios = [ 'sueldo_trabajado', 'devengados_total', 'deducciones_total', 'comprobante_total', 'auxilio_transporte', 'deduccion_salud', 'deduccion_pension' ];
foreach ($camposMonetarios as $campo) { if (isset($datos[$campo])) { throw new Exception( "No se pueden modificar valores monetarios con Reemplazo. " . "Use Novedad para corregir '$campo'" ); } } }
private function prepararDatosReemplazo($original, $correcciones) { $datos = $original; // Copiar todo
// Nuevo consecutivo $datos['prefijo'] = 'ADJ'; $datos['consecutivo'] = $this->obtenerSiguienteConsecutivo('ADJ'); $datos['numero'] = $datos['prefijo'] . $datos['consecutivo'];
// Fecha actual $datos['fecha_generacion'] = date('Y-m-d'); $datos['hora_generacion'] = date('H:i:s-05:00');
// Aplicar correcciones NO monetarias foreach ($correcciones as $campo => $valor) { $datos[$campo] = $valor; }
// Agregar nota $datos['notas'] = sprintf( "Corrección de información no monetaria de la nómina %s. " . "Campos corregidos: %s", $original['numero'], implode(', ', array_keys($correcciones)) );
return $datos; }
private function generarXMLAjuste($datos, $original) { $dom = new DOMDocument('1.0', 'UTF-8'); $dom->formatOutput = true;
// Nodo raíz de AJUSTE $root = $dom->createElementNS( 'dian:gov:co:facturaelectronica:NominaIndividualDeAjuste', 'NominaIndividualDeAjuste' );
// Namespaces $root->setAttributeNS( 'http://www.w3.org/2000/xmlns/', 'xmlns:xs', 'http://www.w3.org/2001/XMLSchema-instance' ); // ... más namespaces
$dom->appendChild($root);
// UBLExtensions $ext = $dom->createElement('ext:UBLExtensions'); $root->appendChild($ext);
// TipoNota = 1 (Reemplazo) $tipoNota = $dom->createElement('TipoNota', '1'); $root->appendChild($tipoNota);
// Nodo Reemplazar $reemplazar = $dom->createElement('Reemplazar'); $root->appendChild($reemplazar);
// ReemplazandoPredecesor $predecesor = $dom->createElement('ReemplazandoPredecesor'); $predecesor->setAttribute('NumeroPred', $original['numero']); $predecesor->setAttribute('CUNEPred', $original['cune']); $predecesor->setAttribute('FechaGenPred', $original['fecha_generacion']); $reemplazar->appendChild($predecesor);
// Agregar todos los nodos del documento corregido $reemplazar->appendChild($this->crearPeriodo($dom, $datos)); $reemplazar->appendChild($this->crearNumeroSecuencia($dom, $datos)); // ... más nodos
return $dom->saveXML(); }
// ... métodos auxiliares}<?php// Caso 1: Corregir apellido del trabajador$correcciones = [ 'trabajador' => [ 'segundo_apellido' => 'GONZALEZ' // Era GOMEZ ]];
$generator = new Nomina_Service_ReemplazoGenerator();$xml = $generator->generarReemplazo($nominaId, $correcciones);
// ---
// Caso 2: Corregir tipo de documento$correcciones = [ 'trabajador' => [ 'tipo_documento' => '13', // Era '31' 'numero_documento' => '1234567890' ]];
// ---
// Caso 3: Corregir fechas del período$correcciones = [ 'periodo' => [ 'fecha_ingreso' => '2024-02-01', // Era 2024-01-01 'tiempo_laborado' => 300 // Recalculado ]];
// ---
// Caso 4: Corregir datos bancarios$correcciones = [ 'pago' => [ 'banco' => 'DAVIVIENDA', // Era BANCOLOMBIA 'numero_cuenta' => '98765432101' // Cuenta corregida ]];<?phpfunction validarReemplazo($nominaOriginalId, $correcciones){ $errores = [];
// 1. Verificar que la nómina existe $nomina = obtenerNomina($nominaOriginalId); if (!$nomina) { $errores[] = "Nómina no encontrada"; return $errores; }
// 2. Verificar estado autorizado if ($nomina['estado'] !== 'AUTORIZADO') { $errores[] = "Solo se pueden reemplazar nóminas autorizadas"; }
// 3. Verificar que tiene CUNE if (empty($nomina['cune'])) { $errores[] = "La nómina no tiene CUNE"; }
// 4. Verificar que no se han hecho ajustes previos if ($nomina['tiene_reemplazo']) { $errores[] = "Esta nómina ya fue reemplazada"; }
// 5. Validar que solo son datos NO monetarios $camposMonetarios = [ 'sueldo', 'devengados_total', 'deducciones_total', 'auxilio_transporte', 'horas_extras', 'bonificaciones' ];
foreach ($camposMonetarios as $campo) { if (isset($correcciones[$campo])) { $errores[] = "No se puede corregir '$campo' con Reemplazo. Use Novedad."; } }
// 6. Validar que hay al menos una corrección if (empty($correcciones)) { $errores[] = "Debe especificar al menos un campo a corregir"; }
return $errores;}
// Uso$errores = validarReemplazo($nominaId, $correcciones);
if (!empty($errores)) { throw new Exception("Validación fallida: " . implode(', ', $errores));}| Aspecto | Novedad | Reemplazo |
|---|---|---|
| Nodo raíz | NominaIndividual | NominaIndividualDeAjuste |
| Corrige | Valores monetarios | Información no monetaria |
| TipoXML | 102 | 103 |
| Nodo especial | <Novedad CUNENov="...">true</Novedad> | <TipoNota>1</TipoNota> |
| Estructura | Igual a nómina normal | Nodo <Reemplazar> contenedor |
| Documento original | Sigue vigente | Queda anulado |
| Prefijo | NOV | ADJ |
| Efecto | Complementa | Reemplaza completamente |
NominaIndividualDeAjusteTipoNota = 1Reemplazar presenteReemplazandoPredecesor correcto