FiveTech Support Forums

FiveWin / Harbour / xBase community
Board index FiveWin para Harbour/xHarbour Fuentes Factura electr贸nica Argentina
Posts: 1364
Joined: Wed Jun 21, 2006 12:39 AM
Fuentes Factura electr贸nica Argentina
Posted: Sun Jun 28, 2015 11:28 PM
Colegas, posteo las fuentes para la generaci贸n de FE en argentina totalmente operativas. Este trabajo fue desarrollado por Carlos A. Fernandez Cardeneu que, generosamente las public贸 en foro de Google sobre este tema. Solo se puede compilar con Harbour ya que utiliza funciones que no tienen equivalencia en xHarbour ( Creo ). Se pueden emitir facturas A y B y con peque帽os cambios tambi茅n C. Lo interesante es que tenemos c贸digo nativo, sin necesidad de usar aplicaciones de terceros y es un buen ejercicio para aquellos que necesiten entender como funciona el consumo de servicios WebService.
Code (fw): Select all Collapse
Static cToken 聽 聽
Static cSign 聽 聽 
Static cCuit 聽 聽 
Static nUltCmpAut

//----------------------------------------------------------------------------//
Function Main()

聽 聽 * Declaro Las Variables De Trabajo
聽 聽 Local nOpc := 1
聽 聽 * Declaro estas Variables como privadas para poder usarlas en todas las funciones
聽 聽 cToken 聽 聽 := ''
聽 聽 cSign 聽 聽 聽:= ''
聽 聽 cCuit 聽 聽 聽:= '20267565393' // CUIT de la Empresa
聽 聽 nUltCmpAut := 0
聽 聽 //Private CRLF 聽 聽 聽 := chr( 13 ) + chr( 10 ) // Retorno de carro y avance de linea

聽 聽 * Leo los valores del Ultimo Ticket De Acceso -> cSign
聽 聽 Leo_Ultimo_Ticket_de_Acceso()
聽 聽 Cls
聽 聽 nOpc := 1
聽 聽 While( nOpc # 0 )
聽 聽 聽 聽 @ 04, 18 Prompt Padr( '1) Consultar el Estado de los Servidores', 44, ' ' )
聽聽 聽聽 聽 @ 06, 18 Prompt Padr( '2) Pedir el Ticket de Acceso', 44, ' ' )
聽聽 聽聽 聽 @ 08, 18 Prompt Padr( '3) Consultar el Nro de la Ultima FACTURA', 44, ' ' )
聽聽 聽聽 聽 @ 10, 18 Prompt Padr( '4) Pedir el CAE de una FACTURA', 44, ' ' )
聽聽 聽聽 聽 Menu to nOpc
聽 聽 聽 聽 聽If( nOpc == 1 )
聽 聽 聽 聽 聽 聽 Opc_FEDummy()
聽聽 聽聽 聽 ElseIf( nOpc == 2 )
聽 聽 聽 聽 聽 聽 Opc_PidoElTicketDeAcceso()
聽聽 聽聽 聽 ElseIf( nOpc == 3 )
聽 聽 聽 聽 聽 聽 Opc_FECompUltimoAutorizado( cToken, cSign, cCUIT )
聽聽 聽聽 聽 ElseIf( nOpc == 4 )
聽 聽 聽 聽 聽 聽 Opc_FECAESolicitar( cToken, cSign, cCUIT )
聽聽 聽聽 聽 End
聽 聽 Enddo
聽 聽 Return( .t. )

//----------------------------------------------------------------------------//
*: Leo_Ultimo_Ticket_de_Acceso 聽 聽 聽 聽 聽:
*: Leo El Ultimo Ticket De Acceso Para Leer El Token Y El Sign Y Validar Si :
*: Esta Dentro De Las 12 Horas De Que Fue Emitido. 聽 聽 聽 :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
聽 聽 Function Leo_Ultimo_Ticket_de_Acceso()

聽 聽 Local nIdx 聽聽 聽 聽 聽 聽 聽 聽:= 0
聽 聽 Local cXml 聽 聽 聽 聽 聽 聽:= ''
聽 聽 Local aRespuesta 聽 聽 聽:= {}
聽 聽 Local cFechaHoraDesde := ''
聽 聽 Local cFechaHoraHasta := ''
聽 聽 聽 聽 
聽 聽 * Si NO existe el archivo TA.xml es porque NO tengo un Ticket de Acceso (TA) 
聽 聽 * Dejo las variables vacias con lo cual obligo a pedir el TA desde el menu ==
聽 聽 If( !File( 'TA.xml' ) )
聽聽 聽聽 聽 MsgStop( 'NO existe TA.xml;Pida un Nuevo TICKET DE ACCESO' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 End
聽 聽 cXml 聽 聽 聽 := MemoRead( 'TA.xml' )
聽 聽 aRespuesta := Opc_LeeRespuesta( cXml, 'TA' )
聽 聽 If( !Empty( aRespuesta ) )
聽聽 聽聽 聽 nIdx := Ascan( aRespuesta, { | aAux | aAux[ 1 ] = 'token' } )
聽聽 聽聽 聽 If( nIdx # 0 )
聽 聽 聽 聽 聽 聽 cToken := aRespuesta[ nIdx, 2 ]
聽聽 聽聽 聽 End
聽聽 聽聽 聽 nIdx := Ascan( aRespuesta, { | aAux | aAux[ 1 ] = 'sign' } )
聽 聽 聽 聽 If( nIdx # 0 )
聽 聽 聽 聽 聽 聽 cSign := aRespuesta[ nIdx, 2 ]
聽聽 聽聽 聽 End
聽 聽 End
聽 聽 * Valido que TA todavia sea VALIDO 
聽 聽 nIdx := Ascan( aRespuesta, { | aAux | aAux[ 1 ] = 'generationtime' } )
聽 聽 If( nIdx # 0 )
聽聽 聽聽 聽 cFechaHoraDesde := CToD( aRespuesta[ nIdx, 2 ] )
聽 聽 End
聽 聽 nIdx := Ascan( aRespuesta, { | aAux | aAux[ 1 ] = 'expirationtime' } )
聽 聽 If( nIdx # 0 )
聽聽 聽聽 聽 cFechaHoraHasta := aRespuesta[ nIdx, 2 ]
聽 聽 End
聽 聽 Return( .t. )

//-----------------------------------------------------------------------------//
*: LlamoAlWSAA Llamo al WS de AUTENTICACION para pedir el Ticket de Acceso :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function LlamoAlWSAA( c_CMS_Base64 )

聽 聽 Local cXml 聽 聽 聽 := ''
聽 聽 Local oWSAA 聽 聽 聽:= ''
聽 聽 Local cWSAA_URL 聽:= 'https://wsaahomo.afip.gov.ar/ws/services/LoginCms'
聽 聽 Local cRespuesta := ''

聽 聽 oWSAA 聽:= Win_OleCreateObject( 'MSXML2.XMLHTTP' )
聽 聽 If( Empty( oWSAA ) )
聽聽 聽聽 聽 MsgStop( 'NO se Pudo Crear el Objeto oWSAA;se Cancela el Programa' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 End
聽 聽 * Armo el XML con el TRA
聽 聽 cXml += '<?xml version="1.0" encoding="UTF-8"?>' 聽 聽+ CRLF
聽 聽 cXml += '<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' + CRLF
聽 聽 cXml += '<soap:Body>' 聽 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽<loginCms xmlns="http://wsaa.view.sua.dvadac.desein.afip.gov">' + CRLF
聽 聽 cXml += ' 聽 聽<in0>' + c_CMS_Base64 + '</in0>' 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽</loginCms>' 聽 聽 聽 + CRLF
聽 聽 cXml += '</soap:Body>' 聽 聽 聽 + CRLF
聽 聽 cXml += '</soap:Envelope>' 聽 聽 聽 + CRLF
聽 聽 * Llamo al Webservice y defino Opciones
聽 聽 oWSAA : Open( 'POST', cWSAA_URL, .f. )
聽 聽 oWSAA : SetRequestHeader( "SOAPAction:", "None" )
聽 聽 oWSAA : SetRequestHeader( "Content-Type", "text/xml;charset=UTF-8" )
聽 聽 * Envio el Archivo y Recibo la Respuesta del WS
聽 聽 oWSAA : Send( cXml )

聽 聽 * Si el status es diferente a 200, ocurri垄 alg拢n error de conectividad con el WS ---
聽聽 聽cRespuesta := oWSAA : ResponseText
聽 聽 if( Empty( cRespuesta ) )
聽聽 聽聽 聽 MsgStop( "Error; cRespuesta esta VACIO" )
聽 聽 End
聽 聽 * Por las Dudas de que la Respuesta venga en Formato RAW
聽 聽 If( !Empty( cRespuesta ) )
聽聽 聽聽 聽 If( '<' $ cRespuesta ) // <
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '<', '<' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '>' $ cRespuesta ) // >
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '>', '>' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&quot;' $ cRespuesta ) // "
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&quot;', '"' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&apos;' $ cRespuesta ) // \
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&apos;', '\' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&amp;' $ cRespuesta ) // &
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&amp;', '&' )
聽聽 聽聽 聽 End
聽 聽 End
聽 聽 * Hago mas legible el XML
聽 聽 cRespuesta := StrTran( cRespuesta, '><', '>' + CRLF + '<' )
聽 聽 * Dicen que si no se borra el Objeto, despues de un tiempo se incrementa mucho
聽 聽 * el uso de memoria por parte del programa. No lo constate, pero por las dudas
聽 聽 oWSAA 聽:= NIL
聽 聽 Release oWSAA
聽 聽 Return( cRespuesta )

//----------------------------------------------------------------------------//
*: LlamoAlWSFE Llamo al WS de Negocios para Procesar el Requerimiento 聽 聽 :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function LlamoAlWSFE( c_Xml, c_ServicioLlamado )

聽 聽 Local oWSFE 聽:= ''
聽 聽 Local cWSFE_URL := 'https://wswhomo.afip.gov.ar/wsfev1/service.asmx' // Modo HOMOLOGACION
聽 聽 *Local cWSFE_URL := 'https://servicios1.afip.gov.ar/wsfev1/service.asmx' // Modo PRODUCCION
聽 聽 Local cRespuesta := ''

聽 聽 * Creo y Valido el Objeto oWSFE
聽 聽 oWSFE 聽:= Win_OleCreateObject( 'MSXML2.XMLHTTP' )
聽 聽 If( empty( oWSFE ) )
聽聽 聽聽 聽 MsgStop( 'NO se Pudo Crear el Objeto oWSFE;se Cancela el Programa' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 End

聽 聽 * Llamo al Webservice y Defino Opciones
聽 聽 oWSFE聽 聽: Open( 'POST', cWSFE_URL, .f. )
聽 聽 oWSFE : SetRequestHeader( 'SOAPAction', 'http://ar.gov.afip.dif.FEV1/' + c_ServicioLlamado )
聽 聽 oWSFE : SetRequestHeader( "Content-Type", "text/xml;charset=UTF-8" )
聽 聽 oWSFE : SetRequestHeader( 'Connection', 'Keep-Alive' )

聽 聽 * Envio el Archivo y Recibo la Respuesta del WS
聽 聽 oWSFE聽 聽: Send( c_Xml )

聽 聽 * Si el status es diferente a 200, ocurri垄 alg拢n error de conectividad con el WS
聽 聽 cRespuesta := oWSFE : ResponseText
聽 聽 If( Empty( cRespuesta ) )
聽聽 聽聽 聽 MsgStop( "Error;cRespuesta esta VACIO" )
聽 聽 End

聽 聽 * Por las Dudas de que la Respuesta venga en Formato RAW
聽 聽 If( !Empty( cRespuesta ) )
聽聽 聽聽 聽 If( '<' 聽$ 聽cRespuesta ) // <
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '<', '<' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '>' 聽$ 聽cRespuesta ) // >
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '>', '>' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&quot;' 聽$ 聽cRespuesta ) // "
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&quot;', '"' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&apos;' 聽$ 聽cRespuesta ) // \
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&apos;', '\' )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 If( '&amp;' 聽$ 聽cRespuesta ) // &
聽 聽 聽 聽 聽 聽 cRespuesta := StrTran( cRespuesta, '&amp;', '&' )
聽聽 聽聽 聽 End
聽 聽 End
聽 聽 * Hago mas legible el XML
聽 聽 cRespuesta := StrTran( cRespuesta, '><', '>' + CRLF + '<' )
聽 聽 oWSFE 聽:= NIL
聽 聽 Release oWSFE
聽 聽 Return( cRespuesta )

//----------------------------------------------------------------------------//
*: Opc_FEDummy Verifica el funcionamiento de los servidores de la afip 聽 聽 :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function Opc_FEDummy()
聽 聽 
聽 聽 Local nHandle
聽 聽 Local cXml 聽 聽 聽 := ''
聽 聽 Local aRespuesta := {}
聽 聽 Local cRespuesta := ''

聽 聽 * Armo El Archivo Xml con el Pedido
聽 聽 cXml += '<?xml version="1.0" encoding="UTF-8"?>' 聽 + CRLF
聽 聽 cXml += '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' + CRLF
聽 聽 cXml += '<soap:Body> ' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 <FEDummy xmlns="http://ar.gov.afip.dif.FEV1/" />' + CRLF
聽 聽 cXml += '</soap:Body>' 聽 聽 聽+ CRLF
聽 聽 cXml += '</soap:Envelope>' 聽 聽 聽+ CRLF
聽 聽 
聽 聽 * Esto NO hace falta, pero lo hago para controlar como se formo el XML
聽 聽 If( ( nHandle := fCreate( 'FEDummy_Req.xml', 0 ) ) == -1 )
聽聽 聽聽 聽 MsgStop( 'NO se pudo crear FEDummy_Req.xml' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 Else
聽 聽 聽聽 聽fWrite( nHandle, cXml )
聽聽 聽聽 聽 fClose( nHandle )
聽 聽 End
聽 聽 * Llamo al WS
聽 聽 cRespuesta := LlamoAlWSFE( cXml, 'FEDummy' )
聽 聽 hb_MemoWrit( 'FEDummy_Res.xml', cRespuesta )
聽 聽 MsgStop( 'FINALIZO la CONSULTA DEL ESTADO;DE LOS SERVIDORES DE LA AFIP;EL PEDIDO SE GRABO COMO: FEDummy_Req; LA RESPUESTA RECIBIDA SE GRABO COMO: FEDummy_Res' )
聽 聽 * Muestro el contenido del Xml Recibido
聽 聽 aRespuesta := Opc_LeeRespuesta( cRespuesta, 'FEDummy' )
聽 聽 MuestroRespuesta( aRespuesta )
聽 聽 Return( .t. )

//----------------------------------------------------------------------------//
*: PidoElTicketDeAcceso Funci垄n para Pedir el Tique de Acceso a los 聽 聽 :
*: 聽 Servidores de la AFIP 聽 聽 聽 聽:
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function Opc_PidoElTicketDeAcceso()

聽 聽 Local cBat
聽 聽 Local nHandle
聽 聽 Local aRespuesta
聽 聽 Local cCert 聽聽 聽聽 聽 聽 聽 聽:= 'c:\pyrece\reingart\reingart.crt' // The X.509 obtained from Seg. Inf. 
聽 聽 Local cPrivateKey 聽 聽:= 'c:\pyrece\reingart\reingart.key' // The private key correspoding to CERT
聽 聽 Local cSource 聽聽聽 聽 聽:= 'C=AR, O=PyAfipWs-Sistemas Agiles, SERIALNUMBER=CUIT 20267565393, CN=Mariano Reingart'
聽 聽 Local cDestinationDn 聽:= 'cn=wsaahomo,o=afip,c=ar,serialNumber=CUIT 33693450239'
聽 聽 Local cUniqueId 聽 聽 聽 聽 聽:= '1432505199' // > VER DE DONDE LO OBTENGO 聽 * NUMERO QUE IDENTIFICA EL REQUERIMIENTO, TIENE QUE SER DISTINTO CADA VEZ
聽 聽 Local cGenerationTime := TimeFMT( HB_DateTime(), -1 ) // - 1Hs
聽 聽 Local cExpirationTime := TimeFMT( HB_DateTime(), 1 ) // + 1Hs
聽 聽 Local cService 聽聽 聽 聽:= 'wsfe' // The WS service name you are asking a TA for ( "wdepmovimientos", "wsfe" )
聽 聽 Local cXML 聽聽 聽 聽 聽 聽 聽 聽:= '' 聽// Variable donde Armo el XML
聽 聽 Local cCMS 聽聽 聽 聽 聽 聽 聽 聽:= '' 聽// Variable donde esta el XML y su Firma Electronica
聽 聽 Local cTRA 聽聽 聽 聽 聽 聽 聽 聽:= '' 聽// Ticket de requerimiento de Acceso
聽 聽 Local cCMS_Base64 聽 聽:= '' 聽// Variable donde esta el CMS Codificado en Base64
聽 聽 Local cCmdSign 聽聽 聽 聽:= '' 聽// Comando para llamar a OpenSsl y Generar la Firma del Archivo XML
聽 聽 Local cPathOpenSsl 聽 聽:= 'C:\OpenSsl-Win32\Bin' // Donde Tengo Instalado OpenSsl
聽 聽 Local cRespuesta 聽 聽 聽:= ''

聽 聽 * Armo El Archivo Xml con el mensaje del TRA (LoginTicketRequest.xml)
聽 聽 cXml += '<?xml version="1.0" encoding="UTF-8"?>' + CRLF
聽 聽 cXml += '<loginTicketRequest version="1.0">' + CRLF
聽 聽 cXml += ' 聽<header>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽<source>' + cSource + '</source>' + CRLF
聽 聽 cXml += ' 聽 聽<destination>' + cDestinationDn + '</destination>' + CRLF
聽 聽 cXml += ' 聽 聽<uniqueId>' + cUniqueId + '</uniqueId>' + CRLF
聽 聽 cXml += ' 聽 聽<generationTime>' + cGenerationTime + '</generationTime>' + CRLF
聽 聽 cXml += ' 聽 聽<expirationTime>' + cExpirationTime + '</expirationTime>' + CRLF
聽 聽 cXml += ' 聽</header>' + CRLF
聽 聽 cXml += ' 聽<service>' + cService + '</service>' + CRLF
聽 聽 cXml += '</loginTicketRequest>' + CRLF
聽 聽 * Grabo el Archivo XML con el Nombre TRA.xml
聽 聽 If( ( nHandle := fcreate( 'TRA.xml', 0 ) ) == -1 )
聽聽 聽聽 聽 MsgStop( 'NO se pudo crear TRA.xml' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 Else
聽聽 聽fWrite( nHandle, cXml )
聽聽 聽fClose( nHandle )
聽 聽 End

聽 聽 * Genero la Firma Electronica de TRA.xml en el Archivo TRA.tmp 
聽 聽 * Creo un Archivo BAT, con los comandos para llamar a OpenSsl y lo ejecuto.
聽 聽 * Preferiria Hacer Lo Siguiente Usando Funciones De Harbour. 
聽 聽 * SI Bien Harbour Tiene La Libreria Hbssl Que Creo Que Sirve Para Firmar El 
聽 聽 * Archivo Como Lo Pide La Afip, No Tengo Conocimientos De Encriptacion Y No
聽 聽 * Se Cual De Sus Funciones Usar.
聽 聽 * Ademas, Tube Muchos Problemas Para Crear La Libreria Y No Quedo Funcional.
聽 聽 * Por Lo Tanto, Si OpenSsl Funciona, No Pierdo Mas Tiempo Y Lo Uso.
聽 聽 * SI Alguien Se Anima A Cambiarlo Por Funciones Propias De Harbour, Bienvenido
聽 聽 * Al Barco :-)
聽 聽 * Otro Pedido, Usando Otros Lenguajes, Vi Que La Salida De Openssl, Se Puede
聽 聽 * Enviar A Pantalla Y De Ahi Tomar Esa Respuesta En Una Variable.
聽 聽 * DE Poder Hacerse Eso En Harbour, SE Evita La Grabacion Y Posterior Lectura
聽 聽 * Del Archivo Tra.tmp

聽 聽 cCmdSign := 'openssl smime' +;
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -sign' +;
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -in ' + 'TRA.xml' +; 聽 聽 聽 // Archivo XML a Firmar
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -out ' + 'TRA.tmp' +; 聽 聽 聽// Archivo con la Firma
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -signer ' + cCert +; 聽 聽 聽 // 
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -inkey ' + cPrivateKey + ; // 
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -outform ' + 'DER' 聽+; 聽 聽 // Lo Graba en Binario ('PEM' lo graba como numeros con 4 lineas de titulos)
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 ' -nodetach' 聽 聽 聽 聽 聽 聽 聽 聽 // NO se Incluye el Archivo Original en la Salida
聽 聽 cBat := ''
聽 聽 cBat += 'path ' + cPathOpenSsl + CRLF
聽 聽 cBat += cCmdSign 聽 + CRLF
聽 聽 MemoWrit( 'FirmoXML.bat', cBat )

聽 聽 * Ejecuto el BAT para Generar TRA.tmp con la Firma 
聽 聽 HB_run( 'FirmoXML.bat' ) 聽 聽 聽// HB_run() -> Funci垄n de Harbour para llamar progrmas externos
聽 聽 cCMS := MemoRead( 'TRA.tmp' ) // Leo el Archivo Firmado 

聽 聽 * Codifico en base64
聽 聽 cCMS_Base64 := hb_base64Encode( cCMS ) // Funci垄n de Harbour

聽 聽 * Llamo al WS de Autenticaci垄n (WSAA)
聽 聽 cRespuesta := LlamoAlWSAA( cCMS_Base64 )
聽 聽 MemoWrit( 'TA.xml', cRespuesta )
聽 聽 MsgStop( 'FINALIZO EL PEDIDO DEL TICKET DE ACCESO;EL PEDIDO SE GRABO COMO: TRA.xml;LA RESPUESTA RECIBIDA SE GRABO COMO: TA.xml' )
聽 聽 * Muestro el contenido del XML RECIBIDO
聽 聽 aRespuesta := Opc_LeeRespuesta( cRespuesta, 'TA' )
聽 聽 MuestroRespuesta( aRespuesta )
聽 聽 Return( .t. )

//----------------------------------------------------------------------------//
*: Opc_FECompUltimoAutorizado 聽 
*: Consulto el Nro. de la ULTIMA FACTURA AUTORIZADA 
*: Estado: OK (funcionando) 
//----------------------------------------------------------------------------//
Function Opc_FECompUltimoAutorizado( c_Token, c_Sign, c_CUIT )

聽 聽 Local nIdx
聽 聽 Local nHandle
聽 聽 Local cRespuesta
聽 聽 Local aRespuesta
聽 聽 Local cXml 聽:= ''
聽 聽 Local cPtoVta 聽:= Alltrim( Str( 0001 ) ) // Punto de Venta
聽 聽 Local cCbteTipo := Alltrim( Str( 001 ) ) // 1=FACTURA

聽 聽 If( Empty( cToken ) .or. Empty( cSign ) )
聽聽 聽聽 聽 MsgStop( 'Antes de usar esta opci垄n;Pida un Nuevo TICKET DE ACCESO' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 End

聽 聽 * Armo El Archivo XML con el Pedido
聽 聽 cXml += '<?xml version="1.0" encoding="UTF-8"?>' 聽 + CRLF
聽 聽 cXml += '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' + CRLF
聽 聽 cXml += '<soap:Body> ' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 <FECompUltimoAutorizado xmlns="http://ar.gov.afip.dif.FEV1/">' + CRLF
聽 聽 cXml += ' 聽 聽 聽<Auth>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Token>' + c_Token + '</Token>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Sign>' + c_Sign + '</Sign>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Cuit>' + c_Cuit + '</Cuit>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽</Auth>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽<PtoVta>' + cPtoVta + '</PtoVta>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽<CbteTipo>' + cCbteTipo + '</CbteTipo>' 聽+ CRLF
聽 聽 cXml += ' 聽 </FECompUltimoAutorizado>' 聽 聽+ CRLF
聽 聽 cXml += '</soap:Body>' 聽 聽 聽+ CRLF
聽 聽 cXml += '</soap:Envelope>' 聽 聽 聽+ CRLF
聽 聽 
聽 聽 * Esto NO hace falta, pero lo hago para controlar como se formo el XML
聽 聽 If( ( nHandle := fCreate( 'FECompUltimoAutorizado_Req.xml', 0 ) ) == -1 )
聽聽 聽聽 聽 MsgStop( 'NO se pudo crear FECompUltimoAutorizado_Req.xml' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 Else
聽聽 聽聽 聽 fWrite( nHandle, cXml )
聽聽 聽聽 聽 fClose( nHandle )
聽 聽 End

聽 聽 * Llamo al WS
聽 聽 cRespuesta := LlamoAlWSFE( cXml, 'FECompUltimoAutorizado' )
聽 聽 MemoWrit( 'FECompUltimoAutorizado_Res.xml', cRespuesta )
聽 聽 MsgStop( 'FINALIZO la CONSULTA DEL ULTIMO;NUMERO DE FACTURA AUTORIZADO;EL PEDIDO SE GRABO COMO: FECompUltimoAutorizado_Req; LA RESPUESTA RECIBIDA SE GRABO COMO: FECompUltimoAutorizado_Res' )
聽 聽 
聽 聽 * Muestro el contenido del XML RECIBIDO
聽 聽 aRespuesta := Opc_LeeRespuesta( cRespuesta, 'FECompUltimoAutorizado' )
聽 聽 MuestroRespuesta( aRespuesta )

聽 聽 * Actualizo el Numero del Ultimo Comprobante Autorizado
聽 聽 nIdx := AScan( aRespuesta, { |aAux| aAux[ 1 ] = 'CbteNro' } )
聽 聽 If( nIdx <> 0 )
聽 聽 聽聽 聽nUltCmpAut := val( aRespuesta[ nIdx, 2 ] )
聽 聽 End
聽 聽 Return( .t. )

//----------------------------------------------------------------------------//
*: Opc_FECAESolicitar Pido la CAE para una FACTURA 聽 聽 聽 :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function Opc_FECAESolicitar( c_Token, c_Sign, c_CUIT )

聽 聽 Local cXml 聽:= ''
聽 聽 Local nhandle
聽 聽 Local cRespuesta
聽 聽 Local aRespuesta
聽 聽 * Estas Variables tienen que Salir del Sistema de Gesti垄n.
聽 聽 * Aca las pongo como valores fijos para probar el WS.
聽 聽 Local cCantReg 聽 聽 聽:= Str( 0001 ) 聽 // 
聽 聽 Local cPtoVta 聽 聽 聽 := Alltrim( Str( 0001 ) ) // Punto de Venta
聽 聽 Local cCbteTipo 聽 聽 := Alltrim( Str( 001 ) ) // 1=FACTURA
聽 聽 Local cConcepto 聽 聽 := Alltrim( Str( 01 ) ) 聽// 1=
聽 聽 Local cDocTipo 聽 聽 聽:= Alltrim( Str( 80 ) ) 聽// 80=CUIT
聽 聽 Local cDocNro 聽 聽 聽 := '30651704657' 聽 聽 聽 聽 聽 聽 聽 聽// CUIT del Comprador
聽 聽 Local cCbteDesde 聽 聽:= Alltrim( Str( 4794 + 1 ) ) // Nro de la 1er. 聽Factura a Autorizar
聽 聽 Local cCbteHasta 聽 聽:= Alltrim( Str( 4794 + 1 ) ) // Nro de la Ultima Factura a Autorizar
聽 聽 Local cCbteFch 聽 聽 聽:= DToS( date() ) 聽聽聽 聽 聽 聽 聽 聽 聽 // Fecha de la Factura
聽 聽 Local cImpTotal 聽 聽 := Alltrim( Str( 14.93 ) ) 聽 聽 // Importe Total de la Factura
聽 聽 Local cImpTotConc 聽 := Alltrim( Str( 0 ) ) 聽 聽 聽 // Neto NO Gravado
聽 聽 Local cImpNeto 聽 聽 聽:= Alltrim( Str( 12.34 ) ) 聽 聽 聽// Importe Neto (Sin Iva)
聽 聽 Local cImpOpEx 聽 聽 聽:= Alltrim( Str( 0 ) ) 聽 聽 聽 聽 聽// Importe Exento
聽 聽 Local cImpTrib 聽 聽 聽:= Alltrim( Str( 0 ) ) 聽 聽 聽 聽 聽// Suma de los importes del array de tributos
聽 聽 Local cImpIVA 聽 聽 聽 := Alltrim( Str( 2.59 ) ) 聽 聽 聽 聽 // 
聽 聽 Local cFchServDesde := '' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽// Cuando cConcepto = 2 o 3
聽 聽 Local cFchServHasta := '' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽// Cuando cConcepto = 2 o 3
聽 聽 Local cFchVtoPago 聽 := '' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽// Cuando cConcepto = 2 o 3
聽 聽 Local cMonId 聽 聽 聽 聽:= 'PES' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 // C垄digo de Moneda (sale de consultar el WS Respectivo)
聽 聽 Local cMonCotiz 聽 聽 := Alltrim( Str( 1 ) ) 聽 聽 聽 聽 // Cotizaci垄n de la Moneda. Para cMonId='PES' es 1.
聽 聽 * Es un array que se repite tantas veces como tasas de iva haya en la factura
聽 聽 Local cId 聽 聽 聽:= Alltrim( Str( 5 ) ) 聽// 21% de IVA
聽 聽 Local cBaseImp := Alltrim( Str( 12.34 ) ) // Base Imponible
聽 聽 Local cImporte := Alltrim( Str( 2.59 ) ) // Importe de Iva
聽 聽 
聽 聽 If( empty( cToken ) 聽.or. 聽empty( cSign ) )
聽聽 聽聽 聽 MsgStop( 'Antes de usar esta opci垄n;Pida un Nuevo TICKET DE ACCESO' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 End
聽 聽 * ARMO EL ARCHIVO XML con el Pedido de CAE
聽 聽 cXml += '<?xml version="1.0" encoding="UTF-8"?>' 聽 + CRLF
聽 聽 cXml += '<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">' + CRLF
聽 聽 cXml += '<soap:Header/>' 聽 聽 聽+ CRLF
聽 聽 cXml += '<soap:Body>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 <FECAESolicitar xmlns="http://ar.gov.afip.dif.FEV1/">' + CRLF
聽 聽 cXml += ' 聽 聽 聽<Auth>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Token>' + c_Token + '</Token>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Sign>' + c_Sign + '</Sign>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <Cuit>' + c_Cuit + '</Cuit>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽</Auth>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽<FeCAEReq>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <FeCabReq>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽<CantReg>' + cCantReg + '</CantReg>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽<PtoVta>' + cPtoVta + '</PtoVta>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽<CbteTipo>' + cCbteTipo + '</CbteTipo>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 </FeCabReq>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 <FeDetReq>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽<FECAEDetRequest>' 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <Concepto>' + cConcepto + '</Concepto>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <DocTipo>' + cDocTipo + '</DocTipo>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <DocNro>' + cDocNro + '</DocNro>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <CbteDesde>' + cCbteDesde + '</CbteDesde>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <CbteHasta>' + cCbteHasta + '</CbteHasta>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <CbteFch>' + cCbteFch + '</CbteFch>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpTotal>' + cImpTotal + '</ImpTotal>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpTotConc>' + cImpTotConc + '</ImpTotConc>'+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpNeto>' + cImpNeto + '</ImpNeto>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpOpEx>' + cImpOpEx + '</ImpOpEx>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpTrib>' + cImpTrib + '</ImpTrib>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <ImpIVA>' + cImpIVA + '</ImpIVA>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <FchServDesde>' + cFchServDesde + '</FchServDesde>' + CRLF // Cuando cConcepto = 2 o 3
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <FchServHasta>' + cFchServHasta + '</FchServHasta>' + CRLF // Cuando cConcepto = 2 o 3
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <FchVtoPago>' + cFchVtoPago + '</FchVtoPago>' + CRLF // Cuando cConcepto = 2 o 3
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <MonId>' + cMonId + '</MonId>' 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <MonCotiz>' + cMonCotiz + '</MonCotiz>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 <Iva>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 聽 聽<AlicIva>' 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 <Id>' + cId + '</Id>' 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 聽 聽<BaseImp>' + cBaseImp + '</BaseImp>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 <Importe>' + cImporte + '</Importe>' + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 聽 聽</AlicIva>' 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽 聽 </Iva>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 聽 聽</FECAEDetRequest>' 聽 聽+ CRLF
聽 聽 cXml += ' 聽 聽 聽 聽 </FeDetReq>' 聽 聽 + CRLF
聽 聽 cXml += ' 聽 聽 聽</FeCAEReq>' 聽 聽 聽+ CRLF
聽 聽 cXml += ' 聽 </FECAESolicitar>' 聽 聽 + CRLF
聽 聽 cXml += '</soap:Body>' 聽 聽 聽+ CRLF
聽 聽 cXml += '</soap:Envelope>' 聽 聽 聽+ CRLF

聽 聽 If( ( nHandle := fCreate( 'FECAESolicitar_Req.xml', 0 ) ) == -1 )
聽聽 聽聽 聽 MsgStop( 'NO se pudo crear FECAESolicitar_Req.xml' )
聽聽 聽聽 聽 Return( .f. )
聽 聽 Else
聽聽 聽聽 聽 fWrite( nHandle, cXml )
聽聽 聽聽 聽 fClose( nHandle )
聽 聽 End

聽 聽 * Llamo al WS
聽 聽 cRespuesta := LlamoAlWSFE( cXml, 'FECAESolicitar' )
聽 聽 MemoWrit( 'FECAESolicitar_Res.xml', cRespuesta )
聽 聽 MsgStop( 'FINALIZO EL PEDIDO DE CAE;EL PEDIDO SE GRABO COMO: FECAESolicitar_Req; LA RESPUESTA RECIBIDA SE GRABO COMO: FECAESolicitar_Res' )

聽 聽 * Muestro el contenido del XML RECIBIDO
聽 聽 aRespuesta := Opc_LeeRespuesta( cRespuesta, 'FECAESolicitar' )
聽 聽 MuestroRespuesta( aRespuesta )
聽 聽 Return( .t. )

//----------------------------------------------------------------------------//
*: Opc_LeeRespuesta Toma el Archivo XML devuelto por la AFIP y muestra 聽:
*: 聽 su contenido. 聽 聽 聽 聽 :
*: 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 聽:
*: Estado: FALTA MEJORARLA MUCHOOOOOO 聽 聽 聽 聽 :
//----------------------------------------------------------------------------//
Function Opc_LeeRespuesta( c_XmlRecibido, c_ServicioLlamado )

聽 聽 Local oXMLDoc
聽 聽 Local oXMLNode
聽 聽 Local cXml 聽:= c_XmlRecibido
聽 聽 Local aRespuesta := {}
聽 聽 Local cText 聽:= ''
聽 聽 Local cName 聽:= ''
聽 聽 Local cData 聽:= ''
聽 聽 Local aText 聽:= {}
聽 聽 Local nIdx 聽:= 0

聽 聽 * Proceso el XML (TXMLDocument sale de la contrib xHb)
聽 聽 oXMLDoc 聽:= TXMLDocument() : New()
聽 聽 cText 聽 聽:= oXMLDoc : Read( cXML )
聽 聽 oXMLNode := oXMLDoc : FindFirst()
聽 聽 While( Valtype( oXMLNode ) == 'O' )
聽聽 聽聽 聽 cName := oXMLNode:cName // Nombre del Nodo
聽聽 聽聽 聽 cData := oXMLNode:cData // Datos dentro del Nodo
聽聽 聽聽 聽 If( valtype( cData ) = 'N' )
聽 聽 聽 聽 聽 聽 cData := Str( cData )
聽聽 聽聽 聽 ElseIf( valtype( cData ) = 'D' )
聽 聽 聽 聽 聽 聽 cData := DTOC( cData )
聽聽 聽聽 聽 ElseIf( valtype( cData ) = 'C' )
聽 聽 聽 聽 聽 聽 cData := Alltrim( cData )
聽 聽 聽 聽 聽 聽 If( subs( cData, 5, 1 ) = '-' .And. Subs( cData, 8, 1 ) = '-' )
聽 聽聽聽 聽 聽 聽 If( len( cData ) = 10 )
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 cData := SubStr( cData, 9, 2 ) + '/' + SubStr( cData, 6, 2 ) + '/' + SubStr( cData, 1, 4 )
聽 聽聽聽 聽 聽 聽 Else
聽 聽 聽 聽 聽 聽 聽 聽 聽 聽 cData := SubStr( cData, 9, 2 ) + '/' + SubStr( cData, 6, 2 ) + '/' + SubStr( cData, 1, 4 ) + ' - ' + SubStr( cData, 11 )
聽 聽聽聽 聽 聽 聽 End
聽 聽 聽 聽 聽 聽 End
聽聽 聽聽 聽 Else
聽 聽 聽 聽 聽 聽 cData := ''
聽聽 聽聽 聽 End 
聽聽 聽聽 聽 If( valtype( cName ) = 'C' )
聽 聽 聽 聽 聽 聽 Aadd( aText , { Alltrim( cName ), Alltrim( cData ) } )
聽聽 聽聽 聽 End
聽聽 聽聽 聽 oXmlNode := oXMLDoc : FindNext()
聽 聽 Enddo

聽 聽 * Proceso los Valores Obtenidos, Esta Parte Da Lastima, Pero Estaba Apurado Asi Que No Tuve Tiempo De Mejorarla.
聽 聽 For nIdx := 1 to Len( aText )
聽聽 聽聽 聽 If( c_ServicioLlamado = 'FEDummy' )
聽 聽 聽 聽 聽 聽 if( aText[ nIdx, 1 ] == 'AppServer' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'DbServer' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'AuthServer' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Code' 聽.or. 聽;
聽聽 聽聽 聽 聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Msg' )
聽 聽聽聽 聽 聽 聽 Aadd( aRespuesta, aText[ nIdx ] )
聽 聽 聽 聽 聽 聽 End
聽聽 聽聽 聽 ElseIf( c_ServicioLlamado = 'FECompUltimoAutorizado' )
聽 聽 聽 聽 聽 聽 If( aText[ nIdx, 1 ] == 'CbteNro' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Code' 聽.or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Msg' )
聽 聽聽聽 聽 聽 聽 Aadd( aRespuesta, aText[ nIdx ] )
聽 聽 聽 聽 聽 聽 End
聽聽 聽聽 聽 ElseIf( c_ServicioLlamado = 'TA' )
聽 聽 聽 聽 聽 聽 If( aText[ nIdx, 1 ] == 'generationTime' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'expirationTime' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'token' 聽.or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'sign' )
聽 聽聽聽 聽 聽 聽 Aadd( aRespuesta, aText[ nIdx ] )
聽 聽 聽 聽 聽 聽 End
聽聽 聽聽 聽 ElseIf( c_ServicioLlamado = 'FECAESolicitar' )
聽 聽 聽 聽 聽 聽 If( aText[ nIdx, 1 ] == 'Resultado' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Reproceso' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'CAE' 聽.or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'CAEFchVto' .or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Code' 聽.or. 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽aText[ nIdx, 1 ] == 'Msg' )
聽 聽聽聽 聽 聽 聽 Aadd( aRespuesta, aText[ nIdx ] )
聽 聽 聽 聽 聽 聽 End
聽 聽 聽 聽 End
聽 聽 Next
聽 聽 Return( aRespuesta )

//----------------------------------------------------------------------------//
*: TimeFMT Devuelve la fecha y hora recibida en forma de texto
//----------------------------------------------------------------------------//
Static Function TimeFMT( dt, n_Horas )

聽 聽 Local c 聽 聽 聽 聽 聽:= ''
聽 聽 Local cFechaHora := ''

聽 聽 dt := dt + ( n_Horas / 24 )
聽 聽 c := hb_TToS( dt )
聽 聽 cFechaHora := SubStr( c, 01, 4 ) + '-' + SubStr( c, 05, 2 ) + '-' + SubStr( c, 07, 2 ) + 聽;
聽 聽 聽 聽 聽 聽 聽 聽 聽'T' + 聽;
聽 聽 聽聽 聽聽 聽 聽 聽 聽 聽 聽 SubStr( c, 09, 2 ) + ':' + SubStr( c, 11, 2 ) + ':' + SubStr( c, 13, 2 ) 聽// + 聽'-' + '03:00'
聽 聽 Return( cFechaHora )

//----------------------------------------------------------------------------//
*: MuestroRespuesta 聽 聽 聽 聽 聽 :
*: Muestra informaci垄n recibida del WS correspondiente 聽 聽 聽 :
*: Estado: OK (funcionando) 聽 聽 聽 聽 聽:
//----------------------------------------------------------------------------//
Function MuestroRespuesta( a_Respuesta )

聽 聽 Local nIdx := 0

聽 聽 Cls
聽 聽 If( !Empty( a_Respuesta ) )
聽聽 聽聽 聽 ? 'COMIENZA LA VISUALIZACION DE LA RESPUESTA'
聽 聽 聽 聽 ?
聽聽 聽聽 聽 For nIdx := 1 to Len( a_Respuesta )
聽 聽 聽 聽 聽 聽 ? a_Respuesta[ nIdx, 01 ], a_Respuesta[ nIdx, 02 ]
聽聽 聽聽 聽 Next
聽 聽 聽 聽 ?
聽聽 聽聽 聽 ? 'FINALIZO LA VISUALIZACION DE LA RESPUESTA'
聽聽 聽聽 聽 ? 'PRESIONE CUALQUIER TECLA PARA CONTINUAR'
聽 聽 Else
聽 聽 聽 聽 ? '****************************************************'
聽聽 聽聽 聽 ? ' HUBO ALGUN TIPO DE ERROR, NO HAY NADA PARA MOSTRAR '
聽聽 聽聽 聽 ? '****************************************************'
聽 聽 End
聽 聽 //Inkey( 0, 128 ) // 128 para que si muevo el mouse no me saque del inkey
聽 聽 Return( .t. )


Saludos
Posts: 389
Joined: Wed Nov 29, 2006 01:51 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Mon Jun 29, 2015 02:59 AM

Horacio,

Gracias x compartirlo.

Salu2, Ariel

Posts: 58
Joined: Thu Nov 02, 2006 01:17 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Mon Jun 29, 2015 02:34 PM

Hola Horacio, gracias por el aporte. Una pregunta donde consigo los siguientes archivos:

Local cCert := 'c:\pyrece\reingart\reingart.crt' // The X.509 obtained from Seg. Inf.
Local cPrivateKey := 'c:\pyrece\reingart\reingart.key' // The private key correspoding to CERT

Posts: 1344
Joined: Wed Nov 16, 2005 09:14 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Mon Jun 29, 2015 03:43 PM
Esos archivos los tenes que generar vos desde la pagina de AFIP
http://www.afip.gob.ar/ws/WSAA/WSAA.ObtenerCertificado.pdf
Posts: 150
Joined: Tue Jul 15, 2008 07:12 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Mon Jun 29, 2015 03:44 PM

son el certificado electronico que te da la afip y su clave privada
luego se procesan con el OpenSSl

Posts: 1364
Joined: Wed Jun 21, 2006 12:39 AM
Re: Fuentes Factura electr贸nica Argentina
Posted: Tue Jun 30, 2015 12:25 AM

Colegas, si necesitan los archivos 'reingart.crt' y 'reingart.key' manden sus correos. Gracias

Saludos

Posts: 133
Joined: Mon May 12, 2008 04:13 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Tue Jun 30, 2015 12:45 AM

Horacio, excelente aporte, gracias

Lo importante es como dices analizar como es el comportamiento del WebService

Fivewin 16.11
Harbour 3.2.0
Visual Studio 2015 community
MariaDb/MySql

Ing. MSc. Luis Duque
http://www.accasoft.net
Posts: 3
Joined: Tue Mar 24, 2020 04:54 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Thu May 07, 2020 04:47 PM

Hola estimado Horacio
Estoy interesado en el c贸digo para factura electr贸nica y los archivos que ofreces.
Pregunto si el c贸digo que esta publicado, todav铆a esta vigente y que version de fwh y harbour necesita para correr correctamente.
Desde ya muchas gracias.

Mi correo es olexyn@gmail.com

// Colegas, si necesitan los archivos 'reingart.crt' y 'reingart.key' manden sus correos. Gracias

Leonardo

Posts: 1364
Joined: Wed Jun 21, 2006 12:39 AM
Re: Fuentes Factura electr贸nica Argentina
Posted: Fri May 08, 2020 02:27 PM

Hola Leonardo, Yo empec茅 a usar este c贸digo desde la versi贸n FWH1204, la 煤nica restricci贸n que encontr茅 en ese momento es que solo funcionaba con con harbour, no xharbour. Actualmente lo estoy compilando con la 煤ltima versi贸n FWH. Tambi茅n lo pod茅s usar solo consola ( de hecho estaba para consola y yo lo adapt茅 ), Si ten茅s alguna duda te dejo mi correo horacio.dellacasa arroba gmail.com

Saludos

Posts: 69
Joined: Tue Jul 17, 2007 12:37 PM
Re: Fuentes Factura electr贸nica Argentina
Posted: Fri Feb 07, 2025 05:24 PM

Buenos Dias

Podrias volver a compartilo , no se ve en su totalidad muchisimas gracias Fabian

Continue the discussion