Exemplo n.º 1
0
    def importa_contactos(self, lista_rapida):

        parser = ParserCsv()

        try:
            estructura_archivo = parser.get_estructura_archivo(lista_rapida)
            cantidad_contactos = 0
            if lista_rapida.cantidad_contactos:
                cantidad_contactos = lista_rapida.cantidad_contactos
            for lista_dato in estructura_archivo[1:]:
                cantidad_contactos += 1
                ContactoListaRapida.objects.create(
                    nombre=lista_dato[0],
                    telefono=lista_dato[1],
                    lista_rapida=lista_rapida,
                )
        except OmlParserMaxRowError:
            lista_rapida.elimina_contactos()
            raise

        except OmlParserCsvImportacionError:
            lista_rapida.elimina_contactos()
            raise

        lista_rapida.cantidad_contactos = cantidad_contactos
        lista_rapida.save()
Exemplo n.º 2
0
    def importa_contactos(self, backlist):
        """
        Segundo paso de la creación de una Backlist.
        Este método se encarga de generar los objectos Contacto por cada linea
        del archivo de importación especificado para la base de datos de
        contactos.
        """

        parser = ParserCsv()

        try:
            estructura_archivo = parser.get_estructura_archivo(backlist)
            cantidad_contactos = 0
            if backlist.cantidad_contactos:
                cantidad_contactos = backlist.cantidad_contactos
            for lista_dato in estructura_archivo[1:]:
                cantidad_contactos += 1
                ContactoBacklist.objects.create(
                    telefono=lista_dato[0],
                    back_list=backlist,
                )
        except OmlParserMaxRowError:
            backlist.elimina_contactos()
            raise

        except OmlParserCsvImportacionError:
            backlist.elimina_contactos()
            raise

        backlist.cantidad_contactos = cantidad_contactos
        backlist.save()
Exemplo n.º 3
0
    def valida_contactos(self, base_datos_contacto):
        """
        Validacion para ver si existe en la base de datos el contacto
        """
        assert (base_datos_contacto.estado in
                (BaseDatosContacto.ESTADO_EN_DEFINICION,
                 BaseDatosContacto.ESTADO_DEFINIDA_ACTUALIZADA))

        parser = ParserCsv()

        try:
            estructura_archivo = parser.get_estructura_archivo(
                base_datos_contacto)
            cantidad_contactos = 0
            for lista_dato in estructura_archivo[1:]:
                cantidad_contactos += 1
                contacto = Contacto.objects.filter(
                    # id_cliente=int(lista_dato[1]),
                    bd_contacto=base_datos_contacto
                )
                if len(contacto) > 0:
                    raise (ContactoExistenteError(_("ya existe el contacto con el"
                                                    "  de id de cliente: {0}"
                                                    " la base de datos ".format(
                                                        int(lista_dato[1])))))

        except OmlParserMaxRowError:
            base_datos_contacto.elimina_contactos()
            raise

        except OmlParserCsvImportacionError:
            base_datos_contacto.elimina_contactos()
            raise
    def get(self, request, *args, **kwargs):
        self.object = self.get_object()

        estructura_archivo = self.obtiene_previsualizacion_archivo(self.object)
        if estructura_archivo:
            parser = ParserCsv()
            encoding = parser.detectar_encoding_csv(estructura_archivo)
            estructura_archivo_transformada = parser.visualizar_estructura_template(
                estructura_archivo, encoding)

            try:
                error_predictor = False
                error_predictor_encabezado = False

                predictor_metadata = PredictorMetadataService()
                metadata = predictor_metadata.inferir_metadata_desde_lineas(
                    estructura_archivo, encoding)
            except NoSePuedeInferirMetadataError:
                initial_predecido_datos_extras = {}
                initial_predecido_encabezado = {}
                error_predictor = True
            except NoSePuedeInferirMetadataErrorEncabezado:
                initial_predecido_datos_extras = {}
                initial_predecido_encabezado = {}

                error_predictor_encabezado = True
            else:
                initial_predecido_datos_extras = dict([
                    ('datos-extras-{0}'.format(col),
                     BaseDatosContacto.DATO_EXTRA_FECHA)
                    for col in metadata.columnas_con_fecha
                ])

                initial_predecido_datos_extras.update(
                    dict([('datos-extras-{0}'.format(col),
                           BaseDatosContacto.DATO_EXTRA_HORA)
                          for col in metadata.columnas_con_hora]))

                initial_predecido_encabezado = {
                    'es_encabezado': metadata.primer_fila_es_encabezado
                }

            form_primer_linea_encabezado = PrimerLineaEncabezadoForm(
                initial=initial_predecido_encabezado)
            form_campos_telefonicos = CamposDeBaseDeDatosForm(
                nombres_campos=estructura_archivo[0])

            return self.render_to_response(
                self.get_context_data(
                    error_predictor_encabezado=error_predictor_encabezado,
                    error_predictor=error_predictor,
                    estructura_archivo=estructura_archivo_transformada,
                    form_primer_linea_encabezado=form_primer_linea_encabezado,
                    form_campos_telefonicos=form_campos_telefonicos))

        return redirect(reverse('nueva_base_datos_contacto'))
    def obtiene_previsualizacion_archivo(self, base_datos_contacto):
        """
        Instancia el servicio ParserCsv e intenta obtener un resumen de las
        primeras 3 lineas del csv.
        """

        try:
            parser = ParserCsv()
            estructura_archivo = parser.previsualiza_archivo(
                base_datos_contacto)

        except OmlParserCsvDelimiterError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('No se pudo determinar el delimitador a ser utilizado '
                  'en el archivo csv. No se pudo llevar a cabo el procesamiento '
                  'de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserMinRowError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee menos de 3 filas. '
                  'No se pudo llevar a cabo el procesamiento de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserOpenFileError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó no pudo ser abierto para su procesamiento.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except Exception as e:
            message = _(
                'Error al procesar el archivo de base de contactos: {0}'.
                format(e))
            logger.error(message)
            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        else:
            return estructura_archivo
    def obtiene_previsualizacion_archivo(self, base_datos_contacto):
        """
        Instancia el servicio ParserCsv e intenta obtener un resumen de las
        primeras 3 lineas del csv.
        """

        # TODO: OML-1012
        #       Estas validaciones deberían realizarse antes de crear la Base de datos
        #       Sino queda una instancia creada inutilizable
        try:
            parser = ParserCsv()
            estructura_archivo = parser.previsualiza_archivo(
                base_datos_contacto)

        except OmlParserCsvDelimiterError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('No se pudo determinar el delimitador a ser utilizado '
                  'en el archivo csv. No se pudo llevar a cabo el procesamiento '
                  'de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserMinRowError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee menos de 3 filas. '
                  'No se pudo llevar a cabo el procesamiento de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserOpenFileError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó no pudo ser abierto para su procesamiento.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserRepeatedColumnsError as e:
            message = _('<strong>Operación Errónea!</strong> ') + e.message
            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        else:
            return estructura_archivo
    def test_con_demas_planillas_de_ejemplo(self):

        PLANILLAS = (
            "planilla-ejemplo-1.csv",
            "planilla-ejemplo-2.csv",
            "planilla-ejemplo-7-celdas-vacias.csv",
            "planilla-ejemplo-8-ultima-celda-vacia.csv",
        )

        for planilla in PLANILLAS:
            logger.debug("Procesando planilla %s", planilla)
            bd_contacto = BaseDatosContacto.objects.create(
                nombre="base-datos-contactos-{0}".format(planilla),
                archivo_importacion=self.copy_test_resource_to_mediaroot(
                    planilla),
                nombre_archivo_importacion=planilla)

            parser = ParserCsv()
            estructura_archivo = parser.previsualiza_archivo(bd_contacto)
            predictor_metadata = PredictorMetadataService()
            metadata_inferida = predictor_metadata.inferir_metadata_desde_lineas(
                estructura_archivo)

            metadata = bd_contacto.get_metadata()
            metadata._metadata = metadata_inferida._metadata
            metadata.nombres_de_columnas = [
                "COL{0}".format(num)
                for num in range(metadata.cantidad_de_columnas)
            ]
            metadata.save()

            creacion_base_datos_service = CreacionBaseDatosService()
            creacion_base_datos_service.importa_contactos(
                bd_contacto, ["Telefono"], None)
            creacion_base_datos_service.define_base_dato_contacto(bd_contacto)

            # ----- checks

            self.assertEquals(
                BaseDatosContacto.objects.get(pk=bd_contacto.id).estado,
                BaseDatosContacto.ESTADO_DEFINIDA,
                "La BD generada desde '{0}' NO ha quedado en estado ESTADO_DEFINIDA"
                "".format(planilla))

            self.assertTrue(
                Contacto.objects.filter(bd_contacto=bd_contacto.id).count() >
                0, "La BD generada desde '{0}' NO posee contactos".format(
                    planilla))
Exemplo n.º 8
0
    def _obtiene_previsualizacion_archivo(self,
                                          lista_rapida,
                                          previsualizacion=True):
        """
        Instancia el servicio ParserCsv e intenta obtener un resumen de las
        primeras 3 lineas del csv.
        """
        try:
            parser = ParserCsv()
            estructura_archivo = parser.previsualiza_archivo(
                lista_rapida, previsualizacion)

        except OmlParserCsvDelimiterError:
            message = _(
                '<strong>Operación Errónea!</strong> '
                'No se pudo determinar el delimitador a ser utilizado '
                'en el archivo csv. No se pudo llevar a cabo el procesamiento '
                'de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserMinRowError:
            message = _(
                '<strong>Operación Errónea!</strong> '
                'El archivo que seleccionó posee menos de 3 filas. '
                'No se pudo llevar a cabo el procesamiento de sus datos.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        except OmlParserOpenFileError:
            message = _(
                '<strong>Operación Errónea!</strong> '
                'El archivo que seleccionó no pudo ser abierto para su procesamiento.'
            )

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
        else:
            return estructura_archivo
    def test_inferir_metadata_correctamente(self):

        planilla = self.copy_test_resource_to_mediaroot("planilla-ejemplo-1.csv")
        nombre_archivo = "planilla-ejemplo-10.csv"
        base_test = BaseDatosContacto.objects.create(
            nombre="test", archivo_importacion=planilla,
            nombre_archivo_importacion=nombre_archivo, metadata="")

        parser = ParserCsv()
        estructura_archivo = parser.previsualiza_archivo(base_test)

        predictor_metadata = PredictorMetadataService()
        metadata = predictor_metadata.inferir_metadata_desde_lineas(estructura_archivo, "utf-8")

        validador_nombre = ValidadorDeNombreDeCampoExtra()
        for nombre_columna in metadata.nombres_de_columnas:
            self.assertTrue(validador_nombre.validar_nombre_de_columna(
                nombre_columna), "el nombre de columna es invalido")
    def test_con_planilla_ejemplo_3(self):
        bd_contacto = BaseDatosContacto.objects.create(
            nombre="base-datos-contactos",
            archivo_importacion=self.copy_test_resource_to_mediaroot(
                "planilla-ejemplo-3-headers-con-no-ascii-y-espacios.csv"),
            nombre_archivo_importacion=
            'planilla-ejemplo-3-headers-con-no-ascii-y-espacios.csv')

        parser = ParserCsv()
        estructura_archivo = parser.previsualiza_archivo(bd_contacto)
        predictor_metadata = PredictorMetadataService()
        metadata_inferida = predictor_metadata.inferir_metadata_desde_lineas(
            estructura_archivo)

        metadata = bd_contacto.get_metadata()
        metadata._metadata = metadata_inferida._metadata
        metadata.nombres_de_columnas = ["Telefono", "NOMBRE", "FECHA", "HORA"]
        metadata.columna_con_telefono = 0
        metadata.columnas_con_telefono = [0]
        metadata.save()

        creacion_base_datos_service = CreacionBaseDatosService()
        creacion_base_datos_service.importa_contactos(bd_contacto,
                                                      ["Telefono"], None)
        creacion_base_datos_service.define_base_dato_contacto(bd_contacto)

        # ----- checks

        self.assertEquals(
            BaseDatosContacto.objects.get(pk=bd_contacto.id).estado,
            BaseDatosContacto.ESTADO_DEFINIDA,
            "La BD no ha quedado en estado ESTADO_DEFINIDA")

        nros_telefono = [
            contacto.telefono
            for contacto in Contacto.objects.filter(bd_contacto=bd_contacto.id)
        ]

        self.assertEquals(len(nros_telefono), 3, "Deberia haber 3 contactos")

        self.assertEquals(
            set(nros_telefono),
            set(['354303459865', '111534509230', '283453013491']),
            "Deberia haber 3 contactos")
 def __init__(self) -> None:
     self.parser = None
     self.legacy_parser = ParserCsv()
Exemplo n.º 12
0
    def test_delimiter_incorrecto(self):
        parser = ParserCsv()

        with self.assertRaises(OmlParserCsvDelimiterError):
            planilla = self.get_test_resource("planilla-ejemplo-5.csv")
            parser._get_dialect(open(planilla, 'r'))
Exemplo n.º 13
0
 def test_cantidad_minima_de_filas(self):
     planilla = self.get_test_resource("planilla-ejemplo-4.csv")
     parser = ParserCsv()
     with self.assertRaises(OmlParserMinRowError):
         parser._get_dialect(open(planilla, 'r'))
Exemplo n.º 14
0
    def importa_contactos(self, base_datos_contacto, campos_telefonicos, columna_id_externo):
        """
        Tercer paso de la creación de una BaseDatosContacto.
        Este método se encarga de generar los objectos Contacto por cada linea
        del archivo de importación especificado para la base de datos de
        contactos.
        """
        assert (base_datos_contacto.estado in
                (BaseDatosContacto.ESTADO_EN_DEFINICION,
                 BaseDatosContacto.ESTADO_DEFINIDA_ACTUALIZADA))

        # FIXME: este metodo valida la consistencia de los metadatos, y
        # lanza una excepcion ante cualquier problema. OJO! Esto no implica
        # que los metadatos sean correctos y consistentes con los datos,
        # pero al menos validan la consistencia "interna" de los metadatos
        # metadata = base_datos_contacto.get_metadata()
        # metadata.validar_metadatos()

        # Antes que nada, borramos los contactos preexistentes
        # base_datos_contacto.elimina_contactos()

        parser = ParserCsv()

        ids_externos = base_datos_contacto.contactos.values_list('id_externo', flat=True)
        ids_externos = set(ids_externos)
        ids_nuevos_contactos = []

        try:
            estructura_archivo = parser.get_estructura_archivo(base_datos_contacto)
            posicion_primer_telefono = estructura_archivo[0].index(
                str(campos_telefonicos[0]))
            cantidad_contactos = 0

            if base_datos_contacto.cantidad_contactos:
                cantidad_contactos = base_datos_contacto.cantidad_contactos
            numero_fila = 0
            for lista_dato in estructura_archivo[1:]:
                numero_fila += 1
                telefono, datos, id_externo = self.obtener_telefono_y_datos(
                    lista_dato, posicion_primer_telefono, columna_id_externo)
                cantidad_contactos += 1

                if id_externo is not None and id_externo != '':
                    # El id_externo no puede estar repetido
                    if id_externo in ids_externos:
                        base_datos_contacto.contactos.filter(id__in=ids_nuevos_contactos).delete()
                        raise(CreacionBaseDatosServiceIdExternoError(numero_fila,
                                                                     columna_id_externo,
                                                                     lista_dato,
                                                                     id_externo))
                    else:
                        ids_externos.add(id_externo)

                contacto = Contacto.objects.create(
                    telefono=telefono,
                    datos=datos,
                    bd_contacto=base_datos_contacto,
                    id_externo=id_externo
                )
                ids_nuevos_contactos.append(contacto.id)

        except OmlParserMaxRowError:
            base_datos_contacto.contactos.filter(id__in=ids_nuevos_contactos).delete()
            raise

        except OmlParserCsvImportacionError:
            base_datos_contacto.contactos.filter(id__in=ids_nuevos_contactos).delete()
            raise

        base_datos_contacto.cantidad_contactos = cantidad_contactos
        base_datos_contacto.save()
    def form_valid(self, estructura_archivo, form_primer_linea_encabezado,
                   form_campos_telefonicos):
        # columna_con_telefono = int(form_columna_telefono.cleaned_data.get(
        #                            'telefono', None))
        # cantidad_columnas = len(form_nombre_columnas.fields)
        cantidad_columnas = len(estructura_archivo[0])

        # for numero_columna in range(cantidad_columnas):
        #     dato_extra = form_datos_extras.cleaned_data.get(
        #         'datos-extras-{0}'.format(numero_columna), None)
        #     if dato_extra == BaseDatosContacto.DATO_EXTRA_FECHA:
        #         lista_columnas_fechas.append(numero_columna)
        #     elif dato_extra == BaseDatosContacto.DATO_EXTRA_HORA:
        #         lista_columnas_horas.append(numero_columna)
        #
        #     nombre_columna = form_nombre_columnas.cleaned_data.get(
        #         'nombre-columna-{0}'.format(numero_columna), None)
        #
        #     validador_nombre = ValidadorDeNombreDeCampoExtra()
        #     if not validador_nombre.validar_nombre_de_columna(nombre_columna):
        #         error = 'El nombre de la Columna{0} no es válido. Debe estar \
        #                  en mayúscula y sin espacios. Por ejemplo: \
        #                  TELEFONO_FIJO'.format(numero_columna)
        #
        #         return self.form_invalid(estructura_archivo,
        #                                  #form_columna_telefono,
        #                                  #form_datos_extras,
        #                                  #form_nombre_columnas,
        #                                  form_primer_linea_encabezado,
        #                                  error=error)
        #
        #     lista_nombre_columnas.append(nombre_columna)

        # error = None
        # lista_columnas_encabezado = estructura_archivo[0]
        # if lista_columnas_encabezado[0] != 'telefono':
        #     error = _("El nombre de la primera columna debe ser telefono")
        # if error:
        #     return self.form_invalid(estructura_archivo,
        #                             form_primer_linea_encabezado,
        #                             form_campos_telefonicos, error=error)

        parser = ParserCsv()
        # Detecto el encondig de la base de datoss recientemente subida
        encoding = parser.detectar_encoding_csv(estructura_archivo)
        metadata = self.object.get_metadata()
        metadata.cantidad_de_columnas = cantidad_columnas

        # predictor_metadata = PredictorMetadataService()
        # columnas_con_telefonos = predictor_metadata.inferir_columnas_telefono(
        #     estructura_archivo[1:], encoding)
        campos_telefonicos = form_campos_telefonicos.cleaned_data.get(
            'campos_telefonicos')
        columnas_con_telefono = form_campos_telefonicos.columnas_de_telefonos
        metadata.columnas_con_telefono = columnas_con_telefono
        columna_id_externo = form_campos_telefonicos.columna_id_externo
        if columna_id_externo is not None:
            metadata.columna_id_externo = columna_id_externo

        metadata.nombres_de_columnas = [
            value.decode(encoding) for value in estructura_archivo[0]
        ]
        es_encabezado = False
        if self.request.POST.get('es_encabezado', False):
            es_encabezado = True
        metadata.primer_fila_es_encabezado = es_encabezado
        metadata.save()

        creacion_base_datos = CreacionBaseDatosService()

        try:
            # creacion_base_datos.valida_contactos(self.object)
            creacion_base_datos.importa_contactos(self.object,
                                                  campos_telefonicos,
                                                  columna_id_externo)
        except CreacionBaseDatosServiceIdExternoError as e:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee contactos con identificadores externos '
                  'repetidos.<br> '
                  '<u>Línea Inválida:</u> {0}<br> <u>Contenido Línea:</u>'
                  ' {1}<br><u>ID repetido:</u> {2}').format(
                e.numero_fila, e.fila, e.valor_celda)

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
            return self.render_to_response(
                self.get_context_data(
                    estructura_archivo=estructura_archivo,
                    form_primer_linea_encabezado=form_primer_linea_encabezado))

        except OmlParserCsvImportacionError as e:

            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee registros inválidos.<br> '
                  '<u>Línea Inválida:</u> {0}<br> <u>Contenido Línea:</u>'
                  '{1}<br><u>Contenido Inválido:</u> {2}').format(
                e.numero_fila, e.fila, e.valor_celda)

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
            # FIXME: Ver bien que hacer acá.

        except ContactoExistenteError as e:

            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee registros inválidos.<br> '
                  'ERROR: {0}. Vuelva a cargar nuevamente la base de datos '
                  'sin el contacto existente ').format(e)

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )

            return self.render_to_response(
                self.get_context_data(
                    estructura_archivo=estructura_archivo,
                    form_primer_linea_encabezado=form_primer_linea_encabezado,
                    form_campos_telefonicos=form_campos_telefonicos))

        except OmlParserMaxRowError:
            message = _('<strong>Operación Errónea!</strong> ') +\
                _('El archivo que seleccionó posee más registros de los '
                  'permitidos para ser importados.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
            return redirect(reverse('lista_base_datos_contacto'))
        else:
            creacion_base_datos.define_base_dato_contacto(self.object)

            message = _('<strong>Operación Exitosa!</strong> ') +\
                _('Se llevó a cabo con éxito la creación de '
                  'la Base de Datos de Contactos.')

            messages.add_message(
                self.request,
                messages.SUCCESS,
                message,
            )
            return redirect(self.get_success_url())