Exemplo n.º 1
0
    def poblar_mesa(self, mesa):
        mesa_categoria = MesaCategoria.objects.get(categoria=self.categoria, mesa=mesa)
        fiscal = Fiscal.objects.all().first()

        cargas = []
        for i in range(self.cant_cargas):
            cargas.append(
                Carga.objects.create(
                    tipo=Carga.TIPOS.parcial,
                    fiscal=fiscal,
                    origen=Carga.SOURCES.csv,
                    mesa_categoria=mesa_categoria
                )
            )
        opciones = self.categoria.opciones_actuales(
            solo_prioritarias=True, excluir_optativas=True
        )

        total_votos = random.randint(1, 101)  # Valor inicial = votos de categorías no prioritarias
        for opcion in opciones:
            if opcion != Opcion.total_votos():
                votos_opcion = random.randint(1, 101)
                total_votos += votos_opcion
                self.poblar_opcion(mesa, opcion, cargas, votos_opcion)

        self.poblar_opcion(mesa, Opcion.total_votos(), cargas, total_votos)
Exemplo n.º 2
0
def test_listar_opciones_todas(admin_client):
    o2 = factories.OpcionFactory()
    o3 = factories.OpcionFactory()

    c = factories.CategoriaFactory(opciones=[])

    co3 = factories.CategoriaOpcionFactory(categoria=c, orden=2, opcion=o3)
    co2 = factories.CategoriaOpcionFactory(categoria=c, orden=3, opcion=o2)

    o1 = factories.CategoriaOpcionFactory(categoria=c, orden=1, prioritaria=True).opcion
    o4 = factories.CategoriaOpcionFactory(categoria=c, orden=4, prioritaria=True).opcion

    url = reverse('opciones', kwargs={'id_categoria': c.id})

    response = admin_client.get(url, data={'solo_prioritarias': False}, format='json')

    assert response.status_code == status.HTTP_200_OK
    assert len(response.data) == 7

    opciones = [(opc['id'], opc['nombre'], opc['nombre_corto'], opc['codigo']) for opc in response.data]
    assert opciones == [
        (o1.id, o1.nombre, o1.nombre_corto, o1.codigo),
        (o3.id, o3.nombre, o3.nombre_corto, o3.codigo),
        (o2.id, o2.nombre, o2.nombre_corto, o2.codigo),
        (o4.id, o4.nombre, o4.nombre_corto, o4.codigo),
    ] + [(
        opcion.id, opcion.nombre, opcion.nombre_corto, opcion.codigo
    ) for opcion in [
        Opcion.blancos(), Opcion.total_votos(), Opcion.nulos()
    ]]
Exemplo n.º 3
0
def test_mesa_de_circuito__url_mesa_con_resultados(carta_marina, fiscal_client):
    # resultados para mesa 1
    mesa1, *otras_mesas = carta_marina
    categoria = mesa1.categorias.get()  # sólo default
  
    # Esto no debería ser necesario si configuramos correctamente las opciones prioritarias en carta_marina
    CategoriaOpcion.objects.filter(categoria=categoria).update(prioritaria=True)

    # opciones a partido
    o1, o2, o3, o4 = categoria.opciones.filter(partido__isnull=False)
    # la opción 4 pasa a ser del mismo partido que la 1
    o4.partido = o1.partido
    o4.save()

    blanco = Opcion.blancos()
    total = Opcion.total_votos()

    mc1 = MesaCategoria.objects.get(mesa=mesa1, categoria=categoria)
    carga = CargaFactory(mesa_categoria=mc1, tipo=Carga.TIPOS.parcial)

    consumir_novedades_y_actualizar_objetos([mesa1])

    VotoMesaReportadoFactory(carga=carga, opcion=o1, votos=20)
    VotoMesaReportadoFactory(carga=carga, opcion=o2, votos=30)
    VotoMesaReportadoFactory(carga=carga, opcion=o3, votos=40)
    VotoMesaReportadoFactory(carga=carga, opcion=o4, votos=5)

    # votaron 95/100 personas
    VotoMesaReportadoFactory(carga=carga, opcion=blanco, votos=5)
    VotoMesaReportadoFactory(carga=carga, opcion=total, votos=100)

    carga.actualizar_firma()

    assert carga.es_testigo.exists()

    query_string_mesa_1 = (
        f'?mesa={mesa1.id}&circuito={mesa1.circuito.id}'
        '&tipoDeAgregacion=todas_las_cargas'
        f'&opcionaConsiderar={OPCIONES_A_CONSIDERAR.prioritarias}'
        )
    url_mesa_1 = reverse('mesas-circuito', args=[categoria.id]) + query_string_mesa_1
    response = fiscal_client.get(url_mesa_1)

    assert response.status_code == 200

    content = response.content.decode('utf8')
    assert response.context['mensaje_no_hay_info'] not in content

    resultados = response.context['resultados']
    assert len(resultados) == 6  # 4 opciones + blanco + total

    for voto_mesa_reportado in resultados:
        assert f'<th>{voto_mesa_reportado.opcion}</th>' in content
        assert f'<td>{voto_mesa_reportado.votos}</td>' in content
Exemplo n.º 4
0
    def opciones(self, create, extracted, **kwargs):

        if not create:
            return

        # Toda categoría debe tener las opciones no partidarias.
        orden = 1000  # Las mandamos 'al fondo' en el orden.
        for nombre in Opcion.opciones_no_partidarias():
            opcion, created = Opcion.objects.get_or_create(**getattr(settings, nombre))
            if created:
                opcion.nombre = opcion.nombre_corto
                opcion.save(update_fields=['nombre'])
            defaults = {'orden': orden}
            CategoriaOpcion.objects.get_or_create(categoria=self, opcion=opcion, defaults=defaults)
            orden += 1

        if extracted is not None:
            #
            for opcion in extracted:
                CategoriaOpcionFactory(categoria=self, opcion=opcion)
        else:
            # Por defecto se crean cuatro opciones partidarias
            CategoriaOpcionFactory(categoria=self, opcion=OpcionFactory(nombre='opc1'))
            CategoriaOpcionFactory(categoria=self, opcion=OpcionFactory(nombre='opc2'))
            CategoriaOpcionFactory(categoria=self, opcion=OpcionFactory(nombre='opc3'))
            CategoriaOpcionFactory(categoria=self, opcion=OpcionFactory(nombre='opc4'))
Exemplo n.º 5
0
    def configurar_categoria_prioritaria(self, categoria, codigos, sensible):
        categoria.activa = True
        categoria.sensible = sensible
        categoria.requiere_cargas_parciales = True
        if sensible:
            categoria.prioridad = 2
        categoria.save()

        # Opciones prioritarias.
        for cod_partido in codigos:
            categoriaopcion = CategoriaOpcion.objects.get(
                categoria=categoria,
                opcion__partido__codigo=cod_partido,
            )
            categoriaopcion.set_prioritaria()

        opciones_obligatorias = [
            Opcion.blancos(),
            Opcion.nulos(),
            Opcion.total_votos(),
            Opcion.sobres(),
            Opcion.recurridos(),
            Opcion.id_impugnada(),
            Opcion.comando_electoral(),
        ]
        for opcion in opciones_obligatorias:
            categoriaopcion = CategoriaOpcion.objects.get(
                categoria=categoria,
                opcion=opcion,
            )
            categoriaopcion.set_prioritaria()
Exemplo n.º 6
0
def test_opciones_actuales(db):
    o2 = OpcionFactory()
    o3 = OpcionFactory()
    c = CategoriaFactory(opciones=[])
    co3 = CategoriaOpcionFactory(categoria=c, orden=2, opcion=o3)
    co2 = CategoriaOpcionFactory(categoria=c, orden=3, opcion=o2)
    o1 = CategoriaOpcionFactory(categoria=c, orden=1, prioritaria=True).opcion

    assert list(c.opciones_actuales()) == [
        o1, o3, o2,
        Opcion.blancos(), Opcion.total_votos(), Opcion.sobres(), Opcion.nulos(),
        Opcion.recurridos(), Opcion.id_impugnada(), Opcion.comando_electoral(),
    ]
    assert list(c.opciones_actuales(solo_prioritarias=True)) == [o1]
    assert list(c.opciones_actuales(excluir_optativas=True)) == [
        o1, o3, o2,
        Opcion.blancos(), Opcion.total_votos(), Opcion.nulos()
    ]
Exemplo n.º 7
0
def test_formset_en_carga_total_reusa_parcial_confirmada(
        db, fiscal_client, admin_user, settings):
    # Solo una carga, para simplificar el setup
    settings.MIN_COINCIDENCIAS_CARGAS = 1

    c = CategoriaFactory(id=25000, opciones=[])

    # Notar que el orden no coincide con el id
    o1 = CategoriaOpcionFactory(categoria=c, orden=3, prioritaria=True).opcion
    o2 = CategoriaOpcionFactory(categoria=c, orden=1, prioritaria=False).opcion
    o3 = CategoriaOpcionFactory(categoria=c, orden=2, prioritaria=False).opcion
    o4 = CategoriaOpcionFactory(categoria=c, orden=4, prioritaria=True).opcion

    mc = MesaCategoriaFactory(categoria=c)
    mc.asignar_a_fiscal()
    admin_user.fiscal.asignar_mesa_categoria(mc)

    # Se carga parcialente, la opcion prioritaira "o"
    carga = CargaFactory(mesa_categoria=mc, tipo='parcial')
    VotoMesaReportadoFactory(carga=carga, opcion=o1, votos=10)
    VotoMesaReportadoFactory(carga=carga, opcion=o4, votos=3)

    # Consolidamos.
    consumir_novedades_carga()
    mc.refresh_from_db()
    assert mc.status == MesaCategoria.STATUS.parcial_consolidada_dc
    assert mc.carga_testigo == carga
    assert set(carga.opcion_votos()) == {(o1.id, 10), (o4.id, 3)}

    # Ahora pedimos la carga total
    totales = reverse('carga-total', args=[mc.id])
    response = fiscal_client.get(totales)

    # Tenemos las tres opciones en orden
    assert len(response.context['formset']) == 4 + len(
        Opcion.opciones_no_partidarias_obligatorias())
    assert response.context['formset'][0].initial['opcion'] == o2
    assert response.context['formset'][1].initial['opcion'] == o3
    assert response.context['formset'][2].initial['opcion'] == o1
    assert response.context['formset'][3].initial['opcion'] == o4

    # y los valores de los votos
    assert response.context['formset'][0].initial['votos'] is None
    assert response.context['formset'][1].initial['votos'] is None
    assert response.context['formset'][2].initial['votos'] == 10
    assert response.context['formset'][3].initial['votos'] == 3

    # el valor previo es readonly
    assert response.context['formset'][2].fields['votos'].widget.attrs[
        'readonly'] is True
    assert response.context['formset'][3].fields['votos'].widget.attrs[
        'readonly'] is True
Exemplo n.º 8
0
def carga_inicial(db):
    d1 = DistritoFactory(numero=1)
    s1 = SeccionFactory(numero=50, distrito=d1)
    circ = CircuitoFactory(numero='2', seccion=s1)

    # Creamos los partidos.
    fdt = OpcionFactory(codigo='FdT', nombre='FdT', partido__nombre='FpT')
    jpc = OpcionFactory(codigo='JpC', nombre='JpC', partido__nombre='JpC')
    c2019 = OpcionFactory(codigo='C2019',
                          nombre='C2019',
                          partido__nombre='C2019')

    categorias = []
    for categoria, prioritaria in CATEGORIAS:
        categoria_general = CategoriaGeneralFactory(nombre=categoria)
        # La categoría en sí tiene un nombre arbitrario para testear que
        # el matching sea en base a la categoría general.
        categoria_bd = CategoriaFactory(nombre=f'Categoría {categoria}',
                                        categoria_general=categoria_general)

        # La factory las crea con unas opciones que hacen ruido en estos tests.
        for nombre in ['opc1', 'opc2', 'opc3', 'opc4']:
            opcion = Opcion.objects.get(nombre=nombre)
            opcion.delete()

        categorias.append(categoria_bd)
        CategoriaOpcionFactory(categoria=categoria_bd,
                               prioritaria=prioritaria,
                               opcion=fdt)
        CategoriaOpcionFactory(categoria=categoria_bd,
                               prioritaria=prioritaria,
                               opcion=jpc)
        if categoria == 'Presidente y vice':
            CategoriaOpcionFactory(categoria=categoria_bd,
                                   prioritaria=False,
                                   opcion=c2019)
        if prioritaria:
            # Adecuamos las opciones prioritarias.
            hacer_prioritaria_en_cat(categoria_bd, Opcion.total_votos())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.blancos())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.nulos())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.sobres())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.recurridos())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.id_impugnada())
            hacer_prioritaria_en_cat(categoria_bd, Opcion.comando_electoral())

    MesaFactory(numero='4012',
                lugar_votacion__circuito=circ,
                electores=100,
                circuito=circ,
                categorias=categorias)
Exemplo n.º 9
0
def test_formset_en_carga_total_muestra_todos(db, fiscal_client, admin_user):
    c = CategoriaFactory(id=100, opciones=[])
    o = CategoriaOpcionFactory(categoria=c, orden=3, prioritaria=True).opcion
    o2 = CategoriaOpcionFactory(categoria=c, orden=1, prioritaria=False).opcion
    mc = MesaCategoriaFactory(categoria=c)
    mc.asignar_a_fiscal()
    admin_user.fiscal.asignar_mesa_categoria(
        mc)  # Para que no lo mande a otra por falta de permisos.
    totales = reverse('carga-total', args=[mc.id])
    response = fiscal_client.get(totales)
    assert len(response.context['formset']) == 2 + len(
        Opcion.opciones_no_partidarias_obligatorias())
    assert response.context['formset'][0].fields['opcion'].choices == [(o2.id,
                                                                        o2)]
    assert response.context['formset'][1].fields['opcion'].choices == [(o.id,
                                                                        o)]
Exemplo n.º 10
0
def test_formset_carga_total_votos_mayor_electores_mesa(db):
    m = MesaFactory(electores=100)
    o1 = Opcion.total_votos()
    VMRFormSet = votomesareportadoformset_factory(min_num=1)
    data = _construir_request_data_para_carga_de_resultados([(o1.id, 200, 0)])
    formset = VMRFormSet(data=data, mesa=m, datos_previos={})

    assert not formset.is_valid()
    assert len(formset.non_form_errors()) == 1

    VMRFormSet = votomesareportadoformset_factory(min_num=1)
    data = _construir_request_data_para_carga_de_resultados([(o1.id, 80, 0)])
    formset = VMRFormSet(data=data, mesa=m, datos_previos={})

    assert formset.is_valid()
    assert len(formset.non_form_errors()) == 0
Exemplo n.º 11
0
def test_solo_consolidados(mesas_con_votos, url_resultados, fiscal_client):
    m1, *_ = mesas_con_votos
    categoria = m1.categorias.all().order_by('id').first()
    o1 = categoria.opciones_actuales().get(nombre_corto='la_elegida')
    blancos = Opcion.blancos()

    # Pide opciones consolidadas, descarta m1 que tiene una sola carga web
    response = fiscal_client.get(
        reverse('resultados-categoria', args=[categoria.id]), {
            'opcionaConsiderar': OPCIONES_A_CONSIDERAR.todas,
            'tipoDeAgregacion': TIPOS_DE_AGREGACIONES.solo_consolidados
        })

    resultados = response.context['resultados']
    assert resultados.total_mesas_escrutadas() == 2
    assert resultados.tabla_positivos()[o1.partido]['votos'] == 135
    assert resultados.tabla_no_positivos()[blancos.nombre_corto]['votos'] == 50
Exemplo n.º 12
0
def test_formset_carga_warning_sobres_mayor_mesa_electores(db):
    m = MesaFactory()
    o1 = Opcion.sobres()

    VMRFormSet = votomesareportadoformset_factory(min_num=1)
    data = _construir_request_data_para_carga_de_resultados([(o1.id, 101, 0)])
    formset = VMRFormSet(data=data, mesa=m, datos_previos={})

    assert not formset.is_valid()
    assert len(formset.non_form_errors()) == 1

    VMRFormSet = votomesareportadoformset_factory(min_num=1)
    data = _construir_request_data_para_carga_de_resultados([(o1.id, 101, 101)
                                                             ])
    formset = VMRFormSet(data=data, mesa=m, datos_previos={})

    assert formset.is_valid()
    assert len(formset.non_form_errors()) == 0
Exemplo n.º 13
0
    def agregar_electores_y_sobres(self, mesa, carga):
        if not carga:
            return

        # XXX Ver qué hacemos con la cantidad de electores.
        # if self.dato_ausente(self.cantidad_electores_mesa):

        # Si no hay sobres no pasa nada.
        if self.dato_ausente(self.cantidad_sobres_mesa):
            return

        opcion_sobres = Opcion.sobres()

        cantidad_votos = int(self.cantidad_sobres_mesa)
        VotoMesaReportado.objects.create(carga=carga,
                                         votos=cantidad_votos,
                                         opcion=opcion_sobres
                                         )
        self.log_debug(f"---- Agregando {cantidad_votos} votos a {opcion_sobres} en carga {carga.tipo}.")
Exemplo n.º 14
0
def test_formset_reusa_metadata(db, fiscal_client, admin_user):
    # Hay una categoria con una opcion metadata ya consolidada.
    o1 = OpcionFactory(tipo=Opcion.TIPOS.metadata)
    cat1 = CategoriaFactory(opciones=[o1])
    from elecciones.models import CategoriaOpcion
    # Me aseguro de que no estuviese asociada con otro orden.
    CategoriaOpcion.objects.filter(categoria=cat1, opcion=o1).delete()
    cat1op1 = CategoriaOpcionFactory(categoria=cat1, opcion=o1, orden=1)
    mc = MesaCategoriaFactory(categoria=cat1,
                              status=MesaCategoria.STATUS.total_consolidada_dc)
    carga = CargaFactory(mesa_categoria=mc, tipo='total')
    VotoMesaReportadoFactory(carga=carga, opcion=o1, votos=10)

    # Otra categoría incluye la misma metadata.
    o2 = OpcionFactory()
    cat2 = CategoriaFactory(opciones=[o1, o2])
    # Me aseguro de que no estuviesen asociadas con otro orden.
    CategoriaOpcion.objects.filter(categoria=cat2, opcion=o1).delete()
    CategoriaOpcion.objects.filter(categoria=cat2, opcion=o2).delete()
    cat2op1 = CategoriaOpcionFactory(categoria=cat2, opcion=o1, orden=1)
    cat2op1 = CategoriaOpcionFactory(categoria=cat2, opcion=o2, orden=2)
    mc2 = MesaCategoriaFactory(categoria=cat2, mesa=mc.mesa)

    mc2.asignar_a_fiscal()
    admin_user.fiscal.asignar_mesa_categoria(mc2)
    response = fiscal_client.get(reverse('carga-total', args=[mc2.id]))
    assert len(response.context['formset']) == 2 + len(
        Opcion.opciones_no_partidarias_obligatorias())
    assert response.context['formset'][0].initial['opcion'] == o1
    assert response.context['formset'][1].initial['opcion'] == o2

    # y los valores de los votos
    assert response.context['formset'][0].initial['votos'] == 10
    assert response.context['formset'][0].fields['votos'].widget.attrs[
        'readonly'] is True

    assert response.context['formset'][1].initial['votos'] is None
Exemplo n.º 15
0
def mesas_con_votos(carta_marina):
    m1, m2, m3, *_ = carta_marina
    categoria = m1.categorias.all().order_by('id').first()
    o1 = OpcionFactory(nombre_corto='la_elegida')
    CategoriaOpcionFactory(categoria=categoria, opcion=o1, prioritaria=False)
    blancos = Opcion.blancos()

    c1 = CargaFactory(tipo=Carga.TIPOS.total,
                      origen=Carga.SOURCES.web,
                      mesa_categoria__mesa=m1,
                      mesa_categoria__categoria=categoria)
    cargar_votos(c1, {o1: 50, blancos: 10})

    c2 = CargaFactory(tipo=Carga.TIPOS.total,
                      origen=Carga.SOURCES.csv,
                      mesa_categoria__mesa=m2,
                      mesa_categoria__categoria=categoria)
    cargar_votos(c2, {o1: 60, blancos: 20})

    c3 = CargaFactory(tipo=Carga.TIPOS.total,
                      origen=Carga.SOURCES.web,
                      mesa_categoria__mesa=m3,
                      mesa_categoria__categoria=categoria)
    cargar_votos(c3, {o1: 75, blancos: 30})

    c4 = CargaFactory(tipo=Carga.TIPOS.total,
                      origen=Carga.SOURCES.web,
                      mesa_categoria__mesa=m3,
                      mesa_categoria__categoria=categoria)
    cargar_votos(c4, {
        o1: 75,
        blancos: 30,
    })

    consumir_novedades_y_actualizar_objetos()
    return [m1, m2, m3]
Exemplo n.º 16
0
def test_configuracion_combinada(db, fiscal_client, url_resultados_computo):
    # Seteamos el modo de elección como PASO; por lo tanto
    # los porcentajes que deberíamos visualizar son los porcentaje_validos
    settings.MODO_ELECCION = settings.ME_OPCION_GEN

    # Asegurar una carta marina con dos distritos extra además del "Distrito único".
    Distrito.objects.all().delete()
    mesas = create_carta_marina(create_distritos=3)

    categoria = Categoria.objects.first()
    for mesa in mesas:
        MesaCategoriaFactory(mesa=mesa, categoria=categoria)

    o1, o2, *_ = categoria.opciones.filter(partido__isnull=False)
    blancos = Opcion.blancos()
    nulos = Opcion.nulos()
    total = Opcion.total_votos()

    # Cargamos los mismos votos en los tres distritos.
    # for distrito in Distrito.objects.exclude(id=1):  # Excluyo al distrito "único" que se crea siempre.
    for distrito in Distrito.objects.all():
        s1, s2 = distrito.secciones.all()

        # En s1 hacemos una carga doble sobre la misma mesa
        mc1, *_ = MesaCategoria.objects.filter(
            mesa__lugar_votacion__circuito__seccion=s1)
        c1 = CargaFactory(mesa_categoria=mc1, tipo=Carga.TIPOS.total)
        cargar_votos(c1, {o1: 60, o2: 40, blancos: 0, nulos: 0, total: 100})

        c2 = CargaFactory(mesa_categoria=mc1, tipo=Carga.TIPOS.total)
        cargar_votos(c2, {o1: 60, o2: 40, blancos: 0, nulos: 0, total: 100})

        # En s2 hacemos dos cargas simples en mesas distintas
        mc2, mc3, *_ = MesaCategoria.objects.filter(
            mesa__lugar_votacion__circuito__seccion=s2)
        c3 = CargaFactory(mesa_categoria=mc2, tipo=Carga.TIPOS.total)
        cargar_votos(c3, {o1: 20, o2: 60, blancos: 10, nulos: 0, total: 90})

        c4 = CargaFactory(mesa_categoria=mc3, tipo=Carga.TIPOS.total)
        cargar_votos(c4, {o1: 20, o2: 60, blancos: 5, nulos: 5, total: 90})

    consumir_novedades_y_actualizar_objetos()

    # Crear una configuración de cómputo combinada con estrategias diferentes para cada distrito
    configuracion_combinada = ConfiguracionComputoFactory()
    d1, d2, d3 = Distrito.objects.all()

    # Para el primer distrito consideramos todas las cargas.
    # Esto nos da 100 votos para la opción 1 (60 + 20 + 20)
    # Y 160 para s2 (40 + 60 + 60)
    # 15 blancos (10 + 5)
    # y 5 nulos (sólo mc3)
    ConfiguracionComputoDistritoFactory(
        configuracion=configuracion_combinada,
        distrito=d1,
        agregacion=TIPOS_DE_AGREGACIONES.todas_las_cargas,
        opciones=OPCIONES_A_CONSIDERAR.todas,
    )

    # Para el segundo distrito consideramos sólo las cargas consolidadas
    # Eso hace que que sólo se consideren los votos de mc1: 60 para o1 y 40 para o2
    # En s1 no hay blancos ni nulos
    ConfiguracionComputoDistritoFactory(
        configuracion=configuracion_combinada,
        distrito=d2,
        agregacion=TIPOS_DE_AGREGACIONES.solo_consolidados_doble_carga,
        opciones=OPCIONES_A_CONSIDERAR.todas,
    )

    # Para el último distrito consideramos todas las cargas,
    # pero utilizamos una proyección que exige dos mesas por agrupacion circuito
    # La sección 1 tiene una única mesa, se ignora.
    # La sección 2 tiene escrutadas 2 de 4 mesas, así que sus votos se multiplican por 2 = (4/2)
    # o1 = (20 + 20) * 2 = 80 votos
    # o2 = (60 + 60) * 2 = 240 votos
    # blancos = (10 + 5) * 2 = 30 votos
    # nulos = 5 * 2 = 10 votos
    ConfiguracionComputoDistritoFactory(
        configuracion=configuracion_combinada,
        distrito=d3,
        agregacion=TIPOS_DE_AGREGACIONES.todas_las_cargas,
        opciones=OPCIONES_A_CONSIDERAR.todas,
        proyeccion=tecnica_proyeccion(minimo_mesas=2),
    )

    response = fiscal_client.get(url_resultados_computo)
    resultados = response.context['resultados']

    assert resultados.total_mesas() == 24  # 8 en c/u de los 3 distritos

    # TODO Los siguientes dos asserts no dan por un bug en proyecciones, decidimos postergar su resolución.
    assert resultados.total_mesas_escrutadas() == 6  # {d1: 3, d2: 1, d3: 2}
    assert resultados.porcentaje_mesas_escrutadas() == '25.00'

    # Totales básicos
    assert resultados.electores() == 2400
    assert resultados.total_votos() == 740  # {d1: 100, d2: 280, d3: 360}

    # Opciones no positivas
    assert resultados.total_blancos() == 45  # {d2: 15, d3: 30}
    assert resultados.total_nulos() == 15  # {d2: 5, d3: 10}
    assert resultados.total_no_positivos() == 60  # 45 + 15

    # Opciones partidarias
    positivos = resultados.tabla_positivos()
    assert positivos[o1.partido]['votos'] == 240  # 60 + 100 + 80
    assert positivos[o2.partido]['votos'] == 440  # 40 + 160 + 240
    assert resultados.total_positivos() == 680  # 240 + 440
    #
    # Se ordena de acuerdo al que va ganando
    assert list(positivos.keys()) == [o2.partido, o1.partido]

    # Porcentajes
    assert resultados.porcentaje_blancos() == '6.08'  # 45 / 740
    assert resultados.porcentaje_nulos() == '2.03'  # 15 / 740

    assert positivos[
        o1.partido]['porcentaje_positivos'] == '35.29'  # 240 / 680
    assert positivos[o1.partido]['porcentaje_validos'] == '33.10'  # 240 / 725
    assert positivos[
        o2.partido]['porcentaje_positivos'] == '64.71'  # 440 / 680
    assert positivos[o2.partido]['porcentaje_validos'] == '60.69'  # 440 / 725

    # Todos los positivos suman 100
    assert sum(float(v['porcentaje_positivos'])
               for v in positivos.values()) == 100.0
Exemplo n.º 17
0
    def clean(self):
        super().clean()
        suma = 0
        errors = []

        for form in self.forms:
            opcion = form.cleaned_data.get('opcion')
            votos = form.cleaned_data.get('votos')
            if votos is None:
                raise ValidationError(_('Invalid value'), code='invalid')
            if opcion.tipo not in [
                    Opcion.TIPOS.metadata, Opcion.TIPOS.metadata_optativa
            ]:
                suma += votos

            previos = self.datos_previos.get(opcion.id, None)
            if previos and previos != votos:
                form.add_error(
                    'votos',
                    ValidationError(
                        f'El valor confirmado que tenemos para esta opción es {previos}'
                    ))

            if opcion == Opcion.total_votos():
                if votos > self.mesa.electores:
                    errors.append(
                        'El campo total de votos no puede ser mayor a la '
                        f'cantidad de electores de la mesa: {self.mesa.electores}'
                    )

        # Controlamos que la suma de votos no sea mayor a cantidad de
        # electores si conocemos la cantidad de electores de una mesa.
        if self.mesa.electores > 0 and suma > self.mesa.electores:
            errors.append(
                'La suma de los votos no puede ser mayor a la '
                f'cantidad de electores de la mesa: {self.mesa.electores}')

        if errors:
            raise forms.ValidationError(errors)

        #warnings
        warnings = []

        cantidad_forms = self.data['form-TOTAL_FORMS']
        mismos_datos = True
        for i in range(int(cantidad_forms)):
            mismos_datos = mismos_datos and (
                self.data['form-' + str(i) + '-valor-previo']
                == self.data['form-' + str(i) + '-votos'])

        if not mismos_datos:
            for form in self.forms:
                opcion = form.cleaned_data.get('opcion')
                votos = form.cleaned_data.get('votos')

                if opcion.partido and opcion.partido.codigo == settings.CODIGO_PARTIDO_NOSOTROS:
                    if votos == 0:
                        warnings.append(
                            f'La cantidad de votos de {opcion.nombre_corto} es cero.'
                        )

                if opcion.partido and opcion.partido.codigo == settings.CODIGO_PARTIDO_ELLOS:
                    if votos == 0:
                        warnings.append(
                            f'La cantidad de votos de {opcion.nombre_corto} es cero.'
                        )

                # sobres > mesa.electores && total_votos > sobres
                if opcion == Opcion.sobres():
                    if votos and votos > self.mesa.electores:
                        warnings.append(
                            'La cantidad de sobres es mayor a la '
                            f'cantidad de electores de la mesa: {self.mesa.electores}'
                        )

                    if votos and suma > votos:
                        warnings.append('La cantidad de votos es mayor a la '
                                        f'cantidad de sobres.')

                # guardo los datos en una variable auxiliar para comprobar si hubo
                # cambios al confirmar el warning
                data = form.data.copy()
                for i in range(int(cantidad_forms)):
                    data['form-' + str(i) +
                         '-valor-previo'] = data['form-' + str(i) + '-votos']

                form.data = data

            if warnings:
                warnings[-1] = mark_safe(
                    warnings[-1] +
                    '<br><br>¿Confirma que están cargados correctamente los valores que figuran en el acta?'
                )
                raise forms.ValidationError(warnings)
Exemplo n.º 18
0
    def procesar(self, **options):

        reader = DictReader(self.CSV.open())

        categoria = Categoria.objects.get(slug=options['categoria'])
        opcion_nosotros = CategoriaOpcion.objects.get(
            categoria=categoria,
            opcion__partido__codigo=settings.CODIGO_PARTIDO_NOSOTROS,
        ).opcion
        opcion_ellos = CategoriaOpcion.objects.get(
            categoria=categoria,
            opcion__partido__codigo=settings.CODIGO_PARTIDO_ELLOS,
        ).opcion

        fiscal = Fiscal.objects.get(id=1)

        for linea, row in enumerate(reader, 1):
            # Estas líneas son para importar los datos de gobernador
            # el csv viene con espacios en los nombres de columna

            # nro_distrito = int(row['distrito '])
            # nro_seccion = int(row[' seccion '])
            # nro_circuito = row[' circuito '].strip().lstrip('0')
            # nro_mesa = int(row[' mesa '])
            # cant_blanco = int(row[' blanco '])
            # cant_nulos = int(row[' nulo '])
            # total_votos = int(row[' total_electores '])
            # cant_nosotros = int(row[' vot_kicilove '])
            # cant_ellos = int(row[' vot_vidal'])

            # Las columnas de presidente no tienen espacios,
            # pero tal vez haya que corregir cambiar macri por alferdez.
            nro_distrito = int(row['distrito'])
            nro_seccion = int(row['seccion'])
            nro_circuito = row['circuito'].strip().lstrip('0')
            nro_mesa = int(row['mesa'])
            cant_blanco = int(row['blanco'])
            cant_nulos = int(row['nulo'])
            total_votos = int(row['total_electores'])
            cant_nosotros = int(row['vot_alferdez'])
            cant_ellos = int(row['vot_macri'])

            mesa = self.get_mesa(nro_distrito, nro_seccion, nro_circuito,
                                 nro_mesa)
            if not mesa:
                continue

            mesa_categoria = self.get_mesa_categoria(mesa, categoria)
            if not mesa_categoria:
                continue

            carga, creada = Carga.objects.get_or_create(
                mesa_categoria=mesa_categoria,
                tipo=Carga.TIPOS.parcial_oficial,
                fiscal=fiscal,
                origen=Carga.SOURCES.web)

            if creada:
                votos = []
                votos.append(
                    self.armar_voto(Opcion.blancos(), carga, cant_blanco))
                votos.append(self.armar_voto(Opcion.nulos(), carga,
                                             cant_nulos))
                votos.append(
                    self.armar_voto(Opcion.total_votos(), carga, total_votos))
                votos.append(
                    self.armar_voto(opcion_nosotros, carga, cant_nosotros))
                votos.append(self.armar_voto(opcion_ellos, carga, cant_ellos))
                VotoMesaReportado.objects.bulk_create(votos)

                carga.actualizar_firma()

                mesa_categoria.parcial_oficial = carga
                mesa_categoria.save(update_fields=['parcial_oficial'])
                self.success(f"Insertando votos en mesa {mesa}.")

            else:
                self.warning(f"Ignorando votos de mesa {mesa}")
Exemplo n.º 19
0
def test_resultados_proyectados(fiscal_client):
    # se crean 3 secciones electorales
    s1, s2, s3 = SeccionFactory.create_batch(3)
    # s1 1000 votantes    # La matanza! :D
    # s2 400 votantes
    # s3 200 votantes

    # Se crean 8 mesas (5 en s1, 2 en s2 y 1 en s3). Todas tienen 200 electores
    ms1, _, ms3 = (
        MesaFactory.create_batch(5, lugar_votacion__circuito__seccion=s1, electores=200),
        MesaFactory.create_batch(2, lugar_votacion__circuito__seccion=s2, electores=200),
        MesaFactory.create_batch(1, lugar_votacion__circuito__seccion=s3, electores=200)
    )
    # ####################################################
    # El padron es de 1600 electores
    # ####################################################
    # La seccion 1 tiene a 1000, el 62.5% del padron
    # La seccion 2 tiene a  400, el 25  % del padron
    # La seccion 3 tiene a  200, el 12.5% del padron

    # tomo las primerar mesas de las secciones 1 y 3
    m1 = ms1[0]
    m3 = ms3[0]

    categoria = Categoria.objects.get()

    # Esto no debería ser necesario si configuramos correctamente las opciones prioritarias en carta_marina
    CategoriaOpcion.objects.filter(categoria=categoria).update(prioritaria=True)

    # opciones a partido
    o1, o2, o3, o4 = categoria.opciones.filter(partido__isnull=False)

    tecnica = tecnica_proyeccion()

    # simulo que van entraron resultados en las mesas 1 (la primera de la seccion 1)
    # y 3 (la primera de la seccion 3).
    #
    # Resultados de la mesa 1: 120 votos partido 1, 80 para el 2, 0 para el 3 y 0 en blanco
    c1 = CargaFactory(mesa_categoria__mesa=m1, tipo=Carga.TIPOS.parcial, mesa_categoria__categoria=categoria)
    cargar_votos(c1, {
        o1: 120,  # 50% de los votos
        o2: 80,  # 40%
        o3: 0,
        o4: 0,
        Opcion.blancos(): 0,
        Opcion.total_votos(): 200,
        # Opcion.sobres(): 200, # Actualmente nuestros sumarizadores descartan los datos sobre sobres.
    })
    consumir_novedades_y_actualizar_objetos([m1])

    # Resultados de la mesa 3: 79 votos al partido 1, 121 al partido 2 (cero los demas)
    c2 = CargaFactory(mesa_categoria__mesa=m3, tipo=Carga.TIPOS.parcial, mesa_categoria__categoria=categoria)
    cargar_votos(c2, {
        o1: 79,
        o2: 121,
        o3: 0,
        Opcion.blancos(): 0,
        Opcion.total_votos(): 200,
        # Opcion.sobres(): 200, # Actualmente nuestros sumarizadores descartan los datos sobre sobres.
    })

    consumir_novedades_y_actualizar_objetos([m1, m3])

    # ###################
    # Totales sin proyectar:
    # o1 (partido 1): 120 + 79 = 199 votos
    # o2 (partido 2): 80 + 121 = 201 votos
    # sin proyeccion va ganando o2 por 2 votos
    response = fiscal_client.get(
        reverse('resultados-categoria', args=[categoria.id]) +
        f'?tipoDeAgregacion=todas_las_cargas&opcionaConsiderar=prioritarias'
    )
    positivos = response.context['resultados'].tabla_positivos()

    assert list(positivos.keys()) == [o2.partido, o1.partido, o3.partido, o4.partido]

    # cuentas
    assert positivos[o2.partido]['votos'] == 201
    assert positivos[o1.partido]['votos'] == 199
    assert positivos[o3.partido]['votos'] == 0
    assert positivos[o2.partido]['porcentaje_positivos'] == '50.25'  # 201/400
    assert positivos[o1.partido]['porcentaje_positivos'] == '49.75'  # 199/400
    # no hay proyeccion
    assert 'proyeccion' not in positivos[o1.partido]

    # cuando se proyecta, o1 gana porque va ganando en s1 que es la mas populosa
    response = fiscal_client.get(
        reverse('resultados-categoria', args=[categoria.id]) +
        f'?tipoDeAgregacion=todas_las_cargas&opcionaConsiderar=prioritarias&tecnicaDeProyeccion={tecnica.id}'
    )
    positivos = response.context['resultados'].tabla_positivos()
    assert list(positivos.keys()) == [o1.partido, o2.partido, o3.partido, o4.partido]

    # PROYECCION:
    # la seccion 3 esta sobre representada por el momento (está al 100%)
    # en la seccion 1 todo se multiplica x 5 (tengo 1 de 5 mesas)
    # proyeccion de la seccion 1 es partido 1 = 120 * 5 (5=mesas totales/mesas actuales) = 600
    #                               partido 2 =  80 * 5 = 400
    # proyeccion p1 = 600 + 79 = 679
    # proyeccion p2 = 400 + 121 = 521
    # votos proyectados = 1200
    # p1 = 679 / 1200 = 56.58%
    # p3 = 521 / 1200 = 43.42%
    # OJO NO SE PUEDE PROYECTAR LA SECCION 2, no tiene ni una mesa
    # OJO, si el % de mesas es bajo la proyeccion puede ser ruidosa
    assert positivos[o1.partido]['porcentaje_positivos'] == '56.58'
    assert positivos[o2.partido]['porcentaje_positivos'] == '43.42'
Exemplo n.º 20
0
    def handle(self, *args, **options):
        slug_categoria = options['categoria']
        self.categoria = Categoria.objects.get(slug=slug_categoria)
        print("Vamos a importar la categoría:", self.categoria)

        url = settings.URL_ARCHIVO_IMPORTAR_CORREO[slug_categoria]
        r = requests.get(url=url, params=PARAMS)
        values = r.json()['values']
        ultima_guardada_con_exito = None
        tz = pytz.timezone('America/Argentina/Buenos_Aires')

        if values:
            # acá se debería consultar la fecha y hora del último registro guardado
            # para luego filtrar las filas nuevas
            fecha_ultimo_registro = CargaOficialControl.objects.filter(
                categoria=self.categoria).first()
            if fecha_ultimo_registro:
                date_format = '%d/%m/%Y %H:%M:%S'
                # fd = datetime.strptime(fecha_ultimo_registro.fecha_ultimo_registro, date_format)
                head, *tail = values
                tail = map(lambda x: dict(zip(head, x)), tail)
                # filtro para quedarme con los datos nuevos
                datos_a_guardar = filter(
                    lambda x: datetime.strptime(x[
                        'Marca temporal'], '%d/%m/%Y %H:%M:%S').replace(
                            tzinfo=tz) > fecha_ultimo_registro.
                    fecha_ultimo_registro, tail)
            else:
                head, *tail = values
                datos_a_guardar = map(lambda x: dict(zip(head, x)), tail)

            fiscal = Fiscal.objects.get(id=1)
            tipo = 'parcial_oficial'

            opcion_nosotros = self.get_opcion_nosotros()
            opcion_ellos = self.get_opcion_ellos()
            opcion_blancos = Opcion.blancos()
            opcion_nulos = Opcion.nulos()
            opcion_total = Opcion.total_votos()
            opciones = [
                opcion_nosotros, opcion_ellos, opcion_blancos, opcion_nulos,
                opcion_total
            ]
            for row in datos_a_guardar:

                nro_distrito = row['Distrito']
                nro_seccion = row['Seccion']
                try:
                    distrito = Distrito.objects.get(numero=nro_distrito)
                    seccion = Seccion.objects.get(numero=nro_seccion,
                                                  distrito=distrito)
                    circuito = Circuito.objects.get(
                        numero=row['Circuito'].strip(), seccion=seccion)
                    mesa = Mesa.objects.get(numero=row['Mesa'],
                                            circuito=circuito)
                    mesa_categoria = MesaCategoria.objects.get(
                        mesa=mesa, categoria=self.categoria)

                    with transaction.atomic:
                        carga = Carga.objects.create(
                            mesa_categoria=mesa_categoria,
                            tipo=tipo,
                            fiscal=fiscal,
                            origen=Carga.SOURCES.csv)

                        votos_a_crear = []
                        for nombre_opcion, opcion in zip([
                                '136-Frente de Todos', '135-JxC', 'Blancos',
                                'Nulos', 'Total'
                        ], opciones):
                            votos_a_crear.append(
                                VotoMesaReportado(carga=carga,
                                                  opcion=opcion,
                                                  votos=row[nombre_opcion]))
                        VotoMesaReportado.objects.bulk_create(votos_a_crear)
                        # actualizo la firma así no es necesario correr consolidar_identificaciones_y_cargas
                        carga.actualizar_firma()

                        # Si hay cargas repetidas esto hace que se tome la última
                        # en el proceso de comparar_mesas_con_correo.
                        mesa_categoria.actualizar_parcial_oficial(carga)

                    ultima_guardada_con_exito = datetime.strptime(
                        row['Marca temporal'],
                        '%d/%m/%Y %H:%M:%S').replace(tzinfo=tz)

                except Distrito.DoesNotExist:
                    self.warning('No existe el distrito %s.' % nro_distrito)
                except Seccion.DoesNotExist:
                    self.warning('No existe la sección %s en el distrito %s.' %
                                 (nro_seccion, nro_distrito))
                except Circuito.DoesNotExist:
                    self.warning('No existe el circuito %s' % row)

            if ultima_guardada_con_exito:
                if fecha_ultimo_registro:
                    fecha_ultimo_registro.fecha_ultimo_registro = ultima_guardada_con_exito
                    fecha_ultimo_registro.save()
                else:
                    CargaOficialControl.objects.create(
                        fecha_ultimo_registro=ultima_guardada_con_exito,
                        categoria=self.categoria)