Obtener cadena original y crear xml

714 views
Skip to first unread message

Pedro Baez

unread,
Dec 27, 2017, 4:08:19 PM12/27/17
to vfp-factura-electronica-mexico
Hola, buen día. 

Me podrían ayudar, tomé los códigos que han compartido en el foro para adaptarlos a la versión de halcón divino pero solo eh obtenido el siguiente mensaje:
" Error no se pudo obtener la cadena original. Utilice CFDProbarOpenSSL para verificar el funcionaiento de la libreria OpenSSL"

anexo los códigos de programación y adjunte el XML que está creando, si tiene oportunidad de apoyarme :-) Agradezco su apoyo!

--------------------------------------------------------------------Parte 1.

?"CFD v" + CFDConf.Version
?"Demo"
?
?

?"- Inicializando..."
WITH CFDConf
 .OpenSSL = ".\SSL"
 .SMTPServer = "smtp.gmail.com
 .SMTPPort = 465
 .SMTPUserName = ""
 .SMTPPassword = ""
 .MailSender = ""
*!* .modoPruebas = .T.
 .XMLversion = CFDVersions.CFDi_33
 .formatoImpresion  = "SCAIFacliente.FRX"
 .incluirBOM = .F.
ENDWITH


?"- Probando OpenSSL..."
IF CFDProbarOpenSSL()
 ??"OK! ("+STRT(CFDConf.ultimoError,CHR(13)+CHR(10),"")+")"
ELSE
 ?"ERROR: "
 ?CFDConf.ultimoError
 RETURN
ENDIF
    
    
?"- Generando CFD..."    
LOCAL oCFD, o
oCFD = CREATEOBJECT("CFDComprobante")
WITH oCFD
 .Serie = SerieCFD
 .Folio = FolioCFD
 .Fecha = DATETIME()
 .FormaPago = FormaDePago
 .Descuento = DescuentoCFD
 .TipoCambio = NULL
 .metodoPago    = MetodoDePago
 .subTotal = SubTotalCFD
 .Total = TotalCFD
 .tipoDeComprobante = TipoDeComprobante
 .motivoDescuento = ''
 .Moneda = "PESOS M.N."
 .LugarExpedicion = LugarExpedicion
 .CondicionesDePago = CondicionesDePago
  
 *-- Atributos CFD 3.2 opcionales 
 .MontoFolioFiscalOrig = NULL
 .FechaFolioFiscalOrig = {}
 .SerieFolioFiscalOrig = NULL
 .FolioFiscalOrig = NULL
 .NumCtaPago = NumCtaPago

 
 *-- Atributos CFD 3.2 requeridos 
 .Emisor.RFC    = Erfc
 .Emisor.nombre = Enombre && Opcional en 3.2
 
 * -- DomicilioFiscal Opcional en 3.2
 .Emisor.domicilioFiscal.Calle = Ecalle
 .Emisor.domicilioFiscal.noExterior = EnoExterior
 .Emisor.domicilioFiscal.noInterior = EnoInterior
 .Emisor.domicilioFiscal.Colonia = Ecolonia
 .Emisor.domicilioFiscal.Municipio = Emunicipio
 .Emisor.domicilioFiscal.Localidad = Elocalidad 
 .Emisor.domicilioFiscal.Estado = Eestado
 .Emisor.domicilioFiscal.Pais = Epais   && Único Requerido si DomicilioFiscal esta presente
 .Emisor.domicilioFiscal.codigoPostal = EcodigoPostal

 * -- ExpedidoEn Opcional
 .Emisor.expedidoEn.Calle = Xcalle
 .Emisor.expedidoEn.noExterior = XnoExterior
 .Emisor.expedidoEn.noInterior = XnoInterior
 .Emisor.expedidoEn.Colonia = Xcolonia
 .Emisor.expedidoEn.Municipio = Xmunicipio
 .Emisor.expedidoEn.Localidad = Xlocalidad
 .Emisor.expedidoEn.Estado = Xestado
 .Emisor.expedidoEn.Pais = Xpais
 .Emisor.expedidoEn.CodigoPostal = XcodigoPostal
 
 * -- Nuevo y obligatorio en 3.2 (puede ser uno o muchos)
*!* .Emisor.regimenFiscal.Add(RegimenFiscal) (PABG comentado 25 dic)
* .Emisor.regimenFiscal.Add("Otro Regimen (Opcional)")
*!* .Emisor.RegimenFiscal.Regimen = RegimenFiscal 
 
 .Receptor.RFC = Rrfc
 .Receptor.Nombre = Rnombre   && Opcional en 3.2
 
 * -- Domicilio de Receptor opcional en 3.2
 .Receptor.domicilioFiscal.Calle = Rcalle
 .Receptor.domicilioFiscal.noExterior = RnoExterior
 .Receptor.domicilioFiscal.noInterior = RnoInterior
 .Receptor.domicilioFiscal.Colonia = Rcolonia
 .Receptor.domicilioFiscal.Localidad = Rlocalidad 
 .Receptor.domicilioFiscal.Municipio = Rmunicipio
 .Receptor.domicilioFiscal.Estado = Restado
 .Receptor.domicilioFiscal.Pais = Rpais    && Único Requerido si Domicilio esta presente
 .Receptor.domicilioFiscal.codigoPostal = RcodigoPostal
 .Receptor.UsoCFDI = ALLTRIM(c_UsoCfdi)
 
 .Impuestos.Traslados.Add("IVA",tasa,IvaF)
 
 Select tbl_inffact
GoTo Top
Do While Not Eof()
   IF .NOT. ALLTRIM(tbl_inffact.str_articulo) = 'DTOI' .AND. .NOT. ALLTRIM(tbl_inffact.str_articulo) = 'DTOG' THEN
 
o = .Conceptos.Add(tbl_inffact.lon_cant, tbl_inffact.str_prod, tbl_inffact.Dou_Pu, tbl_inffact.Dou_TotPro)
o.noIdentificacion = tbl_inffact.str_articulo
o.Unidad = unidad
o.ValorUnitario = 0
o.Importe = 2
o.TasaoCuota = 0
o.Base = 0
o.Impuesto = 0
o.TipoFactor = 0
o.Iimporte = 0
o.ClaveProdServ = 'P'
o.Cantidad = 1
o.Descripcion = 'Mi Descripcion'
     
  ENDIF

  SKIP
ENDDO
 
ENDWITH
??"...Version " + CFDVersions.ToLongString(CFDVersions.fromString(oCFD.Version))


*-- Se carga la informacion del certificado 
*
LOCAL cArchivoKey, cArchivoCer
* Para pruebas con certificados del SAT
*!* cArchivoKey = "aaa010101aaa_CSD_01.key"
*!* cArchivoCer = "aaa010101aaa_CSD_01.cer"
*!* cPasswrdKey = "a0123456789"

*Certificado del cliente
cArchivoKey = ArchivoKey
cArchivoCer = ArchivoCertificado
cPasswrdKey = PasswordKey

?"- Validando archivos key y cer..."
IF NOT CFDValidarKeyCer(cArchivoKey, cArchivoCer, cPasswrdKey,".\SSL")
 ?"ERROR: " + CFDConf.ultimoError
 RETURN
ENDIF

?"- Leyendo certificado"
LOCAL oCert
oCert = oCFD.leerCertificado(cArchivoCer)
IF ISNULL(oCert)
 ?"ERROR: " + CFDConf.ultimoError
 RETURN
ENDIF

IF NOT oCert.Valido
 ?"ERROR: El certificado no es valido"
 RETURN
ENDIF

IF (NOT oCert.Vigente) AND (NOT CFDConf.modoPruebas)
 ?"ERROR: El certificado no esta vigente"
 RETURN
ENDIF



*-- Se sella el CFD
*
?"- Generando sello digital"
IF NOT oCFD.Sellar(cArchivoKey,cPasswrdKey)
 ?"ERROR: " + CFDConf.ultimoError
 RETURN
ENDIF



*-- Se crea el CFD
*
?"- Creando CFD"
*!* oCFD.CrearXML("test32.xml")
oCFD.CrearXML(ArchivoTimbrar)


*-- Se valida el CFD
*
?"- Validando CFD"
*!* IF NOT CFDValidarXML("test32.xml",cArchivoKey, cPasswrdKey, "sha1", ".\SSL")
IF NOT CFDValidarXML(ArchivoTimbrar,cArchivoKey, cPasswrdKey, "sha1", ".\SSL")
 ?"ERROR: " + CFDConf.ultimoError
 RETURN
ELSE 
  ??" OK"
ENDIF






--------------------------------------------------------------------------------------------------------------------Parte 2.
#DEFINE CRLF CHR(13)+CHR(10)
#DEFINE True .T.
#DEFINE False .F.


*-- CFDInit (Procedure)
*   Crea el objeto public CFDConf, el cual contiene
*   configuraciones generales de uso en varios de 
*   los metodos y funciones de la libreria
*
*   VES Dic 30, 2011
*   Se aprovecha para declarar algunas enumeraciones de
*   uso en la clase
*
PROCEDURE CFDInit
 *
 PUBLIC CFDVersions,CFDConf
 CFDVersions = CREATE("CFDVersionsEnum")
 CFDConf = CREATE("CFDConf")
 
 DECLARE Sleep IN kernel32 INTEGER dwMilliseconds  
 
 DECLARE INTEGER GetShortPathName IN kernel32;
    STRING    lpszLongPath,;
    STRING  @ lpszShortPath,;
    INTEGER   cchBuffer
    
DECLARE INTEGER GenerateFile ;
  IN BarCodeLibrary.dll;
  STRING   cData, ;
  STRING   cFileName 

    
 *
ENDPROC


*-- CFDVersionsEnum (Enumeracion)
*   Lista de valores validos para Version
*
DEFINE CLASS CFDVersionsEnum AS Custom
 *
 CFD_20 = 2
 CFD_22 = 22
 CFDi_30 = 3
 CFDi_32 = 32
 CFDi_33 = 33 && Versión 3.3 ByVigar.
 validVersionList = "[2][22][3][32][33]"

 PROCEDURE ToString(pnVersion)
  DO CASE
     CASE pnVersion = THIS.CFD_20
          RETURN "2.0"
          
     CASE pnVersion = THIS.CFD_22
          RETURN "2.2"
          
     CASE pnVersion = THIS.CFDi_30
          RETURN "3.0"
          
     CASE pnVersion = THIS.CFDi_32
          RETURN "3.2"

     CASE pnVersion = THIS.CFDi_33 && Versión 3.3 ByVigar.
          RETURN "3.3"
          
     OTHERWISE
          RETURN ""
  ENDCASE
 ENDPROC

 PROCEDURE FromString(pcVersion)
  DO CASE
     CASE pcVersion = "2.0"
          RETURN THIS.CFD_20
          
     CASE pcVersion = "2.2"
          RETURN THIS.CFD_22

     CASE pcVersion = "3.0"
          RETURN THIS.CFDi_30

     CASE pcVersion = "3.2"
          RETURN THIS.CFDi_32

     CASE pcVersion = "3.3"
          RETURN THIS.CFDi_33 && Versión 3.3 ByVigar.
                    
     OTHERWISE
          RETURN 0
  ENDCASE
 ENDPROC
 
 PROCEDURE ToLongString(pcVersion)
  DO CASE
     CASE pcVersion = THIS.CFD_20
          RETURN "CFD 2.0"
          
     CASE pcVersion = THIS.CFD_22
          RETURN "CFD 2.2"
          
     CASE pcVersion = THIS.CFDi_30
          RETURN "CFDi 3.0"
          
     CASE pcVersion = THIS.CFDi_32
          RETURN "CFDi 3.2"

     CASE pcVersion = THIS.CFDi_33 && Versión 3.3 ByVigar.
          RETURN "CFDi 3.3"
          
     OTHERWISE
          RETURN "Valor incorrecto (" + pcVersion + ")"
  ENDCASE
 ENDPROC
 
 PROCEDURE Validate(vNewVal, puCurValue)
  *
  LOCAL uValue
  IF VARTYPE(m.vNewVal)="N"
   m.vNEwVal = CFDVersions.ToString(m.vNewVal)
  ENDIF
  uValue = CFDVersions.FromString(m.vNewVal)
  IF EMPTY(uValue)
   uValue = puCurValue
   MESSAGEBOX("El valor de version indicado no es correcto.",16,"CFD") 
  ENDIF

  RETURN uValue  
  *
 ENDPROC
 *
ENDDEFINE


*-- CFDConf (Clase)
*   Configuraciones generales de uso en la libreria
*
DEFINE CLASS CFDConf AS Custom
 *
 Version = "3.7"
 OpenSSL = ""
 SMTPServer = ""
 SMTPPort = ""
 SMTPUseSSL = .T.
 SMTPAuthenticate = .T.
 SMTPUserName = ""
 SMTPPassword = ""
 MailSender = ""
 UltimoError = ""
 modoPruebas = .F.
 metodoDigest = "md5"
 ubicacionRepositorio = ".\CFD"
 ultimoCertificado = NULL
 formatoImpresion = "CFD.FRX"
 XMLVersion = 0
 incluirBOM = .F.
 NTOCMoneda = "Pesos"
 NTOCPrefijo = ""
 nTOCSufijo = "M.N."
 usarPrint2PDF = .T.

 PROCEDURE Init
  THIS.Version = CFDVersions.CFDi_33
  THIS.OpenSSL = ADDBS(FULLPATH(".\SSL"))
  THIS.XMLVersion = CFDVersions.CFDi_33
 ENDPROC
  
 PROCEDURE Version_Assign(vNEwVal)
 ENDPROC
 
 PROCEDURE XMLVersion_Assign(vNewVal)
  THIS.XMLVersion = CFDVersions.Validate(m.vNewVal, THIS.XMLVersion)
 ENDPROC
 *
ENDDEFINE




*-- CFDComprobante (Clase)
*   Representa a un comprobante digital
*
DEFINE CLASS CFDComprobante AS Custom
 *
 *-- Atributos requeridos
 * 
 *   ARC Dic 20, 2011: Se agregan las nuevas versiones
 *
 Version = ""  && VES Dic 30, 2011: Se elimino el valor por omision para establecerlo en el constructor
 Folio = 0
 Fecha = {}
 Sello = ""
 FormaPago = "" && Versión 3.3 ByVigar. se cambio de formadePago a FormaPago
 noAprobacion = 0
 anoAprobacion = 0
 NoCertificado = "" && Versión 3.3 ByVigar.
 SubTotal = 0.00
 Total = 0.00
 TipoDeComprobante = "" && Se sustituye tipoDeComprobante por TipoDeComprobante Requerido en v.3.3 ByVigar.
 Emisor = NULL
 Receptor = NULL
 Conceptos = NULL

 formaDePago = "Pago en una sola exhibición"
  
 *-- Atributos opcionales
 Serie = "" 
 Certificado = "" 
 CondicionesDePago = "" 
 Descuento = 0.00
 motivoDescuento = ""
 Impuestos = NULL
 Addenda = NULL
 CfdiRelacionados = NULL && Pagos UUDI Relacionados v.3.3 ByVigar


 *-- Atributos CFD 2.2 y CFDI 3.2 opcionales 
 MontoFolioFiscalOrig = NULL
 FechaFolioFiscalOrig = {}
 SerieFolioFiscalOrig = NULL
 FolioFiscalOrig = NULL
 NumCtaPago = NULL 
 Moneda = NULL
 TipoCambio = NULL
 
 *-- Atributos CFD 2.2 y CFDI 3.2 requeridos 
 LugarExpedicion = NULL
 *metodoDePago = ""  && ARC Dic 20, 2011: es requerido en CFD 2.2 y CFDI 3.2
 MetodoPago = ""  && ARC Dic 20, 2011: es requerido en CFD 2.2 y CFDI 3.2
  
 *-- Propiedades
 cadenaOriginal = ""   && Solo-lectura
 ubicacionOpenSSL = ".\SSL"
  
 
 *-- Getters / Setters
 PROCEDURE cadenaOriginal_Access
  RETURN THIS._genCadenaOriginal()
 ENDPROC
 PROCEDURE cadenaOriginal_Assign(vNewVal)
 ENDPROC 
 
 
 *-- Constructor de la clase
 *   
 *   VES Dic 30, 2011: Se incluyo el parametro opcional pnVersion
 *
 PROCEDURE Init(pnVersion)
  *
  IF PCOUNT() = 0   && Si no se indico una version, se asume la version indicada en CFDConf.XMLVersion
   pnVersion = CFDConf.XMLVersion
  ENDIF
  
  THIS.Version = pnVersion
  THIS.Emisor = CREATEOBJECT("CFDPersona")
  THIS.Receptor = CREATEOBJECT("CFDPersona")
  THIS.CfdiRelacionados = CREATEOBJECT("CfdiRelacionados")
  THIS.Conceptos = CREATEOBJECT("CFDConceptos")
  THIS.Impuestos = CREATEOBJECT("CFDImpuestos")
  THIS.ubicacionOpenSSL = CFDConf.OpenSSL
  *
 ENDPROC
 
 
 *-- Setter para propiedad Version
 *
 PROCEDURE Version_Assign(vNewVal)
  LOCAL nVersion
  nVersion = CFDVersions.Validate(m.vNewVal, 0)
  IF nVersion > 0
   THIS.Version = CFDVersions.ToString(nVersion)
  ENDIF
 ENDPROC

 
 
 
 *-- Metodos
 
 *-- _genCadenaOriginal (Metodo)
 *   Genera la cadena original que sirve de base para generar el sello digital. El codigo original
 *   pertenece al amigo Halcon Divino, y fue adaptado para el uso dentro de esta clase.
 *
 *   VES Ene 4, 2011
 *   Se cambio el codigo para obtener la cadena original directametne del XML aplicando el archivo
 *   XSLT proporcionado por el SAT. De esta forma nos garantizamos que no haya diferencia entre
 *   la cadena original generada por la clase y la que genera el SAT a partir del XML, lo cual 
 *   elimina los problemas de sellado por diferencia en la cadena original.
 *
 PROCEDURE _genCadenaOriginal()
  *
  LOCAL cTempFile
  cTempFile = GetTempFile("XML")
  THIS.CrearXML(cTempFile)
  
  LOCAL cStr
  cStr = CFDExtraerCadenaOriginal(cTempFile)
  
  ERASE (cTempFile)
  
  RETURN cStr
  *
 ENDPROC
 
 
 *-- _fixStr (Metodo)
 *   Recibe una cadena y realiza los siguientes cambios:
 *   a) Sustituye cualquier caracter invalido por el caracter "."
 *   b) Elimina los espacios en blanco al inicio y al final de la cadena
 *   c) Elimina cualquier secuencia de espacios en blanco repetidos dentro de la cadena
 *   d) Si la cadena resultante contiene al menos 1 caracter, se le anade la cadena
 *      indicada en el parametro pcSep
 *
 *   La funcion fue reeacrita a partir de la funcion QtarChrInval() de Halcon Divino, a fin
 *   de simplificar el codigo y depurarlo. El metodo utilizado por Halcon Divino para incluir
 *   cada elemento en la cadena original implicaba una doble llamada a QtarChrInval() para 
 *   cada valor en la cadena:
 *
 *   cStr  = cStr  + Iif(Len(QtarChrInval(valor)) = 0, "" ,QtarChrInval(valor) + "|") 
 *
 *   Este codigo se simplifica y mejora haciendo una sola invocacion a fixStr:
 *
 *   cStr = cStr + THIS._fixStr(valor, "|")
 *
 *   Adicionalmente se incluyo codigo para permitir que la funcion reciba cualquier tipo
 *   de datos, haciendo la conversion adecuada segun el tipo. En los casos donde el parametro
 *   de entraada no sea un string, no se realiza la verificacion de caracteres invalidos
 *
 HIDDEN PROCEDURE _fixStr(puValue, pcSep)
  *
  IF PCOUNT() = 1
   pcSep = ""
  ENDIF
  
  LOCAL cType
  cType = VARTYPE(puValue)
  
  DO CASE
     CASE cType = "N" 
          IF EMPTY(puValue)
           RETURN ""
          ENDIF
          RETURN ALLT(STR(puValue,15,2)) + pcSep
          
     CASE cType = "D"
          IF EMPTY(puValue)
           RETURN ""
          ENDIF
          RETURN STR(YEAR(puValue),4) + "-" + PADL(MONTH(puValue),2,"0") + "-" + PADL(DAY(puValue),2,"0") + pcSEP
          
     CASE cType = "T"
          IF EMPTY(puValue)
           RETURN ""
          ENDIF
          RETURN STR(YEAR(puValue),4) + "-" + PADL(MONTH(puValue),2,"0") + "-" + PADL(DAY(puValue),2,"0") + "T" + ;
                 PADL(HOUR(puValue),2,"0") + ":" + PADL(MINUTE(puValue),2,"0") + ":" + PADL(SEC(puValue),2,"0") + pcSEP     
     
     CASE cType = "X"  && Valor NULL
          RETURN ""
  ENDCASE
  
  
  LOCAL cFixed
  cFixed = ALLTRIM(puValue)
  cFixed = STRT(STRT(STRT(STRT(STRT(cFixed,[&],[&amp;]),[<],[&lt;]),[>],[&gt;]),["],[&quot;]),['],[&apos;])
  cFixed = STRT(cFixed, CHR(13)+CHR(10), "")
 
  DO WHILE AT(SPACE(2), cFixed) <> 0
   cFixed = STRTRAN(cFixed,SPACE(2),SPACE(1))
  ENDDO
 
  IF LEN(cFixed) > 0 AND !EMPTY(pcSep)
   cFixed = cFixed + pcSep
  ENDIF
  
  RETURN cFixed
  *
 ENDPROC
 

 *-- Sellar (Metodo)
 *   Genera el sello digital del comprobante y actualiza los atributos apropiados
 *
 PROCEDURE Sellar(pcArchivoKey, pcPassword)
  *
  CFDConf.ultimoError = ""

  *-- Si la fecha del comprobante es igual o posterior al 1-1-2011, se cambia
  *   el metodo MD5 por SHA-256
  *
  LOCAL cMetodo
  cMetodo = "md5"
  IF YEAR(THIS.fecha) > 2010 
   cMetodo = "sha256"
  ENDIF
  CFDConf.metodoDigest = cMetodo
  
  *-- Se obtiene la cadena original
  *
  LOCAL cCadenaOriginal
  cCadenaOriginal = THIS.cadenaOriginal
  IF EMPTY(cCadenaOriginal)
   CFDConf.ultimoError = "No se pudo obtener la cadena original. Utilize CFDProbarOpenSSL() para verificar el funcionamiento de la libreria OpenSSL"
   RETURN .F.
  ENDIF
  
  
  *-- Se genera el sello para la cadena original
  *
  THIS.Sello = CFDGenerarSello(cCadenaOriginal, pcArchivoKey, pcPassword, cMetodo, THIS.ubicacionOpenSSL)
  
  RETURN !EMPTY(THIS.Sello)
  *
 ENDPROC
 
 
 *-- leerCertificado
 *   Lee el archivo de certificado indicado y actualiza
 *   los atributos apropiados
 *
 *   VES Ene 4, 2011
 *   Se utiliza la propiedad CFDConf.ultimoCertificado como
 *   un "cache" para evitar leer innecesariamente el mismo
 *   certificado varias veces seguidas
 *
 PROCEDURE leerCertificado(pcArchivoCER)
  *
  *-- Se lee el certificado (solo si es necesario)
  LOCAL oCert  
  IF ISNULL(CFDConf.ultimoCertificado) OR CFDConf.ultimoCertificado.Archivo <> LOWER(pcArchivoCER)
   oCert = CFDLeerCertificado(pcArchivoCER)
   IF ISNULL(oCert)
    RETURN NULL
   ENDIF  
   CFDConf.ultimoCertificado = oCert
  ELSE
   oCert = CFDConf.ultimoCertificado 
   *?"Cached!"
  ENDIF 
  
  IF oCert.Valido AND (oCert.Vigente OR CFDConf.modoPruebas)
   THIS.Certificado = oCert.Certificado
   THIS.noCertificado = oCert.Serial
  ENDIF
  
  RETURN oCert
  *
 ENDPROC
 
 
 *-- CrearXML (Metodo)
 *   Crea el archivo XML que representa el comprobante
 *
 PROCEDURE CrearXML(pcArchivo, plValidar, pcArchivoKey, pcPassword, pcMetodo)
  *
  #DEFINE CFD_OPCIONAL .T.  
  
  CFDConf.ultimoError = ""

*!* EXIT &&Agregado para debugear por errores
  
  LOCAL oParser,nVersion
  oParser = CREATEOBJECT("XmlParser")
  nVersion = CFDVersions.fromString(THIS.Version)
  WITH oParser
   *
   .indentString = ""
   .New()
   
   *-- Nodo "Comprobante"
   .XML.addNode("Comprobante")
   IF INLIST(nVersion, CFDVersions.CFDi_32, CFDVersions.CFDi_33) && Versión 3.3 ByVigar.
    .XML._Comprobante.NameSpace = "cfdi"  && Al anadir el NS "Cfdi" al nodo comprobante, todos los subnodos lo heredaran automaticamente
   ENDIF
   WITH .XML._Comprobante
    DO CASE 
      CASE nVersion = CFDVersions.CFD_20
    .addProp("xmlns","http://www.sat.gob.mx/cfd/2")
    .addProp("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
   
      CASE nVersion = CFDVersions.CFDi_30
    .addProp("xmlns:cfdi","http://www.sat.gob.mx/cfd/3")
    .addProp("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
   
      CASE nVersion = CFDVersions.CFD_22
    .addProp("xmlns","http://www.sat.gob.mx/cfd/2")
    .addProp("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
   
      CASE nVersion = CFDVersions.CFDi_32
    .addProp("xmlns:cfdi","http://www.sat.gob.mx/cfd/3")
    .addProp("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
   
      CASE nVersion = CFDVersions.CFDi_33 && Versión 3.3 ByVigar.
    .addProp("xmlns:cfdi","http://www.sat.gob.mx/cfd/3")
    .addProp("xmlns:xsi","http://www.w3.org/2001/XMLSchema-instance")
    IF THIS.TipoDeComprobante='P'
    .addProp("xmlns:pago10","http://www.sat.gob.mx/Pagos")
    .addProp("xmlns:xs","http://www.w3.org/2001/XMLSchema")
    ENDIF
    ENDCASE  
    .addProp("Version",THIS._fixStr(THIS.version))
    .addProp("Serie",THIS._fixStr(THIS.serie),CFD_OPCIONAL)
    .addProp("Folio",THIS._fixStr(STR(THIS.folio,10,0)))
    .addProp("Fecha",THIS._fixStr(THIS.fecha))
    IF INLIST(nVersion, CFDVersions.CFD_20, CFDVersions.CFD_22)
    .addProp("noAprobacion",THIS._fixStr(STR(THIS.noAprobacion,10,0)))
    .addProp("anoAprobacion",THIS._fixStr(STR(THIS.anoAprobacion,10,0)))
    ENDIF 
    IF INLIST(nVersion, CFDVersions.CFD_22, CFDVersions.CFDi_30, CFDVErsions.CFDi_32)
    .addProp("Moneda",THIS._fixStr(THIS.moneda),CFD_OPCIONAL)
    .addProp("TipoCambio",THIS._fixStr(THIS.tipocambio),CFD_OPCIONAL)
    ENDIF  
    IF INLIST(nVersion, CFDVersions.CFDi_33)
    .addProp("MontoFolioFiscalOrig",THIS._fixStr(THIS.MontoFolioFiscalOrig),CFD_OPCIONAL)
    .addProp("FechaFolioFiscalOrig",THIS._fixStr(THIS.FechaFolioFiscalOrig),CFD_OPCIONAL)
    .addProp("SerieFolioFiscalOrig",THIS._fixStr(THIS.SerieFolioFiscalOrig),CFD_OPCIONAL)
    .addProp("FolioFiscalOrig",THIS._fixStr(THIS.FolioFiscalOrig),CFD_OPCIONAL)
    .addProp("NumCtaPago",THIS._fixStr(THIS.NumCtaPago),CFD_OPCIONAL)
    .addProp("LugarExpedicion",THIS._fixStr(THIS.LugarExpedicion))
    ENDIF 
    .addProp("MetodoPago",THIS._fixStr(THIS.MetodoPago),CFD_OPCIONAL)
    IF THIS.TipoDeComprobante='I' && Versión 3.3 ByVigar. no para tipo 'P' Pago10
    .addProp("FormaPago",THIS._fixStr(THIS.FormaPago)) && Versión 3.3 ByVigar.
    ENDIF
    .addProp("FormaDePago",THIS._fixStr(THIS.formaDePago))
    *.addProp("",THIS._fixStr(THIS.))
    .addProp("CondicionesDePago",THIS._fixStr(THIS.CondicionesDePago),CFD_OPCIONAL)
    
    IF THIS.TipoDeComprobante='I' && ByVigar v.3.3
    .addProp("SubTotal",THIS._fixStr(STR(THIS.SubTotal,15,2)))
    ELSE
    .addProp("SubTotal",THIS._fixStr('0'))
    ENDIF
    
*    IF m.imp_dscnt <> 0 && No debe de aparecer si es 0    V.3.3 ByVigar
        IF DescuentoF <> 0 && No debe de aparecer si es 0    V.3.3 ByVigar
    .addProp("Descuento",THIS._fixStr(TRANSFORM(THIS.Descuento,"@Z 999999999999.99")))
    .addProp("motivoDescuento",THIS._fixStr(THIS.motivoDescuento),CFD_OPCIONAL)
    ENDIF

IF THIS.TipoDeComprobante='I' && ByVigar v.3.3
    .addProp("Total",THIS._fixStr(STR(THIS.Total,15,2)))
    ELSE
    .addProp("Total",THIS._fixStr('0'))
    ENDIF
    
    .addProp("TipoDeComprobante",THIS._fixStr(THIS.TipoDeComprobante))
    .addProp("NoCertificado",THIS.noCertificado)
    .addProp("Certificado",THIS.Certificado) && Versión 3.3 ByVigar.
    .addProp("Sello",THIS.sello)
   ENDWITH
  
   *-- Nodo "Emisor"
   .XML._Comprobante.addNode("Emisor")
   WITH .XML._Comprobante._Emisor
    .addProp("Rfc",CHRT(THIS._fixStr(THIS.Emisor.Rfc),".- ",""))  && VES Nov 16, 2011
    .addProp("RegimenFiscal",THIS._fixStr(THIS.Emisor.RegimenFiscal))  && ByVigar v.3.3 16/09/2017     
    IF INLIST(nVersion, CFDVersions.CFD_20, CFDVersions.CFDi_30)  && ARC Ene 03, 2012: Nombre de Emisor opcional en 2.2 y 3.2
      .addProp("Nombre",THIS._fixStr(THIS.Emisor.Nombre))
    ELSE 
      IF NOT EMPTY(THIS.Emisor.Nombre)
        .addProp("Nombre",THIS._fixStr(THIS.Emisor.Nombre))
      ENDIF 
    ENDIF 
    
    IF NOT EMPTY(THIS.Emisor.domicilioFiscal.Pais) && ARC Dic 27, 2011: domiciolio del emisor es opcional en 2.2 y 3.2
      .addNode("DomicilioFiscal")
      WITH ._DomicilioFiscal
       .addProp("calle",THIS._fixStr(THIS.Emisor.DomicilioFiscal.Calle))
       .addProp("noExterior",THIS._fixStr(THIS.Emisor.DomicilioFiscal.noExterior),CFD_OPCIONAL)
       .addProp("noInterior",THIS._fixStr(THIS.Emisor.DomicilioFiscal.noInterior),CFD_OPCIONAL)
       .addProp("colonia",THIS._fixStr(THIS.Emisor.DomicilioFiscal.colonia),CFD_OPCIONAL)
       .addProp("localidad",THIS._fixStr(THIS.Emisor.DomicilioFiscal.localidad),CFD_OPCIONAL)
       .addProp("referencia",THIS._fixStr(THIS.Emisor.DomicilioFiscal.referencia),CFD_OPCIONAL)
       .addProp("municipio",THIS._fixStr(THIS.Emisor.DomicilioFiscal.municipio))
       .addProp("estado",THIS._fixStr(THIS.Emisor.DomicilioFiscal.estado))
       .addProp("pais",THIS._fixStr(THIS.Emisor.DomicilioFiscal.pais))
       .addProp("CodigoPostal",THIS._fixStr(THIS.Emisor.DomicilioFiscal.CodigoPostal))
      ENDWITH
    ENDIF 

    IF NOT EMPTY(THIS.Emisor.ExpedidoEn.Pais) && ARC Dic 27, 2011: Ya que Pais es el unico atributo requerido
     .addNode("ExpedidoEn")
     WITH ._ExpedidoEn
*!*       .addProp("calle",THIS._fixStr(THIS.Emisor.ExpedidoEn.Calle))
*!*       .addProp("noExterior",THIS._fixStr(THIS.Emisor.ExpedidoEn.noExterior),CFD_OPCIONAL)
*!*       .addProp("noInterior",THIS._fixStr(THIS.Emisor.ExpedidoEn.noInterior),CFD_OPCIONAL)
*!*       .addProp("colonia",THIS._fixStr(THIS.Emisor.ExpedidoEn.colonia),CFD_OPCIONAL)
*!*       .addProp("localidad",THIS._fixStr(THIS.Emisor.ExpedidoEn.localidad),CFD_OPCIONAL)
*!*       .addProp("referencia",THIS._fixStr(THIS.Emisor.ExpedidoEn.referencia),CFD_OPCIONAL)
*!*       .addProp("municipio",THIS._fixStr(THIS.Emisor.ExpedidoEn.municipio))
*!*       .addProp("estado",THIS._fixStr(THIS.Emisor.ExpedidoEn.estado))
*!*       .addProp("pais",THIS._fixStr(THIS.Emisor.ExpedidoEn.pais))
      .addProp("CodigoPostal",THIS._fixStr(THIS.Emisor.ExpedidoEn.CodigoPostal))
     ENDWITH
    ENDIF
    
*!*     IF INLIST(nVersion, CFDVersions.CFDi_33) && Se integra como propiedad del Emisor.RegimenFiscal v.3.3 ByVigar
*!*       LOCAL nRegimen,oRegimen,oNodoRegimen   && VES Ene 12, 2012
*!*       FOR nRegimen = 1 TO THIS.Emisor.RegimenFiscal.Count
*!*        oRegimen = THIS.Emisor.RegimenFiscal.Items[nRegimen]
*!*        oNodoRegimen = .addNode("RegimenFiscal")
*!*        oNodoRegimen.addProp("RegimenFiscal",THIS._fixStr(oRegimen.RegimenFiscal))
*!*       ENDFOR
*!*     ENDIF 
   ENDWITH
   
   
   *-- Nodo "Receptor"
   .XML._Comprobante.addNode("Receptor")
   WITH .XML._Comprobante._Receptor
    .addProp("Rfc",CHRT(THIS._fixStr(THIS.Receptor.Rfc),".- ",""))   && VES Nov 16, 2011
    .addProp("UsoCFDI",THIS._fixStr(THIS.Receptor.UsoCFDI)) && v.3.3 ByVigar.     
    IF NOT EMPTY(THIS.Receptor.Nombre)   && ARC Ene 03, 2012: Nombre de Receptor es opcional
      .addProp("Nombre",THIS._fixStr(THIS.Receptor.Nombre))
    ENDIF 
    
    IF NOT EMPTY(THIS.Receptor.DomicilioFiscal.pais) && ARC Ene 03, 2012: Ya que Pais es el unico atributo requerido
      .addNode("Domicilio")  && Es opcional en 3.0, 2.2 y 3.2
      WITH ._Domicilio
       .addProp("calle",THIS._fixStr(THIS.Receptor.DomicilioFiscal.Calle),CFD_OPCIONAL)
       .addProp("noExterior",THIS._fixStr(THIS.Receptor.DomicilioFiscal.noExterior),CFD_OPCIONAL)
       .addProp("noInterior",THIS._fixStr(THIS.Receptor.DomicilioFiscal.noInterior),CFD_OPCIONAL)
       .addProp("colonia",THIS._fixStr(THIS.Receptor.DomicilioFiscal.colonia),CFD_OPCIONAL)
       .addProp("localidad",THIS._fixStr(THIS.Receptor.DomicilioFiscal.localidad),CFD_OPCIONAL)
       .addProp("referencia",THIS._fixStr(THIS.Receptor.DomicilioFiscal.referencia),CFD_OPCIONAL)
       .addProp("municipio",THIS._fixStr(THIS.Receptor.DomicilioFiscal.municipio),CFD_OPCIONAL)
       .addProp("estado",THIS._fixStr(THIS.Receptor.DomicilioFiscal.estado),CFD_OPCIONAL)
       .addProp("pais",THIS._fixStr(THIS.Receptor.DomicilioFiscal.pais))
       .addProp("codigoPostal",THIS._fixStr(THIS.Receptor.DomicilioFiscal.codigoPostal),CFD_OPCIONAL)
      ENDWITH
    ENDIF 
   ENDWITH
   
   
   *-- Nodo "Conceptos"
   *   
   *   La clase XmlParser no reconoce que un nodo pueda contener dos subnodos con el mismo nombre. Para
   *   solucionar este impase, se le anade un contador al nombre de cada nodo Concepto, de modo que quede 
   *   asi:
   *
   *   <Conceptos>
   *     <Concepto001 ... />
   *     <Concepto002 ... />
   *   </Conceptos>
   *
   *   Una vez generado el Xml, se cargara en memoria para quitar las secuencias y asi corregir el problema
   *
   *   VES Nov 11, 2011
   *   La nueva propiedad createNodeLinks en la clas XMLNodeClass permite superar este problema
   *
   LOCAL i,oItem,oNodo,oxNodo
   .XML._Comprobante.addNode("Conceptos")
   WITH .XML._Comprobante._Conceptos
    .createNodeLinks = .F.   && Nov 11, 2011
    FOR i = 1 TO THIS.Conceptos.Count
     oItem = THIS.Conceptos.Items(i)
     oNodo = .addNode("Concepto")
     WITH oNodo
        .addProp("ClaveProdServ",THIS._fixStr(oItem.ClaveProdServ))
        .addProp("NoIdentificacion",THIS._fixStr(oItem.NoIdentificacion),CFD_OPCIONAL) && Cambio en Orden y de "noIdentificacion" a "NoIdentificacion" v.3.3 ByVigar.
    IF THIS.TipoDeComprobante='P'
      .addProp("Cantidad",THIS._fixStr(oItem.Cantidad)) && Fijo '1' Cambio de "cantidad" a "Cantidad" para  v.3.3 ByVigar
  ELSE
      .addProp("Cantidad",THIS._fixStr(STR(oItem.Cantidad,10,2))) && Cambio de "cantidad" a "Cantidad" para  v.3.3 ByVigar.
        ENDIF
        .addProp("ClaveUnidad",THIS._fixStr(oItem.ClaveUnidad)) && Nuevo y Obligatorio v.3.3 ByVigar.       
        .addProp("Unidad",THIS._fixStr(oItem.Unidad),CFD_OPCIONAL) && Sigue Opcional y Cambio de "unidad" a "Unidad" para  v.3.3 ByVigar.
        .addProp("Descripcion",THIS._fixStr(oItem.Descripcion)) && Cambio de "descripcion" a "Descripcion" para  v.3.3 ByVigar.
  IF THIS.TipoDeComprobante='P'
      .addProp("ValorUnitario",THIS._fixStr(oItem.ValorUnitario)) && Fijo '0' Cambio de "valorUnitario" a "ValorUnitario" para  v.3.3 ByVigar.
      .addProp("Importe",THIS._fixStr(oItem.Importe)) && Fijo '0' Cambio de "importe" a "Importe" para  v.3.3 ByVigar.
  ELSE
      .addProp("ValorUnitario",THIS._fixStr(STR(oItem.ValorUnitario,15,2))) && Cambio de "valorUnitario" a "ValorUnitario" para  v.3.3 ByVigar.
      .addProp("Importe",THIS._fixStr(STR(oItem.Importe,15,2))) && Cambio de "importe" a "Importe" para  v.3.3 ByVigar.
  ENDIF
      
  IF THIS.TipoDeComprobante='I'
      oNodo = .addNode("Impuestos")
    WITH oNodo
    oNodo = .addNode("Traslados")
      WITH oNodo
      .createNodeLinks = .F.  && Nov 11, 2011
        oNodo = .addNode("Traslado")
        oNodo.addProp("Base",THIS._fixStr(STR(oItem.Base,15,2)))
        oNodo.addProp("Impuesto",THIS._fixStr(oItem.Impuesto))
        oNodo.addProp("TipoFactor",THIS._fixStr(oItem.TipoFactor))
        oNodo.addProp("TasaOCuota",THIS._fixStr(STR((oItem.TasaOCuota/100),10,6)))      && Nuevo u obligatorio v.3.3 ByVigar.
        oNodo.addProp("Importe",THIS._fixStr(STR(oItem.Iimporte,15,2)))
      ENDWITH
      ENDWITH
      ENDIF
      
          IF !EMPTY(oItem.CuentaPredial.Numero)
        .addNode("CuentaPredial")
      WITH .Nodes[1]  && ARC Feb 2, 2014
        .addProp("numero",THIS._fixStr(oItem.CuentaPredial.numero))
        ENDWITH
        ENDIF

      
                 
      *-- VES Ene 12, 2012: Si el concepto contiene un complemento, se inserta como si
      *   fuera una addenda en el concepto
      IF !ISNULL(oItem.Complemento) AND LOWER(oItem.Complemento.ParentClass) == "icfdaddenda"
        oNodo = .addNode("ComplementoConcepto")
        oNodo.Data = oItem.Complemento.ToString() 
        IF !EMPTY(oItem.Complemento.NSTag)
        * VES Ago 3, 2012: Se valida que no se haya declarado el Namespace anteriormente, antes
        * de anadir su declaracion en las propiedades del nodo Comprobante 
        IF NOT oParser.XML._Comprobante.isProp("xmlns:" + oItem.Complemento.NSTag)
          oParser.XML._Comprobante.addProp("xmlns:" + oItem.Complemento.NSTag, oItem.Complemento.NSUrl)
        ENDIF
        ENDIF
        IF !EMPTY(oItem.Complemento.schemaLocation)
        WITH oParser.XML._Comprobante.Props["xsi:schemaLocation"]
          .Value = .Value + SPACE(1) + oItem.Complemento.schemaLocation
        ENDWITH
        ENDIF
      ENDIF 
      ENDWITH
    ENDFOR
    ENDWITH

   
   IF THIS.TipoDeComprobante='I'   
   *-- Nodo "Impuestos"
   *
   *   Tanto para los subnodos de Retenciones como de Impuestos se aplico la misma tecnica de enumeracion
   *   aplicada con los subnodos de Conceptos
   *
   *   VES Nov 11, 2011
   *   Se aplica la nueva propiedad createNodeLinks para evitar este problema
   *
    .XML._Comprobante.addNode("Impuestos")
   WITH .XML._Comprobante._Impuestos
    IF THIS.Impuestos.Retenciones.Count > 0
     .addProp("TotalImpuestosRetenidos",THIS._fixStr(STR(THIS.Impuestos.TotalImpuestosRetenidos,15,2)))
     .addNode("Retenciones")
     WITH ._Retenciones
     .createNodeLinks = .F.   && Nov 11, 2011     
      FOR i = 1 TO THIS.Impuestos.Retenciones.Count
       oItem = THIS.Impuestos.Retenciones.Items(i)
       oNodo = .addNode("Retencion")
           oNodo.addProp("Impuesto",THIS._fixStr(oItem.Impuesto)) && 002 IVA v.3.3 ByVigar
       oNodo.addProp("Importe",THIS._fixStr(STR(oItem.Importe,15,2)))
      ENDFOR
     ENDWITH
    ENDIF
    
    IF THIS.Impuestos.Traslados.Count > 0
     .addProp("TotalImpuestosTrasladados",THIS._fixStr(STR(THIS.Impuestos.TotalImpuestosTrasladados,15,2))) 
     .addNode("Traslados")
     WITH ._Traslados
      .createNodeLinks = .F.  && Nov 11, 2011
      FOR i = 1 TO THIS.Impuestos.Traslados.Count
       oItem = THIS.Impuestos.Traslados.Items(i)
       oNodo = .addNode("Traslado")
        oNodo.addProp("Impuesto",THIS._fixStr(oItem.Impuesto))
        oNodo.addProp("TipoFactor",THIS._fixStr(oItem.TipoFactor))
        oNodo.addProp("TasaOCuota",THIS._fixStr(STR((oItem.TasaOCuota/100),10,6)))      && Nuevo u obligatorio v.3.3 ByVigar.
        oNodo.addProp("Importe",THIS._fixStr(STR(oItem.Importe,15,2)))
      ENDFOR
     ENDWITH
    ENDIF
   ENDWITH
   ENDIF

   * set step on 
   *-- Nodo "Addenda"
   *
   *   VES Nov 14, 2011
   *   Se reprogramo esta rutina para hacer uso de la nueva clase ICFDAddenda
   *
   IF !ISNULL(THIS.Addenda) AND LOWER(THIS.Addenda.ParentClass) == "icfdaddenda"
    oNodo = oParser.XML._Comprobante.addNode(THIS.Addenda.nodeName)
    oNodo.Data = THIS.Addenda.ToString() 
    IF !EMPTY(THIS.Addenda.NSTag)
     oParser.XML._Comprobante.addProp("xmlns:" + THIS.Addenda.NSTag, THIS.Addenda.NSUrl)
    ENDIF
    IF !EMPTY(THIS.Addenda.schemaLocation)
     WITH oParser.XML._Comprobante.Props["xsi:schemaLocation"]
      .Value = .Value + SPACE(1) + THIS.Addenda.schemaLocation
     ENDWITH
    ENDIF
   ENDIF 

IF THIS.TipoDeComprobante='P' && ByVigar Foxlatino
    .XML._Comprobante.addNode("Complemento")
    WITH .XML._Comprobante._Complemento
      oNodo = oParser.XML._Comprobante._Complemento.addNode("pago10:Pagos")
      WITH oParser.XML._Comprobante._Complemento._Pagos
      *WITH oParser.XML._Comprobante._Complemento._pago10._Pagos
     
      *oNodo = oParser.XML._Comprobante._Complemento.addNode("pago10Pagos")
      *WITH oParser.XML._Comprobante._Complemento._pago10Pagos
      .addProp('Version',THIS._fixStr('1.0'))
      oNodo = oParser.XML._Comprobante._Complemento._Pagos.addNode("pago10:Pago")
      WITH oParser.XML._Comprobante._Complemento._Pagos._Pago
oNodo.addProp("FechaPago", THIS._fixStr(xfecpago))
oNodo.addProp("FormaDePagoP", THIS._fixStr(xfdpago))
oNodo.addProp("MonedaP", THIS._fixStr(xmoneda))
*oNodo.addProp("TipoCambioP", THIS._fixStr((STR(TipoCambioP,10,6)),_OPCIONAL))
oNodo.addProp("Monto", THIS._fixStr(STR(m.imp_net,15,2)))
*oNodo.addProp("NumOperacion", THSI._fixStr(NumOperacion),_OPCIONAL)
*oNodo.addProp("RfcEmisorCtaOrd", THIS._fixStr(RfcEmisorCtaOrd),_OPCIONAL)
*oNodo.addProp("NomBancoOrdExt", THIS._fixStr(NomBancoOrdExt))
*oNodo.addProp("CtaOrdenante", THIS._fixStr(CtaOrdenante),_OPCIONAL)
*oNodo.addProp("RfcEmisorCtaBen", THIS._fixStr(RfcEmisorCtaBen),_OPCIONAL)
*oNodo.addProp("CtaBeneficiario", THIS._fixStr(CtaBeneficiario),_OPCIONAL)  
      oNodo = oParser.XML._Comprobante._Complemento._Pagos._Pago.addNode("pago10:DoctoRelacionado")
      WITH oParser.XML._Comprobante._Complemento._Pagos._Pago._DoctoRelacionado
oNodo.addProp("IdDocumento",this._fixStr(xtimbre))
*oNodo.addProp("Serie",this._fixStr(Serie))
*oNodo.addProp("Folio",this._fixStr(Folio))
oNodo.addProp("MonedaDR",this._fixStr(xmoneda))
*oNodo.addProp("TipoCambioDR",this.TipoCambioDR)
oNodo.addProp("MetodoDePagoDR",this._fixStr(xmetpago))
oNodo.addProp("NumParcialidad",this._fixStr(xnumparc))
oNodo.addProp("ImpSaldoAnt",THIS._fixStr(STR(xsdoant,15,2)))
oNodo.addProp("ImpPagado",THIS._fixStr(STR(m.imp_net,15,2)))
oNodo.addProp("ImpSaldoInsoluto",THIS._fixStr(STR(xinsoluto,15,2)))
        ENDWITH
       
        ENDWITH
       
        ENDWITH
       
        ENDWITH
       
ENDIF
   IF swfetim
IF THIS.TipoDeComprobante<>'P'
    .XML._Comprobante.addNode("Complemento")
    ENDIF
    WITH .XML._Comprobante._Complemento
      .addNode("tfd:TimbreFiscalDigital")
    ENDWITH
      WITH .XML._Comprobante._Complemento._TimbreFiscalDigital
.addProp('Version',THIS._fixStr('1.1'))
.addProp('xsi:schemaLocation',THIS._fixStr(xtlcencabtfd))
.addProp('xmlns:tfd', THIS._fixStr(xtlcpietfd))
        .addProp("UUID",THIS._fixStr(xtlcfolio))
        .addProp("RfcProvCertif",THIS._fixStr(xtlrfcprocer))
        .addProp("FechaTimbrado",THIS._fixStr(xtlcFechaTimbrado))
        .addProp("SelloCFD",THIS._fixStr(xtlcselloCFD))
        .addProp("NoCertificadoSAT",THIS._fixStr(xtlccertificadoSAT))
        .addProp("SelloSAT",THIS._fixStr(xtlcselloSAT))
       ENDWITH
   ENDIF
   

   *-- Se crea el archivo Xml
   .Save(pcArchivo)
   
   *-- Se carga el Xml en memoria de nuevo para eliminar los tags consecutivos
   *   de los nodos Concepto, Retenciones y Traslados, asi como eliminar los
   *   CRLF
   LOCAL cBuff
   cBuff = FILETOSTR(pcArchivo)
   cBuff = STRT(cBuff, ">" + CHR(13)+CHR(10), ">")
   cBuff = STRT(cBuff, "?>", "?>" + CHR(13) + CHR(10))
   
   
   *-- Si es CFDI se agrega a los nodos el prefijo 'cfdi:'
   *
   *   VES Nov 11, 2011
   *   Solucionado con la nueva propiedad NameSpace de la clase XMLNodeClass
   *
*!*    IF ALLTRIM(THIS.version) = "3.0"
*!* cBuff = STRT(cBuff, "<Comprobante", "<cfdi:Comprobante")    
*!* cBuff = STRT(cBuff, "<Emisor", "<cfdi:Emisor")
*!* cBuff = STRT(cBuff, "<DomicilioFiscal", "<cfdi:DomicilioFiscal")
*!* cBuff = STRT(cBuff, "<ExpedidoEn", "<cfdi:ExpedidoEn")
*!* cBuff = STRT(cBuff, "</Emisor>", "</cfdi:Emisor>")
*!* cBuff = STRT(cBuff, "<Receptor", "<cfdi:Receptor")
*!* cBuff = STRT(cBuff, "<Domicilio", "<cfdi:Domicilio")
*!* cBuff = STRT(cBuff, "</Receptor>", "</cfdi:Receptor>")
*!* cBuff = STRT(cBuff, "<Conceptos>", "<cfdi:Conceptos>")
*!* cBuff = STRT(cBuff, "<Concepto ", "<cfdi:Concepto ")
*!* cBuff = STRT(cBuff, "<InformacionAduanera", "<cfdi:InformacionAduanera")
*!* cBuff = STRT(cBuff, "<CuentaPredial", "<cfdi:CuentaPredial")
*!* cBuff = STRT(cBuff, "<ComplementoConcepto", "<cfdi:ComplementoConcepto")
*!* cBuff = STRT(cBuff, "<Parte", "<cfdi:Parte")
*!* cBuff = STRT(cBuff, "</Concepto>", "</cfdi:Concepto>")
*!* cBuff = STRT(cBuff, "</Conceptos>", "</cfdi:Conceptos>")
*!* cBuff = STRT(cBuff, "<Impuestos", "<cfdi:Impuestos")
*!* cBuff = STRT(cBuff, "<Retenciones>", "<cfdi:Retenciones>")
*!* cBuff = STRT(cBuff, "<Retencion", "<cfdi:Retencion")
*!* cBuff = STRT(cBuff, "</Retenciones>", "</cfdi:Retenciones>")
*!* cBuff = STRT(cBuff, "<Traslados>", "<cfdi:Traslados>")
*!* cBuff = STRT(cBuff, "<Traslado", "<cfdi:Traslado")
*!* cBuff = STRT(cBuff, "</Traslados>", "</cfdi:Traslados>")
*!* cBuff = STRT(cBuff, "</Impuestos>", "</cfdi:Impuestos>")
*!* cBuff = STRT(cBuff, "<Addenda>", "<cfdi:Addenda>")
*!* cBuff = STRT(cBuff, "</Comprobante>", "</cfdi:Comprobante>")
*!*    ENDIF 
   
   
   *-- Se graba de nuevo el Xml ya en su forma final
   cBuff = CFDAsc2UTF8(cBuff)
   
   *-- El 4 del tercer parámetro en STRTOFILE() agrega el BOM al XML en UTF-8
   IF CFDConf.incluirBOM
      * VES Jul 25, 2012
      * Se sustituyo el codigo original por un codigo compatible con VFP 6
      *
      * Codigo original:
      *STRTOFILE(cBuff,pcArchivo,4)
      LOCAL cBOM
      cBOM = CHR(0xEF) + CHR(0xBB) + CHR(0xBF)
      STRTOFILE(cBOM + cBuff, pcArchivo)
   ELSE 
      STRTOFILE(cBuff,pcArchivo)
   ENDIF 
   cBuff=""
   
   
   *-- Si se indico el parametro plValidar, se verifica que el XML este bien formado y que el sello sea valido
   *
   IF plValidar
    *
    *-- Se valida la sintaxis del XML
    IF NOT CFDValidarXML(pcArchivo, pcArchivoKey, pcPassword, pcMetodo, THIS.ubicacionOpenSSL)
     RETURN .F.
    ENDIF
    *
   ENDIF
   
   RETURN .T.
   *
  ENDWITH 
  
  *
 ENDPROC
 *

ENDDEFINE


*!* *-- CFDRegimenFiscal && Se sustituye por Emisor.RegimenFiscal v.3.3 ByVigar.
*!* *   Datos de un regimen fiscal
*!* *
*!* DEFINE CLASS CFDRegimenFiscal AS Custom
*!* *
*!* RegimenFiscal = ""
*!* *
*!* ENDDEFINE


*!* *-- CFDRegimenFiscalCollection (Clase) && Se sustituye por Emisor.RegimenFiscal v.3.3 ByVigar.
*!* *   Lista de regimenes fiscales de una persona
*!* *
*!* DEFINE CLASS CFDRegimenFiscalCollection AS CFDCollection
*!* *
*!* RegimenFiscal = ""   && Regimen por omision
*!*  
*!* *-- Regimen (Setter)
*!* PROCEDURE Regimen_Assign(vNewVal)
*!*   IF THIS.Count = 0
*!*    THIS.Add(m.vNewVal)
*!*   ENDIF
*!* ENDPROC
*!*  
*!* *-- Regimen (Getter)
*!* PROCEDURE Regimen_Access
*!*   IF THIS.Count > 0
*!*    RETURN THIS.Items[1].Regimen
*!*   ELSE
*!*    RETURN ""
*!*   ENDIF
*!* ENDPROC
 
 
*!* *-- Add (Metodo)
*!* *   Incluye un nuevo elemento en la coleccion
*!* PROCEDURE Add(pcRegimen)
*!*   *
*!*   LOCAL oItem
*!*   oItem = CREATEOBJECT("CFDRegimenFiscal")
*!*   WITH oItem
*!*    .RegimenFiscal = pcRegimen
*!*   ENDWITH
*!*   
*!*   RETURN DODEFAULT(oItem)
*!*   *
*!* ENDPROC
*!*  
*!* *
*!* ENDDEFINE



*-- CFDPersona (Clase)
*   Representa los datos de una persona juridica especifica
*   dentro de un comprobante digital
*
DEFINE CLASS CFDPersona AS Custom
 *
 *-- Atributos requeridos
 Rfc = ""
 RegimenFiscal = ""
 UsoCfdi = ""
&& Se sustituye por Emisor.RegimenFiscal v.3.3 ByVigar.
* RegimenFiscal = NULL && ARC Dic 20, 2011: Requerido solo para Emisor
 
 *-- Atributos opcionales
 expedidoEn = NULL
 Nombre = ""
 domicilioFiscal = NULL
 
 *-- Contructor de la clase
 PROCEDURE Init
  THIS.domicilioFiscal = CREATEOBJECT("CFDDireccion")
  THIS.ExpedidoEn = CREATEOBJECT("CFDDireccion")  
  && Se sustituye por Emisor.RegimenFiscal v.3.3 ByVigar.
  *THIS.RegimenFiscal = CREATEOBJECT("CFDRegimenFiscalCollection")
 ENDPROC
 *
ENDDEFINE



*-- CFDDireccion (Clase)
*   Representa una direccion fiscal dentro de un
*   comprobante digital
*
DEFINE CLASS CFDDireccion AS Custom
 *
 *-- Atributos requeridos
 Calle = ""
 Municipio = ""
 Estado = ""
 Pais = ""
 codigoPostal = ""

 *-- Atributos opcionales 
 noExterior = ""
 noInterior = ""
 Colonia = ""
 Localidad = ""
 Referencia = ""
 *
ENDDEFINE





DEFINE CLASS CfdiRelacionados AS CFDCollection
 *
 *-- Add (Metodo)
 *   Incluye un nuevo elemento en la coleccion. && Incluyo 2 Nuevos elementos en la colección ByVigar.
 *
 PROCEDURE Add(pcUUID)
  *
  LOCAL oCfdiRelacionado
  oCfdiRelacionado = CREATEOBJECT("CfdiRelacionado")
  WITH oCfdiRelacionado
   .UUID = pcUUID && Nuevo Obligatorio v.3.3 ByVigar.
  ENDWITH
  
  RETURN DODEFAULT(oCfdiRelacionado)
  *
 ENDPROC
 *
ENDDEFINE
 
*-- CfdiRelacionado (Clase)
*   Representa una linea UUID'S Relacionados de un comprobante digital.
*
DEFINE CLASS CfdiRelacionado AS Custom
 *
 *-- Atributos requeridos
 UUID = ""
ENDDEFINE





*-- CFDConceptos (Clase)
*   Representa la lista de conceptos contenidos en el comprobante
*
DEFINE CLASS CFDConceptos AS CFDCollection
 *
 *-- Add (Metodo)
 *   Incluye un nuevo elemento en la coleccion. && Incluyo 2 Nuevos elementos en la colección ByVigar.
 *
 PROCEDURE Add(pcClaveProdServ, pcNoIdentificacion, pnCantidad, pcClaveUnidad, pcUnidad, pcDescripcion, pnPU, pnImporte, pnDescuento, PnBase, pcImpuesto, pcTipoFactor, pnTasaOCuota, pnIimporte)
  *
  LOCAL oConcepto
  oConcepto = CREATEOBJECT("CFDConcepto")
  WITH oConcepto
   .ClaveProdServ = pcClaveProdServ && Nuevo Obligatorio v.3.3 ByVigar.
   .NoIdentificacion = pcNoIdentificacion && Nuevo Opcional v.3.3 ByVigar.
   .Cantidad = pnCantidad
   .ClaveUnidad = pcClaveUnidad && Nuevo Obligatorio v.3.3 ByVigar.
   .Unidad = pcUnidad
   .Descripcion = pcDescripcion
   .ValorUnitario = pnPU
   .Importe = pnImporte
   .Base = pnBase
   .Impuesto = pcImpuesto
   .TipoFactor = pcTipoFactor
   .TasaOCuota = pnTasaOCuota
   .Iimporte = pnIimporte
   pnDescuento = 0
   IF pnDescuento <> 0
   .Descuento = pnDescuento && Nuevo Obligatorio v.3.3 ByVigar.
   ENDIF
   
  ENDWITH
  
  
  
  RETURN DODEFAULT(oConcepto)
  *
 ENDPROC
 *
ENDDEFINE



*-- CFDConcepto (Clase)
*   Representa una linea de la factura dentro de un comprobante digital
*
DEFINE CLASS CFDConcepto AS Custom
 *
 *-- Atributos requeridos
  ClaveProdServ = ''
 NoIdentificacion = ''
 Cantidad = 0.00
 ClaveUnidad = ''
 Unidad = ""
 Descripcion = ""
 ValorUnitario = 0.00
 Importe = 0.00
 Descuento = 0.00
 Base = 0.00
 Impuesto = ''
 TipoFactor = ''
 TasaOCuota = 0.00
 Iimporte = 0.00
  
 *-- Atributos opcionales
 Impuestos = NULL
 informacionAduanera = NULL
 cuentaPredial = NULL
 Complemento = NULL   && VES Ene 12, 2012

 *-- Constructor de la clase
 PROCEDURE Init
  THIS.Impuestos = CREATEOBJECT("CFDComplementoImpuestos") 
  THIS.InformacionAduanera = CREATEOBJECT("CFDInformacionAduanera")
  THIS.CuentaPredial = CREATEOBJECT("CFDCuentaPredial")
  THIS.Complemento = NULL  && VES Ene 12, 2012
 ENDPROC 
 *
ENDDEFINE




LAN7008173R5_CFDI_A25965_20171227.xml

Héctor Bernal

unread,
Dec 27, 2017, 4:21:13 PM12/27/17
to vfp-factura-ele...@googlegroups.com
Buenas tardes, Pedro.

Le di una pasada en validador.finkok.com y me aparece el siguiente mensaje: El XML no está codificado en UTF-8. Habrá que ver tu código, para saber donde esta el problema.



Saludos desde CDMX.


--
Has recibido este mensaje porque estás suscrito al grupo "vfp-factura-electronica-mexico" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mex...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/vfp-factura-electronica-mexico.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--

Saludos.

Héctor Hugo Bernal Díaz.

  |  04455 8530 4061   |   GAM 07040   |   Ciudad de México |

Pedro Baez

unread,
Dec 27, 2017, 5:06:18 PM12/27/17
to vfp-factura-electronica-mexico
Hola Héctor, 

gracias, puedo compartir mi código para ver si encontramos el detalle, investigará la parte donde está la codificación a UTF-8.

Saludosl
...

Pedro Baez

unread,
Dec 27, 2017, 5:51:51 PM12/27/17
to vfp-factura-electronica-mexico
Hola, 

Adjunto los códigos.

Gracias!


On Wednesday, December 27, 2017 at 3:21:13 PM UTC-6, Héctor Bernal wrote:
...
Parte 1.txt
Parte 2.txt

Victor López (Montand)

unread,
Dec 27, 2017, 6:02:35 PM12/27/17
to vfp-factura-electronica-mexico
Que tal Pedro

Estoy también modificando la rutina del grupo para CFDI 3.3, resolví el probleman del error " Error no se pudo obtener la cadena original. Utilice CFDProbarOpenSSL para verificar el funcionaiento de la libreria OpenSSL"

Lo que tienes que hacer es:
  1. copiar o renombrar el archivo "cadenaoriginal_3_3.xslt" por "cadenaoriginal_3_3_local.xslt"
  2. Editar dicho archivo y cambiar la referencia a las rutas que marca, el archivo original contiene: <xsl:include href="./utilerias.xslt"/>, cámbialo a <xsl:include href="<ssl-path>/utilerias.xslt"/>
  3. Para esto también deberás copiar los 3 archivos .xslt a la carpeta donde tienes el archivo OpenSSL.exe
Yo ahora tengo el problema de error en el sello, me manda el error:

ERROR: El sello no es valido para este certificado


Si alguien tiene alguna idea para solucionarlo se los agradezco



Saludos y hasta que quede !!
...

Pedro Baez

unread,
Dec 28, 2017, 12:27:35 AM12/28/17
to vfp-factura-electronica-mexico
Hola Víctor,

Gracias por la información, efectivamente hacía falta hacer ese cambio en el archivo y copiarlo como local, ya hice los pasos que mencionas y grabé los archivos en la carpeta en la que tengo la librería OpenSSL, y el problema persiste será que falta información? Ahora no logró crear el archivo XML :-( 
seguiré probando para ver que logró identificar, si ves que algo me hace falta me ayudarías mucho!
Y hasta que quedé ...
...

Victor Lopez

unread,
Dec 28, 2017, 11:40:41 AM12/28/17
to vfp-factura-ele...@googlegroups.com
Que tal Pedro

Te doy otro tip que a mi me funcionó

Dentro del código de la clase hay una parte donde se valida que el XML cumpla con los estándares del CFD/CFDI
Ahí hay una condición que dice que si existen los archivos CFDVALIDATOR.EXE y Interop.MSXML2.dll los utilizar para hacer la validación, pero estos archivos (al menos los que yo tengo) son los que tenía desde CFDI 3.2, por lo tanto supongo que no va a validar correctamente

Lo que hice fue solo renombrar los archivos para que no los tome y valide con la segunda opción
que lo toma utilizando: oXmlSchema = CREATEOBJECT("MSXML2.XMLSchemaCache.6.0")

Así pude generar sin errores el XML inicial

Me sigue mandando error al intentar timbrar con Finkok, pongo el error:


Imágenes integradas 1

Esto lo manda en ciertas lineas nuevas que no tenía para timbrar CFDI 3.2 (el código lo saqué de la página de Finkok donde dan el código para hacer el timbrado)

* --- Si el status es diferente a 200, ocurrió algún error de conectividad con el WS ---
IF oHTTP.STATUS = 200
objXMLReceive = oHTTP.responseXML
objXMLReceive.save(pXMLResponse)                               && En esta linea manda el error


Espero te sirva y ojala alguien pueda ayudarnos a terminar esto, aunque creo que están descanzando o siguen de fiesta, jeje


Saludos y hasta que quede !!

--
Has recibido este mensaje porque estás suscrito al grupo "vfp-factura-electronica-mexico" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mex...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/vfp-factura-electronica-mexico.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--

______________________
Victor Gerardo López
Director de desarrollo
POSMEX, Guadalajara
33 3359 9565

Héctor Bernal

unread,
Dec 28, 2017, 10:03:36 PM12/28/17
to vfp-factura-ele...@googlegroups.com
Victor.

Buenas noches. Sobre el error con MSXML2, alguna vez tuve ese problema y solamente tuve que descargar Net Framework 2.0 y luego la ver. 4, con lo que se resolvió el problema.

También, asegurate que las url de Finkok, sean como las que muestro abajo, pues tuve problemas parecidos a los que estas reportando.


 
Ojo son https, pues si tienes http, genera error.


Espero te sea de ayuda.



Saludos desde CDMX.

Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsub...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mexico@googlegroups.com.
--

______________________
Victor Gerardo López
Director de desarrollo
POSMEX, Guadalajara
33 3359 9565

--
Has recibido este mensaje porque estás suscrito al grupo "vfp-factura-electronica-mexico" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mex...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/vfp-factura-electronica-mexico.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--

Héctor Bernal

unread,
Dec 28, 2017, 10:17:17 PM12/28/17
to vfp-factura-ele...@googlegroups.com
Buenas noches, Pedro.

Busca el post de Vinicio García, donde aparece el código de la clase, actualizado para 3.3, el cual te será de gran ayuda para resolver los problemas que se te estan presentando.



Saludos.


El 27 de diciembre de 2017, 23:27, Pedro Baez<ing...@gmail.com> escribió:

--
Has recibido este mensaje porque estás suscrito al grupo "vfp-factura-electronica-mexico" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mex...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/vfp-factura-electronica-mexico.
Para acceder a más opciones, visita https://groups.google.com/d/optout.

Héctor Bernal

unread,
Dec 28, 2017, 10:20:27 PM12/28/17
to vfp-factura-ele...@googlegroups.com
Pedro,

El compañero Rodolfo Ortíz, publicó la forma en que se genera el código QR, por lo que te sugiero lo busques en el foro, pues ha cambiado en la versión 3.3.



Saludos.


El 28 de diciembre de 2017, 10:40, Victor Lopez<victo...@gmail.com> escribió:
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsub...@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mexico@googlegroups.com.
--

______________________
Victor Gerardo López
Director de desarrollo
POSMEX, Guadalajara
33 3359 9565

--
Has recibido este mensaje porque estás suscrito al grupo "vfp-factura-electronica-mexico" de Grupos de Google.
Para cancelar la suscripción a este grupo y dejar de recibir sus mensajes, envía un correo electrónico a vfp-factura-electronica-mexico+unsubscribe@googlegroups.com.
Para publicar en este grupo, envía un correo electrónico a vfp-factura-electronica-mex...@googlegroups.com.
Visita este grupo en https://groups.google.com/group/vfp-factura-electronica-mexico.
Para acceder a más opciones, visita https://groups.google.com/d/optout.



--

Victor López (Montand)

unread,
Dec 30, 2017, 1:06:13 PM12/30/17
to vfp-factura-electronica-mexico
Que tal Hector

Gracias por tu recomendación, en realidad ya tengo el código funcionando sin problemas para timbrar, he tenido que hacer varios cambios a la clase.
Aún sigo modificando mi sistema para Cancelación y voy a entrar apenas a probar cuando se trata de método de pago PPD, o sea lo que se vende a crédito.

Espero en cuanto termine los cambios retroalimentar la clase al foro


Gracias y feliz año 2018 a todos !!
...
Reply all
Reply to author
Forward
0 new messages