WhyNotHugo/django-afip

DataError: value too long for type character varying(24) when trying to fetch point of sales

Alvezgr opened this issue · 4 comments

Hi, I recently came across an issue when trying to fetch point of sales from a given taxpayer.
I'm using

django=3.2.13
python=3.10.4
postgresql=14

When I run taxpayer.fetch_point_of_sales() an exception occurs.
The traceback is the following:

---------------------------------------------------------------------------
DoesNotExist                              Traceback (most recent call last)
File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:581, in QuerySet.get_or_create(self, defaults, **kwargs)
    580 try:
--> 581     return self.get(**kwargs), False
    582 except self.model.DoesNotExist:

File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:435, in QuerySet.get(self, *args, **kwargs)
    434 if not num:
--> 435     raise self.model.DoesNotExist(
    436         "%s matching query does not exist." %
    437         self.model._meta.object_name
    438     )
    439 raise self.model.MultipleObjectsReturned(
    440     'get() returned more than one %s -- it returned %s!' % (
    441         self.model._meta.object_name,
    442         num if not limit or num < limit else 'more than %s' % (limit - 1),
    443     )
    444 )

DoesNotExist: PointOfSales matching query does not exist.

During handling of the above exception, another exception occurred:

StringDataRightTruncation                 Traceback (most recent call last)
File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:84, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
     83 else:
---> 84     return self.cursor.execute(sql, params)

StringDataRightTruncation: value too long for type character varying(24)


The above exception was the direct cause of the following exception:

DataError                                 Traceback (most recent call last)
Input In [34], in <cell line: 1>()
----> 1 tp.fetch_points_of_sales()

File /usr/local/lib/python3.10/site-packages/django_afip/models.py:468, in TaxPayer.fetch_points_of_sales(self, ticket)
    465 results = []
    466 for pos_data in response.ResultGet.PtoVenta:
    467     results.append(
--> 468         PointOfSales.objects.update_or_create(
    469             number=pos_data.Nro,
    470             owner=self,
    471             defaults={
    472                 "issuance_type": pos_data.EmisionTipo,
    473                 "blocked": pos_data.Bloqueado == "N",
    474                 "drop_date": parsers.parse_date(pos_data.FchBaja),
    475             },
    476         )
    477     )
    479 return results

File /usr/local/lib/python3.10/site-packages/django/db/models/manager.py:85, in BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method(self, *args, **kwargs)
     84 def manager_method(self, *args, **kwargs):
---> 85     return getattr(self.get_queryset(), name)(*args, **kwargs)

File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:608, in QuerySet.update_or_create(self, defaults, **kwargs)
    604 self._for_write = True
    605 with transaction.atomic(using=self.db):
    606     # Lock the row so that a concurrent update is blocked until
    607     # update_or_create() has performed its save.
--> 608     obj, created = self.select_for_update().get_or_create(defaults, **kwargs)
    609     if created:
    610         return obj, created

File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:588, in QuerySet.get_or_create(self, defaults, **kwargs)
    586     with transaction.atomic(using=self.db):
    587         params = dict(resolve_callables(params))
--> 588         return self.create(**params), True
    589 except IntegrityError:
    590     try:

File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:453, in QuerySet.create(self, **kwargs)
    451 obj = self.model(**kwargs)
    452 self._for_write = True
--> 453 obj.save(force_insert=True, using=self.db)
    454 return obj

File /usr/local/lib/python3.10/site-packages/django/db/models/base.py:739, in Model.save(self, force_insert, force_update, using, update_fields)
    736     if loaded_fields:
    737         update_fields = frozenset(loaded_fields)
--> 739 self.save_base(using=using, force_insert=force_insert,
    740                force_update=force_update, update_fields=update_fields)

File /usr/local/lib/python3.10/site-packages/django/db/models/base.py:776, in Model.save_base(self, raw, force_insert, force_update, using, update_fields)
    774     if not raw:
    775         parent_inserted = self._save_parents(cls, using, update_fields)
--> 776     updated = self._save_table(
    777         raw, cls, force_insert or parent_inserted,
    778         force_update, using, update_fields,
    779     )
    780 # Store the database on which the object was saved
    781 self._state.db = using

File /usr/local/lib/python3.10/site-packages/django/db/models/base.py:881, in Model._save_table(self, raw, cls, force_insert, force_update, using, update_fields)
    878     fields = [f for f in fields if f is not meta.auto_field]
    880 returning_fields = meta.db_returning_fields
--> 881 results = self._do_insert(cls._base_manager, using, fields, returning_fields, raw)
    882 if results:
    883     for value, field in zip(results[0], returning_fields):

File /usr/local/lib/python3.10/site-packages/django/db/models/base.py:919, in Model._do_insert(self, manager, using, fields, returning_fields, raw)
    914 def _do_insert(self, manager, using, fields, returning_fields, raw):
    915     """
    916     Do an INSERT. If returning_fields is defined then this method should
    917     return the newly created data for the model.
    918     """
--> 919     return manager._insert(
    920         [self], fields=fields, returning_fields=returning_fields,
    921         using=using, raw=raw,
    922     )

File /usr/local/lib/python3.10/site-packages/django/db/models/manager.py:85, in BaseManager._get_queryset_methods.<locals>.create_method.<locals>.manager_method(self, *args, **kwargs)
     84 def manager_method(self, *args, **kwargs):
---> 85     return getattr(self.get_queryset(), name)(*args, **kwargs)

File /usr/local/lib/python3.10/site-packages/django/db/models/query.py:1270, in QuerySet._insert(self, objs, fields, returning_fields, raw, using, ignore_conflicts)
   1268 query = sql.InsertQuery(self.model, ignore_conflicts=ignore_conflicts)
   1269 query.insert_values(fields, objs, raw=raw)
-> 1270 return query.get_compiler(using=using).execute_sql(returning_fields)

File /usr/local/lib/python3.10/site-packages/django/db/models/sql/compiler.py:1416, in SQLInsertCompiler.execute_sql(self, returning_fields)
   1414 with self.connection.cursor() as cursor:
   1415     for sql, params in self.as_sql():
-> 1416         cursor.execute(sql, params)
   1417     if not self.returning_fields:
   1418         return []

File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:98, in CursorDebugWrapper.execute(self, sql, params)
     96 def execute(self, sql, params=None):
     97     with self.debug_sql(sql, params, use_last_executed_query=True):
---> 98         return super().execute(sql, params)

File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:66, in CursorWrapper.execute(self, sql, params)
     65 def execute(self, sql, params=None):
---> 66     return self._execute_with_wrappers(sql, params, many=False, executor=self._execute)

File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:75, in CursorWrapper._execute_with_wrappers(self, sql, params, many, executor)
     73 for wrapper in reversed(self.db.execute_wrappers):
     74     executor = functools.partial(wrapper, executor)
---> 75 return executor(sql, params, many, context)

File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:79, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
     77 def _execute(self, sql, params, *ignored_wrapper_args):
     78     self.db.validate_no_broken_transaction()
---> 79     with self.db.wrap_database_errors:
     80         if params is None:
     81             # params default might be backend specific.
     82             return self.cursor.execute(sql)

File /usr/local/lib/python3.10/site-packages/django/db/utils.py:90, in DatabaseErrorWrapper.__exit__(self, exc_type, exc_value, traceback)
     88 if dj_exc_type not in (DataError, IntegrityError):
     89     self.wrapper.errors_occurred = True
---> 90 raise dj_exc_value.with_traceback(traceback) from exc_value

File /usr/local/lib/python3.10/site-packages/django/db/backends/utils.py:84, in CursorWrapper._execute(self, sql, params, *ignored_wrapper_args)
     82     return self.cursor.execute(sql)
     83 else:
---> 84     return self.cursor.execute(sql, params)

DataError: value too long for type character varying(24)

For context:

response = client.service.FEParamGetPtosVenta(
serializers.serialize_ticket(ticket),
)

The response in the line above is:

{
    'ResultGet': {
        'PtoVenta': [
            {
                'Nro': 7,
                'EmisionTipo': 'CAEA - Ri Iva CONTINGENCIA',
                'Bloqueado': 'N',
                'FchBaja': 'NULL'
            }
        ]
    },
    'Errors': None,
    'Events': None
}

This results in a length of 26 characters for EmisionTipo, which is too long for the issuance_type field defined in PointOfSales model.

Huh, I've never seen this value before. Do you know if there is a list of all possible values? If so we can check the longest possible value. Otherwise, we can just extend it to 32.

I really don't know, in the developers manual it's says that the EmisionTipo has a kind String(8) but I'll ask those AFIP guys and I post the response.

Thanks. If we don't get a reply in a couple of days, we can push this to just 32.

The response from AFIP sri team:

 
Segun lo tratado con las areas intervinientes se remite lo informado a efectos de brindar una solucion al presente requerimiento.

En base al analisis tecnico realizado se verifica que la longitud maxima es de 200 BYTE

Saludos


-----------------------------------
Atte.
Div. Centro de Servicios de Tecnologia
[sri@afip.gob.ar](mailto:sri@afip.gob.ar)

So we can push to 32 as you suggested, until another weird value is returned.