Web Service CERTIPASS Página 1
Contenido 1. Introducción... 5 1.1 Tipos de CFDI... 5 2. Funcionalidad del Web Service... 5 2.1 Timbrado de CFDI... 5 2.1.1 Datos de entrada... 6 2.1.2 Estructura de petición SOAP... 6 2.1.3 Datos de respuesta... 7 2.1.4 Estructura de respuesta SOAP... 7 2.1.5 Códigos de respuesta... 7 2.1.5.1 Códigos de éxito... 8 2.1.5.2 Códigos de error... 8 2.1.6 Verificación de Timbrado... 9 2.1.6.1 Datos de entrada... 9 2.1.6.2 Estructura de petición SOAP... 9 2.1.6.3 Datos de respuesta... 10 2.1.6.4 Estructura de respuesta SOAP... 10 2.1.7 Códigos de respuesta... 11 2.1.7.1 Códigos de éxito... 11 2.1.7.2 Códigos de error... 11 2.2 Cancelación de CFDI... 11 2.2.1 Datos de entrada... 11 2.2.2 Estructura de petición SOAP... 12 2.2.3 Datos de respuesta... 12 2.2.4 Estructura de respuesta SOAP... 13 2.2.5 Códigos de respuesta... 13 2.2.5.1 Códigos de éxito... 13 2.2.5.2 Códigos de error... 13 2.3 Validación de CFDI... 14 2.3.1 Datos de entrada... 14 2.3.2 Estructura de petición SOAP... 14 Página 2
2.3.3 Datos de respuesta... 15 2.3.4 Estructura de respuesta SOAP... 15 2.3.5 Códigos de respuesta... 15 2.3.5.1 Códigos de éxito... 15 2.3.5.2 Códigos de error... 16 2.4 Consulta de CFDI... 16 2.4.1 Datos de entrada... 16 2.4.2 Estructura de petición SOAP... 17 2.4.3 Datos de respuesta... 17 2.4.4 Estructura de respuesta SOAP... 18 2.4.5 Códigos de respuesta... 18 2.4.5.1 Códigos de éxito... 18 2.4.5.2 Códigos de error... 18 2.5 Autenticación... 19 2.6 Respuestas con mensajes de error... 19 2.6.1 Estructura de respuesta SOAP de errores... 19 3. Códigos de Respuesta... 20 3.1 Códigos de respuesta definidos por el SAT... 20 3.2 Códigos de respuesta definidos por el Web Service... 22 4. Ejemplos de implementación... 24 4.1 JAVA... 24 4.1.1 Asunciones y dependencias... 24 4.1.2 Generación de clases del Web Service... 25 4.1.3 Cliente ejemplo... 27 4.2.NET... 31 4.2.1 Asunciones y dependencias... 31 4.2.2 Referencia del Web service... 31 4.2.3 Configuración de la conexión... 32 4.2.4 Cliente ejemplo en C#... 34 4.2.5 Cliente ejemplo en Visual Basic... 35 4.3 DELPHI... 37 4.3.1 Asunciones y dependencias... 37 4.3.2 Unidad CertipassWs... 37 4.3.3 Unidad WSSecurity... 41 Página 3
4.3.4 Unidad Client... 45 4.3.5 Cliente ejemplo... 49 4.4 Python... 50 4.4.1 Asunciones y dependencias... 50 4.4.1.1 Librería Suds... 50 4.4.2 WsSecurity... 52 4.4.3 Cliente ejemplo... 53 4.5 PHP... 54 4.5.1 Asunciones y dependencias... 54 4.5.2 Cliente Ejemplo... 54 4.5.2.1 Clase CertipassClient... 54 4.5.2.2 Clase CfdiInfoWrapper... 57 4.5.2.3 Consulta de cfdi utilizando la clase CfdiInfoWrapper... 59 Página 4
1. Introducción El Web Service de CERTIPASS es un servicio basado en SOAP que le permitirá timbrar y cancelar facturas electrónicas vía internet desde su sistema corporativo. El servicio es gratuito y fácil de implementar. 1.1. Tipos de CFDI En el protocolo CERTIPASS se identifica como un CFDI a los siguientes tipos de comprobantes: Comprobante Fiscal Digital por Internet (CFDI V3.2) Documento Electrónico de Retenciones e información de Pagos (Retención Pago V1.0) Por lo que al hacer referencia a un CFDI dentro de este manual tomaremos en cuenta los comprobantes previamente mencionados. 2. Funcionalidad del Web Service A continuación se describen las funciones del Web Service de Certipass: Servicio Método Descripción Timbrado de CFDI signcfdi Valida, sella (de ser requerido) y timbra un CFDI. Verificación de Timbrado Cancelación de CFDI verifyoperation cancelcfdi Consulta el estatus final de una petición de timbrado mediante el Web Service. Cancela un CFDI timbrado por CERTIPASS. Validación de CFDI validatecfdi Verifica la validez de un CFDI timbrado por CERTIPASS. Consulta de CFDI getcfdiinfo Consulta el estatus actual de un CFDI timbrado por CERTIPASS. 2.1. Timbrado de CFDI El método signcfdi se usa para timbrar un CFDI. Si la factura no cuenta con el sello, el servicio se encargará de generarlo. Página 5
Importante Si desea que el Web Service genere el sello de la factura, antes deberá registrar el RFC emisor en www.certipass.mx El sistema le solicitará su llave privada, el certificado (archivos.key y.cer) y la contraseña de la llave privada. Si enviará los XML con el sello, no es necesario registrar el RFC en CERTIPASS. 2.1.1. Datos de entrada Los atributos del objeto de entrada CfdiSignWrapper son los siguientes: Nombre del parámetro Tipo Requerido/Opcional Descripción cfdi String Requerido XML del CFDI, codificado en Base64 transactionid String Opcional Identificador de transacción de timbrado. 2.1.2. Estructura de petición SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/"> <soap:header> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecuritysecext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd"> <wsse:usernametoken> <wsse:username></wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText"></wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> <soap:body> <ws:signcfdi> <ws:cfdisignwrapper> <ws:cfdi></ws:cfdi> <ws:transactionid></ws:transactionid> </ws:cfdisignwrapper> </ws:signcfdi> </soap:body> </soap:envelope> Página 6
Figura 1 - Estructura de petición SOAP Servicio de timbrado 2.1.3. Datos de respuesta Los atributos del objeto de respuesta SignCfdiResponse son los siguientes: Nombre de la propiedad Tipo Descripción responsecode int Código de respuesta del timbrado responsedescription String Descripción de la respuesta servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). signedxml String XML del CFDI timbrado, codificado en Base64 2.1.4. Estructura de respuesta SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <signcfdiresponse xmlns= http://ws.certipass.mx/ > <return> <responsecode></responsecode> <responsedescription></responsedescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> <signedxml></signedxml> </return> </signcfdiresponse> </soap:body> </soap:envelope> Figura 2 - Estructura de respuesta SOAP Servicio de timbrado 2.1.5. Códigos de respuesta A continuación se mencionan los posibles códigos de respuesta del comando signcfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta. Página 7
2.1.5.1. Códigos de éxito A continuación se enlistan los códigos de éxito para el comando signcfdi: 1000 2.1.5.2. Códigos de error A continuación se enlistan los códigos de error para el comando signcfdi: 301 302 303 304 305 306 307 308 401 402 403 2010 2309 2600 2601 2602 2603 4100 4200 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4222 4223 4224 4230 Página 8
2.1.6. Verificación de Timbrado Bajo algunas circunstancias (fallos de red, timeouts, et), es posible que no reciba la respuesta del comando de timbrado. El método verifyoperation le permite recuperar un CFDI mediante su cadena original o el identificador de transacción de timbrado. 2.1.6.1. Datos de entrada Los atributos del objeto de entrada VerifyOperationWrapper son los siguientes: Parámetro Tipo Requerido/Opcional Descripción Observaciones transactionid String Opcional signtransactionid String Opcional originalchain String Opcional Identificador de la transacción Verify. Identificador utilizado en la transacción de timbrado a verificar. Cadena original del CFDI, codificada en Base64 Es requerido si no se incluye el atributo originalchain. Es requerido si no se incluye el atributo signtransactionid. 2.1.6.2. Estructura de petición SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/"> <soap:header> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecuritysecext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd"> <wsse:usernametoken> <wsse:username></wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText"></wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> <soap:body> <ws:verifyoperation> <ws:verifyoperationwrapper> <ws:originalchain></ws:originalchain> <ws:signtransactionid></ws:signtransactionid> <ws:transactionid></ws:transactionid> </ws:verifyoperationwrapper> </ws:verifyoperation> </soap:body> </soap:envelope> Figura 3 - Estructura de petición SOAP Servicio de Verificación Página 9
2.1.6.3. Datos de respuesta Los atributos del objeto de respuesta VerifyOperationResponse son los siguientes: Parámetro Tipo Descripción responsecode int Código de respuesta de la verificación responsedescription String Descripción de la respuesta servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). cfdi String XML del CFDI consultado, codificado en Base64 uuid String Folio fiscal de CFDI cfdistatus String Estatus del CFDI 2.1.6.4. Estructura de respuesta SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <VerifyOperationResponse xmlns= http://ws.certipass.mx/ > <return> <responsecode></responsecode> <responsedescription></responsedescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> <cfdi></cfdi> <uuid></uuid> <cfdistatus></cfdistatus> </return> </VerifyOperationResponse> </soap:body> </soap:envelope> Figura 4 - Estructura de respuesta SOAP Servicio de Verificación Página 10
2.1.7. Códigos de respuesta A continuación se mencionan los posibles códigos de respuesta del comando verifyoperation. Si requiere más información, favor de consultar la sección de códigos de respuesta. 2.1.7.1. Códigos de éxito A continuación se enlistan los códigos de éxito para el comando verifyoperation: 1000 2.1.7.2. Códigos de error A continuación se enlistan los códigos de error para el comando verifyoperation: 205 2700 4200 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4230 4231 2.2. Cancelación de CFDI El método cancelcfdi se usa para cancelar un CFDI timbrado por CERTIPASS. Importante Si desea que el Web Service genere el signaturevalue, antes deberá registrar el RFC emisor en www.certipass.mx El sistema le solicitará su llave privada, el certificado (archivos.key y.cer) y la contraseña de la llave privada. Si su sistema calculará y enviará el signaturevalue, no es necesario registrar el RFC en CERTIPASS para cancelar sus facturas. 2.2.1. Datos de entrada Los atributos del objeto de entrada CfdiCancelWrapper son los siguientes: Nombre del parámetro Tipo Requerido/Opcional Descripción Página 11
uuid String Requerido Folio fiscal del CFDI previamente timbrado. cancelationdate Date Requerido Fecha de cancelación del CFDI. signaturevalue String Opcional Firma requerida para cancelar el CFDI codificada en Base64; se obtiene con el RFC del emisor, el UUID del CFDI, la fecha de cancelación, el certificado y la llave privada del emisor. transactionid String Opcional Identificador de transacción de cancelación. 2.2.2. Estructura de petición SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/"> <soap:header> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecuritysecext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd"> <wsse:usernametoken> <wsse:username></wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText"></wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> <soap:body> <ws:cancelcfdi> <ws:cfdicancelwrapper> <ws:uuid></ws:uuid> <ws:signaturevalue></ws:signaturevalue> <ws:cancelationdate></ws:cancelationdate> <ws:transactionid></ws:transactionid> </ws:cfdicancelwrapper> </ws:cancelcfdi> </soap:body> </soap:envelope> Figura 5 - Estructura de petición SOAP Servicio de cancelación 2.2.3. Datos de respuesta Los atributos del objeto de salida CancelCfdiResponse son los siguientes: Parámetro Tipo Descripción responsecode int Código de respuesta de la cancelación responsedescription String Descripción de la respuesta servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. Página 12
transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). receipt String Acuse de cancelación del SAT, codificado en Base64 2.2.4. Estructura de respuesta SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <CancelCfdiResponse xmlns= http://ws.certipass.mx/ > <return> <responsecode></responsecode> <responsedescription></responsedescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> <receipt></receipt> </return> </CancelCfdiResponse> </soap:body> </soap:envelope> Figura 6 - Estructura de respuesta SOAP Servicio de cancelación 2.2.5. Códigos de respuesta A continuación se mencionan los posibles códigos de respuesta del comando cancelcfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta. 2.2.5.1. Códigos de éxito A continuación se enlistan los códigos de éxito para el comando cancelcfdi: 1000 2.2.5.2. Códigos de error A continuación se enlistan los códigos de error para el comando cancelcfdi: 201 202 203 205 303 1201 1202 1203 1205 1300 1301 1302 1303 1304 1305 Página 13
1306 1307 1308 1309 4200 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4221 4230 2.3. Validación de CFDI El método validatecfdi se usa para verificar la validez de un CFDI timbrado por CERTIPASS. 2.3.1. Datos de entrada Los atributos del objeto de entrada ValidateCfdiWrapper son los siguientes: Parámetro Tipo Requerido/Opcional Descripción cfdi String Requerido XML del CFDI a validar, codificado en Base64 2.3.2. Estructura de petición SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/"> <soap:header> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecuritysecext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd"> <wsse:usernametoken> <wsse:username></wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText"></wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> <soap:body> <ws:validatecfdi> <ws:validatecfdiwrapper> <ws:cfdi></ws:cfdi> <ws:transactionid></ws:transactionid> </ws:validatecfdiwrapper> </ws:validatecfdi> </soap:body> </soap:envelope> Figura 7 - Estructura de petición SOAP Servicio de validación Página 14
2.3.3. Datos de respuesta Los atributos del objeto de salida ValidateCfdiResponse son los siguientes: Parámetro Tipo Descripción responsecode int Código de respuesta de la validación responsedescription String Descripción de la respuesta servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). 2.3.4. Estructura de respuesta SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <validatecfdiresponse xmlns= http://ws.certipass.mx/ > <return> <responsecode></responsecode> <responsedescription></responsedescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> </return> </validatecfdiresponse> </soap:body> </soap:envelope> Figura 8 - Estructura de respuesta SOAP Servicio de validación 2.3.5. Códigos de respuesta A continuación se mencionan los posibles códigos de respuesta del comando validatecfdi. Si requiere más información, favor de consultar la sección de códigos de respuesta. 2.3.5.1. Códigos de éxito A continuación se enlistan los códigos de éxito para el comando validatecfdi: Página 15
1000 1002 2.3.5.2. Códigos de error A continuación se enlistan los códigos de error para el comando validatecfdi: 301 302 303 304 305 401 402 403 2010 2309 2600 2601 2602 2603 4200 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4230 2.4. Consulta de CFDI El método getcfdiinfo se usa para consultar el estatus de un CFDI timbrado por CERTIPASS. 2.4.1. Datos de entrada Los atributos del objeto de entrada CfdiInfoWrapper son los siguientes: Parámetro Tipo Requerido/Opcional Descripción uuid String Requerido transactionid String Opcional Folio fiscal del CFDI previamente timbrado Identificador de transacción de consulta. Página 16
2.4.2. Estructura de petición SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:ws="http://ws.certipass.mx/"> <soap:header> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecuritysecext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurityutility-1.0.xsd"> <wsse:usernametoken> <wsse:username></wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wssusername-token-profile-1.0#PasswordText"></wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> <soap:body> <ws:getcfdiinfo> <ws:cfdiinfowrapper> <ws:uuid></ws:uuid> <ws:transactionid></ws:transactionid> </ws:cfdiinfowrapper> </ws:getcfdiinfo> </soap:body> </soap:envelope> Figura 9 - Estructura de petición SOAP Servicio de Consulta 2.4.3. Datos de respuesta Los atributos del objeto de respuesta GetCfdiInfoResponse son los siguientes: Parámetro Tipo Descripción responsecode int Código de respuesta de la consulta responsedescription String Descripción de la respuesta servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). cfdi String XML del CFDI consultado, codificado en Base64 uuid String Folio fiscal de CFDI consultado Página 17
cfdistatus String Estatus del CFDI consultado 2.4.4. Estructura de respuesta SOAP <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <getcfdiinforesponse xmlns= http://ws.certipass.mx/ > <return> <responsecode></responsecode> <responsedescription></responsedescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> <uuid></uuid> <cfdistatus></cfdistatus> <cfdi></cfdi> </return> </getcfdiinforesponse> </soap:body> </soap:envelope> Figura 10 - Estructura de respuesta SOAP Servicio de Consulta 2.4.5. Códigos de respuesta A continuación se mencionan los posibles códigos de respuesta del comando getcfdiinfo. Si requiere más información, favor de consultar la sección de códigos de respuesta. 2.4.5.1. Códigos de éxito A continuación se enlistan los códigos de éxito para el comando getcfdiinfo: 1000 2.4.5.2. Códigos de error A continuación se enlistan los códigos de error para el comando getcfdiinfo: 205 4200 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219 4220 4230 Página 18
2.5. Autenticación Para conectarse al Web Service de CERTIPASS es necesario proporcionar el usuario y contraseña que utiliza para ingresar a CERTIPASS. La autenticación se realiza mediante el uso de un WSSecurityHeader, el cual incluye un UsernameToken con los datos de autenticación del usuario. <soap:header xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <wsse:security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsse:usernametoken> <wsse:username>username</wsse:username> <wsse:password Type="http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-username-token-profile- 1.0#PasswordText">password</wsse:Password> </wsse:usernametoken> </wsse:security> </soap:header> Figura 11 - Ejemplo de WSSecurityHeader de una petición SOAP. 2.6. Respuestas con mensajes de error En algunas situaciones, el WebService de Certipass puede regresar una respuesta que describe excepciones en la comunicación con el cliente. Este tipo de respuesta esta formada por un objeto OperationFailed. Los atributos del objeto OperationFault se describen a continuación: Parámetro Tipo Descripción errorcode int Código de error errordescription String Descripción del error servertransactionid String Identificador de la transacción proporcionado por el servidor de la aplicación. transactionid String Identificador de la transacción ingresado por el usuario. requestdate Date Fecha de petición al servidor. responsedate Date Fecha de respuesta del servidor. executiontime long Tiempo de ejecución del comando (en milisegundos). 2.6.1. Estructura de una excepción <soap:envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"> <soap:body> <soap:fault> <soap:code> </soap:code> Página 19
<soap:reason> </soap:reason> <soap:detail> <OperationFailed xmlns = http://ws.certipass.mx/ > <errorcode></errorcode> <errordescription></errordescription> <transactionid></ transactionid> <servertransactionid></ servertransactionid> <requestdate></ requestdate> <responsedate></ responsedate> <executiontime></ executiontime> </OperationFailed > </soap:detail> </soap:fault> </soap:body> </soap:envelope> Figura 12 - Ejemplo de la estructura de una excepción 3. Códigos de Respuesta 3.1. Códigos de respuesta definidos por el SAT Código Mensaje Descripción 201 UUID Cancelado exitosamente 202 UUID Previamente cancelado 203 UUID No corresponde el RFC del emisor y de quien solicita la cancelación 205 UUID No existe 301 XML mal formado Cuando se puede cancelar correctamente un CFDI V3.2 con el UUID ingresado. Cuando se intenta cancelar un CFDI V3.2 y ya ha sido cancelado previamente. Cuando se intenta cancelar un CFDI V3.2 y el RFC emisor es diferente al RFC que intenta cancelar. Cuando se trata de consultar, verificar o cancelar un CFDI V3.2 con un UUID que no existe. Cuando el XML del CFDI V3.2 no cumple con la estructura definida por el SAT. 302 Sello mal formado o inválido El sello del emisor no es válido. 303 Sello no corresponde a emisor 304 Certificado revocado o caduco 305 La fecha de emisión no está dentro de la vigencia del CSD del emisor 306 El certificado no es de tipo CSD El CSD del emisor no corresponde al RFC emisor del comprobante. El CSD del emisor se encuentra revocado de acuerdo a la lista LCO. El CSD del emisor no está vigente para la fecha de emisión del CFDI V3.2. El certificado no tiene la estructura de uno de tipo CSD. Página 20
307 El CFDI contiene un timbre previo 308 Certificado no expedido por el SAT 401 402 403 La fecha de emisión se encuentra en el futuro y fuera del rango de tolerancia (12 horas) El tiempo entra la fecha de emisión y la fecha de firmado excede el límite establecido (72 horas) RFC del emisor no se encuentra en el régimen de contribuyentes La fecha de emisión no es posterior al 01 de enero 2012 1201 UUID Cancelado exitosamente 1202 UUID Previamente cancelado 1203 UUID no corresponde con el emiso 1205 UUID No existe 1300 Autenticación no válida 1301 XML mal formado 1302 Estructura de folios no válida 1303 Estructura de RFC no válida 1304 Estructura de fecha no válida 1305 Certificado no corresponde al emisor 1306 Certificado no vigente 1307 Uso de FIEL no permitido 1308 Certificado revocado o caduco El XML enviado a CERTIPASS ya contiene un timbre. El CSD del emisor no fue firmado por un Certificado de Autoridad del SAT. El rango entre la fecha de emisión y la fecha actual es mayor a 12 horas. El rango entre la fecha de emisión y fecha de timbrado es mayor a 72 horas. El RFC del emisor no se encuentra en la lista LCO del SAT. La fecha de emisión no es posterior al 01 de enero 2012. Cuando se puede cancelar correctamente una Retención Pago V1.0 con el UUID ingresado. Cuando se intenta cancelar una Retención Pago V1.0 y ya ha sido cancelado previamente. Cuando se intenta cancelar una Retención Pago V1. y el RFC emisor es diferente al RFC que intenta cancelar. Cuando se trata de consultar, verificar o cancelar una Retención Pago V1.0 con un UUID que no existe. Cuando el token de autenticación no es válido para el servicio de cancelación. Cuando el XML de la Retención Pago V1. no cumple con la estructura definida por el SAT. Cuando la estructura Folio que contiene los UUID no es válida. Cuando la estructura en que se presenta el RFC del emisor no es válida. Cuando la estructura en que se presenta la fecha de expedición no es válida Cuando el Certificado del emisor de la Retención Pago V1.0 no coincide con el certificado con el cual fue firmado el CFDI. El CSD del emisor no está vigente para la fecha de emisión de la Retención Pago V1.0. Cuando se intenta cancelar una Retencion Pago V1.0 utilizando una FIEL El CSD del emisor se encuentra revocado de acuerdo a la lista LCO. Página 21
1309 Firma mal formada o inválida El sello del emisor no es válido. 3.2. Códigos de respuesta definidos por el Web Service Los siguientes códigos son definidos por CERTIPASS y pertenecen exclusivamente a su protocolo de comunicación y reglas de negocio. Código Mensaje Descripción 1000 Comando completado exitosamente Respuesta a un comando exitoso. 1002 2010 El comprobante no se encuentra en el sistema del SAT Error al validar la cantidad del parámetro 2309 Timbres no disponibles 2500 2600 Comando falló, servidor cerrando conexión. Error en la estructura del comprobante El sistema del SAT no cuenta con el comprobante. Le sugerimos intentar más tarde. Cuando las cantidades utilizadas en el CFDI no concuerdan, por ejemplo, la suma de los conceptos no es igual a la cantidad del subtotal. 1 Cuando el Servicio recibe un comando para timbrar pero la cuenta no tiene timbres disponibles. Cuando hubo un error inesperado del lado del servidor. En cancelaciones puede indicar fallas por parte del servicio de cancelación del SAT. Cuando el xml del CFDI esta mal formado. 2601 2602 2603 RFC emisor no coincide con el certificado emisor Fecha de expedición del comprobante no es válida Error en la validación del sello de la firma del comprobante Cuando el RFC del emisor del CFDI no coincide con el certificado con el cual fue firmado el CFDI. Cuando la fecha de expedición del CFDI no es válida. Cuando el certificado del emisor no esta en la lista del LCO. Cuando el CFDI es inválido debido a que fue modificado. Cuando hay problemas de enconding. 1 CERTIPASS valida los totales y subtotales de acuerdo a lo especificado en el Anexo 20. En un concepto o parte el valor unitario multiplicado por la cantidad no puede diferir del total más de medio centavo. El subtotal de los nodos de impuestos o conceptos debe ser igual a la suma de cada impuesto/concepto de dicho nodo. Se permite un margen de tolerancia de medio centavo por cada impuesto/concepto del nodo. El total de la factura debe ser igual a la suma del subtotal menos los descuentos, menos los impuestos retenidos y más los impuestos trasladados (ver Anexo 20, pag. 71). Se permite un margen de tolerancia de medio centavo por cada impuesto/descuento. Página 22
2700 CFDI No encontrado 2800 4100 4200 4210 4211 No fue posible realizar la validación del CFDI ante el SAt. Favor de intentar más tarde. No se encontró el certificado y la llave privada para el RFC Error interno al procesar el si comando El usuario o la contraseña no son válidos. Favor de verificar Los datos de autenticación están incompletos. Por favor, verifique el usuario y la contraseña 4212 La IP ha sido bloqueada 4213 La IP no es válida 4214 El usuario ha sido bloqueado 4215 La petición SOAP contiene elementos no reconociodos 4216 Error en el WSHeader 4217 4218 4219 El estatus del usuario no permite el acceso:<estatus> Se ha excedido el tamaño máximo de texto Error en la codificación base 64 de:<elemento> Cuando no se encuentra el CFDI correspondiente al signtransactionid o a la cadena original ingresada. Cuando ocurre un error en la conexión al servicio de validación del SAT o éste tiene una falla interna. Cuando se quiere timbrar un CFDI y no se tienen los archivos para generar el sello. Cuando ocurre un erro no esperado en la ejecución de un comando. Cuando las credenciales que se envían para la autenticación del usuario no corresponden a algún usuario de CERTIPASS. Cuando no se envían completos los datos de autenticación del usuario. Cuando el usuario intenta autenticarse 5 o más veces sin éxito. Si por alguna razón no es posible detectar su dirección IP. Cuando el usuario intenta autenticarse 5 o más veces sin éxito. Cuando la petición SOAP contiene elementos que no están definidos dentro de la estructura del Servicio web Cuando el usuario envía elementos no reconocidos en el header de autenticación de la petición SOAP Cuando un usuario que no se encuentra en Operación intenta acceder a los servicios del Servicio Web de CERTIPASS Cuando el usuario intenta enviar un elemento de texto con un tamaño superior al definido como máximo en el sistema. Cuando el usuario envía un dato que no corresponde con una codificación en Base64 4220 4221 Error en la estructura de la petición SOAP La fecha de cancelación debe ser poesterior a la fecha de emisión del CFDI Cuando la petición SOAP tiene elementos no válidos para su estructura Cuando se envía una fecha de cancelación anterior a la fecha de emisión del CFDI 4222 Archivo de certificado inválido Cuando el certificado del cliente no es válido. Página 23
4223 Archivo de llave privada inválido Cuando la llave privada no es válida. 4224 4225 Ocurrió un error al parsear uno o más de los parámetros de la petición, favor de verificar. Se ha excedido el máximo de caracteres de en la petición El valor de uno o más parámetros del comando están en un formato no válido y no pudo ser interpretado (error de conversión de tipos de datos). Cuando el tamaño de la petición SOAP (número de caracteres) supera el máximo permitido. Por favor proporciona: <valor> Cuando no se ingresa un valor requerido. 4230 4231 Por favor verifica la escritura de: <valor> Valor fuera de rango: <valor> Error en políticas: : <valor> La fecha no puede ser posterior a la actual: <valor> La fecha no puede ser anterior a la actual: <valor> No se encontró una operación de timbrado con el identificador de transacción proporcionado Cuando el valor ingresado tiene errores de sintaxis. Cuando el valor ingresado no esta dentro del rango permitido. Cuando el valor ingresado no cumple con alguna regla de negocio. Cuando el valor de la fecha ingresada es anterior a la actual y es requerido que sea posterior. Cuando el valor de la fecha ingresada es posterior a la actual y es requerido que sea anterior. Cuando el identificador de timbrado no has ido utilizado previamente para identificar una operación de timbrado o han transcurrido más de 72 horas desde que se utilizó. 4. Ejemplos de implementación El propósito de esta sección es explicar el proceso de creación de un cliente que consuma los servicios del Web Service de CERTIPASS. 4.1. JAVA 4.1.1. Asunciones y dependencias Para iniciar el desarrollo del cliente es necesario contar con: 1. Archivo CERTIPASSWs.wsdl (https://ws.certipass.mx/services?wsdl) 2. Librería Apache CXF 2.7.11 (http://cxf.apache.org/) Página 24
4.1.2. Generación de clases del Web Service A continuación se describe como generar las clases del Web Service de CERTIPASS usando la herramienta Wsdl2Java de Apache CXF, es posible generar las clases del WSDL mediante otras herramientas como wsdl2java de Apache Axis2 o wsimport de Java. La generación de las clases se puede realizar desde línea de comandos o mediante código: a) Mediante línea de comando Ubicados en la carpeta bin del directorio de instalación de Apache CXF ingresamos el siguiente comando: wsdl2java -d rutadeloutput rutadelwsdl\certipassws.wsdl Ejemplo: Figura 13 - Ejemplo de uso de comando wsdl2java En la imagen anterior se puede apreciar que en la primera línea se accede a la ruta donde se encuentra la herramienta wsdl2java y en la segunda ingresamos el comando requerido, donde X es la ruta en donde se encuentra el archivo CERTIPASS.wsdl y X:\CERTIPASSCode es la ruta donde se creará el código. La estructura de salida se aprecia en la siguiente imagen: Figura 14 - Ejemplo del output del comando wsdl2java Después de ejecutar el comando, el siguiente paso es copiar la carpeta mx que se creó y agregarla a la carpeta src del proyecto en el que se desarrollará el cliente java. b) Mediante código Importando la clase org.apache.cxf.tools.wsdlto.wsdltojava (Contenida en la librería Apache CXF ) y ejecutando su método main: Página 25
WSDLToJava.main(new String[]{"- d","rutadeloutput","rutadelwsdl\certipassws.wsdl"); Ejemplo: package test; import org.apache.cxf.tools.wsdlto.wsdltojava; public class CodeGenerator { public static void main(string args[]) { try { WSDLToJava.main(new String[] { "-d", "src", "CertipassWs.wsdl"); System.out.println("finished"); catch (Exception e) { e.printstacktrace(); Figura 15 - Ejemplo de uso del método "main" de la clase WSDLToJava La estructura de salida se aprecia en la siguiente imagen: Figura 16 - Ejemplo del output del método "main" de la clase WSDLToJava Página 26
Página 27 4.1.3. Cliente ejemplo En la imagen siguiente se muestra el código ejemplo de una clase que funciona como cliente del Web Service de CERTIPASS: public class CertipassClient { public static void main(string args[]) { JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setserviceclass(certipasssoapws.class); // URL de beta: https://beta.ws.certipass.mx/services?wsdl String wsurl = "https://ws.certipass.mx/services?wsdl"; factory.setaddress(wsurl); factory.getininterceptors().add(new LoggingInInterceptor()); Map<String, Object> outprops = new HashMap<String, Object>(); outprops.put(wshandlerconstants.action, WSHandlerConstants.USERNAME_TOKEN); outprops.put(wshandlerconstants.user, "username "); outprops.put(wshandlerconstants.password_type, WSConstants.PW_TEXT); outprops.put(wshandlerconstants.pw_callback_class, ClientAutenticationCallBack.class.getName()); WSS4JOutInterceptor loggingoutinterceptor = new WSS4JOutInterceptor(outProps); factory.getoutinterceptors().add(loggingoutinterceptor); CertipassSOAPWS webservice = (CertipassSOAPWS) factory.create(); Client client = ClientProxy.getClient(webService); HTTPConduit conduit = (HTTPConduit) client.getconduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); policy.setconnectiontimeout(1000000l); policy.setreceivetimeout(1000000l); policy.setallowchunking(false); conduit.setclient(policy); CfdiInfoWrapper wrapper = new CfdiInfoWrapper(); wrapper.setuuid("753e9e17-39f2-44f1-91fe-c7c0bec617a0"); wrapper.settransactionid("cii1"); try { CfdiInfoResult result=webservice.getcfdiinfo(wrapper); System.out.println("Cfdi: "+result.getcfdi()); System.out.println("Estatus: "+result.getcfdistatus()); System.out.println("Código de respuesta: "+result.getresponsecode()); System.out.println("Descripción de la respuesta: "+result.getresponsedescription()); System.out.println("Transaction ID: "+result.gettransactionid()); System.out.println("Server transaction ID: "+result.getservertransactionid()); System.out.println("Fecha de consulta: "+result.getrequestdate()); System.out.println("Fecha de respuesta: "+result.getresponsedate()); System.out.println("Tiempo de ejecución: "+result.getexecutiontime()); catch (OperationFailedException fault) {
System.out.println("Código: "+fault.getfaultinfo().geterrorcode()); System.out.println("Mensaje: "+fault.getfaultinfo().geterrordescription()); Figura 17 - Ejemplo de clase que consume los servicios del Web Service de CERTIPASS A continuación se describe brevemente las partes que componen el código anterior 1. Configuración del Factory necesario para obtener la instancia del Web Service: // Se crea el factory necesario para obtener una instancia del servicio web JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean(); factory.setserviceclass(certipasssoapws.class); // URL de beta: https://beta.ws.certipass.mx/services?wsdl String wsurl = https://ws.certipass.mx/services?wsdl"; factory.setaddress(wsurl); // Creamos un interceptor de entrada default factory.getininterceptors().add(new LoggingInInterceptor()); Figura 18 - Ejemplo de configuración del factory Es importante notar que la url del web Service de CERTIPASS usa el protocolo HTTPS, ya que si tratamos de conectarnos mediante un protocolo HTTP el servicio no será accedido. IMPORTANTE: Es muy común que los sitios de beta tengan certificados firmados por el dueño del ambiente (mientras que los sitios de Producción sí tengan certificados firmados por una Autoridad Certificadora como Verisign, GlobalSign o Symantec). Es por ello que al apuntar al ambiente Beta se requiere añadir el certificado HTTPS del Web Service (%CERT_FILE% en el ejemplo) a la lista de trusted certificates de Java (archivo %JAVA_HOME%/lib/security/cacerts). La herramienta Keytool (de Java) cuenta con un comando para realizar este import (Ver: http://docs.acl.com/ax/310/index.jsp?topic=%2fcom.acl.ax.admin.help%2fsystem_administration %2Ft_importing_certificates_into_the_java_cacerts_file.html). keytool import v storetype jks keystore %CACERT_FiLE% -alias %ALIAS% -file %CERT_FILE% Dado que el certificado HTTPS de Producción del Web Service de CERTIPASS sí está firmado por una autoridad certificadora, no es necesario realizar esto al apuntar a Producción. 2. Configuración de la autenticación del usuario: Para configurar la autenticación del usuario es necesario implementar una clase Callback que realizará la obtención del password del usuario necesario para autenticarse en el Web Service de CERTIPASS. El código de la clase se presenta a continuación: Página 28
import java.io.ioexception; import javax.security.auth.callback.callback; import javax.security.auth.callback.callbackhandler; import javax.security.auth.callback.unsupportedcallbackexception; import org.apache.ws.security.wspasswordcallback; public class ClientAutenticationCallBack implements CallbackHandler { @Override public void handle(callback[] cbarray) throws IOException, UnsupportedCallbackException { WSPasswordCallback passwordcallback = (WSPasswordCallback) cbarray[0]; // Password que se usa para acceder a Certipass passwordcallback.setpassword("password"); // User que se usa para acceder a Certipass passwordcallback.setidentifier("username"); Figura 19 - Ejemplo de clase Callback El siguiente paso es usar el Callback en la configuración de la autenticación: // Configuramos un interceptor de salida usando el callback de salida que // definimos que hará la validación de la contraseña contra el callback de // entrada del servicio web Map<String, Object> outprops = new HashMap<String, Object>(); outprops.put(wshandlerconstants.action, WSHandlerConstants.USERNAME_TOKEN); // Agregamos nuestro nombre de usuario de Certipass outprops.put(wshandlerconstants.user, "username "); outprops.put(wshandlerconstants.password_type, WSConstants.PW_TEXT); // Agregamos el callback que generamos para autenticar al usuario outprops.put(wshandlerconstants.pw_callback_class, ClientAutenticationCallBack.class.getName()); WSS4JOutInterceptor loggingoutinterceptor = new WSS4JOutInterceptor(outProps); factory.getoutinterceptors().add(loggingoutinterceptor); Figura 20 - Ejemplo de configuración de la autenticación del usuario 3. Configuración del cliente que consumirá el Web Service: // Obtenemos la instancia del servicio web CertipassSOAPWS webservice = (CertipassSOAPWS) factory.create(); // Creamos el cliente que consumirá el webservice Client client = ClientProxy.getClient(webService); // Configuramos el canal por el que se conectará el cliente al servicio web HTTPConduit conduit = (HTTPConduit) client.getconduit(); HTTPClientPolicy policy = new HTTPClientPolicy(); // Establecemos el tiempo máximo de conexión policy.setconnectiontimeout(1000000l); // Establecemos el tiempo máximo que el cliente esperará una respuesta policy.setreceivetimeout(1000000l); policy.setallowchunking(false); conduit.setclient(policy); Página 29
Figura 21 - Ejemplo de configuración del cliente Es importante establecer tiempos suficientes o considerables para permitir a la aplicación esperar por la conexión y el tiempo de respuesta de los servicios del Web Service, ya que si hay interferencias en la red podría ocasionar timeouts en la comunicación de los sistemas. 4. Llamada a métodos del Web Service: En este punto ya se tiene todo listo para usar los servicios del Web Service de CERTIPASS. A continuación se muestra una llamada al método getcfdiinfo: // Una vez configurada la conexión podemos llamar a los métodos del servicio web CfdiInfoWrapper wrapper = new CfdiInfoWrapper(); wrapper.setuuid("753e9e17-39f2-44f1-91fe-c7c0bec617a0"); wrapper.settransactionid("cii1"); try { CfdiInfoResult result=webservice.getcfdiinfo(wrapper); System.out.println("Cfdi: "+result.getcfdi()); System.out.println("Estatus: "+result.getcfdistatus()); System.out.println("Código de respuesta: "+result.getresponsecode()); System.out.println("Descripción de la respuesta: "+result.getresponsedescription()); System.out.println("Transaction ID: "+result.gettransactionid()); System.out.println("Server transaction ID: "+result.getservertransactionid()); System.out.println("Fecha de consulta: "+result.getrequestdate()); System.out.println("Fecha de respuesta: "+result.getresponsedate()); System.out.println("Tiempo de ejecución: "+result.getexecutiontime()); catch (OperationFailedException fault) { System.out.println("Código: "+fault.getfaultinfo().geterrorcode()); System.out.println("Mensaje: "+fault.getfaultinfo().geterrordescription()); Figura 22 - Ejemplo de llamada a métodos del Web Service Al ejecutar el código anterior se obtendrá la siguiente salida: Figura 23 -Ejemplo de salida de una ejecución exitosa Página 30
4.2..NET 4.2.1. Asunciones y dependencias El propósito de esta sección es explicar el proceso de creación de clientes.net, usando C# y Visual Basic para consumir el Servicio Web de CERTIPASS. Utilizaremos Microsoft Visual Studio 2010 como plataforma de desarrollo, los pasos podrían variar ligeramente para versiones inferiores. 4.2.2. Referencia del Web service El primer paso para crear el cliente del servicio web agregar la referencia del Web Service de CERTIPASS al proyecto en que estará nuestro cliente. El proceso para agregar la referencia es el siguiente: 1) Seleccionar el proyecto al cual consumirá el servicio web : Figura 24 - Ejemplo de agregación de referencia de un servicio web, selección del proyecto 2) Ingresar la URL del Servicio Web de CERTIPASS y especificar el namespace que queremos usar para identificar las clases que se generarán. Página 31
Figura 25 - Ejemplo de creación de referencia de un servicio web, especificación de URL del servico Al realizar el paso anterior, tendremos importadas las clases del Servicio Web al proyecto. 4.2.3. Configuración de la conexión El siguiente paso es configurar la aplicación para que se conecte al Servicio Web. A continuación se muestra un ejemplo del archivo app.config configurado para realizar la conexión. <?xml version="1.0" encoding="utf-8"?> <configuration> <system.servicemodel> <bindings> <wshttpbinding> <binding name="wsbinding" messageencoding="text" maxreceivedmessagesize="2147483647" maxbufferpoolsize="2147483647" textencoding="utf-8" > <readerquotas maxarraylength="2147483647" maxstringcontentlength="2147483647"/> <security mode="transport"> <transport clientcredentialtype="basic" /> <message clientcredentialtype="username" establishsecuritycontext="true"/> </security> </binding> </wshttpbinding> </bindings> <client> <endpoint name="certipassendpoint" address="https://ws.certipass.mx/services" binding="wshttpbinding" bindingconfiguration="wsbinding" Página 32
contract="certipass.certipasssoapws" > <headers> <Wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-secext-1.0.xsd" > <Wsse:UsernameToken> <Wsse:Username>pfg_certipass</Wsse:Username> <Wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-username-token-profile-1.0#passwordtext">0certipass</wsse:password> </Wsse:UsernameToken> </Wsse:Security> </headers> </endpoint> </client> </system.servicemodel> </configuration> Figura 26 - Ejemplo de configuración de conexión en.net Cabe recordar que la URL de producción es https://ws.certipass.mx/services mientras que la URL de Pruebas Beta es https://beta.ws.certipass.mx/services?wsdl A continuación se describe brevemente las partes que componen el código anterior Configuración del Binding que indicará al cliente la forma en la que se transmiten los mensajes al servidor. <bindings> <wshttpbinding> <! Configuración de la encodificación del mensaje y el tamaño máximo permitido--> <binding name="wsbinding" messageencoding="text" maxreceivedmessagesize="2147483647" maxbufferpoolsize="2147483647" textencoding="utf-8" > <readerquotas maxarraylength="2147483647" maxstringcontentlength="2147483647"/> <! Se configura el modo de transferencia de mensajes--> <security mode="transport"> <transport clientcredentialtype="basic" /> <message clientcredentialtype="username" establishsecuritycontext="true"/> </security> </binding> </wshttpbinding> </bindings> Figura 27 - Ejemplo de configuración del binding Configuración del endpoint (con la URL de beta o producción): <! Se configura el endpoint indicando la dirección del servicio web y se usa el binding que se definió anteriormente, así mismo indicamos el nombre del contrato --> <endpoint name="certipassendpoint" address="https://ws.certipass.mx/services" binding="wshttpbinding" bindingconfiguration="wsbinding" contract="certipass.certipasssoapws" > Figura 28 - Ejemplo de configuración del endpoint Configuración de la autenticación del usuario: Página 33
<headers> <--Se define elsecurity header que llevarán las peticiones realizadas al serivio web por el cliente--> <Wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-secext-1.0.xsd" > <--Establecer las credencialesc que usará el cliente para accede al servicio web--> <Wsse:UsernameToken> <Wsse:Username>username</Wsse:Username> <Wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-username-token-profile-1.0#passwordtext">password</wsse:password> </Wsse:UsernameToken> </Wsse:Security> </headers> Figura 29 - Ejemplo de configuración de la autenticación del usuario En este punto ya se tiene todo listo para usar los servicios del servicio web de Certipass, el siguiente paso es crear el cliente. Página 34 4.2.4. Cliente ejemplo en C# A continuación se muestra el código de implementación de un cliente que consume el servicio web de Certipass en C#: using System; using System.Collections.Generic; using System.Linq; using System.Text; using ClientTest.Certipass; using System.ServiceModel; using System.Net; using System.ServiceModel.Channels; namespace ClientTest { class Program { static void Main(string[] args) { //Creamos el proxy que servirá como cliente y le especificamos el endpoint al cual debe apuntar CertipassSOAPWSClient clientproxy = new CertipassSOAPWSClient("CertipassEndpoint"); //Indicamos las credenciales con las que se idenficiará el cliente en el servicio web clientproxy.clientcredentials.username.username = "username"; clientproxy.clientcredentials.username.password = "password"; try { //Se llama a los métodos del Servicio web mediante las clases que importamos cfdiinfowrapper wrapper = new cfdiinfowrapper(); wrapper.uuid = "905b5fec-720e-480c-b679-61d8a3d7c71a";
CfdiInfoResult result = clientproxy.getcfdiinfo(wrapper); Console.WriteLine("Response Code: {0 " + result.responsecode); Console.WriteLine("Response Description: {0 " + result.responsedescription); Console.WriteLine("Request Date {0" + result.requestdate); Console.WriteLine("Response Date: {0 " + result.responsedate); Console.WriteLine("Server transaction ID: {0 " + result.servertransactionid); Console.WriteLine("Transaction ID: {0 " + result.transactionid); Console.WriteLine("Execution Time: {0 " + result.executiontime); Console.WriteLine("CfdiStatus: {0 " + result.cfdistatus); Console.WriteLine("--------------------------------------------------"); Console.WriteLine(result.cfdiStatus); Console.ReadLine(); catch (FaultException<operationFailed> e) { Console.WriteLine("Código de error: " + e.detail.errorcode); Console.WriteLine("Descripción del error: " + e.detail.errordescription); Console.ReadLine(); catch (FaultException e) { Console.WriteLine("Error en la petición: " + e.message); Console.ReadLine(); Figura 30 - Ejemplo de cliente en C#. 4.2.5. Cliente ejemplo en Visual Basic A continuación se muestra el código de implementación de un cliente que consume el servicio web de Certipass en Visual Basic: Imports System.ServiceModel Module Module1 Sub Main() System.Net.ServicePointManager.ServerCertificateValidationCallback = AddressOf AcceptAllCertifications 'Creamos el proxy que servirá como cliente y le especificamos el endpoint al cual debe apuntar Dim clientproxy As Certipass.CertipassSOAPWSClient clientproxy = New Certipass.CertipassSOAPWSClient Dim wrapper As Certipass.cfdiInfoWrapper wrapper = New Certipass.cfdiInfoWrapper Dim result As Certipass.CfdiInfoResult result = New Certipass.CfdiInfoResult Página 35
Try 'Indicamos las credenciales con las que se idenficiará el cliente en el servicio web clientproxy.clientcredentials.username.username = "username" clientproxy.clientcredentials.username.password = "password" 'Se llama a los métodos del Servicio web mediante las clases que importamos wrapper.uuid = "753e9e17-39f2-44f1-91fe-c7c0bec617a0" result = clientproxy.getcfdiinfo(wrapper) Console.WriteLine("Response Code: {0 " + result.responsecode); Console.WriteLine("Response Description: {0 " + result.responsedescription); Console.WriteLine("Execution Time: {0 " + result.executiontime); Console.WriteLine("Request Date {0" + result.requestdate); Console.WriteLine("Response Date: {0 " + result.responsedate); Console.WriteLine("Server transaction ID: {0 " + result.servertransactionid); Console.WriteLine("Transaction ID: {0 " + result.transactionid); Console.WriteLine("CfdiStatus: {0 " + result.cfdistatus); Console.ReadLine() Catch ex As FaultException(Of Certipass.operationFailed) ' Si ocurre algún error se imprime el código y la descripción Console.WriteLine("Código de error: " + ex.detail.errorcode.tostring ) Console.WriteLine("Descripción del error: " + ex.detail.errordescription) Next Console.ReadLine() End Try End Sub Public Function AcceptAllCertifications(ByVal sender As Object, ByVal certifications As System.Security.Cryptography.X509Certificates.X509Certificate, ByVal chain As System.Security.Cryptography.X509Certificates.X509Chain, ByVal sslpolicyerros As System.Net.Security.SslPolicyErrors) As Boolean Return True End Function End Module Figura 31 - Ejemplo de cliente en Visual Basic. Al ejecutar cualquiera de los dos clientes anterior obtendremos obtendrá el siguiente resultado: Figura 32 - Ejemplo de Output del cliente en.net, cuando se consutla un cfdi Página 36
4.3. DELPHI 4.3.1. Asunciones y dependencias Para iniciar el desarrollo del cliente daremos por hecho que el usuario usará Delphi XE6 como IDE. 4.3.2. Unidad CertipassWs El primer paso para crear el cliente del servicio web agregar la definición del Servicio Web de CERTIPASS al proyecto en que estará nuestro cliente, es decir, crear la unidad CertipassWs. El proceso para agregar la referencia es el siguiente: 1. Como Delphi no puede importar automáticamente el XSD en el WSDL con la etiqueta import, se necesita descargar el WSDL desde la url https://ws.certipass.mx/services?wsdl, la estructura del wsdl se muestra en la siguiente imagen: necesitamos reemplazar la parte del wsdl que esta delimitada por el rectángulo azul con el contenido del XSD, el cual podemos descargar desde la url que viene en el atributo schemalocation y esta subrayada con rojo. La estructura del WSDL modificado se muestra en la siguiente imagen. Página 37
La parte delimitada por el rectángulo azul son los elementos que se incrustan manualmente desde el XSD, por cuestiones de tamaño de la imagen solo se muestra una parte del archivo, una vez hecho esto, se guarda el WSDL localmente y se procede a importarlo. 2. Seleccionar el proyecto al cual consumirá el servicio web e ir al menú File>New>other y seleccionar WSDL importer : Página 38
Figura 33 - Ejemplo de la importación del WSDL, parte 1 3. Ingresar la URL del Servicio Web de CERTIPASS y hacer clic en Next dejando las opciones default del Wizard. Página 39
Figura 34 - Ejemplo de la importación del WSDL, parte 2 IMPORTANTE La imagen anterior contiene la url https://ws.certipass.mx/services?wsdl como ubicación del wsdl, pero en este caso se tiene que buscar el wsdl que se generó manualmente en el paso 1, para que Delphi genere correctamente todas las definiciones de clases soap. Al realizar el paso anterior se creará la unidad services con la definición de las clases del Servicio Web de Certipass: Figura 35 - Ejemplo de la estructura del proyecto al terminar de crear la unidad Services Para fines prácticos, renombremos la unidad a CertipassWS. Página 40
Abrimos el archivo que acabamos de renombrar y nos dirigimos hacia las ultimas líneas de este. Ya que estemos ahí, veremos unas líneas como la siguiente. RemClassRegistry.RegisterXSClass(ValidateCfdiWrapper, 'http://ws.certipass.mx/', 'ValidateCfdiWrapper'); Vemos que en el recuadro anterior, el tercer argumento del metodo RegisterXSClass tiene la primera letra coloreada con rojo. Dicha letra se tiene que cambiar de mayúscula a minúscula para que las peticiones soap puedan funcionar de forma correcta. Cabe mencionar que asi como esa línea hay varias mas, a las cuales se les tendrá que hacer el mismo cambio. 4.3.3. Unidad WSSecurity El siguiente paso es añadir al proyecto la unidad WS-Security que contiene la estructura del header de autenticación que usará en las peticiones del cliente : Figura 36 - Ejemplo de como agregar una unidad al proyecto Sobrescribimos el archivo con el siguiente código: unit WSSecurity; Página 41
interface uses SysUtils, InvokeRegistry, SOAPHTTPClient, Types, XSBuiltIns, XMLIntf; const IS_OPTN=$0001; IS_ATTR=$0010; IS_TEXT=$0020; IS_REF =$0080; IS_QUAL=$0100; NS_SECEXT = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd'; NS_UTILITY = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd'; type ttimestampfault=(wsu_messageexpired); Id = type WideString; Created=class(TXSDateTime) end; Expires=class(TXSDateTime) end; Timestamp=class(TRemotable) private FCreated:Created; FExpires:Expires; FId: Id; public destructor Destroy; override; published property Created:Created Index (IS_OPTN) read FCreated write FCreated; property Expires:Expires Index (IS_OPTN) read FExpires write FExpires; property Id:Id Index (IS_ATTR or IS_QUAL) read FId write FId; end; AttributedString=class(TRemotable) private FText:WideString; FId:Id; FId_Specified:boolean; procedure SetId(Index:Integer; const AId:Id); function Id_Specified(Index:Integer):boolean; published property Text:WideString Index (IS_TEXT) read FText write FText; property Id:Id Index (IS_ATTR or IS_OPTN or IS_QUAL) read FId write SetId stored Id_Specified; end; Página 42
Nonce=class(AttributedString) private FEncodingType: WideString; FEncodingType_Specified:boolean; procedure SetEncodingType(Index:Integer; const AWideString:WideString); function EncodingType_Specified(Index:Integer):boolean; published property EncodingType:WideString Index (IS_ATTR or IS_OPTN) read FEncodingType write SetEncodingType stored EncodingType_Specified; end; Password=class(AttributedString) private FType_:WideString; FType Specified:boolean; procedure SetType_(Index:Integer; const AWideString:WideString); function Type Specified(Index:Integer):boolean; published property Type_:WideString Index (IS_ATTR or IS_OPTN) read FType_ write SetType_ stored Type Specified; end; UsernameToken=class(TRemotable) private FUserName:string; FCreated:Created; FPassword:Password; FNonce: Nonce; FId: Id; public destructor Destroy; override; function ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode; override; property Id:Id Index (IS_ATTR or IS_QUAL) read FId write FId; published property Username:String read FUsername write FUsername; property Password:Password read FPassword write FPassword; property Nonce: Nonce read FNonce write FNonce; property Created:Created index (IS_REF) read FCreated write FCreated; end; Security=class(TSOAPHeader) private FUserNameToken:UserNameToken; public destructor Destroy; override; Página 43
published property UsernameToken:UsernameToken index (IS_REF) read FUserNameToken write FUserNameToken; end; implementation destructor Timestamp.Destroy; begin FreeAndNIL(FCreated); FreeAndNIL(FExpires); inherited Destroy; end; destructor UsernameToken.Destroy; begin FreeAndNil(FCreated); FreeAndNil(FPassword); FreeAndNil(FNonce); inherited Destroy; end; function UsernameToken.ObjectToSOAP(RootNode, ParentNode: IXMLNode; const ObjConverter: IObjConverter; const NodeName, NodeNamespace, ChildNamespace: InvString; ObjConvOpts: TObjectConvertOptions; out RefID: InvString): IXMLNode; begin Result := inherited; if (Result <> nil) and (Length(FId) > 0) then begin Result.DeclareNamespace('wsu', NS_UTILITY); Result.SetAttributeNS('Id', NS_UTILITY, FId); end; end; procedure AttributedString.SetId(Index:Integer; const AId:Id); begin FId:=AId; FId_Specified:=True; end; function AttributedString.Id_Specified(Index:Integer):boolean; begin Result:=FId_Specified; end; procedure Password.SetType_(Index:Integer; const AWideString:WideString); begin FType_:=AWideString; FType Specified:=True; end; Página 44
function Password.Type Specified(Index:Integer):boolean; begin Result:=FType Specified; end; procedure Nonce.SetEncodingType(Index:Integer; const AWideString:WideString); begin FEncodingType:=AWideString; FEncodingType_Specified:=True; end; function Nonce.EncodingType_Specified(Index:Integer):boolean; begin Result:=FEncodingType_Specified; end; destructor Security.Destroy; begin FreeAndNIL(FUserNameToken); inherited Destroy; end; initialization RemClassRegistry.RegisterXSClass(Security, NS_SECEXT, 'Security'); RemClassRegistry.RegisterXSClass(UsernameToken, NS_SECEXT, 'UsernameToken'); RemClassRegistry.RegisterXSClass(Password, NS_SECEXT, 'Password'); RemClassRegistry.RegisterXSInfo(TypeInfo(Nonce), NS_SECEXT, 'Nonce'); RemClassRegistry.RegisterXSInfo(TypeInfo(tTimestampFault), NS_UTILITY, 'ttimestampfault'); RemClassRegistry.RegisterExternalPropName(TypeInfo(tTimestampFault), 'wsu_messageexpired', 'wsu:messageexpired'); RemClassRegistry.RegisterXSInfo(TypeInfo(Id), NS_UTILITY, 'Id'); RemClassRegistry.RegisterXSClass(AttributedString, NS_SECEXT, 'AttributedString'); RemClassRegistry.RegisterExternalPropName(TypeInfo(Password), 'Type_', 'Type'); end. Figura 37 - Código de la unidad WSSecurity 4.3.4. Unidad Client A continuación se muestra el código de implementación de una unidad cliente que llama a los métodos del servicio web de Certipass (en el ejemplo se usa la URL de producción, no de beta) : unit Client; interface uses Página 45
certipasswsdl, xmldom,wssecurity, Soap.InvokeRegistry, Soap.Rio, Soap.SOAPHTTPClient,Xml.XMLIntf,Soap.XSBuiltIns; type TClient=Class published const //Las credenciales para autenticarse en Certipass stusername = 'pfg_certipass'; stpassword = '0certipass'; var stwebserviceproxy:certipasssoapws; constructor Create(); procedure addsecurityheader(service: CertipassSOAPWS); function cancelcfdi(transactionid:string; uuid:string; signaturevalue:string; canceldate:txsdatetime):cfdicancelresult; end; implementation //Configuración del endpoint constructor TClient.Create; var sthttprio1: THTTPRIO; begin sthttprio1:=thttprio.create(nil); sthttprio1.url:='https://ws.certipass.mx/services'; sthttprio1.wsdllocation:='https://ws.certipass.mx/services?wsdl'; //Se obtiene la instancia del webservice stwebserviceproxy:=getcertipasssoapws(true,sthttprio1.wsdllocation,sthttprio1); //Se agrega el SegurityHeader addsecurityheader(stwebserviceproxy); end; Página 46 //Configuración del Header de seguridad procedure TClient.addSecurityHeader(Service: CertipassSOAPWS); var Header: Security; Headers: ISOAPHeaders; begin Header := Security.Create; Header.MustUnderstand := false; Header.UsernameToken := UsernameToken.Create; Header.UsernameToken.Id := 'UsernameToken'; Header.UsernameToken.Username := TClient.stUsername; Header.UsernameToken.Password := Password.Create; Header.UsernameToken.Password.Type_ :='http://docs.oasis-
open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#passwordtext'; Header.UsernameToken.Password.Text := TClient.stPassword; Header.UsernameToken.Nonce := Nonce.Create; Header.UsernameToken.Nonce.EncodingType :='http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#base64binary'; Header.UsernameToken.Created := Created.Create; Headers := (Service as ISOAPHeaders); Headers.OwnsSentHeaders := True; Headers.Send(Header); end; // Llamada al método getcfdicancel de Certipass web service function TClient.cancelCfdi (transactionid:string; uuid:string; signaturevalue:string; canceldate:txsdatetime):cfdicancelresult; var stwrapper:cfdicancelwrapper; begin stwrapper:= CfdiCancelWrapper.Create; stwrapper.uuid:=uuid; stwrapper.transactionid:= transactionid; stwrapper.signaturevalue:= signaturevalue; stwrapper.canceldate:=canceldate; Result:= stwebserviceproxy.cancelcfdi(stwrapper); end; end. Figura 38 - Ejemplo de una unidad Cliente que hace llamadas a los métodos del Servicio web de CERTIPASS A continuación se describe brevemente las partes que componen el código anterior 1. Definición de la clase type TClient=Class published const //Las credenciales para autenticarse en Certipass stusername = 'username'; stpassword = 'password'; var stwebserviceproxy:certipasssoapws; constructor Create(); procedure addsecurityheader(service: CertipassSOAPWS); function cancelcfdi(transactionid:string; uuid:string; signaturevalue:string; canceldate:txsdatetime):cfdicancelresult; end; Figura 39 - Ejemplo de la sección de definición de una clase 2. Implementación de los procedure y functions: Página 47
implementation //Configuración del endpoint constructor TClient.Create; var sthttprio1: THTTPRIO; begin sthttprio1:=thttprio.create(nil); sthttprio1.url:='https://ws.certipass.mx/services'; sthttprio1.wsdllocation:='https://ws.certipass.mx/services?wsdl'; //Se obtiene la instancia del webservice stwebserviceproxy:=getcertipasssoapws(true,sthttprio1.wsdllocation,sthttprio1); //Se agrega el SegurityHeader addsecurityheader(stwebserviceproxy); end; //Configuración del Header de seguridad procedure TClient.addSecurityHeader(Service: CertipassSOAPWS); var Header: Security; Headers: ISOAPHeaders; begin Header := Security.Create; Header.MustUnderstand := false; Header.UsernameToken := UsernameToken.Create; Header.UsernameToken.Id := 'UsernameToken'; Header.UsernameToken.Username := TClient.stUsername; Header.UsernameToken.Password := Password.Create; Header.UsernameToken.Password.Type_ :='http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#passwordtext'; Header.UsernameToken.Password.Text := TClient.stPassword; Header.UsernameToken.Nonce := Nonce.Create; Header.UsernameToken.Nonce.EncodingType :='http://docs.oasisopen.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#base64binary'; Header.UsernameToken.Created := Created.Create; Headers := (Service as ISOAPHeaders); Headers.OwnsSentHeaders := True; Headers.Send(Header); end; // Llamada al método getcfdicancel de Certipass web service function TClient.cancelCfdi (transactionid:string; uuid:string; signaturevalue:string; canceldate:txsdatetime):cfdicancelresult; var stwrapper:cfdicancelwrapper; begin stwrapper:= CfdiCancelWrapper.Create; stwrapper.uuid:=uuid; stwrapper.transactionid:= transactionid; stwrapper.signaturevalue:= signaturevalue; stwrapper.canceldate:=canceldate; Página 48
Result:= stwebserviceproxy.cancelcfdi(stwrapper); end; end. Figura 40 - Ejemplo de la sección de implementación de una clase 4.3.5. Cliente ejemplo El último paso es usar las unidades que se definieron anteriormente para consumir el Servicio Web. A continuación se muestra un ejemplo de cómo realizarlo: program Project1; {$APPTYPE CONSOLE {$R *.res uses System.SysUtils,Soap.XSBuiltIns, CertipassWs in 'CertipassWs.pas', WSSecurity in 'WSSecurity.pas', Client in 'Client.pas',ActiveX,Windows,InvokeRegistry; var proxy:tclient; userexit:string; //Variable de apoyo para evitar que la consola se cierre cuando se completa el proceso consultresult:cfdicancelresult; date:txsdatetime; begin date:=txsdatetime.create(); date.xstonative('2014-12-01t00:00:00'); CoInitialize(nil); //Inicialización del cliente proxy:=tclient.create; //Inicialización del objeto que guardará la respuesta consultresult:=cfdicancelresult.create; WriteLn('Cliente creado'); try //Llamada al método que se definio en la unidad Client consultresult:=proxy.cancelcfdi('tran1';'d170f2c1-885f-4a64-95ec-5a22e75d07a4'; 'signaturevalue';date); WriteLn('Código de Respuesta: '+consultresult.responsecode.tostring()); WriteLn('Descripción de Respuesta: '+consultresult.responsedescription); WriteLn('ID de transacción: '+consultresult.transactionid); WriteLn('ID de transacción en el Servidor: '+consultresult.servertransactionid); WriteLn('Fecha de Solicitud: '+DateTimeToStr(consultResult.requestDate.AsDateTime)); WriteLn('Fecha de Respuesta: '+ DateTimeToStr(consultResult.responseDate.AsDateTime); WriteLn('Tiempo de Ejecución: '+consultresult.executiontime.tostring()); ReadLn(userExit); Página 49
except on E: ERemotableException do begin Writeln('Error '+E.FaultDetail); ReadLn(userExit); end; end; end. Figura 41 - Ejemplo de cliente en Delphi Al ejecutar el proyecto obtendremos obtendrá el siguiente resultado: Figura 42 - Ejemplo de Output del cliente en Delphi, cuando se quiere cancelar un CFDI que no existe 4.4. Python 4.4.1. Asunciones y dependencias El propósito de este documento es describir el proceso de creación de clientes en python para consumir el Servicio Web de CERTIPASS. Para iniciar el desarrollo es necesario contar con: 1. IDE Eclipse. 2. Pydev, Plugin para el desarrollo de Python en Eclipse. 3. Archivo Suds, librería de Python para el desarrollo den clientes de web services. 4. La herramienta Cygwin para extraer los archivos.py de la librería Suds. 4.4.1.1. Librería Suds El primer paso para crear el cliente del servicio web agregar la librería Suds. El proceso para agregar la librería es el siguiente: 3.1. Obtener los archivos.py de la librería Suds, extrayéndolos del archivo python-suds- 0.4.tar.gz.En la herramienta Cygwin,ubicados en el directorio donde se encuentra el archivo.gz (Ejemplo, disco X ) y ejecutamos el siguiente comando. tar xvf python-suds-0.4.tar.gz Figura 43 - Ejemplo de comando para obtener los archivos de la librería Suds Ejemplo Página 50
Figura 44 - Ejemplo de ejecución del comando para obtener los archivos de la librería suds Al ejecutar el comando anterior tendremos la siguiente estructura de carpetas creada: Figura 45 - Ejemplo de salida del comando anterior 4. Agregar la carpeta suds al proyecto. Página 51
Figura 46 - Ejemplo de la estructura del proyecto al agregar los archivos de la librería suds Al realizar el paso anterior ya podremos usar las clases de la librería para realizar el cliente del Web Service del pac. 4.4.2. WsSecurity El siguiente paso es crear la clase que realizará la autenticación del cliente al Servicio Web. A continuación se muestra un ejemplo de cómo realizarlo: #importamos la clase Element de suds.wsse from suds.wsse import Element class WsSecurityHeader(object): def init (self): #do nothing pass ''' Método que crear el Security header necesario para autenticar al cliente al Web service Página 52
''' def getsecurityheader(self,username,password): #Define del namespace wsns=('wsse','http://docs.oasis-open.org/wss/2004/01/oasis-200401- wss-wssecurity-secext-1.0.xsd') ##Crea el elemento Security security=element('security',ns=wsns) #Crea del usernametoken usernametoken=element('usernametoken',ns=wsns) username=element('username',ns=wsns).settext(username) password=element('password',ns=wsns).settext(password) password.set('type', 'http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-username-token-profile-1.0#PasswordText') #Agrega el username y el password al usernametoken usernametoken.insert(username) usernametoken.insert(password) #Agrega el usernametoken al Security security.insert(usernametoken) return security Figura 47 - Código de la clase WsSecurityHeader 4.4.3. Cliente ejemplo A continuación se muestra el código de implementación de un cliente que consume los métodos del servicio web de Certipass (en el ejemplo se usa la URL de producción no de beta): if name == ' main ': from suds.client import Client,WebFault from ws.wssecurity import WsSecurityHeader try: #URL del webservice url='https://ws.certipass.mx/services?wsdl' #Se crea el proxy del Web service client=client(url) #Se agrega el security header con el username y password para la autenticación secureheader=wssecurityheader().getsecurityheader('pac_certipass','mdybbl wm') client.set_options(soapheaders=secureheader) #Se usan los métodos y objetos propios del Web service de CERTIPASS wrapper=client.factory.create('cfdicancelwrapper') wrapper.uuid='e08b6418-5f55-428a-b5eb-d469531ada1b' wrapper.transactionid='tic1' timez=time.strftime('%y-%m-%dt%h:%m:%s') wrapper.cancelationdate=timez inforesult=client.factory.create('cfdicancelresult') inforesult=client.service.getcfdiinfo(wrapper) print inforesult except WebFault as detail: error= detail.fault.detail.operationfailed Página 53
pass print error.errorcode+': '+error.errordescription Figura 48 - Ejemplo de un Cliente que hace llamadas a los métodos del Servicio web de CERTIPASS Al ejecutar el proyecto se obtendrá el siguiente resultado: (CfdiCancelResult){ responsecode = 202 responsedescription = UUID previamente cancelado transactionid = TIC1 servertransactionid = 6396 requestdate = 2014-11-20 13:14:41 responsedate = 2014-11-20 13:14:41.000658 executiontime = 658 Figura 49 - Ejemplo de Output del cliente en Python, cuando se quiere cancelar un CFDI que ya ha sido cancelado 4.5. PHP 4.5.1. Asunciones y dependencias El propósito de esta sección es explicar el proceso de creación de clientes PHP para consumir el Servicio Web de CERTIPASS. Se utilizará notepad++ como IDE para el desarrollo, el motor de php versión 5.5.17 y la línea de comandos de Windows. A continuación se muestra un cliente ejemplo desarrollado en php. 4.5.2. Cliente Ejemplo 4.5.2.1. Clase CertipassClient A continuación se muestra el código de la clase CertipassClient que se conecta al web service de certipass. En el ejemplo se usa la URL de producción. <?php class CertipassClient { protected $soapclient; protected $responsecode; protected $responsedescription; protected $transactionid; protected $servertransactionid; protected $requestdate; protected $responsedate; protected $executiontime; Página 54
private $wsseuser; private $wssepassword; protected $wsseheader; protected $soapresult; //Constructor que inicializa el objeto. public function construct($wsseuser, $wssepassword) { $this->wsseuser = $wsseuser; $this->wssepassword = $wssepassword; $this->initializewsse(); $this->initializesoapclient(); //En este método inicializamos el header para implementar wsse en //el cliente. private function initializewsse() { $this->wsseheader = '<wsse:security env:mustunderstand="1" xmlns:soap- ENV="http://schemas.xmlsoap.org/soap/envelope/" '. ' xmlns:soap="http://sc hemas.xmlsoap.org/soap/envelope/" '. ' xmlns:wsu="http://docs.oasis- open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility- 1.0.xsd"'. ' xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis- 200401-wss-wssecurity-secext- 1.0.xsd"> '. ' <wsse:usernametoken><wsse:username>'. $this->wsseuser. '</wsse:username> '. ' <wsse:password Type="http://docs.oasisopen.org/wss/2004/01/oasis-200401-'. 'wss-username-token-profile- 1.0#PasswordText">'. $this->wssepassword. '</wsse:password></wsse:usernametoken></wsse:security>'; $this->wsseheader = new SoapVar($this->wsseHeader, XSD_ANYXML); //En esta parte dejamos listo el SoapHeader que vamos a utilizar //cada vez que hagamos un request con el cliente Soap. $this->wsseheader = new SoapHeader('http://docs.oasis- open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext- 1.0.xsd', 'Security', $this->wsseheader, true); //En este método inicializamos el cliente soap con sus respectivos //parámetros: //Url del wsdl, versión de soap:1_2, //le especificamos que no ponga en cache el wsdl, //y le indicamos que utilizará ssl como método de encryptamiento. private function initializesoapclient() { $this- >soapclient = new SoapClient('https://ws.certipass.mx/services?wsdl', array Página 55
( 'soap_version' => SOAP_1_2, 'cache_wsdl' => WSDL_CACHE_NONE, 'ssl_method' => SOAP_SSL_METHOD_TLS )); //Método que devuelve el código de respuesta. public function getresponsecode() { return $this->responsecode; //Método que devuelve la descripción de la respuesta. public function getresponsedescription() { return $this->responsedescription; //Método que devuelve el transaction id. public function gettransactionid() { return $this->transactionid; //Método que devuelve server transaction id. public function getservertransactionid() { return $this->servertransactionid; //Método que devuelve el requestdate. public function getrequestdate() { return $this->requestdate; //Método que devuelve el responsedate. public function getresponsedate() { return $this->responsedate; //Método que devuelve el executiontime. public function getexecutiontime() { return $this->executiontime;?> Figura 50 Ejemplo de clase base para la implementación de la funcionalidad básica del cliente soap. De esta clase se tienen que heredar subclases para cada una de las funciones que ofrece el web service, se muestra un ejemplo de la operación cfdiinfo. Página 56
4.5.2.2. Clase CfdiInfoWrapper A continuación se muestra el código de la clase CfdiInfoWrapper. La cual extiende a CertipassClient e implementa métodos y propiedades llamar a la función cfdiinfo del web service. <?php include_once( DIR. DIRECTORY_SEPARATOR. 'CertipassClient.php'); class CfdiInfoWrapper extends CertipassClient { private $cfdi; private $uuid; private $cfdistatus; public function construct($wsseuser, $wssepassword) { //Se construye el padre de la clase(certipassclient) parent:: construct($wsseuser, $wssepassword); //En este método ingresamos los parámetros y los headers, //al cliente soap y llamamos a la operación del web service //que deseamos, que en este caso es getcfdiinfo. public function getcfdiinfo($uuid) { try { //Arreglo que se va a utilizar para ingresar el wrapper //específico de esta operación(cfdiinfowrapper), a la //solicitud soap. $param = array(); //Arreglo que se va a utilizar para ingresar los //parámetros que se necesitan para el web service $parametros = array(); $parametros[] = new SoapVar($uuid, XSD_STRING, null, null, 'ns1:uuid'); $param[] = new SoapVar($parametros, SOAP_ENC_OBJECT, null, null, 'ns1:cfdiinfowrapper'); //Agregamos el header wsse el se construye en la clase //padre una vez que llamamos a su constructor. $this->soapclient-> setsoapheaders($this->wsseheader); //Realizamos la llamada soap $this->soapresult = $this->soapclient->getcfdiinfo( new SoapVar($param, SOAP_ENC_OBJECT)); Página 57
//Obtenemos cada una de las propiedades de la respuesta //enviada por el webservice. $this->responsecode = $this->soapresult->return->responsecode; $this->responsedescription = $this->soapresult->return->responsedescription; $this->transactionid = $this->soapresult->return-> transactionid ; $this->servertransactionid = $this->soapresult->return-> servertransactionid ; $this->requestdate = $this->soapresult->return-> requestdate ; $this->responsedate = $this->soapresult->return-> responsedate ; $this->executiontime = $this->soapresult->return-> executiontime ; $this->cfdi = isset($this->soapresult->return->cfdi)? $this->soapresult->return->cfdi : ''; $this->uuid = isset($this->soapresult->return->uuid)? $this->soapresult->return->uuid : ''; $this->cfdistatus = isset($this->soapresult->return->cfdistatus)? $this->soapresult->return->cfdistatus : ''; catch (SoapFault $e) { //En esta parte se manejan las excepciones mandadas por //el web service. if(isset($e->detail->operationfailed)) { echo('codigo de Error:'. $e->detail->operationfailed->errorcode."\n"); echo('descripcion de Error:'. $e->detail->operationfailed->errordescription."\n"); echo('id de Transaccion:'. $e->detail->operationfailed- >servertransactionid."\n"); echo('fecha de Solicitud:'. $e->detail->operationfailed->requestdate."\n"); echo('fecha de Respuesta:'. $e->detail->operationfailed->responsedate."\n"); echo('tiempo de Ejecucion:'. $e->detail->operationfailed->executiontime."\n"); else { echo('codigo de Error:'. $e->getcode()."\n"); echo('descripcion de Error:'. $e->detail->getmessage()."\n"); Página 58
//Métodos que retornan el valor de cada uno de los parámetros. //de respuesta enviados por el webservice. public function getcfdi() { return $this->cfdi; public function getuuid() { return $this->uuid; public function getcfdistatus() { return $this->cfdistatus;?> Figure 51 Ejemplo de una subclase heredada de la clase base CertipassClient la cual es utilizada para obtener la información de un cfdi. 4.5.2.3. Consulta de cfdi utilizando la clase CfdiInfoWrapper Se ejecuta el siguiente script php: <?php include_once( DIR. DIRECTORY_SEPARATOR. 'CfdiInfoWrapper.php'); $user='username'; $password='password'; $uuid='uuid'; $cfdi_info= new CfdiInfoWrapper($user,$password); $cfdi_info->getcfdiinfo($uuid); echo ($cfdi_info->getresponsecode()); echo ("\n"); echo ($cfdi_info->getresponsedescription()); echo ("\n"); echo ($cfdi_info->getservertransactionid()); echo ("\n"); echo ($cfdi_info->getrequestdate()); echo ("\n"); echo ($cfdi_info->getresponsedate()); echo ("\n"); echo ($cfdi_info->getexecutiontime());?> Página 59
Figure 52 Ejemplo de script para ejecutar el client php. En esta sección muestra como utilizar la clase CfdiInfoWrapper desde el script php anterior. Figura 53 Ejemplo de como ejecutar el script php en la línea de comandos de Windows. A continuación se muestra la respuesta que manda el web service al ejecutar el script. Figura 54 Datos de salida devueltos el script ejecutado. Página 60