Generación de Envíos de Documentos Tributarios Electrónicos en Java: Clase EnvioDTE
La generación de Documentos Tributarios Electrónicos (DTE) es una parte esencial del cumplimiento fiscal en Chile. Este artículo explica cómo la clase EnvioDTE
se utiliza para construir y gestionar un "sobre electrónico" (EnvioDTE), necesario para enviar documentos al Servicio de Impuestos Internos (SII).
Descripción General de la Clase EnvioDTE
La clase EnvioDTE
pertenece al paquete com.egga.appdte.sii.utilidades
. Se utiliza para construir documentos XML que cumplen con los estándares establecidos por el SII para los DTE. Los métodos principales de esta clase son:
generaEnvio
: Construye la estructura base del sobre electrónico (EnvioDTE), incluyendo la carátula con los metadatos del envío.addDTE
: Agrega documentos DTE timbrados y firmados al sobre electrónico generado previamente.
Código:
Puedes adaptar el código según tus requerimientos
package com.egga.appdte.sii.utilidades; import com.egga.appdte.models.DteModel; import java.io.ByteArrayOutputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.w3c.dom.Document; import org.w3c.dom.Element; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.StringReader; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.Date; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerConfigurationException; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.w3c.dom.Attr; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class EnvioDTE { private Document doc; public void generaEnvio(DteModel objdte,String nombredte,String pathdte,String rutusuario) throws ParserConfigurationException, FileNotFoundException, IOException, SAXException, TransformerConfigurationException, TransformerException{ ConfigAppDTE objconfig = new ConfigAppDTE(); DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); this.doc = docBuilder.newDocument(); /* this.doc.createComment("eeee"); */ Element setdte = this.doc.createElement("SetDTE"); Attr attrversion = this.doc.createAttribute("ID"); attrversion.setValue("SetDoc"); setdte.setAttributeNode(attrversion); Element caratula = this.doc.createElement("Caratula"); caratula.setAttribute("version", "1.0"); Element rutemisor = this.doc.createElement("RutEmisor"); rutemisor.setTextContent(objdte.getRutemisor().trim()); Element rutenvia = this.doc.createElement("RutEnvia"); rutenvia.setTextContent(rutusuario); Element rutreceptor = this.doc.createElement("RutReceptor"); rutreceptor.setTextContent("60803000-K"); caratula.appendChild(rutemisor); caratula.appendChild(rutenvia); caratula.appendChild(rutreceptor); /* agrego la fecha de resolucón que nos entrega el SII */ Element fecharesol = this.doc.createElement("FchResol"); fecharesol.setTextContent(objdte.getFecharesol()); caratula.appendChild(fecharesol); Element nroresol = this.doc.createElement("NroResol"); nroresol.setTextContent(objdte.getNumresol()); caratula.appendChild(nroresol); Date date = new Date(); DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd"); String stringFecha = dateFormat.format(date); DateFormat timeFormat = new SimpleDateFormat("HH:mm:ss"); String stringHora = timeFormat.format(date); Element tmstfirmaenv = this.doc.createElement("TmstFirmaEnv"); tmstfirmaenv.setTextContent(stringFecha+"T"+stringHora); caratula.appendChild(tmstfirmaenv); Element subtotdte = this.doc.createElement("SubTotDTE"); Element tpodte = this.doc.createElement("TpoDTE"); tpodte.setTextContent(objdte.getTipodte()); subtotdte.appendChild(tpodte); Element nrodte = this.doc.createElement("NroDTE"); nrodte.setTextContent("1"); subtotdte.appendChild(nrodte); caratula.appendChild(subtotdte); Element enviodte = this.doc.createElement("EnvioDTE"); enviodte.appendChild(setdte); setdte.appendChild(caratula); /* xmlns="http://www.sii.cl/SiiDte" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="1.0" xsi:schemaLocation="http://www.sii.cl/SiiDte EnvioDTE_v10.xsd" */ Attr attr1 = this.doc.createAttribute("xmlns"); attr1.setValue("http://www.sii.cl/SiiDte"); enviodte.setAttributeNode(attr1); Attr attr2 = this.doc.createAttribute("xmlns:xsi"); attr2.setValue("http://www.w3.org/2001/XMLSchema-instance"); enviodte.setAttributeNode(attr2); Attr attr3 = this.doc.createAttribute("version"); attr3.setValue("1.0"); enviodte.setAttributeNode(attr3); Attr attr4 = this.doc.createAttribute("xsi:schemaLocation"); attr4.setValue("http://www.sii.cl/SiiDte EnvioDTE_v10.xsd"); enviodte.setAttributeNode(attr4); this.doc.appendChild(enviodte); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.ENCODING, "iso-8859-1"); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "0"); DOMSource source = new DOMSource(this.doc); StreamResult result; /* GUARDO EL SOBRE ELECTRONICO YA INDENTADO, PPERO SIN EL DTE AUN */ result = new StreamResult(new File(objconfig.getPathdte()+"ENV"+nombredte+".xml")); transformer.transform(source, result); System.out.println("Done"); /* EN ESTA SECCIÓN ME ENCARGO DE AGREGAR EL DTE TIMBRADO Y FIRMADO FIRMADO AL SOBRE */ addDTE(nombredte); } private void addDTE(String nombredte) throws ParserConfigurationException, SAXException, IOException, TransformerException{ ConfigAppDTE objconfig = new ConfigAppDTE(); String archivo = objconfig.getPathdte()+ nombredte+".xml"; FileInputStream archivodte = new FileInputStream(archivo); InputStreamReader inputdte = new InputStreamReader(archivodte,"ISO-8859-1"); InputSource sourcedte = new InputSource(inputdte); ByteArrayOutputStream bos=new ByteArrayOutputStream(); StreamResult result=new StreamResult(bos); DocumentBuilderFactory docFactory2 = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder2 = docFactory2.newDocumentBuilder(); Document doc2 = docBuilder2.parse(sourcedte); Node dte = doc2.getElementsByTagName("DTE").item(0); /* StringWriter buf = new StringWriter(); */ Transformer xform = TransformerFactory.newInstance().newTransformer(); xform.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes"); xform.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); xform.setOutputProperty(OutputKeys.INDENT, "no"); xform.transform(new DOMSource(dte), result); byte []array=bos.toByteArray(); String stringnode = new String(array,"ISO-8859-1"); String filepath = objconfig.getPathdte()+"ENV"+nombredte.trim()+".xml"; DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); System.out.print(filepath); Document docENV = docBuilder.parse(filepath.trim()); /* datos del emisor */ Node setdte = docENV.getElementsByTagName("SetDTE").item(0); Node fragmentNode = docBuilder.parse(new InputSource(new StringReader(stringnode))).getDocumentElement(); fragmentNode = docENV.importNode(fragmentNode, true); setdte.appendChild(fragmentNode); TransformerFactory transformerFactory = TransformerFactory.newInstance(); Transformer transformer = transformerFactory.newTransformer(); transformer.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "no"); transformer.setOutputProperty(OutputKeys.ENCODING, "ISO-8859-1"); transformer.setOutputProperty(OutputKeys.INDENT, "no"); DOMSource source = new DOMSource(docENV); StreamResult result2; result2 = new StreamResult(new File(objconfig.getPathdte()+"ENV"+nombredte+".xml")); transformer.transform(source, result2); System.out.println("Done"); } }
Flujo Principal
1. Preparación del Documento XML
El método generaEnvio
crea un documento XML utilizando la API DOM de Java. Esto incluye:
- Construcción del nodo
SetDTE
: Nodo raíz del sobre electrónico. - Creación de la
Caratula
: Contiene información clave como:- RUT del emisor (
RutEmisor
). - RUT del usuario que envía (
RutEnvia
). - Fecha y hora del envío (
TmstFirmaEnv
). - Resolución del emisor (
FchResol
,NroResol
). - Subtotal de DTE enviados (
SubTotDTE
).
- RUT del emisor (
2. Transformación y Escritura
El XML es transformado y almacenado como archivo utilizando la clase Transformer
. Esto asegura que el formato final cumpla con los estándares de codificación y estructura exigidos por el SII.
3. Adición de DTE
El método addDTE
carga un DTE previamente firmado, lo inserta en el nodo SetDTE
, y reescribe el sobre electrónico. Esto implica:
- Leer el archivo XML del DTE con
DocumentBuilder
. - Importar y agregar el nodo
DTE
al XML principal.
Características Clave del Código
1. Uso de API DOM para Manejo de XML
El código aprovecha DocumentBuilder
, Transformer
, y otros elementos de la API DOM para:
- Crear nodos.
- Agregar atributos y contenido.
- Escribir el documento XML resultante.
2. Manejo de Formatos de Fecha y Hora
El código utiliza SimpleDateFormat
para generar las marcas de tiempo (TmstFirmaEnv
), garantizando que cumplen con el formato ISO exigido.
3. Codificación y Estandarización
Todos los documentos se generan con codificación ISO-8859-1
, estándar para documentos XML del SII. Además, el uso de xsi:schemaLocation
asegura la validez del esquema.
4. Módulos Extensibles
El diseño de la clase permite integrarse con módulos adicionales, como:
ConfigAppDTE
: Para manejar rutas y configuraciones específicas.- Modelos (
DteModel
): Contienen los datos básicos del DTE.
Ejemplo de Uso
Conclusión
La clase EnvioDTE
proporciona un enfoque robusto y eficiente para gestionar el envío de DTE en cumplimiento con las normativas chilenas. Al combinar estructuras claras de XML, manejo de codificaciones y diseño modular, permite un fácil mantenimiento y adaptabilidad en proyectos de factura electrónica. Este diseño facilita su integración en sistemas existentes y garantiza la generación de documentos confiables y válidos para el SII.
Comentarios
Publicar un comentario