django-afip icon indicating copy to clipboard operation
django-afip copied to clipboard

Validating receipts

Open gusarg81 opened this issue 4 years ago • 7 comments

Hi,

I have a doubt about validating receipts in batch.

Let suppose that I'm trying to validated receipts from a queryset. If I understand, errors on the validation process are appended to a list, but that list does not contain a reference to which receipt failed to validate. Or I am wrong?

I am asking this because In my view I generate ReceiptPDF once is validated, but If I validate a batch of receipts and one of them failed, I need to know which one in that process.

Thanks in advance.

gusarg81 avatar Feb 03 '20 18:02 gusarg81

Hmmm... why you're saying makes sense. Let me double check if the response from Afip actually has this information and if can somehow map it (in case it is).

WhyNotHugo avatar Feb 03 '20 19:02 WhyNotHugo

Hola,

¿Se pudo ver algo sobre esto? Es lo único que me impide enviar por batches (lo hago en baches en mi aplicación, pero no hacia la AFIP. De esta manera si se dá un error, sé a que comprobante pertenece).

Salvo que lo pueda hacer de otra manera.

Gracias!

gusarg81 avatar Jun 08 '20 22:06 gusarg81

Este es el resultado que devuelve el AFIP (convertido de XML a algo legible).

Es de un escenario donde se intentan validar tres comprobantes, pero el segundo es inválido.

{
    'FeCabResp': {
        'Cuit': 20329642330,
        'PtoVta': 1,
        'CbteTipo': 6,
        'FchProceso': '20200612165914',
        'CantReg': 3,
        'Resultado': 'P',
        'Reproceso': 'N'
    },
    'FeDetResp': {
        'FECAEDetResponse': [
            {
                'Concepto': 1,
                'DocTipo': 96,
                'DocNro': 203012345,
                'CbteDesde': 6468,
                'CbteHasta': 6468,
                'CbteFch': '20200612',
                'Resultado': 'A',
                'Observaciones': None,
                'CAE': '70240840044538',
                'CAEFchVto': '20200622'
            },
            {
                'Concepto': 1,
                'DocTipo': 80,
                'DocNro': 203012345,
                'CbteDesde': 6469,
                'CbteHasta': 6469,
                'CbteFch': '20200612',
                'Resultado': 'R',
                'Observaciones': {
                    'Obs': [
                        {
                            'Code': 10015,
                            'Msg': 'Factura B (CbteDesde igual a CbteHasta), DocTipo: 80, DocNro 203012345 no se encuentra registrado en los padrones de AFIP y no corresponde a una cuit pais.'
                        }
                    ]
                },
                'CAE': None,
                'CAEFchVto': None
            },
            {
                'Concepto': 1,
                'DocTipo': 96,
                'DocNro': 203012345,
                'CbteDesde': 6470,
                'CbteHasta': 6470,
                'CbteFch': '20200612',
                'Resultado': 'R',
                'Observaciones': None,
                'CAE': None,
                'CAEFchVto': None
            }
        ]
    },
    'Events': None,
    'Errors': None
}

En principio, AFIP intenta validarlos en order, así que:

  1. Cuando validás N comprobantes y hay una falla, el error aplica al primero no-validado.
  2. Los anteriores son validados exitosamente (y les queda el CAE y número de comprobante).
  3. Todos los no-validados no tienen ni CAE ni número de comprobante.

El parseo del resultado se hace en esta función.

Creo que sería perfectamente aceptable cambiar el resultado de una lista de errores a un dict con Receipt como clave y listas de errores como valores (Dict[Receipt, List[str]]).

El cambio es backwards-incompatible, pero master ya tiene otros cambios que también lo son, así que sería aceptable agregar esto; iría para v8.0.0.

WhyNotHugo avatar Jun 12 '20 20:06 WhyNotHugo

Hugo,

Hoy estoy empezando a ver el tema de validar por batches (dado que de a uno veo que tarda bastante cuando son muchos).

Por ejemplo, mi duda es: es como identificar a qué receipt pertenece el error, por ejemplo, en una excepción (en este caso, que lo hice adrede):

django_afip.exceptions.AfipException: Error 10069: Campo DocNro no puede ser igual al del emisor.

Más allá de que los que no dan error se validan, acorde a lo que me explicás, me interesaría saber en el momento de la excepción específicamente el receipt que no fue validado/dió error de ser posible.

En este ejemplo, fue aplicado validate() en el queryset.

Gracias.

gusarg81 avatar Sep 18 '20 14:09 gusarg81

Tengo curiosidad en que tipo de errores de devuelve frequentemente.

Al estar desarrollado capaz uno ve errores seguidos, pero en producción sería raro -- implica que estás mandando datos inconsitentes. Qué tipo de error te cruzás frequemente?

WhyNotHugo avatar Sep 28 '20 18:09 WhyNotHugo

En realidad no me cruzo con errores frecuentes (quizás un poco más en el entorno de testing, pero no tanto). Pero sí me gustaría tener el control exacto de que cuando valido por batches, identificar qué comprobante en cuestión dió error, dado que el error no informa el comprobante en cuestión.

gusarg81 avatar Sep 29 '20 18:09 gusarg81

Implemente devoler un Dict[Receipt, List[str]] (la lista es una lista de errores), pero, la verdad, me parece una API pésima.

Voy a guardar en la DB los intentos fallidos junto con los errores, y tras validar, devolver simplemente todos los receipts. Se pueden reconocer los exisotos porque receipt.validation.result == RESULT_APPROVED (tal como es ahora), y el resto tendrá las observaciones que corresponda.

Esto da más libertad a como se manejan los errores -- incluyendo que una persona los audite en otro momento, etc. Además, encaja bien en el modelo actual.

WhyNotHugo avatar Oct 03 '20 14:10 WhyNotHugo