From 71a88e84f7f5833b0ef3c19f26be435aed56626f Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Fri, 7 Feb 2020 22:23:37 +0100 Subject: [PATCH 01/18] initiate import command --- apps/member/management/__init__.py | 0 apps/member/management/commands/__init__.py | 0 .../member/management/commands/import_nk15.py | 30 +++++++++++ map_db.json | 50 +++++++++++++++++++ 4 files changed, 80 insertions(+) create mode 100644 apps/member/management/__init__.py create mode 100644 apps/member/management/commands/__init__.py create mode 100644 apps/member/management/commands/import_nk15.py create mode 100644 map_db.json diff --git a/apps/member/management/__init__.py b/apps/member/management/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/member/management/commands/__init__.py b/apps/member/management/commands/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py new file mode 100644 index 00000000..264262a9 --- /dev/null +++ b/apps/member/management/commands/import_nk15.py @@ -0,0 +1,30 @@ +#!/usr/env/bin python3 + +from django.core.management.base import BaseCommand +from django.utils import timezone +import psycopg2 as pg +import json + + +class Command(BaseCommand): + """ + Command for importing the database of NK15. + Need to be run by a user with a registered role in postgres for the database nk15. + """ + help = 'Displays current time' + + def add_arguments(self,parser): + parser.add_argument("--map",type=str,help="json mapping of table header to field models") + + + def handle(self, *args, **options): + map_file= options.get("map",None) + with open(map_file,'rb') as f: + map_dict = json.load(f); + + #conn = pg.connect(database="nk15",user="nk_15") + #cur = conn.cursor() + + for old_table in map_dict: + print(old_table) + diff --git a/map_db.json b/map_db.json new file mode 100644 index 00000000..5e8569f9 --- /dev/null +++ b/map_db.json @@ -0,0 +1,50 @@ +[ + "comptes": { + "idbde":"Note.id", + "type": null, + "pseudo":"User.username", + "passwd":"User.password", + "solde":"Note.solde", + "nom":"User.first_name", + "prenom":"User.last_name", + "tel":"Profile.phone_number", + "mail":"User.email", + "adresse":"Profile.address", + "fonction": null, + "normalien": "Profile.paid", + "pbsante": null, + "droit": null, + "surdroit": null, + "supreme": null, + "bloque": null, + "last_adhesion": null + }, + "transaction":{ + "id":"Transaction.id", + "date":"Transaction.created_at", + "type": null, + "emetteur":"Transaction.source_id", + "destinataire":"Transaction.destination_id", + "quantite":"Transaction.quantity", + "montant":"Transaction.amount", + "description":"Transaction.reason", + "valide":"Transaction.valid", + "cantinvalidate": null, + "categorie":"Transaction.transaction_type" + }, + "boutons":{ + "id":"TransactionTemplate.id", + "label":"TransactionTemplate.name", + "montant":"TransactionTemplate.amount", + "destinataire":"TransactionTemplate.destination_id", + "categorie":null, + "affiche":null, + "description":null, + "consigne":null + }, + "aliases":{ + "id":"Alias.id", + "alias":"Alias.name", + "idbde":"Alias.note_id" + } +] From 4fe61fdc5fd93a7fc8cd9b2acf644ff22125e0d7 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 9 Feb 2020 15:40:46 +0100 Subject: [PATCH 02/18] fix json file format test struct of json json file finish --- .../member/management/commands/import_nk15.py | 18 +- map_db.json | 199 ++++++++++++++---- 2 files changed, 168 insertions(+), 49 deletions(-) diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py index 264262a9..1342cc09 100644 --- a/apps/member/management/commands/import_nk15.py +++ b/apps/member/management/commands/import_nk15.py @@ -3,6 +3,7 @@ from django.core.management.base import BaseCommand from django.utils import timezone import psycopg2 as pg +import psycopg2.extras as pge import json @@ -19,12 +20,19 @@ class Command(BaseCommand): def handle(self, *args, **options): map_file= options.get("map",None) - with open(map_file,'rb') as f: + with open(map_file,'r') as f: map_dict = json.load(f); - #conn = pg.connect(database="nk15",user="nk_15") - #cur = conn.cursor() + conn = pg.connect(database="nk15",user="nk15_user") + cur = conn.cursor(cursor_factory = pge.DictCursor) - for old_table in map_dict: - print(old_table) + # Start with comptes table. + cur.execute("SELECT * FROM comptes ORDER BY -idbde LIMIT 5") + old_fields = [d[0] for d in cur.description] + + print(type(old_fields)) + for row in cur: + for old_field in old_fields: + + print(old_field,row[old_field]) diff --git a/map_db.json b/map_db.json index 5e8569f9..bd8b19c5 100644 --- a/map_db.json +++ b/map_db.json @@ -1,50 +1,161 @@ -[ - "comptes": { - "idbde":"Note.id", - "type": null, - "pseudo":"User.username", - "passwd":"User.password", - "solde":"Note.solde", - "nom":"User.first_name", - "prenom":"User.last_name", - "tel":"Profile.phone_number", - "mail":"User.email", - "adresse":"Profile.address", - "fonction": null, - "normalien": "Profile.paid", - "pbsante": null, - "droit": null, - "surdroit": null, - "supreme": null, - "bloque": null, - "last_adhesion": null +{ + "comptes":{ + "idbde":{ + "app":"note", + "model":"Note", + "field":"id" + }, + "type": null, + "pseudo":{ + "app":"member", + "model":"User", + "field":"username" + }, + "passwd":{ + "app":"member", + "model":"User", + "field":"password" + }, + "solde":{ + "app":"note", + "model":"Note", + "field":"solde" + }, + "nom":{ + "app":"member", + "model":"User", + "field":"first_name", + }, + "prenom":{ + "app":"member", + "model":"User", + "field":"last_name" + }, + "tel":{ + "app":"member", + "model":"Profile", + "field":"phone_number", + }, + "mail":{ + "app":"member", + "model":"User", + "field":"email" + }, + "adresse":{ + "app":"member", + "model":"Profile", + "field":"address" + }, + "fonction": null, + "normalien":{ + "app":"member", + "model":"Profile", + "field":"paid" + }, + "pbsante": null, + "droit": null, + "surdroit": null, + "supreme": null, + "bloque": null, + "last_adhesion": null, + "commentaire":null, + "last_negatif": null, + "deleted":null }, - "transaction":{ - "id":"Transaction.id", - "date":"Transaction.created_at", - "type": null, - "emetteur":"Transaction.source_id", - "destinataire":"Transaction.destination_id", - "quantite":"Transaction.quantity", - "montant":"Transaction.amount", - "description":"Transaction.reason", - "valide":"Transaction.valid", - "cantinvalidate": null, - "categorie":"Transaction.transaction_type" + "transactions":{ + "id":{ + "app":"note", + "model":"Transaction", + "field":"" + },"Transaction.id", + "date":{ + "app":"note", + "model":"Transaction", + "field":"" + }"Transaction.created_at", + "type":{ + "app":"note", + "model":"Transaction", + "field":"" + } null, + "emetteur":{ + "app":"note", + "model":"Transaction", + "field":"id" + }, + "destinataire":{ + "app":"note", + "model":"Transaction", + "field":"destination_id" + }, + "quantite":{ + "app":"note", + "model":"Transaction", + "field":"quantity" + }, + "montant":{ + "app":"note", + "model":"Transaction", + "field":"amount" + }, + "description":{ + "app":"note", + "model":"Transaction", + "field":"reason" + }, + "valide":{ + "app":"note", + "model":"Transaction", + "field":"valid" + }, + "cantinvalidate": null, + "categorie":{ + "app":"note", + "model":"Transaction", + "field":"transaction_type" + } }, "boutons":{ - "id":"TransactionTemplate.id", - "label":"TransactionTemplate.name", - "montant":"TransactionTemplate.amount", - "destinataire":"TransactionTemplate.destination_id", - "categorie":null, - "affiche":null, - "description":null, - "consigne":null + "id":{ + "app":"note", + "model":"Transaction", + "field":"transaction_type" + }"TransactionTemplate.id", + "label":{ + "app":"note", + "model":"TransactionTemplate", + "field":"name" + }, + "montant":{ + "app":"note", + "model":"TransactionTemplate", + "field":"amount" + }, + "destinataire":{ + "app":"note", + "model":"TransactionTemplate", + "field":"destination_id" + }, + "categorie":null, + "affiche":null, + "description":null, + "consigne":null }, "aliases":{ - "id":"Alias.id", - "alias":"Alias.name", - "idbde":"Alias.note_id" + "id":{ + "app":"note", + "model":"Alias", + "field":"id" + }, + "alias":{ + "app":"note", + "model":"Alias", + "field":"name" + }, + "idbde":{ + "app":"note", + "model":"Alias", + "field":"note_id" + } } -] +} From e28b19b353de7eac781680dd0773faecc02a425c Mon Sep 17 00:00:00 2001 From: Yohann D'ANELLO Date: Thu, 20 Feb 2020 10:26:00 +0100 Subject: [PATCH 03/18] Import NK15 passwords --- apps/member/hashers.py | 27 +++++++++++++++++++++++++++ note_kfet/settings/base.py | 6 ++++++ 2 files changed, 33 insertions(+) create mode 100644 apps/member/hashers.py diff --git a/apps/member/hashers.py b/apps/member/hashers.py new file mode 100644 index 00000000..0c5d010b --- /dev/null +++ b/apps/member/hashers.py @@ -0,0 +1,27 @@ +# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay +# SPDX-License-Identifier: GPL-3.0-or-later + +import hashlib + +from django.contrib.auth.hashers import PBKDF2PasswordHasher +from django.utils.crypto import constant_time_compare + + +class CustomNK15Hasher(PBKDF2PasswordHasher): + """ + Permet d'importer les mots de passe depuis la Note KFet 2015. + Si un hash de mot de passe est de la forme : + `custom_nk15$$` + où est un entier quelconque (symbolisant normalement un nombre d'itérations) + et le hash du mot de passe dans la Note Kfet 2015, + alors ce hasher va vérifier le mot de passe. + N'ayant pas la priorité (cf note_kfet/settings/base.py), le mot de passe sera + converti automatiquement avec l'algorithme PBKDF2. + """ + algorithm = "custom_nk15" + + def verify(self, password, encoded): + if '|' in encoded: + salt, db_hashed_pass = encoded.split('$')[2].split('|') + return constant_time_compare(hashlib.sha256((salt + password).encode("utf-8")).hexdigest(), db_hashed_pass) + return super().verify(password, encoded) diff --git a/note_kfet/settings/base.py b/note_kfet/settings/base.py index e583d8a6..b147e5c2 100644 --- a/note_kfet/settings/base.py +++ b/note_kfet/settings/base.py @@ -110,6 +110,12 @@ AUTH_PASSWORD_VALIDATORS = [ }, ] +# Use our custom hasher in order to import NK15 passwords +PASSWORD_HASHERS = [ + 'django.contrib.auth.hashers.PBKDF2PasswordHasher', + 'member.hashers.CustomNK15Hasher', +] + # Django Guardian object permissions AUTHENTICATION_BACKENDS = ( From cfd881887deb5cf7be35c1e379d9ae8f082ac73f Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 22 Feb 2020 16:31:01 +0100 Subject: [PATCH 04/18] add description field to transactionTemplates --- apps/note/models/transactions.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 4ce23311..7a058607 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -40,6 +40,11 @@ class TransactionTemplate(models.Model): max_length=31 ) + description = models.CharField( + verbose_name=_('description'), + max_length=255, + ) + class Meta: verbose_name = _("transaction template") verbose_name_plural = _("transaction templates") From c5ebd0297ca879ebc461dbe874b25a2db8f15d5d Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sat, 22 Feb 2020 16:33:35 +0100 Subject: [PATCH 05/18] Make disctinction between club/user/special --- map_db.json | 388 ++++++++++++++++++++++++++++++++-------------------- 1 file changed, 237 insertions(+), 151 deletions(-) diff --git a/map_db.json b/map_db.json index bd8b19c5..edde898b 100644 --- a/map_db.json +++ b/map_db.json @@ -1,161 +1,247 @@ { "comptes":{ - "idbde":{ - "app":"note", - "model":"Note", - "field":"id" + "personne":{ + "idbde":{ + "app":"note", + "model":"NoteUser", + "field":"id" + }, + "type": null, + "pseudo":{ + "app":"member", + "model":"User", + "field":"username" + }, + "passwd":{ + "app":"member", + "model":"User", + "field":"password" + }, + "solde":{ + "app":"note", + "model":"NoteUser", + "field":"solde" + }, + "nom":{ + "app":"member", + "model":"User", + "field":"first_name" + }, + "prenom":{ + "app":"member", + "model":"User", + "field":"last_name" + }, + "tel":{ + "app":"member", + "model":"Profile", + "field":"phone_number" + }, + "mail":{ + "app":"member", + "model":"User", + "field":"email" + }, + "adresse":{ + "app":"member", + "model":"Profile", + "field":"address" + }, + "fonction": null, + "normalien":{ + "app":"member", + "model":"Profile", + "field":"paid" + }, + "pbsante": null, + "droit": null, + "surdroit": null, + "supreme": null, + "bloque": null, + "last_adhesion": null, + "commentaire":null, + "last_negatif": null, + "deleted":null }, - "type": null, - "pseudo":{ - "app":"member", - "model":"User", - "field":"username" + "club":{ + "idbde":{ + "app":"note", + "model":"NoteClub", + "field":"id" + }, + "type": null, + "pseudo":{ + "app":"member", + "model":"Club", + "field":"name" + }, + "passwd":null, + "solde":{ + "app":"note", + "model":"NoteClub", + "field":"solde" + }, + "nom":null, + "prenom":null, + "tel":null, + "mail":{ + "app":"member", + "model":"Club", + "field":"email" + }, + "adresse":null, + "fonction": null, + "normalien": null, + "pbsante": null, + "droit": null, + "surdroit": null, + "supreme": null, + "bloque": null, + "last_adhesion": null, + "commentaire":null, + "last_negatif": null, + "deleted":null }, - "passwd":{ - "app":"member", - "model":"User", - "field":"password" + "special":{ + "idbde":{ + "app":"note", + "model":"NoteSpecial", + "field":"id" + }, + "type": null, + "pseudo":{ + "app":"member", + "model":"NoteSpecial", + "field":"special_type" + }, + "passwd":null, + "solde":{ + "app":"note", + "model":"NoteClub", + "field":"solde" + }, + "nom":null, + "prenom":null, + "tel":null, + "mail":null, + "adresse":null, + "fonction": null, + "normalien": null, + "pbsante": null, + "droit": null, + "surdroit": null, + "supreme": null, + "bloque": null, + "last_adhesion": null, + "commentaire":null, + "last_negatif": null, + "deleted":null }, - "solde":{ - "app":"note", - "model":"Note", - "field":"solde" - }, - "nom":{ - "app":"member", - "model":"User", - "field":"first_name", - }, - "prenom":{ - "app":"member", - "model":"User", - "field":"last_name" - }, - "tel":{ - "app":"member", - "model":"Profile", - "field":"phone_number", - }, - "mail":{ - "app":"member", - "model":"User", - "field":"email" - }, - "adresse":{ - "app":"member", - "model":"Profile", - "field":"address" - }, - "fonction": null, - "normalien":{ - "app":"member", - "model":"Profile", - "field":"paid" - }, - "pbsante": null, - "droit": null, - "surdroit": null, - "supreme": null, - "bloque": null, - "last_adhesion": null, - "commentaire":null, - "last_negatif": null, - "deleted":null + } + +}, +"transactions":{ + "id":{ + "app":"note", + "model":"Transaction", + "field":"" + },"Transaction.id", + "date":{ + "app":"note", + "model":"Transaction", + "field":"" + }"Transaction.created_at", + "type":{ + "app":"note", + "model":"Transaction", + "field":"" + } null, + "emetteur":{ + "app":"note", + "model":"Transaction", + "field":"id" }, - "transactions":{ - "id":{ - "app":"note", - "model":"Transaction", - "field":"" - },"Transaction.id", - "date":{ - "app":"note", - "model":"Transaction", - "field":"" - }"Transaction.created_at", - "type":{ - "app":"note", - "model":"Transaction", - "field":"" - } null, - "emetteur":{ - "app":"note", - "model":"Transaction", - "field":"id" - }, - "destinataire":{ - "app":"note", - "model":"Transaction", - "field":"destination_id" - }, - "quantite":{ - "app":"note", - "model":"Transaction", - "field":"quantity" - }, - "montant":{ - "app":"note", - "model":"Transaction", - "field":"amount" - }, - "description":{ - "app":"note", - "model":"Transaction", - "field":"reason" - }, - "valide":{ - "app":"note", - "model":"Transaction", - "field":"valid" - }, - "cantinvalidate": null, - "categorie":{ - "app":"note", - "model":"Transaction", - "field":"transaction_type" - } + "destinataire":{ + "app":"note", + "model":"Transaction", + "field":"destination_id" }, - "boutons":{ - "id":{ - "app":"note", - "model":"Transaction", - "field":"transaction_type" - }"TransactionTemplate.id", - "label":{ - "app":"note", - "model":"TransactionTemplate", - "field":"name" - }, - "montant":{ - "app":"note", - "model":"TransactionTemplate", - "field":"amount" - }, - "destinataire":{ - "app":"note", - "model":"TransactionTemplate", - "field":"destination_id" - }, - "categorie":null, - "affiche":null, - "description":null, - "consigne":null + "quantite":{ + "app":"note", + "model":"Transaction", + "field":"quantity" }, - "aliases":{ - "id":{ - "app":"note", - "model":"Alias", - "field":"id" - }, - "alias":{ - "app":"note", - "model":"Alias", - "field":"name" - }, - "idbde":{ - "app":"note", - "model":"Alias", - "field":"note_id" - } + "montant":{ + "app":"note", + "model":"Transaction", + "field":"amount" + }, + "description":{ + "app":"note", + "model":"Transaction", + "field":"reason" + }, + "valide":{ + "app":"note", + "model":"Transaction", + "field":"valid" + }, + "cantinvalidate": null, + "categorie":{ + "app":"note", + "model":"Transaction", + "field":"transaction_type" + } +}, +"boutons":{ + "id":{ + "app":"note", + "model":"TransactionTemplate", + "field":"pk" + } + "label":{ + "app":"note", + "model":"TransactionTemplate", + "field":"name" + }, + "montant":{ + "app":"note", + "model":"TransactionTemplate", + "field":"amount" + }, + "destinataire":{ + "app":"note", + "model":"TransactionTemplate", + "field":"destination_id" + }, + "categorie":null, + "affiche":{ + "app":"note", + "model":"TransactionTemplate", + "field":"display" + }, + "description":{ + "app":"note", + "model":"TransactionTemplate", + "field":"description" + }, + "consigne":null +}, +"aliases":{ + "id":{ + "app":"note", + "model":"Alias", + "field":"id" + }, + "alias":{ + "app":"note", + "model":"Alias", + "field":"name" + }, + "idbde":{ + "app":"note", + "model":"Alias", + "field":"note_id" } } +} From 201c5f667cc1171608491f103b4c8b35788a2f19 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 13:46:25 +0100 Subject: [PATCH 06/18] add error_code to Exceptions --- apps/note/models/notes.py | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/apps/note/models/notes.py b/apps/note/models/notes.py index 3b616f0e..3d929bc8 100644 --- a/apps/note/models/notes.py +++ b/apps/note/models/notes.py @@ -64,7 +64,8 @@ class Note(PolymorphicModel): if aliases.exists(): # Alias exists, so check if it is linked to this note if aliases.first().note != self: - raise ValidationError(_('This alias is already taken.')) + raise ValidationError(_('This alias is already taken.'), + code="same_alias") # Save note super().save(*args, **kwargs) @@ -87,7 +88,8 @@ class Note(PolymorphicModel): if aliases.exists(): # Alias exists, so check if it is linked to this note if aliases.first().note != self: - raise ValidationError(_('This alias is already taken.')) + raise ValidationError(_('This alias is already taken.'), + code="same_alias",) else: # Alias does not exist yet, so check if it can exist a = Alias(name=str(self)) @@ -222,16 +224,19 @@ class Alias(models.Model): def clean(self): normalized_name = Alias.normalize(self.name) if len(normalized_name) >= 255: - raise ValidationError(_('Alias too long.')) + raise ValidationError(_('Alias is too long.'), + code='alias_too_long') try: - if self != Alias.objects.get(normalized_name=normalized_name): - raise ValidationError( - _('An alias with a similar name ' - 'already exists.')) + sim_alias = Alias.objects.get(normalized_name=normalized_name) + if self != sim_alias: + raise ValidationError(_('An alias with a similar name already exists:'), + code="same_alias" + ) except Alias.DoesNotExist: pass def delete(self, using=None, keep_parents=False): if self.name == str(self.note): - raise ValidationError(_("You can't delete your main alias.")) + raise ValidationError(_("You can't delete your main alias."), + code="cant_delete_main_alias") return super().delete(using, keep_parents) From f47d803a2c15f3f52d8089aedcda76d2d699955d Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 13:47:12 +0100 Subject: [PATCH 07/18] import comptes table --- .../member/management/commands/import_nk15.py | 104 +++++++++++++++--- 1 file changed, 88 insertions(+), 16 deletions(-) diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py index 1342cc09..ea13e96d 100644 --- a/apps/member/management/commands/import_nk15.py +++ b/apps/member/management/commands/import_nk15.py @@ -4,35 +4,107 @@ from django.core.management.base import BaseCommand from django.utils import timezone import psycopg2 as pg import psycopg2.extras as pge +from django.db import transaction import json +import collections +from django.core.exceptions import ValidationError +from django.contrib.auth.models import User +from note.models import Note, NoteSpecial, NoteUser, NoteClub +from member.models import Profile, Club class Command(BaseCommand): """ Command for importing the database of NK15. Need to be run by a user with a registered role in postgres for the database nk15. """ - help = 'Displays current time' - - def add_arguments(self,parser): - parser.add_argument("--map",type=str,help="json mapping of table header to field models") - def handle(self, *args, **options): - map_file= options.get("map",None) - with open(map_file,'r') as f: - map_dict = json.load(f); - conn = pg.connect(database="nk15",user="nk15_user") cur = conn.cursor(cursor_factory = pge.DictCursor) - # Start with comptes table. - cur.execute("SELECT * FROM comptes ORDER BY -idbde LIMIT 5") - old_fields = [d[0] for d in cur.description] + # Start with Special accounts + cur.execute("SELECT * FROM comptes WHERE idbde <0 ORDER BY idbde;") - - print(type(old_fields)) for row in cur: - for old_field in old_fields: + with transaction.atomic(): + obj,created = NoteSpecial.objects.get_or_create(special_type = row["pseudo"], + balance = row["solde"], + is_active =True) + if created: + obj.save() + # The rest + cur.execute("SELECT * FROM comptes WHERE idbde=0;") + res = cur.fetchone() + clubBde, c = Club.objects.get_or_create(pk = 1, + name = "Bde", + email = "bureau.bde@lists.crans.org", + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee = 5, + ) + clubKfet, c = Club.objects.get_or_create(pk = 2, + name = "Kfet", + email = "tresorerie.bde@lists.crans.org", + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee = 35, + ) + clubBde.save() + clubKfet.save() + clubBde.note.solde=res["solde"] - print(old_field,row[old_field]) + cur.execute("SELECT * FROM comptes WHERE idbde > 0 ORDER BY idbde;") + pkclub = 3 + with transaction.atomic(): + for row in cur: + row["idbde"] += 7 # do not overwrite the already populated id. + if row["type"] == "personne": + try: + user = User.objects.create( + username =row["pseudo"], + password = row["passwd"] if row["passwd"] != '*|*' else '', + first_name = row["nom"], + last_name = row["prenom"], + email = row["mail"], + ) + except ValidationError as e: + if e.code == 'same_alias': + user = User.objects.create( + username = row["pseudo"]+str(row["idbde"]), + password = row["passwd"] if row["passwd"] != '*|*' else '', + first_name = row["nom"], + last_name = row["prenom"], + email = row["mail"], + ) + + + profile = Profile.objects.create( + phone_number = row["tel"], + address = row["adresse"], + paid = row["normalien"], + user = user, + ) + note = user.note + note.balance = row["solde"] + + obj_list =[user, profile, note] + else:#club + print(row) + club,c = Club.objects.get_or_create(pk=pkclub, + name = row["pseudo"], + email = row["mail"], + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee =0, + ) + pkclub +=1 + note = club.note + note.balance = row["solde"] + obj_list = [club,note] + for obj in obj_list: + obj.save() + #endfor From 889ddc15f82c9e52d9b97d6f70d56ee4dfe4f276 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 14:23:02 +0100 Subject: [PATCH 08/18] handle password the correct way --- apps/member/management/commands/import_nk15.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py index ea13e96d..1ae59ee2 100644 --- a/apps/member/management/commands/import_nk15.py +++ b/apps/member/management/commands/import_nk15.py @@ -62,14 +62,20 @@ class Command(BaseCommand): for row in cur: row["idbde"] += 7 # do not overwrite the already populated id. if row["type"] == "personne": + #sanitize password + if row["passwd"] != "*|*": + passwd_nk15 = "$".join(["custom_nk15","1",row["passwd"]]) + else: + passwd_nk15 = '' try: user = User.objects.create( username =row["pseudo"], - password = row["passwd"] if row["passwd"] != '*|*' else '', + password = passwd_nk15, first_name = row["nom"], last_name = row["prenom"], email = row["mail"], ) + #sanitize duplicate aliases (nk12) except ValidationError as e: if e.code == 'same_alias': user = User.objects.create( @@ -79,8 +85,6 @@ class Command(BaseCommand): last_name = row["prenom"], email = row["mail"], ) - - profile = Profile.objects.create( phone_number = row["tel"], address = row["adresse"], From ea5737ac8f7d8425b936c8f07f956de34fd0a41a Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 16:43:13 +0100 Subject: [PATCH 09/18] refactoring in atomic function --- .../member/management/commands/import_nk15.py | 225 +++++++++++------- 1 file changed, 137 insertions(+), 88 deletions(-) diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py index 1ae59ee2..28b946e9 100644 --- a/apps/member/management/commands/import_nk15.py +++ b/apps/member/management/commands/import_nk15.py @@ -11,104 +11,153 @@ from django.core.exceptions import ValidationError from django.contrib.auth.models import User from note.models import Note, NoteSpecial, NoteUser, NoteClub +from note.models import Transaction, TransactionTemplate, TransactionCategory, TransactionType from member.models import Profile, Club + +@transaction.atomic +def import_special(cur): + cur.execute("SELECT * FROM comptes WHERE idbde <0 ORDER BY idbde;") + map_idbde = dict() + for row in cur: + obj,created = NoteSpecial.objects.get_or_create(special_type = row["pseudo"], + balance = row["solde"], + is_active =True) + if created: + obj.save() + map_idbde[row["idbde"]] = obj.pk + + cur.execute("SELECT * FROM comptes WHERE idbde=0;") + res = cur.fetchone() + clubBde, c = Club.objects.get_or_create(pk = 1, + name = "Bde", + email = "bureau.bde@lists.crans.org", + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee = 5, + ) + clubKfet, c = Club.objects.get_or_create(pk = 2, + name = "Kfet", + email = "tresorerie.bde@lists.crans.org", + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee = 35, + ) + clubBde.save() + clubKfet.save() + clubBde.note.solde=res["solde"] + map_idbde[0] = clubKfet.note.pk + return map_idbde + + +@transaction.atomic +def import_comptes(cur,map_idbde): + cur.execute("SELECT * FROM comptes WHERE idbde > 0 ORDER BY idbde;") + pkclub = 3 + for row in cur: + if row["type"] == "personne": + #sanitize password + if row["passwd"] != "*|*": + passwd_nk15 = "$".join(["custom_nk15","1",row["passwd"]]) + else: + passwd_nk15 = '' + try: + user = User.objects.create( + username =row["pseudo"], + password = passwd_nk15, + first_name = row["nom"], + last_name = row["prenom"], + email = row["mail"], + ) + #sanitize duplicate aliases (nk12) + except ValidationError as e: + if e.code == 'same_alias': + user = User.objects.create( + username = row["pseudo"]+str(row["idbde"]), + password = row["passwd"] if row["passwd"] != '*|*' else '', + first_name = row["nom"], + last_name = row["prenom"], + email = row["mail"], + ) + else: + raise(e) + else: + pass + profile = Profile.objects.create( + phone_number = row["tel"], + address = row["adresse"], + paid = row["normalien"], + user = user, + ) + note = user.note + note.balance = row["solde"] + + obj_list =[user, profile, note] + else:#club + club,c = Club.objects.get_or_create(pk=pkclub, + name = row["pseudo"], + email = row["mail"], + membership_duration = "396 00:00:00", + membership_start = "213 00:00:00", + membership_end = "273 00:00:00", + membership_fee =0, + ) + pkclub +=1 + note = club.note + note.balance = row["solde"] + obj_list = [club,note] + for obj in obj_list: + obj.save() + map_idbde[row["idbde"]] = note.pk + # + return map_idbde + +@transaction.atomic +def import_boutons(cur,map_idbde): + cur.execute("SELECT * FROM boutons;") + for row in cur: + cat, created = TransactionCategory.objects.get_or_create(name=row["categorie"]) + + button = TransactionTemplate.objects.create(pk=row["id"], + name=row["label"], + amount=row["montant"], + destination_id=map_idbde[row["destinataire"]], + category = cat, + display = row["affiche"], + description = row["description"], + ) + if created: + cat.save() + button.save() + + class Command(BaseCommand): """ Command for importing the database of NK15. Need to be run by a user with a registered role in postgres for the database nk15. """ + def add_arguments(self,parser): + parser.add_argument('-s', '--special', action = 'store_true') + parser.add_argument('-c', '--comptes', action = 'store_true') + parser.add_argument('-b', '--boutons', action = 'store_true') - def handle(self, *args, **options): + + def handle(self, *args, **kwargs): conn = pg.connect(database="nk15",user="nk15_user") cur = conn.cursor(cursor_factory = pge.DictCursor) - # Start with Special accounts - cur.execute("SELECT * FROM comptes WHERE idbde <0 ORDER BY idbde;") + if kwargs["special"]: + map_idbde = import_special(cur) + print("Minimal setup created") - for row in cur: - with transaction.atomic(): - obj,created = NoteSpecial.objects.get_or_create(special_type = row["pseudo"], - balance = row["solde"], - is_active =True) - if created: - obj.save() - # The rest - cur.execute("SELECT * FROM comptes WHERE idbde=0;") - res = cur.fetchone() - clubBde, c = Club.objects.get_or_create(pk = 1, - name = "Bde", - email = "bureau.bde@lists.crans.org", - membership_duration = "396 00:00:00", - membership_start = "213 00:00:00", - membership_end = "273 00:00:00", - membership_fee = 5, - ) - clubKfet, c = Club.objects.get_or_create(pk = 2, - name = "Kfet", - email = "tresorerie.bde@lists.crans.org", - membership_duration = "396 00:00:00", - membership_start = "213 00:00:00", - membership_end = "273 00:00:00", - membership_fee = 35, - ) - clubBde.save() - clubKfet.save() - clubBde.note.solde=res["solde"] + if kwargs["comptes"]: + map_idbde = import_comptes(cur,map_idbde) + print("comptes table imported") - cur.execute("SELECT * FROM comptes WHERE idbde > 0 ORDER BY idbde;") - pkclub = 3 - with transaction.atomic(): - for row in cur: - row["idbde"] += 7 # do not overwrite the already populated id. - if row["type"] == "personne": - #sanitize password - if row["passwd"] != "*|*": - passwd_nk15 = "$".join(["custom_nk15","1",row["passwd"]]) - else: - passwd_nk15 = '' - try: - user = User.objects.create( - username =row["pseudo"], - password = passwd_nk15, - first_name = row["nom"], - last_name = row["prenom"], - email = row["mail"], - ) - #sanitize duplicate aliases (nk12) - except ValidationError as e: - if e.code == 'same_alias': - user = User.objects.create( - username = row["pseudo"]+str(row["idbde"]), - password = row["passwd"] if row["passwd"] != '*|*' else '', - first_name = row["nom"], - last_name = row["prenom"], - email = row["mail"], - ) - profile = Profile.objects.create( - phone_number = row["tel"], - address = row["adresse"], - paid = row["normalien"], - user = user, - ) - note = user.note - note.balance = row["solde"] - - obj_list =[user, profile, note] - else:#club - print(row) - club,c = Club.objects.get_or_create(pk=pkclub, - name = row["pseudo"], - email = row["mail"], - membership_duration = "396 00:00:00", - membership_start = "213 00:00:00", - membership_end = "273 00:00:00", - membership_fee =0, - ) - pkclub +=1 - note = club.note - note.balance = row["solde"] - obj_list = [club,note] - for obj in obj_list: - obj.save() - #endfor + if kwargs["boutons"]: + import_boutons(cur,map_idbde) + print("boutons table imported") + if kwargs["transaction"]: + import_transaction(cur) From f3ec0836f894129d8c7d7efb9a25ad8b97608412 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 16:48:35 +0100 Subject: [PATCH 10/18] add display field to TransactionTemplate --- apps/note/admin.py | 4 ++-- apps/note/models/transactions.py | 6 ++++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/apps/note/admin.py b/apps/note/admin.py index 3a9721ae..0aa3be39 100644 --- a/apps/note/admin.py +++ b/apps/note/admin.py @@ -141,8 +141,8 @@ class TransactionTemplateAdmin(admin.ModelAdmin): """ Admin customisation for TransactionTemplate """ - list_display = ('name', 'poly_destination', 'amount', 'template_type') - list_filter = ('template_type', ) + list_display = ('name', 'poly_destination', 'amount', 'category', 'display', ) + list_filter = ('category', 'display') autocomplete_fields = ('destination', ) def poly_destination(self, obj): diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 4db2eda1..043cbbe9 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -54,13 +54,15 @@ class TransactionTemplate(models.Model): verbose_name=_('amount'), help_text=_('in centimes'), ) - template_type = models.ForeignKey( + category = models.ForeignKey( TransactionCategory, on_delete=models.PROTECT, verbose_name=_('type'), max_length=31, ) - + display = models.BooleanField( + default = True, + ) description = models.CharField( verbose_name=_('description'), max_length=255, From 126686ab03cb1ac0d8ff2dd45476f030c5206a41 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 16:50:14 +0100 Subject: [PATCH 11/18] add a TransactionType model --- apps/note/admin.py | 10 +++++++++- apps/note/models/__init__.py | 4 ++-- apps/note/models/transactions.py | 24 +++++++++++++++++++++++- 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/apps/note/admin.py b/apps/note/admin.py index 0aa3be39..f403dcd1 100644 --- a/apps/note/admin.py +++ b/apps/note/admin.py @@ -7,7 +7,7 @@ from polymorphic.admin import PolymorphicChildModelAdmin, \ PolymorphicChildModelFilter, PolymorphicParentModelAdmin from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser -from .models.transactions import Transaction, TransactionCategory, TransactionTemplate +from .models.transactions import Transaction, TransactionCategory, TransactionTemplate, TransactionType class AliasInlines(admin.TabularInline): @@ -161,3 +161,11 @@ class TransactionCategoryAdmin(admin.ModelAdmin): """ list_display = ('name', ) list_filter = ('name', ) + +@admin.register(TransactionType) +class TransactionTypeAdmin(admin.ModelAdmin): + """ + Admin customisation for TransactionTemplate + """ + list_display = ('name', ) + list_filter = ('name', ) diff --git a/apps/note/models/__init__.py b/apps/note/models/__init__.py index 7e6cc310..e372fc46 100644 --- a/apps/note/models/__init__.py +++ b/apps/note/models/__init__.py @@ -3,11 +3,11 @@ from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser from .transactions import MembershipTransaction, Transaction, \ - TransactionCategory, TransactionTemplate + TransactionCategory, TransactionTemplate, TransactionType __all__ = [ # Notes 'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser', # Transactions - 'MembershipTransaction', 'Transaction', 'TransactionCategory', 'TransactionTemplate', + 'MembershipTransaction', 'Transaction', 'TransactionCategory', 'TransactionTemplate','TransactionType', ] diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index 043cbbe9..d441785e 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -76,6 +76,26 @@ class TransactionTemplate(models.Model): return reverse('note:template_update', args=(self.pk, )) +class TransactionType(models.Model): + """ + Defined a recurrent transaction category + + Example: food, softs, ... + """ + name = models.CharField( + verbose_name=_("name"), + max_length=31, + unique=True, + ) + + class Meta: + verbose_name = _("transaction type") + verbose_name_plural = _("transaction types") + + def __str__(self): + return str(self.name) + + class Transaction(models.Model): """ General transaction between two :model:`note.Note` @@ -107,7 +127,9 @@ class Transaction(models.Model): default=1, ) amount = models.PositiveIntegerField(verbose_name=_('amount'), ) - transaction_type = models.CharField( + transaction_type = models.ForeignKey( + TransactionType, + on_delete=models.PROTECT, verbose_name=_('type'), max_length=31, ) From 40a7d3b2957d6aeac8e1914be755578592a43795 Mon Sep 17 00:00:00 2001 From: Benjamin Graillot Date: Sun, 23 Feb 2020 17:27:55 +0100 Subject: [PATCH 12/18] [note] TransactionCategory --> TemplateCategory --- apps/note/admin.py | 6 +++--- apps/note/fixtures/initial.json | 18 +++++++++--------- apps/note/models/__init__.py | 4 ++-- apps/note/models/transactions.py | 24 ++++++++++++++++++++++-- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/apps/note/admin.py b/apps/note/admin.py index f403dcd1..e8966d44 100644 --- a/apps/note/admin.py +++ b/apps/note/admin.py @@ -7,7 +7,7 @@ from polymorphic.admin import PolymorphicChildModelAdmin, \ PolymorphicChildModelFilter, PolymorphicParentModelAdmin from .models.notes import Alias, Note, NoteClub, NoteSpecial, NoteUser -from .models.transactions import Transaction, TransactionCategory, TransactionTemplate, TransactionType +from .models.transactions import Transaction, TemplateCategory, TransactionTemplate, TransactionType class AliasInlines(admin.TabularInline): @@ -154,8 +154,8 @@ class TransactionTemplateAdmin(admin.ModelAdmin): poly_destination.short_description = _('destination') -@admin.register(TransactionCategory) -class TransactionCategoryAdmin(admin.ModelAdmin): +@admin.register(TemplateCategory) +class TemplateCategoryAdmin(admin.ModelAdmin): """ Admin customisation for TransactionTemplate """ diff --git a/apps/note/fixtures/initial.json b/apps/note/fixtures/initial.json index f853d3cb..c0e92bda 100644 --- a/apps/note/fixtures/initial.json +++ b/apps/note/fixtures/initial.json @@ -162,59 +162,59 @@ } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 1, "fields": { "name": "Soft" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 2, "fields": { "name": "Pulls" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 3, "fields": { "name": "Gala" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 4, "fields": { "name": "Clubs" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 5, "fields": { "name": "Bouffe" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 6, "fields": { "name": "BDA" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 7, "fields": { "name": "Autre" } }, { - "model": "note.transactioncategory", + "model": "note.templatecategory", "pk": 8, "fields": { "name": "Alcool" } } -] \ No newline at end of file +] diff --git a/apps/note/models/__init__.py b/apps/note/models/__init__.py index e372fc46..bac4f0ba 100644 --- a/apps/note/models/__init__.py +++ b/apps/note/models/__init__.py @@ -3,11 +3,11 @@ from .notes import Alias, Note, NoteClub, NoteSpecial, NoteUser from .transactions import MembershipTransaction, Transaction, \ - TransactionCategory, TransactionTemplate, TransactionType + TemplateCategory, TransactionTemplate, TransactionType __all__ = [ # Notes 'Alias', 'Note', 'NoteClub', 'NoteSpecial', 'NoteUser', # Transactions - 'MembershipTransaction', 'Transaction', 'TransactionCategory', 'TransactionTemplate','TransactionType', + 'MembershipTransaction', 'Transaction', 'TemplateCategory', 'TransactionTemplate','TransactionType', ] diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index d441785e..388efb3d 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -13,7 +13,7 @@ Defines transactions """ -class TransactionCategory(models.Model): +class TemplateCategory(models.Model): """ Defined a recurrent transaction category @@ -55,7 +55,7 @@ class TransactionTemplate(models.Model): help_text=_('in centimes'), ) category = models.ForeignKey( - TransactionCategory, + TemplateCategory, on_delete=models.PROTECT, verbose_name=_('type'), max_length=31, @@ -173,6 +173,26 @@ class Transaction(models.Model): return self.amount * self.quantity +class TemplateTransaction(Transaction): + """ + Special type of :model:`note.Transaction` associated to a :model:`note.TransactionTemplate`. + + """ + + template = models.ForeignKey( + TransactionTemplate, + null=True + on_delete=models.SET_NULL + ) + category = models.ForeignKey( + TemplateCategory, + on_delete=models.PROTECT + ) + name = models.CharField( + max_length=255 + ) + + class MembershipTransaction(Transaction): """ Special type of :model:`note.Transaction` associated to a :model:`member.Membership`. From b18e5b03a43a720cf4752624ba006ab95ffa37ec Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 18:45:21 +0100 Subject: [PATCH 13/18] add boutons import --- .../member/management/commands/import_nk15.py | 110 ++++++++++-------- apps/note/models/transactions.py | 1 + 2 files changed, 65 insertions(+), 46 deletions(-) diff --git a/apps/member/management/commands/import_nk15.py b/apps/member/management/commands/import_nk15.py index 28b946e9..ea18e4f1 100644 --- a/apps/member/management/commands/import_nk15.py +++ b/apps/member/management/commands/import_nk15.py @@ -5,10 +5,11 @@ from django.utils import timezone import psycopg2 as pg import psycopg2.extras as pge from django.db import transaction -import json -import collections -from django.core.exceptions import ValidationError +import collections + +from django.core.exceptions import ValidationError +from django.db import IntegrityError from django.contrib.auth.models import User from note.models import Note, NoteSpecial, NoteUser, NoteClub from note.models import Transaction, TransactionTemplate, TransactionCategory, TransactionType @@ -64,46 +65,44 @@ def import_comptes(cur,map_idbde): else: passwd_nk15 = '' try: - user = User.objects.create( - username =row["pseudo"], - password = passwd_nk15, - first_name = row["nom"], - last_name = row["prenom"], - email = row["mail"], - ) - #sanitize duplicate aliases (nk12) + obj_dict = { + "username": row["pseudo"], + "password": passwd_nk15, + "first_name": row["nom"], + "last_name": row["prenom"], + "email": row["mail"], + } + user = User.objects.create(**obj_dict) + #sanitize duplicate aliases (nk12) except ValidationError as e: if e.code == 'same_alias': - user = User.objects.create( - username = row["pseudo"]+str(row["idbde"]), - password = row["passwd"] if row["passwd"] != '*|*' else '', - first_name = row["nom"], - last_name = row["prenom"], - email = row["mail"], - ) + obj_dict["username"] = row["pseudo"]+str(row["idbde"]) + user = User.objects.create(**obj_dict) else: raise(e) else: pass - profile = Profile.objects.create( - phone_number = row["tel"], - address = row["adresse"], - paid = row["normalien"], - user = user, - ) + obj_dict ={ + "phone_number": row["tel"], + "address": row["adresse"], + "paid": row["normalien"], + "user": user, + } + profile = Profile.objects.create(**obj_dict) note = user.note note.balance = row["solde"] - obj_list =[user, profile, note] - else:#club - club,c = Club.objects.get_or_create(pk=pkclub, - name = row["pseudo"], - email = row["mail"], - membership_duration = "396 00:00:00", - membership_start = "213 00:00:00", - membership_end = "273 00:00:00", - membership_fee =0, - ) + else: # club + obj_dict = { + "pk":pkclub, + "name": row["pseudo"], + "email": row["mail"], + "membership_duration": "396 00:00:00", + "membership_start": "213 00:00:00", + "membership_end": "273 00:00:00", + "membership_fee": 0, + } + club,c = Club.objects.get_or_create(**obj_dict) pkclub +=1 note = club.note note.balance = row["solde"] @@ -111,27 +110,46 @@ def import_comptes(cur,map_idbde): for obj in obj_list: obj.save() map_idbde[row["idbde"]] = note.pk - # return map_idbde + @transaction.atomic def import_boutons(cur,map_idbde): cur.execute("SELECT * FROM boutons;") for row in cur: cat, created = TransactionCategory.objects.get_or_create(name=row["categorie"]) - - button = TransactionTemplate.objects.create(pk=row["id"], - name=row["label"], - amount=row["montant"], - destination_id=map_idbde[row["destinataire"]], - category = cat, - display = row["affiche"], - description = row["description"], - ) + try: + obj_dict = { + "pk": row["id"], + "name": row["label"], + "amount": row["montant"], + "destination_id": map_idbde[row["destinataire"]], + "category": cat, + "display" : row["affiche"], + "description": row["description"], + } + with transaction.atomic(): # required for error management + button = TransactionTemplate.objects.create(**obj_dict) + except IntegrityError as e: + if "unique" in e.args[0]: + qs = Club.objects.filter(note__id=map_idbde[row["destinataire"]]).values('name') + note_name = qs[0]["name"] + obj_dict["name"] = ' '.join([obj_dict["name"],note_name]) + button = TransactionTemplate.objects.create(**obj_dict) + else: + raise(e) if created: cat.save() button.save() +@transaction.atomic +def import_transaction(cur, map_idbde): + cur.execute("SELECT * FROM transactions;") + for row in cur: + obj_dict = { + "pk":row["id"], + } + class Command(BaseCommand): """ @@ -142,7 +160,7 @@ class Command(BaseCommand): parser.add_argument('-s', '--special', action = 'store_true') parser.add_argument('-c', '--comptes', action = 'store_true') parser.add_argument('-b', '--boutons', action = 'store_true') - + parser.add_argument('-t', '--transactions', action = 'store_true') def handle(self, *args, **kwargs): conn = pg.connect(database="nk15",user="nk15_user") @@ -159,5 +177,5 @@ class Command(BaseCommand): if kwargs["boutons"]: import_boutons(cur,map_idbde) print("boutons table imported") - if kwargs["transaction"]: + if kwargs["transactions"]: import_transaction(cur) diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index d441785e..30c892b0 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -43,6 +43,7 @@ class TransactionTemplate(models.Model): verbose_name=_('name'), max_length=255, unique=True, + error_messages={'unique':_("A template with this name already exist")}, ) destination = models.ForeignKey( NoteClub, From 7230f9c5357ec38fb7ffea8f7443803cbdd1ed74 Mon Sep 17 00:00:00 2001 From: Pierre-antoine Comby Date: Sun, 23 Feb 2020 18:56:03 +0100 Subject: [PATCH 14/18] transaction_type -> category --- apps/note/views.py | 4 ++-- templates/note/conso_form.html | 14 +++++++------- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/apps/note/views.py b/apps/note/views.py index 167ef4f0..c42c243f 100644 --- a/apps/note/views.py +++ b/apps/note/views.py @@ -138,8 +138,8 @@ class ConsoView(LoginRequiredMixin, CreateView): Add some context variables in template such as page title """ context = super().get_context_data(**kwargs) - context['transaction_templates'] = TransactionTemplate.objects.all() \ - .order_by('template_type') + context['transaction_templates'] = TransactionTemplate.objects.filter(display=True) \ + .order_by('category') context['title'] = _("Consommations") # select2 compatibility diff --git a/templates/note/conso_form.html b/templates/note/conso_form.html index b121ad54..10b06589 100644 --- a/templates/note/conso_form.html +++ b/templates/note/conso_form.html @@ -7,7 +7,7 @@ {% block content %} {# Regroup buttons under categories #} - {% regroup transaction_templates by template_type as template_types %} + {% regroup transaction_templates by category as categories %}
{% csrf_token %} @@ -44,10 +44,10 @@ {# Tabs for button categories #}