1 | ' Ejemplo de Uso de Interface COM con Web Service Factura Electrónica Exportación AFIP |
---|
2 | ' RG2758 Version 1 (V.1) |
---|
3 | ' 2011 (C) Mariano Reingart <reingart@gmail.com> |
---|
4 | |
---|
5 | Sub Main() |
---|
6 | Dim WSAA As Object, WSFEXv1 As Object |
---|
7 | |
---|
8 | On Error GoTo ManejoError |
---|
9 | Set WSAA = CreateObject("WSAA") |
---|
10 | |
---|
11 | ' inicializo las variables: |
---|
12 | token = "" |
---|
13 | sign = "" |
---|
14 | |
---|
15 | ' busco un ticket de acceso previamente almacenado: |
---|
16 | If Dir("ta.xml") <> "" Then |
---|
17 | ' leo el xml almacenado del archivo |
---|
18 | Open "ta.xml" For Input As #1 |
---|
19 | Line Input #1, ta_xml |
---|
20 | Close #1 |
---|
21 | ' analizo el ticket de acceso previo: |
---|
22 | ok = WSAA.AnalizarXml(ta_xml) |
---|
23 | If Not WSAA.Expirado() Then |
---|
24 | ' puedo reusar el ticket de acceso: |
---|
25 | token = WSAA.ObtenerTagXml("token") |
---|
26 | sign = WSAA.ObtenerTagXml("sign") |
---|
27 | End If |
---|
28 | End If |
---|
29 | |
---|
30 | ' Si no reuso un ticket de acceso, solicito uno nuevo: |
---|
31 | If token = "" Or sign = "" Then |
---|
32 | ' Generar un Ticket de Requerimiento de Acceso (TRA) |
---|
33 | tra = WSAA.CreateTRA("wsfex", 43200) ' 3600*12hs |
---|
34 | |
---|
35 | Path = WSAA.InstallDir + "\" |
---|
36 | |
---|
37 | ' Especificar la ubicacion de los archivos certificado y clave privada |
---|
38 | cert = "reingart.crt" ' certificado de prueba |
---|
39 | clave = "reingart.key" ' clave privada de prueba |
---|
40 | ' Generar el mensaje firmado (CMS) |
---|
41 | cms = WSAA.SignTRA(tra, Path + cert, Path + clave) |
---|
42 | If cms <> "" Then |
---|
43 | ' Llamar al web service para autenticar (cambiar URL para produccion): |
---|
44 | wsdl = "https://wsaahomo.afip.gov.ar/ws/services/LoginCms?wsdl" |
---|
45 | ok = WSAA.Conectar("", wsdl) |
---|
46 | ta_xml = WSAA.LoginCMS(cms) |
---|
47 | If ta_xml <> "" Then |
---|
48 | ' guardo el ticket de acceso en el archivo |
---|
49 | Open "ta.xml" For Output As #1 |
---|
50 | Print #1, ta_xml |
---|
51 | Close #1 |
---|
52 | End If |
---|
53 | token = WSAA.token |
---|
54 | sign = WSAA.sign |
---|
55 | End If |
---|
56 | ' reviso que no haya errores: |
---|
57 | Debug.Print "Excepcion:", WSAA.Excepcion |
---|
58 | If WSAA.Excepcion <> "" Then |
---|
59 | Debug.Print WSAA.Traceback |
---|
60 | End If |
---|
61 | |
---|
62 | End If |
---|
63 | |
---|
64 | ' Imprimir los datos del ticket de acceso: ToKen y Sign de autorización |
---|
65 | Debug.Print "Token: " + token |
---|
66 | Debug.Print "Sign: " + sign |
---|
67 | |
---|
68 | ' Una vez obtenido, se puede usar el mismo token y sign por 24 horas |
---|
69 | ' (este perÃodo se puede cambiar) |
---|
70 | |
---|
71 | ' Crear objeto interface Web Service de Factura Electrónica de Exportación |
---|
72 | Set WSFEXv1 = CreateObject("WSFEXv1") |
---|
73 | Debug.Print WSFEXv1.Version |
---|
74 | |
---|
75 | ' Setear tocken y sing de autorización (pasos previos) |
---|
76 | WSFEXv1.token = token |
---|
77 | WSFEXv1.sign = sign |
---|
78 | |
---|
79 | ' CUIT del emisor (debe estar registrado en la AFIP) |
---|
80 | WSFEXv1.Cuit = "20267565393" |
---|
81 | |
---|
82 | ' Conectar al Servicio Web de Facturación V1 |
---|
83 | wsdl_url = "https://wswhomo.afip.gov.ar/wsfexv1/service.asmx?WSDL" |
---|
84 | ok = WSFEXv1.Conectar(cache, wsdl_url) ' homologación |
---|
85 | |
---|
86 | ' Llamo a un servicio nulo, para obtener el estado del servidor (opcional) |
---|
87 | WSFEXv1.Dummy |
---|
88 | Debug.Print "appserver status", WSFEXv1.AppServerStatus |
---|
89 | Debug.Print "dbserver status", WSFEXv1.DbServerStatus |
---|
90 | Debug.Print "authserver status", WSFEXv1.AuthServerStatus |
---|
91 | |
---|
92 | ' Establezco los valores de la factura a autorizar: |
---|
93 | tipo_cbte = 19 ' FC Expo (ver tabla de parámetros) |
---|
94 | punto_vta = 7 |
---|
95 | ' Obtengo el último número de comprobante y le agrego 1 |
---|
96 | cbte_nro = WSFEXv1.GetLastCMP(tipo_cbte, punto_vta) + 1 '16 |
---|
97 | |
---|
98 | fecha_cbte = Format(Date, "yyyymmdd") |
---|
99 | tipo_expo = 1 ' tipo de exportación (ver tabla de parámetros) |
---|
100 | permiso_existente = "N" |
---|
101 | dst_cmp = 235 ' paÃs destino |
---|
102 | cliente = "Joao Da Silva" |
---|
103 | cuit_pais_cliente = "50000000016" |
---|
104 | domicilio_cliente = "Rua N°76 km 34.5 Alagoas" |
---|
105 | id_impositivo = "PJ54482221-l" |
---|
106 | moneda_id = "DOL" ' para reales, "DOL" o "PES" (ver tabla de parámetros) |
---|
107 | moneda_ctz = "1400.00" |
---|
108 | obs_comerciales = "Observaciones comerciales" |
---|
109 | obs = "Sin observaciones" |
---|
110 | forma_pago = "takataka" |
---|
111 | incoterms = "FOB" ' (ver tabla de parámetros) |
---|
112 | incoterms_ds = "Info complementaria" ' (opcional) Nuevo! 20 caracteres |
---|
113 | idioma_cbte = 1 ' (ver tabla de parámetros) |
---|
114 | imp_total = "15000.00" |
---|
115 | fecha_pago = "" ' Format(Date, "yyyymmdd") |
---|
116 | cancela_misma_moneda_ext = "N" |
---|
117 | |
---|
118 | ' Creo una factura (internamente, no se llama al WebService): |
---|
119 | ok = WSFEXv1.CrearFactura(tipo_cbte, punto_vta, cbte_nro, fecha_cbte, _ |
---|
120 | imp_total, tipo_expo, permiso_existente, dst_cmp, _ |
---|
121 | cliente, cuit_pais_cliente, domicilio_cliente, _ |
---|
122 | id_impositivo, moneda_id, moneda_ctz, _ |
---|
123 | obs_comerciales, obs, forma_pago, incoterms, _ |
---|
124 | idioma_cbte, incoterms_ds, fecha_pago, _ |
---|
125 | cancela_misma_moneda_ext) |
---|
126 | |
---|
127 | ' Agrego un item: |
---|
128 | codigo = "PRO1" |
---|
129 | ds = "Producto Tipo 1 Exportacion MERCOSUR ISO 9001" |
---|
130 | qty = 1 |
---|
131 | precio = "15000.00" |
---|
132 | umed = 1 ' Ver tabla de parámetros (unidades de medida) |
---|
133 | imp_total = "15000.00" ' importe total final del artÃculo |
---|
134 | bonif = "0" ' Nuevo! |
---|
135 | ' lo agrego a la factura (internamente, no se llama al WebService): |
---|
136 | ok = WSFEXv1.AgregarItem(codigo, ds, qty, umed, precio, imp_total, bonif) |
---|
137 | 'ok = WSFEXv1.AgregarItem(codigo, ds, qty, umed, precio, imp_total, bonif) |
---|
138 | 'ok = WSFEXv1.AgregarItem(codigo, "Descuento", 0, 99, 0, "-250.00", 0) |
---|
139 | 'ok = WSFEXv1.AgregarItem("--", "texto adicional", 0, 0, 0, 0, 0) |
---|
140 | |
---|
141 | ' Agrego un permiso (ver manual para el desarrollador) |
---|
142 | If permiso_existente = "S" Then |
---|
143 | id = "99999AAXX999999A" |
---|
144 | dst = 225 ' paÃs destino de la mercaderia |
---|
145 | ok = WSFEXv1.AgregarPermiso(id, dst) |
---|
146 | End If |
---|
147 | |
---|
148 | ' Agrego un comprobante asociado (ver manual para el desarrollador) |
---|
149 | If tipo_cbte <> 19 Then |
---|
150 | tipo_cbte_asoc = 19 |
---|
151 | punto_vta_asoc = 2 |
---|
152 | cbte_nro_asoc = 1 |
---|
153 | cuit_asoc = "20111111111" ' CUIT Asociado Nuevo! |
---|
154 | ok = WSFEXv1.AgregarCmpAsoc(tipo_cbte_asoc, punto_vta_asoc, cbte_nro_asoc, cuit_asoc) |
---|
155 | End If |
---|
156 | |
---|
157 | 'id = "99000000000100" ' número propio de transacción |
---|
158 | ' obtengo el último ID y le adiciono 1 (advertencia: evitar overflow!) |
---|
159 | id = CStr(CDec(WSFEXv1.GetLastID()) + CDec(1)) |
---|
160 | |
---|
161 | ' Deshabilito errores no capturados: |
---|
162 | WSFEXv1.LanzarExcepciones = False |
---|
163 | |
---|
164 | ' Llamo al WebService de Autorización para obtener el CAE |
---|
165 | CAE = WSFEXv1.Authorize(CDec(id)) |
---|
166 | |
---|
167 | If WSFEXv1.Excepcion <> "" Then |
---|
168 | MsgBox WSFEXv1.Traceback, vbExclamation, WSFEXv1.Excepcion |
---|
169 | End If |
---|
170 | If WSFEXv1.ErrMsg <> "" And WSFEXv1.ErrCode <> "0" Then |
---|
171 | MsgBox WSFEXv1.ErrMsg, vbExclamation, "Error de AFIP" |
---|
172 | End If |
---|
173 | |
---|
174 | ' Verifico que no haya rechazo o advertencia al generar el CAE |
---|
175 | If CAE = "" Or WSFEXv1.Resultado <> "A" Then |
---|
176 | MsgBox "No se asignó CAE (Rechazado). Observación (motivos): " & WSFEXv1.obs, vbInformation + vbOKOnly |
---|
177 | ElseIf WSFEXv1.obs <> "" And WSFEXv1.obs <> "00" Then |
---|
178 | MsgBox "Se asignó CAE pero con advertencias. Observación (motivos): " & WSFEXv1.obs, vbInformation + vbOKOnly |
---|
179 | End If |
---|
180 | |
---|
181 | Debug.Print "Numero de comprobante:", WSFEXv1.CbteNro |
---|
182 | |
---|
183 | ' Imprimo pedido y respuesta XML para depuración (errores de formato) |
---|
184 | Debug.Print WSFEXv1.XmlRequest |
---|
185 | Debug.Print WSFEXv1.XmlResponse |
---|
186 | Debug.Assert False |
---|
187 | |
---|
188 | MsgBox "Resultado:" & WSFEXv1.Resultado & " CAE: " & CAE & " Venc: " & WSFEXv1.Vencimiento & " Reproceso: " & WSFEXv1.Reproceso & " Obs: " & WSFEXv1.obs, vbInformation + vbOKOnly |
---|
189 | |
---|
190 | ' Muestro los eventos (mantenimiento programados y otros mensajes de la AFIP) |
---|
191 | For Each evento In WSFEXv1.Eventos |
---|
192 | If evento <> "0: " Then |
---|
193 | MsgBox "Evento: " & evento, vbInformation |
---|
194 | End If |
---|
195 | Next |
---|
196 | |
---|
197 | ' vuelvo a habilitar el control de errores tradicional |
---|
198 | WSFEXv1.LanzarExcepciones = True |
---|
199 | |
---|
200 | ' Buscar la factura |
---|
201 | cae2 = WSFEXv1.GetCMP(tipo_cbte, punto_vta, cbte_nro) |
---|
202 | |
---|
203 | Debug.Print "Fecha Comprobante:", WSFEXv1.FechaCbte |
---|
204 | Debug.Print "Fecha Vencimiento CAE", WSFEXv1.Vencimiento |
---|
205 | Debug.Print "Importe Total:", WSFEXv1.ImpTotal |
---|
206 | Debug.Print WSFEXv1.XmlResponse |
---|
207 | |
---|
208 | If CAE <> cae2 Then |
---|
209 | MsgBox "El CAE de la factura no concuerdan con el recuperado en la AFIP!" |
---|
210 | Else |
---|
211 | MsgBox "El CAE de la factura concuerdan con el recuperado de la AFIP" |
---|
212 | End If |
---|
213 | |
---|
214 | ' analizo la respuesta xml para obtener campos especÃficos: |
---|
215 | If WSFEXv1.Version >= "1.06a" Then |
---|
216 | ok = WSFEXv1.AnalizarXml("XmlResponse") |
---|
217 | If ok Then |
---|
218 | Debug.Print "CAE:", WSFEXv1.ObtenerTagXml("Cae"), WSFEXv1.CAE |
---|
219 | Debug.Print "CbteFch:", WSFEXv1.ObtenerTagXml("Fecha_cbte"), WSFEXv1.FechaCbte |
---|
220 | Debug.Print "Moneda:", WSFEXv1.ObtenerTagXml("Moneda_Id") |
---|
221 | Debug.Print "Cotizacion:", WSFEXv1.ObtenerTagXml("Moneda_ctz") |
---|
222 | Debug.Print "Cuit_pais_cliente:", WSFEXv1.ObtenerTagXml("Cuit_pais_cliente") |
---|
223 | Debug.Print "Id_impositivo:", WSFEXv1.ObtenerTagXml("Id_impositivo") |
---|
224 | |
---|
225 | ' recorro el detalle de items (artÃculos) |
---|
226 | For i = 0 To 100 |
---|
227 | ' salgo del bucle si no hay más items (ObtenerTagXml devuelve nulo): |
---|
228 | If IsNull(WSFEXv1.ObtenerTagXml("Items", "Item", i)) Then Exit For |
---|
229 | Debug.Print i, "Articulo (codigo):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_codigo") |
---|
230 | Debug.Print i, "Articulo (ds):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_ds") |
---|
231 | Debug.Print i, "Articulo (qty):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_qty") |
---|
232 | Debug.Print i, "Articulo (umed):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_umed") |
---|
233 | Debug.Print i, "Articulo (precio):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_precio_uni") |
---|
234 | Debug.Print i, "Articulo (bonif):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_bonificacion") |
---|
235 | Debug.Print i, "Articulo (subtotal):", WSFEXv1.ObtenerTagXml("Items", "Item", i, "Pro_total_item") |
---|
236 | Next |
---|
237 | Else |
---|
238 | ' hubo error, muestro mensaje |
---|
239 | Debug.Print WSFEXv1.Excepcion |
---|
240 | End If |
---|
241 | End If |
---|
242 | |
---|
243 | |
---|
244 | Exit Sub |
---|
245 | ManejoError: |
---|
246 | ' Si hubo error: |
---|
247 | If Not WSFEXv1 Is Nothing Then |
---|
248 | ' Depuración (grabar a un archivo los detalles del error) |
---|
249 | fd = FreeFile |
---|
250 | Open "c:\excepcion.txt" For Append As fd |
---|
251 | Print #fd, WSFEXv1.Excepcion |
---|
252 | Print #fd, WSFEXv1.Traceback |
---|
253 | Print #fd, WSFEXv1.XmlRequest |
---|
254 | Print #fd, WSFEXv1.XmlResponse |
---|
255 | Close fd |
---|
256 | Debug.Print WSFEXv1.Traceback |
---|
257 | Debug.Print WSFEXv1.XmlRequest |
---|
258 | Debug.Print WSFEXv1.XmlResponse |
---|
259 | MsgBox WSFEXv1.Excepcion & vbCrLf & WSFEXv1.ErrMsg, vbCritical + vbOKOnly, "Excepcion WSFEXv1" |
---|
260 | End If |
---|
261 | Debug.Print Err.Description ' descripción error afip |
---|
262 | Debug.Print Err.Number - vbObjectError ' codigo error afip |
---|
263 | Select Case MsgBox(Err.Description, vbCritical + vbRetryCancel, "Error:" & Err.Number - vbObjectError & " en " & Err.Source) |
---|
264 | Case vbRetry |
---|
265 | Debug.Assert False |
---|
266 | Resume |
---|
267 | Case vbCancel |
---|
268 | Debug.Print Err.Description |
---|
269 | End Select |
---|
270 | 'Debug.Assert False |
---|
271 | |
---|
272 | End Sub |
---|