def test_importa_contacto(self):
        # 3543009865,lkasdjlfkaf,0351156219387
        # 111534509230,dkasjflkja,0351156982639
        # 2830173491,alsdkjfieasdf,3516983419
        # 3560127341,kahvuahdsfasdfa,2954638961

        bd = BaseDatosContacto(id=1)
        bd.archivo_importacion = File(open(self.get_test_resource(
            "planilla-ejemplo-1.csv"), 'r'))
        bd.nombre_archivo_importacion = "planilla-ejemplo-1.csv"
        bd.save()

        metadata = bd.get_metadata()
        metadata.cantidad_de_columnas = 3
        metadata.columna_con_telefono = 0
        metadata.columnas_con_telefono = [0, 2]
        metadata.columna_id_externo = 1
        metadata.nombres_de_columnas = ["telefono",
                                        "nombre",
                                        "celular"]
        metadata.save()

        # -----

        creacion_base_de_datos_service = CreacionBaseDatosService()
        creacion_base_de_datos_service.importa_contactos(bd, ["telefono", "celular"], 1)

        self.assertEqual(bd.contactos.count(), 4)
        for contacto in bd.contactos.all():
            self.assertIsNotNone(contacto.id_externo)
    def test_importa_archivo_utf8_correctamente(self):
        bd = BaseDatosContacto(id=1)
        bd.archivo_importacion = File(open(self.get_test_resource(
            "planilla-ejemplo-6.csv"), 'r'))

        bd.nombre_archivo_importacion = "bd-contactos-utf8.csv"
        bd.save()

        # -----
        service = CreacionBaseDatosService()
        service.genera_base_dato_contacto(bd)

        metadata = bd.get_metadata()
        metadata.cantidad_de_columnas = 2
        metadata.columna_con_telefono = 0
        metadata.columnas_con_telefono = [0]
        metadata.nombres_de_columnas = ["telefono", "Nombre"]
        metadata.primer_fila_es_encabezado = True
        metadata.save()

        service.importa_contactos(bd, ['telefono'], None)

        self.assertEquals(Contacto.objects.count(), 2)
        contactos = list(Contacto.objects.all())
        contactos_dict = dict([(c.telefono, c.datos) for c in contactos])

        self.assertIn('375849371648', contactos_dict)
        self.assertIn('957327493493', contactos_dict)
    def test_genera_base_datos_falla_archivo_xls(self):
        bd = BaseDatosContacto(id=1)
        bd.nombre_archivo_importacion = "planilla-ejemplo-0.xls"
        bd.save()

        # -----
        creacion_base_de_datos_service = CreacionBaseDatosService()
        with self.assertRaises(OmlArchivoImportacionInvalidoError):
            creacion_base_de_datos_service.genera_base_dato_contacto(bd)
    def test_define_base_dato_contacto(self):
        bd = BaseDatosContacto(id=1)
        bd.save()

        # -----

        creacion_base_de_datos_service = CreacionBaseDatosService()
        creacion_base_de_datos_service.define_base_dato_contacto(bd)

        self.assertEqual(bd.estado, BaseDatosContacto.ESTADO_DEFINIDA)
    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))
    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 form_valid(self, form):

        self.object = form.save(commit=False)
        self.object.estado = BaseDatosContacto.ESTADO_DEFINIDA_ACTUALIZADA
        # self.object.nombre_archivo_importacion = nombre_archivo_importacion

        try:
            creacion_base_datos = CreacionBaseDatosService()
            creacion_base_datos.genera_base_dato_contacto(self.object)
        except OmlArchivoImportacionInvalidoError:
            message = _('<strong>Operación Errónea!</strong> ') + \
                _('El archivo especificado para realizar la importación de contactos '
                  'no es válido.')

            messages.add_message(
                self.request,
                messages.ERROR,
                message,
            )
            return self.form_invalid(form)

        return redirect(self.get_success_url())
    def form_valid(self, estructura_archivo, form_primer_linea_encabezado):

        cantidad_columnas = len(estructura_archivo[0])

        lista_columnas_encabezado = estructura_archivo[0]

        error = None

        metadata = self.object.get_metadata()
        metadata.cantidad_de_columnas = cantidad_columnas

        for columna_base, columna_csv in zip(metadata.nombres_de_columnas,
                                             lista_columnas_encabezado):
            if str(columna_base).capitalize() != str(columna_csv).capitalize():
                error = _("El nombre de la columna debe ser {0} en vez de {1}".
                          format(columna_base, columna_csv))

        if error:
            return self.form_invalid(estructura_archivo,
                                     form_primer_linea_encabezado,
                                     error=error)

        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)
            bd_metadata = self.object.get_metadata()
            columnas_con_telefono = bd_metadata.nombres_de_columnas_de_telefonos
            columna_id_externo = bd_metadata.columna_id_externo

            creacion_base_datos.importa_contactos(self.object,
                                                  columnas_con_telefono,
                                                  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,
            )
            return self.render_to_response(
                self.get_context_data(
                    estructura_archivo=estructura_archivo,
                    form_primer_linea_encabezado=form_primer_linea_encabezado))

        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))

        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:
            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,
            )

            # En caso de que sea agregar a una campaña preview, genero los AgenteEnContacto
            # para los contactos nuevos.
            if self.campana is not None and self.campana.type == Campana.TYPE_PREVIEW:
                self._generar_relaciones_agente_en_contacto()

            return redirect(self.get_success_url())
    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())