Code: Select all
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( '"' $ cRespuesta ) // "
cRespuesta := StrTran( cRespuesta, '"', '"' )
End
If( ''' $ cRespuesta ) // \
cRespuesta := StrTran( cRespuesta, ''', '\' )
End
If( '&' $ cRespuesta ) // &
cRespuesta := StrTran( cRespuesta, '&', '&' )
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( '"' $ cRespuesta ) // "
cRespuesta := StrTran( cRespuesta, '"', '"' )
End
If( ''' $ cRespuesta ) // \
cRespuesta := StrTran( cRespuesta, ''', '\' )
End
If( '&' $ cRespuesta ) // &
cRespuesta := StrTran( cRespuesta, '&', '&' )
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