Introducción al Uso de iText para la Impresión de Documentos Tributarios Electrónicos (DTE)

 

Nota Importante:

Esta guía está diseñada para abordar la implementación de generación de documentos tributarios electrónicos en el contexto de Chile, considerando las normativas del Servicio de Impuestos Internos (SII). Es posible que ciertos detalles o enfoques técnicos no sean aplicables en otros países con legislaciones diferentes.

En el mundo de la facturación electrónica, la generación y manejo eficiente de documentos tributarios electrónicos (DTE) es esencial para cumplir con las normativas y garantizar la integridad de los datos. Uno de los retos más comunes es la impresión de DTE en formato PDF, manteniendo la fidelidad del contenido y un diseño claro y profesional. Aquí es donde iText, una biblioteca de código abierto para manipulación de PDF, se convierte en una herramienta poderosa.

¿Qué es iText?

iText es una librería de Java especializada en la creación, manipulación y personalización de documentos PDF. Se utiliza ampliamente en aplicaciones empresariales que requieren generar documentos dinámicos como facturas, reportes, contratos y, en nuestro caso, DTE.

Ventajas de Usar iText en la Impresión de DTE

  1. Automatización del Proceso: Permite generar DTE en formato PDF de forma automatizada a partir de archivos XML.
  2. Compatibilidad con Normas Tributarias: Facilita la personalización del diseño para cumplir con los estándares de presentación exigidos por el Servicio de Impuestos Internos.

El flujo típico de impresión de un DTE incluye los siguientes pasos:

  1. Lectura del Documento XML: Extraer los datos necesarios, como RUT del emisor, tipo de documento, detalle de ítems, entre otros.
  2. Creación del PDF: Usar una plantilla base (opcional) y añadir dinámicamente los datos extraídos del XML.
  3. Formateo: Ajustar la presentación de los datos, como la alineación de tablas, el uso de fuentes específicas y la posición de los elementos en el documento.
  4. Incorporación de Timbre Elecrónico: Añade el timbre electrónico en formato PDF47 a la representación impresa del documento.
  5. Exportación: Guardar el documento en una carpeta específica o enviarlo directamente al cliente.

Un Ejemplo Práctico

Un ejemplo común es la impresión de una Factura Electrónica:

  • A partir del archivo XML del DTE, se extraen datos como el emisor, receptor, detalle de productos, totales y resoluciones.
  • Estos datos se colocan en un diseño predefinido utilizando iText, asegurando que la información clave se muestre de manera clara.
  • El documento se exporta como un archivo PDF, listo para ser entregado o almacenado.

Paso 1: Crear una plantilla PDF

Crea un archivo PDF base con herramientas como Adobe Acrobat, LibreOffice o cualquier editor de PDF que permita agregar campos de formulario. Asegúrate de:

  • Diseñar el layout del documento. 
  • Añadir campos de formulario con nombres únicos para cada dato que desees rellenar dinámicamente.

Guarda tu plantilla como plantilla.pdf 



Puedes descargar una copia de la plantilla acá.

Paso 2: Crear un Proyecto Maven

Crea un proyecto Maven que gestione las dependencias necesarias para trabajar con iText. Maven simplifica la configuración del entorno y asegura que todas las librerías estén disponibles para el desarrollo.

<dependencies>
    <dependency>
        <groupId>com.itextpdf</groupId>
        <artifactId>itext7-core</artifactId>
        <version>5.5.13.3</version> <!-- Sustituir por la versión más reciente -->
    </dependency>
</dependencies>

Paso 3: Cargar la plantilla y rellenar los datos

Crea una clase en tu proyecto, por ejemplo PrintDTE.java. Usa el siguiente código como base:


package printerdte;
import com.itextpdf.text.pdf.BarcodePDF417;
import java.io.FileOutputStream;
import com.itextpdf.text.pdf.BaseFont;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import java.io.StringWriter;
import java.text.DateFormat;
import java.text.DecimalFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

 


public class PrintDTE{
    
public void printDTE(String parmnombredte, String nroresol, String tipoCopia) throws Exception {

 
       DecimalFormat formatea = new DecimalFormat("###,###.##");
    
       String nombredte = parmnombredte;
       
 
         
        
        /* apunto donde esta el xml */
        String filepath = "/home/esteban/appdte/DTE/"+nombredte+"TED.xml";
	DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
	DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
        System.out.print(filepath);
        Document doc = docBuilder.parse(filepath.trim());
        
        
        /* datos del emisor */
        Node giroemisor = doc.getElementsByTagName("GiroEmis").item(0);
        Node DirOrigen  = doc.getElementsByTagName("DirOrigen").item(0);    
        Node ted = doc.getElementsByTagName("TED").item(0); 
        Node ciuemisor = doc.getElementsByTagName("CiudadOrigen").item(0); 
        Node CmnaOrigen = doc.getElementsByTagName("CmnaOrigen").item(0); 
        
        /*
        Node NroResol = doc.getElementsByTagName("NroResol").item(0); 
        
        
       */
        
        
        
        
        
        
        /* texto resolucion */
        /* esto va en la parte inferior de lado izquierdo */						
        int intvalue2 = 243;
     char convertedchar2 = (char)intvalue2;

        int intvalue = 186;
        char convertedchar = (char)intvalue;

        String textores = "Resoluci" + convertedchar2 +  "n Ex. SII N" + convertedchar + " " + nroresol + "" + " de "+ "";




        
        /* datos del receptor */
        Node rutreceptor = doc.getElementsByTagName("RUTRecep").item(0);
        Node rutemisor = doc.getElementsByTagName("RUTEmisor").item(0);
        Node tipodte = doc.getElementsByTagName("TipoDTE").item(0);
        Node foliodte= doc.getElementsByTagName("Folio").item(0);
        
        Node razreceptor = doc.getElementsByTagName("RznSocRecep").item(0);
        Node giroreceptor = doc.getElementsByTagName("GiroRecep").item(0);
        Node dirreceptor = doc.getElementsByTagName("DirRecep").item(0);
        Node cmnareceptor = doc.getElementsByTagName("CmnaRecep").item(0);
        Node ciureceptor = doc.getElementsByTagName("CiudadRecep").item(0);
        Node fechaemis = doc.getElementsByTagName("FchEmis").item(0);
        
        String auxmntneto;
        if(doc.getElementsByTagName("MntNeto").item(0)==null){
            auxmntneto ="0";
            
        }else{
            
             Node mntneto = doc.getElementsByTagName("MntNeto").item(0);
             auxmntneto = mntneto.getTextContent();
        }
        
        String auxiva;
        if(doc.getElementsByTagName("IVA").item(0)==null){
          auxiva="0";
        }else{
             Node iva = doc.getElementsByTagName("IVA").item(0);
             auxiva = iva.getTextContent();
        }
        
        String auxmntexe;
        if(doc.getElementsByTagName("MntExe").item(0)==null){
            auxmntexe ="0";
            
        }else{
            
             Node mntexe = doc.getElementsByTagName("MntExe").item(0);
             auxmntexe = mntexe.getTextContent();
        }
        
        
        
        
        Node mnttotal =doc.getElementsByTagName("MntTotal").item(0);
        
        
        
        
        Node RznSoc = doc.getElementsByTagName("RznSoc").item(0);
        /* cargo el template pdf */
        PdfReader reader = new PdfReader("/home/esteban/appdte/template/plantilla.pdf");/* ESPECIFICO LA RUTA DE SALIDA (outputPath) */      PdfStamper stamper = new PdfStamper(reader, new FileOutputStream("/home/esteban/appdte/PDF/"+nombredte+".pdf"));     PdfContentByte content = stamper.getOverContent(1);
        BaseFont bf=BaseFont.createFont(BaseFont.HELVETICA,BaseFont.CP1252,BaseFont.NOT_EMBEDDED);
        BaseFont bf2=BaseFont.createFont(BaseFont.HELVETICA_BOLD,BaseFont.CP1252,BaseFont.NOT_EMBEDDED);
        content.setFontAndSize(bf2, 14);
         /* ahora imprimo el rut y el folio del recuadro */
        content.setTextMatrix(470, 739);
        
        String arrayrutemisor[] = rutemisor.getTextContent().split("-");
        
        String auxrutemisor = formatea.format(Integer.parseInt(arrayrutemisor[0]));
        String auxdvemisor = arrayrutemisor[1];
        
        content.showText(auxrutemisor+"-"+auxdvemisor);
         
       int y1 = 720;
        content.setTextMatrix(410, y1);
      
         switch(tipodte.getTextContent()){
            
            case "33":
                       content.showText("FACTURA ELECTRONICA");
                       break;
                    
            case "52":
                       content.showText("GUIA DE DESPACHO");
                       y1 = y1-20;
                       content.setTextMatrix(420, y1);
                       content.showText("ELECTRONICA");
                       break;
                              
            case "61":
                      content.showText("NOTA DE CREDITO");
                      y1 = y1 - 20;
                      content.setTextMatrix(420, y1); 
                      content.showText("ELECTRONICA");
                      break;
            
                      
              case "34":
                      content.showText("FACTURA EXENTA");
                      y1 = y1 - 20;
                      content.setTextMatrix(420, y1); 
                      content.showText("ELECTRONICA");
                      break;
                       
                      
            
        }
        
        y1 = y1 - 20;
        
        
        content.setTextMatrix(445, y1);
        content.showText("N"+convertedchar);
        
        
        content.setTextMatrix(465, y1);
        content.showText(foliodte.getTextContent());
        
        content.setFontAndSize(bf2, 13);
        content.setTextMatrix(457,654); 
        content.showText(CmnaOrigen.getTextContent());
        
        
        /* DATOS DEL EMISOR Y EMISION  */
        content.setFontAndSize(bf, 8);
        content.setTextMatrix(24,641); 
        content.showText(RznSoc.getTextContent());
        
        content.setTextMatrix(54,624); 
        content.showText(giroemisor.getTextContent());
        
        content.setTextMatrix(92,604); 
        content.showText(DirOrigen.getTextContent());
        
        content.setTextMatrix(262,604); 
        content.showText(ciuemisor.getTextContent());
        
        /* DATOS DEL RECEPTOR */
        
        content.setTextMatrix(429,576); 
        content.showText(rutreceptor.getTextContent());
        content.setTextMatrix(429,556); 
        content.showText(ciureceptor.getTextContent());
        content.setTextMatrix(429,536); 
        content.showText("-");
        content.setTextMatrix(429,516); 
      
        String dateString = fechaemis.getTextContent();
        Date parsed = new SimpleDateFormat("yyyy-MM-dd").parse(dateString);
        DateFormat df = new SimpleDateFormat("dd-MM-yyyy");
        content.showText(df.format(parsed));
        
        content.setTextMatrix(109,576); 
        content.showText(razreceptor.getTextContent());
        
        content.setTextMatrix(109,556); 
        content.showText(dirreceptor.getTextContent());
        
        content.setTextMatrix(109,536); 
        content.showText(cmnareceptor.getTextContent());
        
        content.setTextMatrix(109,516); 
        content.showText(giroreceptor.getTextContent());
     
        /* cargo DETALLE DEL DOCUMENTO e imprimo los descuentos si los hay*/
        
 
        NodeList nodedetalle = doc.getElementsByTagName("Detalle");
       
        
        
        int y = 450;
              for (int temp = 0; temp < nodedetalle.getLength(); temp++) {
                Node nodo = nodedetalle.item(temp);
                System.out.println("Elemento:" + nodo.getNodeName());
                if (nodo.getNodeType() == Node.ELEMENT_NODE) {
                    Element element = (Element) nodo; 
                    
                    NodeList nodedetalle2 = element.getElementsByTagName("CdgItem");
                    
                    
                    for(int temp2 = 0; temp2 < nodedetalle2.getLength(); temp2++){
                        Node nodo2 = nodedetalle2.item(temp2);
                        if(nodo2.getNodeType() == Node.ELEMENT_NODE){
                          Element element2 = (Element) nodo2;
                            System.out.println("Codigo: " + element2.getElementsByTagName("VlrCodigo").item(0).getTextContent());            
                                content.setFontAndSize(bf,10);
                                content.setTextMatrix(25,y); 
                                if(element2.getElementsByTagName("VlrCodigo").item(0).getTextContent()==null){
                                    
                                }else{
                                    
                                content.showText( element2.getElementsByTagName("VlrCodigo").item(0).getTextContent());
                                }
                                
                        }
                        
                        
                    }
                    
                    content.setFontAndSize(bf,10);
                    content.setTextMatrix(100,y); 
                    content.showText(element.getElementsByTagName("NmbItem").item(0).getTextContent());
                    
                    
                    
            if(element.getElementsByTagName("QtyItem").item(0)==null){
                
                
            }else{   
                    content.setFontAndSize(bf,10);
                    content.setTextMatrix(250,y); 
                    content.showText(formatea.format(Integer.parseInt(element.getElementsByTagName("QtyItem").item(0).getTextContent())));
            }       
        
            
           if(element.getElementsByTagName("PrcItem").item(0)==null){
               
               
           }else{
                    content.setFontAndSize(bf,10);
                    content.setTextMatrix(340,y); 
               content.showText(formatea.format(Integer.parseInt(element.getElementsByTagName("PrcItem").item(0).getTextContent())));
                     }
                   if(element.getElementsByTagName("DescuentoPct").item(0)==null){
                         content.setFontAndSize(bf,10);
                         content.setTextMatrix(430,y); 
                         content.showText("0");
                   
                       
                   }else{
                       
                         content.setFontAndSize(bf,10);
                         content.setTextMatrix(430,y); 
                         content.showText(element.getElementsByTagName("DescuentoPct").item(0).getTextContent());                
                   }
                   
                   
                    
                    
                    
                    
                    
                    content.setFontAndSize(bf,10);
                    content.setTextMatrix(490,y); 
                    content.showText(formatea.format(Integer.parseInt(element.getElementsByTagName("MontoItem").item(0).getTextContent()))); 
                    y = y - 20;
                    
                
                }
            }
              
              /* SI HAY ALGUN DESCUENTO GLOBAL */
   
                   if(doc.getElementsByTagName("DscRcgGlobal").item(0)==null){            
                        
                   }else{
                       
                       
                       
                         Node tipomov = doc.getElementsByTagName("TpoMov").item(0);
                         Node ValorDR = doc.getElementsByTagName("ValorDR").item(0);
                         Node TpoValor = doc.getElementsByTagName("TpoValor").item(0);
                          content.setTextMatrix(250,y);
                             if("D".equals(tipomov.getTextContent())){
                                content.showText("DESCUENTO GLOBAL ITEMS AFECTO " + ValorDR.getTextContent()+TpoValor.getTextContent());
                             }
                             if("R".equals(tipomov.getTextContent())){
                                content.showText("RECARGO GLOBAL ITEMS AFECTO " + ValorDR.getTextContent()+TpoValor.getTextContent());
                             }
                        }
                   
                     
/* campo para imprimir referencia */
y = y-20;
content.setTextMatrix(25,y); 
content.showText("DATOS ADICIONALES");


y = y - 20;             
content.setTextMatrix(25,y); 

if(doc.getElementsByTagName("RazonRef").item(0)==null){
    
    
}else{

Node nodereferencia =  doc.getElementsByTagName("RazonRef").item(0);
content.showText("REFERENCIA GENERAL: "+nodereferencia.getTextContent());
/* si la referencia es una nota de credito */ 


Node nodotipodocref = doc.getElementsByTagName("TpoDocRef").item(0);
Node folioref = doc.getElementsByTagName("FolioRef").item(0);
Node fecharef = doc.getElementsByTagName("FchRef").item(0);


if ("0".equals(folioref.getTextContent().trim())==false){
             y = y - 20;             
            content.setTextMatrix(25,y); 
            content.showText("DOCUMENTO REFERENCIA: "+ getNombredoc(nodotipodocref.getTextContent())); 
           
            
            y = y - 20;             
            content.setTextMatrix(25,y); 
            content.showText("FOLIO: "+folioref.getTextContent()); 
        
            
            
            y = y - 20;             
            content.setTextMatrix(25,y); 
            content.showText("FECHA: "+formatFecha(fecharef.getTextContent())); 
}               
}   
        
        /* Imprimo totales del documento */
       content.setFontAndSize(bf,10);
       content.setTextMatrix(480,90); 
       content.showText(formatea.format(Integer.parseInt(auxmntneto)));
       
       content.setFontAndSize(bf,10);
       content.setTextMatrix(480,70); 
       content.showText(formatea.format(Integer.parseInt(auxmntexe)));
     
     
       content.setFontAndSize(bf,10);
       content.setTextMatrix(480,50); 
       content.showText(formatea.format(Integer.parseInt((auxiva))));
      
       
       content.setFontAndSize(bf,10);
       content.setTextMatrix(480,30); 
       content.showText(formatea.format(Integer.parseInt(mnttotal.getTextContent())));
        
       
       content.setFontAndSize(bf,10);
       content.setTextMatrix(189,51);
       content.showText(textores); 
       
       
       content.setFontAndSize(bf,10);
       content.setTextMatrix(10,10);
       
       switch(tipoCopia){
       
           case "0":   
           
                    content.showText("ORIGINAL: CLIENTE"); 
                    break;
                    
                    
           
           case "1":   
           
                    content.showText("COPIA: CEDIBLE"); 
                    break;         
                    
       
       }
       
      
        /* tomo el nodo ted ya firmado e imprimo el timbre electr�nico */ 
        StringWriter buf = new StringWriter();
        Transformer xform = TransformerFactory.newInstance().newTransformer();
        xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
         xform.setOutputProperty(OutputKeys.INDENT, "no");
        
        xform.transform(new DOMSource(ted), new StreamResult(buf));
        String timbre;
        timbre = buf.toString();
      
      
      
                
        System.out.print(timbre);
        
        BarcodePDF417 barcode = new BarcodePDF417();
	barcode.setCodeRows(5);
	barcode.setCodeColumns(18);
	barcode.setErrorLevel(5);
	barcode.setLenCodewords(999);	        
	barcode.setText(timbre.getBytes("ISO-8859-1"));
        barcode.setOptions(BarcodePDF417.PDF417_FORCE_BINARY);
       	com.itextpdf.text.Image image = barcode.getImage();
        /* tama?o de la imagen */
        image.scaleAbsolute(184, 72);
        /* ahora establezco las coordenadas del documento */
	image.setAbsolutePosition(60, 73);		
	content.addImage(image);
        stamper.close();
        
        
        
    }
    
    
    private String getNombredoc(String codsii){
        String nombredoc="";
        switch (codsii) {
            
            case "33":
                     nombredoc = "FACTURA ELECTRONICA";   
                     break;     
                     
                     
             case "34":
                     nombredoc = "FACTURA EXENTA ELECTRONICA";   
                     break;     
            
            case "52":
                     nombredoc = "GUIA DE DESPACHO ELECTRONICA";   
                     break;        
            
            case "61":
                     nombredoc = "NOTA DE CREDITO ELECTRONICA";   
                     break;                 
            
            case "801":
                     nombredoc = "ORDEN DE COMPRA";   
                     break;                 
         
                     
            case "39":
                     nombredoc = "BOLETA ELECTRONICA";   
                     break;                 
                  
            
            case "41":
                     nombredoc = "BOLETA EXENTA ELECTRONICA";   
                     break;                          
                     
        }
        return nombredoc;
    }
    
    
    private String formatFecha(String fechainput) throws ParseException{
        
        SimpleDateFormat input = new SimpleDateFormat("yyyy-MM-dd");
        Date dateValue = input.parse(fechainput);
        SimpleDateFormat output = new SimpleDateFormat("dd/MM/yyyy");
        String fecha= output.format(dateValue);
        return fecha;
    }
     
 }


Paso 4: Ejecutar el programa

Ejecuta la clase y revisa el archivo generado en la ruta especificada (outputPath). Ahora tendrás un PDF completamente personalizado basado en tu plantilla.


Conclusión

El uso de iText facilita la generación de PDFs dinámicos en Java. Su flexibilidad y potencia la convierten en una herramienta ideal para aplicaciones que requieren generación de documentos personalizados.

Comentarios

Publicar un comentario

Entradas populares de este blog

Configurando Servlets y JSP en Jetty

Firma de un Documento XML con Certificado Digital en Java para Uso Tributario en Chile

RESOLUCION SET BASICO DE FACTURA ELECTRÓNICA SII