From c5a70604945c23ebc8ac5c62cfe3266c0f3aa263 Mon Sep 17 00:00:00 2001 From: Vincent Le Gallic Date: Wed, 10 Feb 2016 05:24:56 +0100 Subject: [PATCH] =?utf8?q?[bde/credits=5Fduplicates]=20Pour=20trouver=20le?= =?utf8?q?s=20cr=C3=A9dits=20note=20kfet=20dupliqu=C3=A9s?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- bde/credits_duplicates.py | 134 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 134 insertions(+) create mode 100755 bde/credits_duplicates.py diff --git a/bde/credits_duplicates.py b/bde/credits_duplicates.py new file mode 100755 index 0000000..d2d7575 --- /dev/null +++ b/bde/credits_duplicates.py @@ -0,0 +1,134 @@ +#!/usr/bin/env python +# -*- encoding: utf-8 -*- + +""" Pour trouver les chèque dupliqués sur la note. """ + +import psycopg2 +import psycopg2.extras +import collections +import pprint +import subprocess + +import pretty_print + +def getcursor(): + con = psycopg2.connect(database="note") + con.set_client_encoding("utf-8") + return (con, con.cursor(cursor_factory = psycopg2.extras.DictCursor)) + +def get_data(cur, delai='1 minute'): + """ + Récupère les paires de crédits effectués à moins de ``delai`` d'intervalle. + ``delai`` est un chaîne de caractères que PostGreSQL comprendra comme une durée. + Les crédits doivent êtres valides, de même destinataire, de même montant. + Pour les crédits chèque, virement et carte bancaire, on vérifie qu'ils aient le même prénom,nom + """ + req_create_credits = """ + CREATE TEMPORARY TABLE credits AS ( + ( + SELECT t.*, c.prenom, c.nom FROM transactions t, cheques c + WHERE t.type = 'crédit' AND t.emetteur = -1 AND t.id = c.idtransaction + ) + UNION + ( + SELECT t.*, v.prenom, v.nom FROM transactions t, virements v + WHERE t.type = 'crédit' AND t.emetteur = -3 AND t.id = v.idtransaction + ) + UNION + ( + SELECT t.*, cb.prenom, cb.nom FROM transactions t, carte_bancaires cb + WHERE t.type = 'crédit' AND t.emetteur = -4 AND t.id = cb.idtransaction + ) + UNION + ( + SELECT t.*, '', '' FROM transactions t + WHERE t.type = 'crédit' AND t.emetteur = -1 + )); + """ + cur.execute(req_create_credits) + + req = u""" + SELECT + t1.id AS id1, + t2.id AS id2, + t1.date AS date1, + t2.date AS date2, + t2.date - t1.date AS deltaT, + t1.montant, + t1.destinataire, + c.pseudo AS destp, + t1.description AS desc1, + t2.description AS desc2 + FROM credits t1,credits t2, comptes c + WHERE t1.destinataire = c.idbde + AND t1.date >= '2016-01-01' + AND t2.date >= '2016-01-01' + AND t1.type='crédit' + AND t2.type='crédit' + AND t1.id != t2.id + AND t1.valide + AND t2.valide + AND t1.destinataire = t2.destinataire + AND t1.montant = t2.montant + AND t1.prenom = t2.prenom + AND t1.nom = t2.nom + AND (t2.date - t1.date) <= %(delai)s + AND (t2.date - t1.date) >= '0 s'; + """ + cur.execute(req, {"delai" : delai}) + l = cur.fetchall() + return l + +def sort_by_blocks(data): + """ + Regroupe les transactions qui vont ensemble. + Sort une liste de chaînes de caractères contenant les ids de chaque block comma-separated. + Oui, le format de sortie est dégueu, mais c'est nettement moin galère pour trouver les doublons. + """ + map = collections.defaultdict(lambda : set()) + for t in data: + id1, id2 = t["id1"], t["id2"] + if id1 in map: + s = map[id1] + elif id2 in map: + s = map[id2] + else: + s = set() + # Comme on touche s en place et que c'est le même mutable qui a été mis + # comme valeur des 2 clés, il sera modifié par les étapes suivantes aussi + s.add(id1) + s.add(id2) + map[id1] = map[id2] = s + # On a tous les blocks, reste à ne garder qu'un exemplaire de chaque + result = [list(s) for s in map.values()] + for l in result: + l.sort() + result = [", ".join([str(i) for i in l]) for l in result] + result = list(set(result)) + return result + +def get_transactions(cur, ids): + """ + Récupère les informations de toutes les transactions dans la liste d'identifiants ``ids`` + qui doit être donné sous la forme d'une chaîne de caractères d'ids comma-separated. + """ + # yuk, mais le format correspond à ce qu'outpute sort_by_blocks + cur.execute("SELECT * FROM credits WHERE id IN (%s)" % ids) + return cur.fetchall() + + +if __name__ == "__main__": + con, cur = getcursor() + data = get_data(cur) + blocks = sort_by_blocks(data) + for b in blocks: + l = get_transactions(cur, b) + formatted = pretty_print.sql_pretty_print(l, keys=["id", "date", "type", "emetteur", "destinataire", "quantite", "montant", "description", "valide", "cantinvalidate"]) + p = subprocess.Popen(["less"], stdin=subprocess.PIPE) + p.communicate(formatted.encode("utf-8")) + print formatted + print "IDs : %s" % b + idkeep = int(b.split(",")[0]) + ans = raw_input("Ne garder que %s (= dévalider les autres) ? [o/N]" % idkeep) + if ans.lower() in ["o", "y"]: + print "bim !" -- 2.39.2