def obtenerDireccionDeTarjeta(peticion, idDeDireccion):
    """Regresa la dirección asociada a la tarjeta dada.

  TODO:
  * Agregar decorador de privilegios.
  * Validar que la dirección pedida sea del cliente en sesión."""
    direccion = Direccion.objects.get(pk=idDeDireccion)
    return utilidades.respuestaJSON(direccion)
def agregarDireccionDeEntrega(peticion):
    """Agrega a la base de datos la dirección dada."""
    datosCrudos = json.loads(peticion.body)
    identificador = json.loads(peticion.session['usuario'])['pk']

    direccionNueva = Direccion(
        tipoDeDireccion=TipoDeDireccion.objects.get(nombre='Punto de entrega'),
        estado=Estado.objects.get(nombre=datosCrudos['estado']),
        municipio=datosCrudos['municipio'].lower(),
        colonia=datosCrudos['colonia'].lower(),
        calle=datosCrudos['calle'].lower(),
        numeroExterior=datosCrudos['numeroExterior'],
        cp=datosCrudos['cp'],
        activa=True)

    # Esta parte se incluye porque, por alguna extraña razón, el número interior
    # no es opcional, sino obligatorio. También, ¿por qué están guardados como
    # caracteres y no como números?
    if 'numeroInterior' in datosCrudos:
        direccionNueva.numeroInterior = datosCrudos['numeroInterior']
    else:
        direccionNueva.numeroInterior = 0

    direcciones = Usuario.objects.get(pk=identificador).direccion.all()

    for direccionGuardada in direcciones:
        if direccionGuardada.calle.lower()  == direccionNueva.calle and \
          direccionGuardada.numeroExterior  == str(direccionNueva.numeroExterior) and \
          direccionGuardada.colonia.lower() == direccionNueva.colonia and \
          direccionGuardada.municipio.lower()==direccionNueva.municipio and \
          direccionGuardada.cp              == direccionNueva.cp and \
          direccionGuardada.estado          == direccionNueva.estado and \
          direccionGuardada.tipoDeDireccion == direccionNueva.tipoDeDireccion:

            if direccionGuardada.activa == True:
                return django.http.HttpResponse("0")
            else:
                direccionGuardada.activa = True
                direccionGuardada.save()
                return utilidades.respuestaJSON(direccionNueva)

    direccionNueva.save()
    Usuario.objects.get(pk=identificador).direccion.add(direccionNueva)

    return utilidades.respuestaJSON(direccionNueva)
def obtenerDirecciones(peticion):
    """Regresa arreglo con las direcciones del usuario en sesión.

  TODO:
  *  El campo «direccion», del usuario, debería de ser «direcciones»: por
     algo es un campo muchos a muchos.
  """
    identificador = json.loads(peticion.session['usuario'])['pk']
    direcciones = Usuario.objects.get(pk=identificador).direccion.filter(
        activa=True)
    return utilidades.respuestaJSON(direcciones)
def obtenerEstados(peticion):
    """Regresa el catálogo de estados."""
    estados = Estado.objects.all()
    return utilidades.respuestaJSON(estados)
def obtenerTipos(peticion):
    """Regresa el catálogo de tipos de tarjeta."""
    tipos = TipoDeTarjeta.objects.all()
    return utilidades.respuestaJSON(tipos)
def obtenerMetodos(peticion):
    """Regresa el catálogo de métodos (algoritmos tokenizadores)."""
    metodos = Metodo.objects.all()
    return utilidades.respuestaJSON(metodos)
def obtenerEmisores(peticion):
    """Regresa el catálogo de emisores."""
    emisores = Emisor.objects.all()
    return utilidades.respuestaJSON(emisores)
def agregarTarjeta(peticion):
    """Registra un nuevo método de pago del cliente en sesión.

  Respuestas:
  * En caso de una inserción exitosa, se regresa el objeto
    de la nueva tarjeta.
  * En caso de una inserción duplicada se regresa un 1.
  * En caso de una inserción duplicada excepto por la fecha de
    expiración, se regresa un 2.
  * En caso de error al comunicarse con el sistema tokenizador,
    se regresa un 3."""

    objetoDePeticion = json.loads(peticion.body)
    identificador = json.loads(peticion.session['usuario'])['pk']

    try:
        # Buscar tarjetas iguales
        # Si no hay, se lanza excepción.
        similar = Usuario.objects.get(pk=identificador).tarjeta.get(
            terminacion=objetoDePeticion['pan'][-4:],
            tipoDeTarjeta=TipoDeTarjeta.objects.get(
                pk=objetoDePeticion['tipo']),
            emisor=Emisor.objects.get(pk=objetoDePeticion['emisor']),
            titular=objetoDePeticion['titular'])

        # Trayectoria alternativa 05E: La tarjeta ingresada ya ha sido almacenada.
        if similar.activa == True:
            fecha_uno = similar.expiracion
            fecha_dos = django.utils.dateparse.parse_datetime(
                objetoDePeticion['expiracion'])
            if fecha_uno.year == fecha_dos.year and \
              fecha_uno.month == fecha_dos.month:
                return django.http.HttpResponse("1")

            # Trayectoria alternativa 05H: Hay una tarjeta existente y activa
            # con los mismos datos, excepto la fecha de vencimiento.
            else:
                return django.http.HttpResponse("2")

        # Trayectoria alternativa 05F: La tarjeta ingresada ya ha sido
        # almacenada y se encuentra inactiva.
        else:
            similar.expiracion = django.utils.dateparse.parse_datetime(
                objetoDePeticion['expiracion'])
            if objetoDePeticion['direccion']['pk'] == 0:
                # Crear nueva dirección
                # TODO: Para evitar posibles duplicados, antes de insertar la nueva
                # dirección se tendría que buscar entre las direcciones inactivas.
                direccion = negocio.crearDireccion(
                    objetoDePeticion['direccion'])
                similar.direccion = direccion

            else:
                # Dirección existente
                similar.direccion = Direccion.objects.get(
                    pk=objetoDePeticion['direccion']['pk'])

            similar.activa = True
            similar.save()
            return utilidades.respuestaJSON(similar)

    except Tarjeta.DoesNotExist:
        pass

    # Trayectoria principal
    token = None
    try:
        token = negocio.tokenizar(objetoDePeticion['pan'],
                                  objetoDePeticion['metodo'])
    except Exception as error:
        # Trayectoria alternativa 05G: El código HTTP de respuesta no es un 2XX.
        print(traceback.format_exc())
        return django.http.HttpResponse("3")

    direccion = None
    if objetoDePeticion['direccion']['pk'] == 0:
        direccion = negocio.crearDireccion(objetoDePeticion['direccion'])
    else:
        direccion = Direccion.objects.get(
            pk=objetoDePeticion['direccion']['pk'])

    tarjeta = Tarjeta(
        token=token,
        terminacion=objetoDePeticion['pan'][-4:],
        metodo=Metodo.objects.get(nombre=objetoDePeticion['metodo']),
        emisor=Emisor.objects.get(pk=objetoDePeticion['emisor']),
        titular=objetoDePeticion['titular'],
        direccion=direccion,
        expiracion=django.utils.dateparse.parse_datetime(
            objetoDePeticion['expiracion']),
        tipoDeTarjeta=TipoDeTarjeta.objects.get(pk=objetoDePeticion['tipo']),
        activa=True)
    tarjeta.save()

    usuario = Usuario.objects.get(pk=identificador)
    usuario.tarjeta.add(tarjeta)
    usuario.save()
    return utilidades.respuestaJSON(tarjeta)