Code source de TresorerieFonctions

# -*- coding: utf-8 -*-

"""Ce module a pour but de regrouper toutes et seulement les fonctions
utiles à l'application Trésorerie.

Évidemment elles sont toutes appelées avec comme premier
paramètre self.
"""

# Import de module utiles
import datetime

# Import de fonctions de bases
import ServeurFonctions

# Import de fonctions de bases
import BaseFonctions


def liste_remises(self):
    """ Renvoie la liste des remises

        En sortie :
        * clos = liste des remises qui sont en cours
        * non_clos = liste des remises qui sont terminées
    """
    # On ouvre une connexion avec la base de données
    _, cur = BaseFonctions.getcursor()

    # On vérifie que l'utilisateur à les droits
    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    req = """ SELECT id, date, type, nb_items, montant, commentaire
              FROM remises
              WHERE close = %s
              ORDER BY id DESC ; """

    # On récupère les remises en cours
    cur.execute(req % "False")
    non_clos = cur.fetchall()
    # On récupère les remises terminées
    cur.execute(req % "True")
    clos = cur.fetchall()

    response = {'listes_remises' : [non_clos, clos],}
    self._debug(4, u"Envoie de la liste des remises.")
    self._send(response)

def remises_open(self):
    """ Renvoie la liste des ``idremise`` non closes"""

    _, cur = BaseFonctions.getcursor()

    cur.execute("SELECT id FROM remises WHERE close = False ORDER BY id DESC; ")
    res = cur.fetchall()
    self._send(res)

def liste_cheques(self, data):
    """
        Renvoie des listes de chèques.

        Prend en entrée :
        * data = ["idremise", <int>] -> on recherche par idremise
        * data = ["date", <date>, <date>] -> on recherche par date


        Renvoie en sortie :
        * un dictionnaire contenant les dates recalculées
        * une liste de chèques non traites / checked = False
        * une liste de chèques traites / checked = True
    """
    # On ouvre une connexion avec la base de données
    _, cur = BaseFonctions.getcursor()

    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    if data[0] == "idremise" and isinstance(data[1], int) and len(data) == 2:
        dico = {"idremise" : data[1]}
        cond = "AND idremise = %(idremise)s"
    # On récupert les dates si elles existent, sinon on prend celle du jour
    elif data[0] == "date" and len(data) == 3:
        if data[1] == " " or data[2] == " ":
            fin_date = datetime.datetime.now()
            debut_date = fin_date + datetime.timedelta(weeks=-24)
            debut_date = debut_date.strftime('%Y-%m-%d')
            fin_date = fin_date.strftime('%Y-%m-%d')
        else:
            debut_date, fin_date = data[1], data[2]
        dico = {"debut_date" : debut_date,
                "fin_date" : fin_date,
                "debut_time" : "",
                "fin_time" : "",}
        cond = "AND c.date BETWEEN %(debut_date)s AND date %(fin_date)s + integer '1'"
    else:
        ServeurFonctions._badparam(self, u"liste_cheques")
        return

    # On cherche le tableau des chèques entre les dates de debuts et de fin
    req = """ SELECT c.date, c.nom, c.prenom, banque, t.montant, idtransaction, co.pseudo, c.idbde,
                     checked, close, t.description
                    FROM cheques AS c
                    INNER JOIN transactions AS t
                        ON (c.idtransaction = t.id)
                    INNER JOIN comptes AS co
                        ON (co.idbde = c.idbde)
                    LEFT OUTER JOIN remises AS r
                        ON (r.id = c.idremise)
                    WHERE retrait = FALSE
                    AND valide = TRUE
                    AND checked = %%(checked)s
                    %s
                    ORDER BY c.date DESC ; """

    req = req % cond
    dico["checked"] = "FALSE"
    cur.execute(req, dico)
    non_traites = cur.fetchall()
    dico["checked"] = "TRUE"
    cur.execute(req, dico)
    traites = cur.fetchall()

    response = {'list' : [non_traites, traites],
                'dico' : dico, }

    self._debug(4, u"Envoie des listes des chèques : %s." % data)
    self._send(response)

def transaction(self, data):
    """
        Renvoie toutes les informations disponibles sur une transaction

        * data = idtransaction, l'id de la transaction dont on veut les infos
    """
    # On ouvre une connexion avec la base de données
    _, cur = BaseFonctions.getcursor()

    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    if isinstance(data, int):
        idtransaction = data
    else:
        ServeurFonctions._badparam(self, "transaction")
        return

    to_do = {
        -1 :   (-1, "cheques"),
        -3 : (-3, "virements"),
        -2 :  (-2, "espèces"),
        -4 : (-4, "carte_bancaires"),
    }
    req = """SELECT * FROM transactions WHERE id = %s ;""" %  (idtransaction)
    cur.execute(req)
    trans_infos = cur.fetchone()

    table = "cheques"
    req = """SELECT * FROM %s WHERE idtransaction = %s ; """ % (table, idtransaction)
    cur.execute(req)
    spec_infos = cur.fetchone()

    response = {"trans_infos" : trans_infos,
                "spec_infos"  : spec_infos,
               }

    self._debug(4, u"Envoie des informations de la transaction %s" % idtransaction)
    self._send(response)

def creer_remise(self, data):
    """
        Créé une remise dans la base de donnée.

        * data = type_remise, n'est pas utilisé pour le moment.

    _log relevant ids : id de la remise
    """
    #TODO Récupérer le type dans data et insérer dans la bonne table.
    _, cur = BaseFonctions.getcursor()

    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    dico = {'type' : 'Cheques',}

    req = """ INSERT INTO remises (date, type)
              VALUES (now(), %(type)s)
              RETURNING id; """

    cur.execute(req, dico)
    dico["id"] = cur.fetchone()["id"]
    self._log("creer_remise",
              cur,
              "Création de la remise %(id)s de type %(type)s" % dico,
              [dico["id"]])
    cur.execute("COMMIT;")
    self._debug(1, u"Création de la remise (%(id)s,%(type)s)" % dico)
    self._send([])

def ajout_remise(self, data):
    """
        Modifie l'état de remise d'une transaction.

        * data["action"] = ajout ou delete
        * data contient idremise, idtransaction ainsi que les informations disponibles
          sur la transaction.
    """

    _, cur = BaseFonctions.getcursor()
    # On renvoie un message d'erreur si on a pas le droit 'tresorerie'
    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    #On récupère les informations sur le chèque/transaction
    if data["action"] == "ajout":
        data["checked"] = 't'
        if self._has_acl("transactions_admin"):
            _update_amount_transaction(self, data, cur=cur)
        cond = """SET (nom,prenom,banque,checked,idremise) =
                      (%(nom)s, %(prenom)s, %(banque)s, %(checked)s, %(idremise)s)"""
    elif data["action"] == "delete":
        data["checked"] = 'f'
        cond = """ SET (idremise, checked) = (NULL, %(checked)s) """
        req = """SELECT idremise
                 FROM cheques
                 WHERE idtransaction = %(idtransaction)s ;"""
        cur.execute(req, data)
        data["idremise"] = cur.fetchone()["idremise"]

    #On met à jour la table de la transaction avec les informations modifiés
    req = """ UPDATE cheques
              %s
              WHERE idtransaction = %%(idtransaction)s ; """
    req = req % cond
    cur.execute(req, data)
    self._log("ajout_remise",
              cur,
              "Mise a jour du cheque %(idtransaction)s" % data,
              [data["idtransaction"]])
    cur.execute("COMMIT;")
    self._debug(1, u"Mise a jour du cheque %(idtransaction)s." % data)
    #On récupère le ``nb_items`` et le``montant`` de la remise n°``idremise``
    req = """ SELECT count(*) AS nb_items, sum(quantite*montant) AS montant
              FROM transactions
              INNER JOIN cheques
              ON transactions.id = idtransaction
              WHERE idremise = %(idremise)s ; """
    #Les jointures, mangez en, c'est bon
    cur.execute(req, data)
    res = cur.fetchone()
    data["nb_items"] = res["nb_items"]
    data["montant"] = 0 if res["montant"] is None else res["montant"]

    # On met à jour la table des remises
    req = """ UPDATE remises
              SET (nb_items, montant) = (%(nb_items)s, %(montant)s)
              WHERE id = %(idremise)s ; """
    cur.execute(req, data)
    self._log("ajout_remise",
              cur,
              "Mise a jour de la remise %(idremise)s" % data,
              [data["idremise"]])
    cur.execute("COMMIT;")
    self._debug(1, u"Mise a jour de la remise %(idremise)s." % data)
    # On renvoie pour confirmer le bon déroulement de la requête.
    self._send(res)

def clore_remise(self, data):
    """
    Clos une remise en prenant en compte les dernières modifications.

     * ``data["commentaire"] = <str>``
     * ``data["idremise"] = <int>``

    #TODO y'en a encore

    _log relevant ids : id de la remise
    """

    _, cur = BaseFonctions.getcursor()
    # On renvoie un message d'erreur si on a pas le droit 'tresorerie'
    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    dico = data
    if dico["clore"]: #On set close à True
        cond = """ SET (commentaire, close) = (%(commentaire)s, %(clore)s) """
    else:
        cond = """ SET (commentaire) = (%(commentaire)s)"""

    req = """ UPDATE remises
              %s
              WHERE id = %%(idremise)s ; """

    req = req % cond
    cur.execute(req, dico)
    self._log("clore_remise",
              cur,
              "Fermeture de la remise %(idremise)s." % dico,
              [data["idremise"]])
    cur.execute("COMMIT;")
    self._debug(1, u"Fermeture de la remise %(idremise)s" % dico)
    self._send([])

def infos_remise(self, data):
    """
        Renvoie les informations sur la remise ``idremise``

        * data = idremise
    """
    if not isinstance(data, int):
        ServeurFonctions._badparam(self, u"infos_remise")
        return

    _, cur = BaseFonctions.getcursor()
    idremise = data
    # On renvoie un message d'erreur si on a pas le droit 'tresorerie'
    if not self._has_acl("tresorerie"):
        ServeurFonctions._pasledroit(self, "tresorerie")
        return

    req = """SELECT id, date, type, nb_items, montant, commentaire, close
             FROM remises
             WHERE id = %s; """
    cur.execute(req, (idremise,))
    remise = cur.fetchone()

    if remise is None:
        self._send(None, 404, u"Cette remise n'existe pas.")
        self._debug(3, u"infos_remise failed : La remise %s n'existe pas." % (idremise,))
    else:
        self._send(remise)
        self._debug(4, u"Envoi des informations de la remise %s" % idremise)


def _update_amount_transaction(self, dico, cur=None):
    """ Permet de modifier le montant d'une transaction """

    # On vérifie que l'utilisateur à les droits
    if not self._has_acl("transactions_admin"):
        ServeurFonctions._pasledroit(self, "transactions_admin")
        return

    if cur is None:
        _, cur = BaseFonctions.getcursor()

    cmd_name = (u"_update_amount_transaction")
    cur.execute("SELECT * FROM transactions WHERE id = %(idtransaction)s;", dico)
    transaction = cur.fetchone()
    if transaction is None:
        self._send(None, 404, u"Cette transaction n'existe pas.")
        self._debug(3, u"%s failed : id %s inconnu" % (cmd_name, dico["idtransaction"]))
        return
    # On calcule le delta du solde de de l'emetteur et du destinataire.
    transaction["montant"] = dico["montant"] - transaction["montant"]

    req = """ UPDATE transactions
              SET montant = montant + %(montant)s
              WHERE id = %(id)s ;"""
    #On met à jour le montant de la transaction
    cur.execute(req, transaction)
    #On met à jour le montant du solde de l'emetteur
    cur.execute("""UPDATE comptes
                   SET solde = solde - %(montant)s
                   WHERE idbde = %(emetteur)s ;""", transaction)
    #On met à jour le montant de la transaction
    cur.execute("""UPDATE comptes
                   SET solde = solde + %(montant)s
                   WHERE idbde = %(destinataire)s ;""", transaction)

    self._log("ajout_remise",
              cur,
              "Mise a jour : idtransaction %(idtransaction)s montant %(montant)s" % dico)
    cur.execute(" COMMIT ;")
    self._debug(5, u"Mise a jour : idtransaction %(idtransaction)s montant %(montant)s." % dico)