| 1 | ' Ejemplo de Uso de Interface COM con Web Service Factura Electrónica Mercado Interno AFIP |
|---|
| 2 | ' Según RG2485 y RG2904 ArtÃculo 4 Opción B (sin detalle, Version 1) |
|---|
| 3 | ' 2010 (C) Mariano Reingart <reingart@gmail.com> |
|---|
| 4 | ' Licencia: GPLv3 |
|---|
| 5 | |
|---|
| 6 | Sub Main() |
|---|
| 7 | Dim WSAA As Object, WSFEv1 As Object |
|---|
| 8 | |
|---|
| 9 | On Error GoTo ManejoError |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | ' Una vez obtenido, se puede usar el mismo token y sign por 10 horas |
|---|
| 13 | ' (este perÃodo se puede cambiar) |
|---|
| 14 | ' revisar WSAA.Expirado() y en dicho caso tramitar nuevo TA |
|---|
| 15 | |
|---|
| 16 | ' Crear objeto interface Web Service de Factura Electrónica de Mercado Interno |
|---|
| 17 | Set WSFEv1 = CreateObject("WSFEv1") |
|---|
| 18 | Debug.Print WSFEv1.Version |
|---|
| 19 | 'Debug.Print WSFEv1.InstallDir |
|---|
| 20 | |
|---|
| 21 | ' Setear tocken y sing de autorización (pasos previos) |
|---|
| 22 | ''WSFEv1.Token = WSAA.Token |
|---|
| 23 | ''WSFEv1.Sign = WSAA.Sign |
|---|
| 24 | |
|---|
| 25 | ' CUIT del emisor (debe estar registrado en la AFIP) |
|---|
| 26 | WSFEv1.Cuit = "20267565393" |
|---|
| 27 | |
|---|
| 28 | ' deshabilito errores no manejados |
|---|
| 29 | WSFEv1.LanzarExcepciones = False |
|---|
| 30 | |
|---|
| 31 | ' Conectar al Servicio Web de Facturación |
|---|
| 32 | proxy = "" ' "usuario:clave@localhost:8000" |
|---|
| 33 | wsdl = "https://servicios1.afip.gov.ar/wsfev1/service.asmx?WSDL" |
|---|
| 34 | cache = "" 'Path |
|---|
| 35 | wrapper = "" ' libreria http (httplib2, urllib2, pycurl) |
|---|
| 36 | |
|---|
| 37 | ok = WSFEv1.Conectar(cache, wsdl, proxy, wrapper, cacert) ' homologación |
|---|
| 38 | Debug.Print WSFEv1.Version |
|---|
| 39 | ControlarExcepcion WSFEv1 |
|---|
| 40 | |
|---|
| 41 | ' mostrar bitácora de depuración: |
|---|
| 42 | Debug.Print WSFEv1.DebugLog |
|---|
| 43 | |
|---|
| 44 | ' Llamo a un servicio nulo, para obtener el estado del servidor (opcional) |
|---|
| 45 | WSFEv1.Dummy |
|---|
| 46 | ControlarExcepcion WSFEv1 |
|---|
| 47 | Debug.Print "appserver status", WSFEv1.AppServerStatus |
|---|
| 48 | Debug.Print "dbserver status", WSFEv1.DbServerStatus |
|---|
| 49 | Debug.Print "authserver status", WSFEv1.AuthServerStatus |
|---|
| 50 | |
|---|
| 51 | |
|---|
| 52 | 'TipoCamioAfip = WSFEv1.ParamGetCotizacion("DOL", "20250403") |
|---|
| 53 | Debug.Print WSFEv1.XmlRequest |
|---|
| 54 | Debug.Print WSFEv1.XmlResponse |
|---|
| 55 | MsgBox TipoCambioAfip |
|---|
| 56 | |
|---|
| 57 | cbte_nro = 0 ' no hay comprobantes emitidos |
|---|
| 58 | fecha = Format(Date, "yyyymmdd") |
|---|
| 59 | concepto = 1 |
|---|
| 60 | tipo_doc = 80: nro_doc = "33693450239" |
|---|
| 61 | cbte_nro = cbte_nro + 1 |
|---|
| 62 | cbt_desde = cbte_nro: cbt_hasta = cbte_nro |
|---|
| 63 | imp_total = "179.25": imp_tot_conc = "2.00": imp_neto = "150.00" |
|---|
| 64 | imp_iva = "26.25": imp_trib = "1.00": imp_op_ex = "0.00" |
|---|
| 65 | fecha_cbte = fecha: fecha_venc_pago = "" |
|---|
| 66 | ' Fechas del perÃodo del servicio facturado (solo si concepto = 1?) |
|---|
| 67 | fecha_serv_desde = "": fecha_serv_hasta = "" |
|---|
| 68 | moneda_id = "PES": moneda_ctz = "1.000" |
|---|
| 69 | |
|---|
| 70 | ok = WSFEv1.CrearFactura(concepto, tipo_doc, nro_doc, tipo_cbte, punto_vta, _ |
|---|
| 71 | cbt_desde, cbt_hasta, imp_total, imp_tot_conc, imp_neto, _ |
|---|
| 72 | imp_iva, imp_trib, imp_op_ex, fecha_cbte, fecha_venc_pago, _ |
|---|
| 73 | fecha_serv_desde, fecha_serv_hasta, _ |
|---|
| 74 | moneda_id, moneda_ctz) |
|---|
| 75 | |
|---|
| 76 | ' Agrego los comprobantes asociados: |
|---|
| 77 | If False Then ' solo nc/nd |
|---|
| 78 | tipo = 19 |
|---|
| 79 | pto_vta = 2 |
|---|
| 80 | nro = 1234 |
|---|
| 81 | ok = WSFEv1.AgregarCmpAsoc(tipo, pto_vta, nro) |
|---|
| 82 | End If |
|---|
| 83 | |
|---|
| 84 | ' Agrego impuestos varios |
|---|
| 85 | id = 99 |
|---|
| 86 | Desc = "Impuesto Municipal Matanza'" |
|---|
| 87 | base_imp = "100.00" |
|---|
| 88 | alic = "0.10" |
|---|
| 89 | importe = "0.10" |
|---|
| 90 | ok = WSFEv1.AgregarTributo(id, Desc, base_imp, alic, importe) |
|---|
| 91 | |
|---|
| 92 | ' Agrego impuestos varios |
|---|
| 93 | id = 4 |
|---|
| 94 | Desc = "Impuestos internos" |
|---|
| 95 | base_imp = "100.00" |
|---|
| 96 | alic = "0.40" |
|---|
| 97 | importe = "0.40" |
|---|
| 98 | ok = WSFEv1.AgregarTributo(id, Desc, base_imp, alic, importe) |
|---|
| 99 | |
|---|
| 100 | ' Agrego impuestos varios |
|---|
| 101 | id = 1 |
|---|
| 102 | Desc = "Impuesto nacional" |
|---|
| 103 | base_imp = "50.00" |
|---|
| 104 | alic = "1.00" |
|---|
| 105 | importe = "0.50" |
|---|
| 106 | ok = WSFEv1.AgregarTributo(id, Desc, base_imp, alic, importe) |
|---|
| 107 | |
|---|
| 108 | ' Agrego tasas de IVA |
|---|
| 109 | id = 5 ' 21% |
|---|
| 110 | base_imp = "100.00" |
|---|
| 111 | importe = "21.00" |
|---|
| 112 | ok = WSFEv1.AgregarIva(id, base_imp, importe) |
|---|
| 113 | |
|---|
| 114 | ' Agrego tasas de IVA al 0% (imp_tot_conc, solo para pruebas) |
|---|
| 115 | id = 4 ' 10.5% |
|---|
| 116 | base_imp = "50.00" |
|---|
| 117 | importe = "5.25" |
|---|
| 118 | ok = WSFEv1.AgregarIva(id, base_imp, importe) |
|---|
| 119 | |
|---|
| 120 | ' Agrego datos opcionales RG 3668 Impuesto al Valor Agregado - Art.12 ("presunci??e no vinculaci??on la actividad gravada", F.8001): |
|---|
| 121 | If tipo_cbte = 1 Then ' solo para facturas A |
|---|
| 122 | ok = WSFEv1.AgregarOpcional(5, "02") ' IVA Excepciones (01: Locador/Prestador, 02: Conferencias, 03: RG 74, 04: Bienes de cambio, 05: Ropa de trabajo, 06: Intermediario). |
|---|
| 123 | ok = WSFEv1.AgregarOpcional(61, "80") ' Firmante Doc Tipo (80: CUIT, 96: DNI, etc.) |
|---|
| 124 | ok = WSFEv1.AgregarOpcional(62, "20267565393") ' Firmante Doc Nro |
|---|
| 125 | ok = WSFEv1.AgregarOpcional(7, "01") ' Car?er del Firmante (01: Titular, 02: Director/Presidente, 03: Apoderado, 04: Empleado) |
|---|
| 126 | End If |
|---|
| 127 | |
|---|
| 128 | ' Habilito reprocesamiento automático (predeterminado): |
|---|
| 129 | WSFEv1.Reprocesar = True |
|---|
| 130 | |
|---|
| 131 | ' Agrego RG 5616 |
|---|
| 132 | ok = WSFEv1.EstablecerCampoFactura("cancela_misma_moneda_ext", "N") |
|---|
| 133 | ok = WSFEv1.EstablecerCampoFactura("condicion_iva_receptor_id", "5") |
|---|
| 134 | |
|---|
| 135 | ' Solicito CAE: |
|---|
| 136 | CAE = WSFEv1.CAESolicitar() |
|---|
| 137 | ControlarExcepcion WSFEv1 |
|---|
| 138 | |
|---|
| 139 | Debug.Print "Resultado", WSFEv1.Resultado |
|---|
| 140 | Debug.Print "CAE", WSFEv1.CAE |
|---|
| 141 | |
|---|
| 142 | Debug.Print "Numero de comprobante:", WSFEv1.CbteNro |
|---|
| 143 | |
|---|
| 144 | ' Imprimo pedido y respuesta XML para depuración (errores de formato) |
|---|
| 145 | Debug.Print WSFEv1.XmlRequest |
|---|
| 146 | Debug.Print WSFEv1.XmlResponse |
|---|
| 147 | |
|---|
| 148 | Debug.Print "Reprocesar:", WSFEv1.Reprocesar |
|---|
| 149 | Debug.Print "Reproceso:", WSFEv1.Reproceso |
|---|
| 150 | Debug.Print "CAE:", WSFEv1.CAE |
|---|
| 151 | Debug.Print "EmisionTipo:", WSFEv1.EmisionTipo |
|---|
| 152 | |
|---|
| 153 | MsgBox "Resultado:" & WSFEv1.Resultado & " CAE: " & CAE & " Venc: " & WSFEv1.Vencimiento & " Obs: " & WSFEv1.obs & " Reproceso: " & WSFEv1.Reproceso, vbInformation + vbOKOnly |
|---|
| 154 | |
|---|
| 155 | ' Muestro los errores |
|---|
| 156 | If WSFEv1.errmsg <> "" Then |
|---|
| 157 | MsgBox WSFEv1.errmsg, vbExclamation, "Error" |
|---|
| 158 | End If |
|---|
| 159 | |
|---|
| 160 | ' Muestro los eventos (mantenimiento programados y otros mensajes de la AFIP) |
|---|
| 161 | For Each evento In WSFEv1.eventos: |
|---|
| 162 | MsgBox evento, vbInformation, "Evento" |
|---|
| 163 | Next |
|---|
| 164 | |
|---|
| 165 | ' Buscar la factura |
|---|
| 166 | cae2 = WSFEv1.CompConsultar(tipo_cbte, punto_vta, cbte_nro) |
|---|
| 167 | ControlarExcepcion WSFEv1 |
|---|
| 168 | |
|---|
| 169 | Debug.Print "Fecha Comprobante:", WSFEv1.FechaCbte |
|---|
| 170 | Debug.Print "Fecha Vencimiento CAE", WSFEv1.Vencimiento |
|---|
| 171 | Debug.Print "Importe Total:", WSFEv1.ImpTotal |
|---|
| 172 | Debug.Print "Resultado:", WSFEv1.Resultado |
|---|
| 173 | |
|---|
| 174 | If WSFEv1.Version >= "1.12a" Then |
|---|
| 175 | ok = WSFEv1.AnalizarXml("XmlResponse") |
|---|
| 176 | If ok Then |
|---|
| 177 | Debug.Print "CAE:", WSFEv1.ObtenerTagXml("CodAutorizacion"), WSFEv1.CAE |
|---|
| 178 | Debug.Print "CbteFch:", WSFEv1.ObtenerTagXml("CbteFch"), WSFEv1.FechaCbte |
|---|
| 179 | Debug.Print "Moneda:", WSFEv1.ObtenerTagXml("MonId") |
|---|
| 180 | Debug.Print "Cotizacion:", WSFEv1.ObtenerTagXml("MonCotiz") |
|---|
| 181 | Debug.Print "DocTIpo:", WSFEv1.ObtenerTagXml("DocTipo") |
|---|
| 182 | Debug.Print "DocNro:", WSFEv1.ObtenerTagXml("DocNro") |
|---|
| 183 | |
|---|
| 184 | ' ejemplos con arreglos (primer elemento = 0): |
|---|
| 185 | Debug.Print "Primer IVA (alci id):", WSFEv1.ObtenerTagXml("Iva", "AlicIva", 0, "Id") |
|---|
| 186 | Debug.Print "Primer IVA (importe):", WSFEv1.ObtenerTagXml("Iva", "AlicIva", 0, "Importe") |
|---|
| 187 | Debug.Print "Segundo IVA (alic id):", WSFEv1.ObtenerTagXml("Iva", "AlicIva", 1, "Id") |
|---|
| 188 | Debug.Print "Segundo IVA (importe):", WSFEv1.ObtenerTagXml("Iva", "AlicIva", 1, "Importe") |
|---|
| 189 | Debug.Print "Primer Tributo (ds):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 0, "Desc") |
|---|
| 190 | Debug.Print "Primer Tributo (importe):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 0, "Importe") |
|---|
| 191 | Debug.Print "Segundo Tributo (ds):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 1, "Desc") |
|---|
| 192 | Debug.Print "Segundo Tributo (importe):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 1, "Importe") |
|---|
| 193 | Debug.Print "Tercer Tributo (ds):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 2, "Desc") |
|---|
| 194 | Debug.Print "Tercer Tributo (importe):", WSFEv1.ObtenerTagXml("Tributos", "Tributo", 2, "Importe") |
|---|
| 195 | Else |
|---|
| 196 | ' hubo error, muestro mensaje |
|---|
| 197 | Debug.Print WSFEv1.Excepcion |
|---|
| 198 | End If |
|---|
| 199 | End If |
|---|
| 200 | |
|---|
| 201 | If CAE = "" Then |
|---|
| 202 | ' hubo error, no comparo |
|---|
| 203 | ElseIf CAE <> cae2 Then |
|---|
| 204 | MsgBox "El CAE de la factura no concuerdan con el recuperado en la AFIP!: " & CAE & " vs " & cae2 |
|---|
| 205 | Else |
|---|
| 206 | MsgBox "El CAE de la factura concuerdan con el recuperado de la AFIP" |
|---|
| 207 | End If |
|---|
| 208 | |
|---|
| 209 | Exit Sub |
|---|
| 210 | ManejoError: |
|---|
| 211 | ' Si hubo error (tradicional, no controlado): |
|---|
| 212 | |
|---|
| 213 | ' Depuración (grabar a un archivo los detalles del error) |
|---|
| 214 | fd = FreeFile |
|---|
| 215 | Open "c:\error.txt" For Append As fd |
|---|
| 216 | If Not WSAA Is Nothing Then |
|---|
| 217 | If WSAA.Version >= "1.02a" Then |
|---|
| 218 | Print #fd, WSAA.Excepcion |
|---|
| 219 | Print #fd, WSAA.Traceback |
|---|
| 220 | Print #fd, WSAA.XmlRequest |
|---|
| 221 | Print #fd, WSAA.XmlResponse |
|---|
| 222 | ' guardo mensaje de error para mostrarlo: |
|---|
| 223 | Excepcion = WSAA.Excepcion |
|---|
| 224 | End If |
|---|
| 225 | End If |
|---|
| 226 | If Not WSFEv1 Is Nothing Then |
|---|
| 227 | If WSFEv1.Version >= "1.10a" Then |
|---|
| 228 | Print #fd, WSFEv1.Excepcion |
|---|
| 229 | Print #fd, WSFEv1.Traceback |
|---|
| 230 | Print #fd, WSFEv1.XmlRequest |
|---|
| 231 | Print #fd, WSFEv1.XmlResponse |
|---|
| 232 | Print #fd, WSFEv1.DebugLog() |
|---|
| 233 | ' guardo mensaje de error para mostrarlo: |
|---|
| 234 | Excepcion = WSFEv1.Excepcion |
|---|
| 235 | End If |
|---|
| 236 | End If |
|---|
| 237 | Close fd |
|---|
| 238 | |
|---|
| 239 | Debug.Print Err.Description ' descripción error afip |
|---|
| 240 | Debug.Print Err.Number - vbObjectError ' codigo error afip |
|---|
| 241 | If Excepcion = "" Then ' si no tengo mensaje de excepcion |
|---|
| 242 | Excepcion = Err.Description ' uso el error de VB |
|---|
| 243 | End If |
|---|
| 244 | |
|---|
| 245 | ' Mostrar el mensaje de error |
|---|
| 246 | Select Case MsgBox(Excepcion, vbCritical + vbRetryCancel, "Error:" & Err.Number - vbObjectError & " en " & Err.Source) |
|---|
| 247 | Case vbRetry |
|---|
| 248 | Debug.Assert False |
|---|
| 249 | Resume |
|---|
| 250 | Case vbCancel |
|---|
| 251 | Debug.Print Err.Description |
|---|
| 252 | End Select |
|---|
| 253 | End Sub |
|---|
| 254 | |
|---|
| 255 | Sub ControlarExcepcion(obj As Object) |
|---|
| 256 | ' Nueva funcion para verificar que no haya habido errores: |
|---|
| 257 | On Error GoTo 0 |
|---|
| 258 | If obj.Excepcion <> "" Then |
|---|
| 259 | ' Depuración (grabar a un archivo los detalles del error) |
|---|
| 260 | fd = FreeFile |
|---|
| 261 | Open "c:\excepcion.txt" For Append As fd |
|---|
| 262 | Print #fd, obj.Excepcion |
|---|
| 263 | Print #fd, obj.Traceback |
|---|
| 264 | Print #fd, obj.XmlRequest |
|---|
| 265 | Print #fd, obj.XmlResponse |
|---|
| 266 | Close fd |
|---|
| 267 | MsgBox obj.Excepcion, vbExclamation, "Excepción" |
|---|
| 268 | End |
|---|
| 269 | End If |
|---|
| 270 | End Sub |
|---|