VBA Excel macro para leer XML CFDI 3.3

22 nov 2018

VBA Excel macro para leer XML CFDI 3.3


Les comparto una macro que he adaptado para leer los XML de los CFDI versión 3.3 de forma masiva.
Para que la macro funcione hay que seguir los siguientes pasos:
1. Abrir el editor Visual Basic para Aplicaciones (VBA).
2. Insertar un módulo.
3. Agregar la referencia "Microsoft XML, v3.0" en el menú herramientas del editor VBA, dar click en referencias.

3. Pegar el siguiente código:
Sub Ruta_CFDI()
'macro para en listar los XML que va a leer
'Adapatado por Luis Reyes
Dim fs, carpeta, archivo, subcarpeta As Object
contador = 2 'determinar en que fila comenzará a colocar la ruta y nombre de los XML
Set fs = CreateObject("Scripting.FileSystemObject")
With Application.FileDialog(msoFileDialogFolderPicker) 'se obtiene la ruta la carpeta
    If .Show = -1 Then
        ruta = .SelectedItems(1)
        Range("V1").Value = ruta & "\"
    End If
End With
    
    If ruta = "" Then
        Exit Sub
    End If
Set carpeta = fs.GetFolder(ruta)
For Each archivo In carpeta.Files
 If Right(archivo, 4) = ".xml" Then
  Range("AD" & contador).Value = ruta & "\" & archivo.Name
  contador = contador + 1
 End If
 If Right(archivo, 4) = ".XML" Then
  Range("AD" & contador).Value = ruta & "\" & archivo.Name
  contador = contador + 1
 End If
Next
If Application.WorksheetFunction.CountA(Columns(30)) <= 1 Then
MsgBox "No se encontro ningún archivo *.XML" & Chr(10) & ruta, vbCritical, "Importar datos CFDI"
End
End If

Call Lectura_CFDI 'ejecuta la macro que lee los XML
End Sub


Private Sub Lectura_CFDI()
'Adapatado por Luis Reyes
With Application
      .ScreenUpdating = False
      .Calculation = xlCalculationManual
      .EnableEvents = False
      .DisplayStatusBar = False
      
Dim Concepto As String
Dim pctCompl As Single
Set DocumentoXML = New DOMDocument
Set r = Range("AD2").CurrentRegion 'determina apartir de donde comienza a contar
filas = r.Rows.Count

For i = 2 To filas + 6 'número de documentos que va a leer

DocumentoXML.Load ("" & Cells(i, 30) & "")

Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante")
On Error Resume Next
For Each Nodo In ListaNodo
    Subtotal = Val(Nodo.Attributes.getNamedItem("SubTotal").Text)
    Fecha = Mid(Nodo.Attributes.getNamedItem("Fecha").Text, 1, 10)
    Serie = Nodo.Attributes.getNamedItem("Serie").Text
    Folio = Serie & " - " & Nodo.Attributes.getNamedItem("Folio").Text
    Total = Val(Nodo.Attributes.getNamedItem("Total").Text)
    Descuento = Val(Nodo.Attributes.getNamedItem("Descuento").Text)
  
Next Nodo
''''''''''''''''''''''''''''''''''''''''''''''''Nombre del emisor'''''''''''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Emisor")
For Each Nodo In ListaNodo
    Proveedor = Nodo.Attributes.getNamedItem("Nombre").Text
    RFC = Nodo.Attributes.getNamedItem("Rfc").Text
Next Nodo
''''''''''''''''''''''''''''''''''''''''''''''''Conceptos'''''''''''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto")
For Each Nodo In ListaNodo
    Concepto = Concepto & Nodo.Attributes.getNamedItem("Descripcion").Text & " - "
Next Nodo
''''''''''''''''''''''''''''''''''''''''''''''''Impuestos'''''''''''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto/cfdi:Impuestos/cfdi:Traslados/cfdi:Traslado")
For Each Nodo In ListaNodo
    If Nodo.Attributes.getNamedItem("Impuesto").Text = "002" Then
        IVA = IVA + Val(Nodo.Attributes.getNamedItem("Importe").NodeValue)
    End If
    If Nodo.Attributes.getNamedItem("Impuesto").Text = "003" Then
        IEPS = IEPS + Val(Nodo.Attributes.getNamedItem("Importe").NodeValue)
    End If
 Next Nodo
''''''''''''''''''''''''''''''''''''''''''''''''Retenciones'''''''''''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto/cfdi:Impuestos/cfdi:Retenciones/cfdi:Retencion")
For Each Nodo In ListaNodo
    If Nodo.Attributes.getNamedItem("Impuesto").Text = "001" Then
        ISRRe = IVARe + Val(Nodo.Attributes.getNamedItem("Importe").NodeValue)
    End If
    If Nodo.Attributes.getNamedItem("Impuesto").Text = "002" Then
        IVARe = IVARe + Val(Nodo.Attributes.getNamedItem("Importe").NodeValue)
        End If
Next Nodo
'''''''''''''''''''''''''''OTROS IMPUESTOS''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("cfdi:Comprobante/cfdi:Complemento/implocal:ImpuestosLocales/implocal:TrasladosLocales")
For Each Nodo In ListaNodo
ISH = Nodo.Attributes.getNamedItem("Importe").Text
Next Nodo
'''''''''''''''''''''''''''AEROLINEAS''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("cfdi:Comprobante/cfdi:Complemento/aerolineas:Aerolineas")
For Each Nodo In ListaNodo
TUA = Nodo.Attributes.getNamedItem("TUA").Text
Next Nodo

Set ListaNodo = DocumentoXML.SelectNodes("cfdi:Comprobante/cfdi:Complemento/aerolineas:Aerolineas/aerolineas:OtrosCargos/aerolineas:Cargo")
'MsgBox ListaNodo.Length
For Each Nodo In ListaNodo
YR = Nodo.Attributes.getNamedItem("Importe").Text
Next Nodo

''''''''''''''''''''''''''''''''''''UUID''''''''''''''''''''''''''''''''''''''''''''
Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Complemento/tfd:TimbreFiscalDigital")
For Each Nodo In ListaNodo
UUID = Nodo.Attributes.getNamedItem("UUID").Text
Next Nodo

Cells(i, 1) = Fecha
Cells(i, 2) = Folio
Cells(i, 3) = RFC
Cells(i, 4) = Proveedor
Cells(i, 5) = Concepto
Cells(i, 5).ClearFormats
Cells(i, 6) = Subtotal - TUA - YR - Descuento
Cells(i, 7) = IVA
Cells(i, 8) = ISRRe
Cells(i, 9) = IVARe
Cells(i, 10) = IEPS
Cells(i, 11) = ISH
Cells(i, 12) = TUA
Cells(i, 13) = YR
Cells(i, 14) = Total
Cells(i, 15) = UUID

Fecha = ""
Folio = ""
RFC = ""
Proveedor = ""
Concepto = ""
Subtotal = 0
Descuento = 0
IVA = 0
ISRRe = 0
IVARe = 0
IEPS = 0
ISH = 0
TUA = 0
YR = 0
Total = 0
UUID = ""

Next
Cells(1, 1).Value = "Fecha"
Cells(1, 2).Value = "Folio"
Cells(1, 3).Value = "RFC"
Cells(1, 4).Value = "Proveedor"
Cells(1, 5).Value = "Concepto"
Cells(1, 6).Value = "Subtotal"
Cells(1, 7).Value = "IVA"
Cells(1, 8).Value = "ISR RETENIDO"
Cells(1, 9).Value = "IVA RETENIDO"
Cells(1, 10).Value = "IEPS"
Cells(1, 11).Value = "ISH"
Cells(1, 12).Value = "TUA"
Cells(1, 13).Value = "YR"
Cells(1, 14).Value = "Total"
Cells(1, 15).Value = "UUID"
      .Calculation = xlCalculationAutomatic
      .EnableEvents = True
      .DisplayStatusBar = True
    
   End With
End Sub

44 comentarios :

  1. Buenas tardes, y para extraer los Pagos de un XML en la parte de RELACIONES, Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Complemento/pago10:Pagos/pago10:Pago/pago10:DoctoRelacionado")
    On Error Resume Next

    ResponderBorrar
  2. por favor me puedes enviar tu xml a zona.lerh@gmail.com

    ResponderBorrar
  3. enviame el xml al correo jcintriadp@yahoo.es

    ResponderBorrar
  4. Hola al pasar tu macro le adapte unos codigos para que me sume por bases de IVA los diferentes conceptos es decir cada uno de los concepos del xml tiene una base y una tasa de iva al 16 al 8 al 0 o exento puse el codigo y todo bien con las tasas pero cuando lee un xml que tiene concepto exento no suma correctamente las otras tasas poniendo en todas las tasas la misma cantidad que el exento

    ResponderBorrar
  5. Buenas noches, para obtener el uuid relacionado del complemento de pago, que se tendria que modificar

    ResponderBorrar
  6. Buenas tardes Luis, copie tu codigo, y jalo, sin embargo veo que duplica unos datos
    donde puedo enviarte por email el codigo y si puedes checarlo.

    ResponderBorrar
  7. Hola buenas noches, estoy adaptando el código para importar los XML en una bases de datos de Access y hasta ahorita he logrado importar todos los conceptos, pero necesito saber como hacer que un nodo de impuestos se pueda asociar al nodo padre que correspondería al de su concepto para copiar los impuestos de manera individual a una tabla independiente de los conceptos, tienes alguna idea de como podría hacerlo?

    ResponderBorrar
    Respuestas
    1. por favor me puedes contactar por correo:
      zona.lerh@gmail.com

      Borrar
  8. Hola, para agregarle a este macro la opción de extraer el uso del CFDI, que es lo que se tiene que hacer ?

    ResponderBorrar
    Respuestas
    1. Hola buen día
      tiene que buscar:
      RFC = Nodo.Attributes.getNamedItem("Rfc").Text
      y debajo de ese código tiene debe colocar:
      UCFDI = Nodo.Attributes.getNamedItem("UsoCFDI").Text
      después busque:
      Cells(i, 15) = UUID
      y después de eso coloque:
      Cells(i, 16) = UCFDI
      después busque:
      Cells(1, 15).Value = "UUID"
      y después de eso coloque:
      Cells(1, 16).Value = "USO CFDI"


      Saludos!!
      Cells(1, 16).Value = "UUID"




      Borrar
    2. Muy buena explicación con los campos, solo que estoy siguiendo este ejemplo (UsoCFDI="G03") y al momento de ejecutar la macro no me mostro el valor en la celda que le correspondia, siempre queda espacio en blanco, y segui las instrucciones paso a paso...

      Habra alguna linea de codigo que requiera de mas?

      muchas gracias.

      Borrar
    3. y lo estas colocando en donde va??

      por favor me puedes enviar correo a zona.lerh@gmail.com con el codigo

      Borrar
    4. Hola, si ya vi el error de mi parte, lo corregi y si funciona

      Borrar
  9. Es necesario llevar un orden para extraer los datos?

    Es decir, yo quiero extraer solo para los combustibles el total de Litros del XML, ejemplo:

    Cells(1, 17).Value = "Cantidad" 'Litros que se cargan

    Gracias por el aporte

    ResponderBorrar
  10. no es necesario, los puede distribuir como guste
    esto si puede ser:
    Cells(1, 17).Value = "Cantidad" 'Litros que se cargan

    ResponderBorrar
  11. Por si le sirve a alguien, en las facturas el UUID note que unas vienen en mayusculas y otras en minusculas, asi que agregue este codigo al final de la macro:

    .DisplayStatusBar = True 'Buscar este codigo de Luis
    ' Voy a convertir de una vez el UUID y Concepto a Mayusculas
    'rango que se convertira a mayusculas, modificar a criterio
    ' agregar solo esta linea de codigo
    [I1:I100] = [INDEX(UPPER(I1:I100),,)]
    End With

    ResponderBorrar
  12. Hola Amigo, corre excelente la macro, solo que tengo un dato que se encuentra en la addenda pero no corresponde a un concepto, solo es un dato que requiero extraer el cual es diferente en cada xml, ¿cómo le podría hacer para extraer datos en esos casos?

    ResponderBorrar
    Respuestas
    1. hola mi estimado, por favor me puedes enviar un ejemplo a zona.lerh@gmail.com

      Borrar
  13. Hola, como podría modificarla para que muestre los conceptos de los xml emitidos de nomina.

    ResponderBorrar
    Respuestas
    1. Hola buen día. revisa esta entrada:
      https://www.elblogdeluisreyes.com/2019/08/vba-excel-macro-para-leer-xml-nomina-12.html

      Espero que te sea úti.

      Borrar
  14. BUENAS TARDES PARA EXTRAER EL IMPORTE DE LOS COMPLEMENTOS DE PAGOS CUAL SERIA EL MACRO

    ResponderBorrar
    Respuestas
    1. Hola FABIAN, buen día, aun no tengo la macro, voy a trabajar en ello y próximamente lo subiré al blog.

      Saludos!!

      Borrar
  15. me podrías ayudar ? que tengo que hacer para que me aparezca el método de pago y la forma de pago ?

    ResponderBorrar
  16. Hola, buen día, me podrías ayudar? que tengo que hacer para que me aparezcan los datos de método de pago y forma de pago ?
    gracias.

    ResponderBorrar
    Respuestas
    1. Hola buen día, si claro, tienes que agregar el nodo
      en:
      Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante")

      FPago = Nodo.Attributes.getNamedItem("FormaPago").text

      Borrar
  17. Me pudieras ayudar, como puedo agregar el método de pago y la forma de pago ?
    gracias.

    ResponderBorrar
  18. hola buenas tardes, yo modifique los nodos para los complementos de pago, solo que no me trae el numero de Facturas por pago (si se pagaron 10 Facturas en un pago solo me trae una) que le faltaría al código, lo comparto por correo

    Saludos

    ResponderBorrar
  19. mi xml tiene cdata, y no se como extrar informacion q eta dentro d esa seccion

    ResponderBorrar
  20. Saludos, excelente sitio, gracias. Sobre esta macro la he copiado a un libro de trabajo en el que concentro mis papeles de trabajo, pero al ejecutarla obtengo el siguiente mensaje de error "Compile error: User-defined type not defined", y resalta el texto "New DOMDocument" que se detalla en la novena línea después del título "Private Sub Lectura_CFDI()", sin embargo al ejecutar la misma macro directamente de el documento que proporcionas no tengo ningún problema, ¿podrías ayudarme a resolver esto?, por favor. Gracias por tu trabajo y atención.

    ResponderBorrar
    Respuestas
    1. Hola G7, al principio de la entrada describo lo que tienes que hacer para que no salga ese error.
      Saludos!!

      Borrar
  21. Buenas noches, me ha sido de mucha utilidad su código, sin embargo, quisiera ver si me pudiera apoyar en ver la forma de que los artículos se desglosen en cada fila, estuve probando varías cosas pero ninguna me ha funcionado, gracias de antemano

    ResponderBorrar
    Respuestas
    1. Hola mi estimado, por favor me puedes contactar por whatsapp 5584553535

      Borrar
  22. Hola, yo hice un VB para leer solo los conceptos del XML pero al abrir el xml y extraer con GET me da caracteres especiales e4n donde hay acentos o CR. como lo puedo arreglar, creo es el conjunto de caracteres al pasarlo a texto en el excel

    ResponderBorrar
    Respuestas
    1. Hola mr_alver, si gustas me puedes contactar por correo: zona.lerh@gmail.com

      Borrar
  23. Hola Luis, saludos de la Ciudad de México, he trabajado con tu código, me ha funcionando bien, ahora estoy atorado ya que unos xml vienen varios concepto pero al correr la macro solo me da el importe de un solo producto.
    En Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto")
    For Each nodo In ListaNodo
    Concepto = Concepto & nodo.Attributes.getNamedItem("Descripcion").Text & " - "
    Next nodo
    Aquí me aparecen todos los conceptos, si incluyo lo siguiente para que me sume todos esos concepto solo aparece uno:
    En Set ListaNodo = DocumentoXML.SelectNodes("/cfdi:Comprobante/cfdi:Conceptos/cfdi:Concepto")
    For Each nodo In ListaNodo
    Concepto = Concepto & nodo.Attributes.getNamedItem("Descripcion").Text & " - "
    If nodo.Attributes.getNamedItem("importe").Text <> "" Then
    Importe = nodo.Attributes.getNamedItem("importe").Text
    End If
    Next nodo
    Como tendría que ser la instruccion para Importe?
    Gracias de antemano, saludos

    ResponderBorrar
    Respuestas
    1. Si, tienes que hacer esto:
      Importe = nodo.Attributes.getNamedItem("importe").Text + Importe

      Borrar