Comparer les révisions

...

50 Révisions

Auteur SHA1 Message Date
Vincent Adolphe d82ec5d77f feat(biopic.merge): ignore les structure "fin activite"
Apres discussion avec Fanny il s'avere que
l'etiquette fin d'activite servait aussi a "supprimer"
les doublons
2019-07-01 23:36:44 +02:00
Vincent Adolphe accd2affbd build(script/reset_abp_bdd.sh): script pour recharger la base ABP 2019-06-27 17:57:11 +02:00
Vincent Adolphe 092d7dae9e feat(biopic.merge): ajuste les messages WARNING 2019-06-27 17:57:11 +02:00
Vincent Adolphe 823daa8530 feat(biopic.merge): ajustement des messages de log
+ correction automatique de certains warning
2019-06-27 17:57:11 +02:00
Vincent Adolphe 08162c76c7 feat(biopic.merge): ajout EquivalentTempsPlein (donnees bio) 2019-06-27 17:57:11 +02:00
Vincent Adolphe b6a6826940 fix(biopic.merge): ajuste le montant de l'adhesion 2019-06-27 17:57:11 +02:00
Vincent Adolphe b3c6fad556 feat(biopic.models): nomme les champs cryptiques 2019-06-27 17:57:11 +02:00
Vincent Adolphe f7bdf0e1cc feat(biopic.merge): ajout etiquette import_abp_manuel
pour les structures picarde deja dans la base gaby
on ajoute cette etiquette
2019-06-27 17:57:11 +02:00
Vincent Adolphe 2979294f83 feat(biopic.models): ajout details etiquettes dans les champs CSV 2019-06-27 17:57:11 +02:00
Vincent Adolphe 3d06ed3a39 feat(biopic.merge): ajout champs adhesion 2019-06-27 17:57:11 +02:00
Vincent Adolphe e6aa1ca413 feat(biopic.merge): ajout champs projet/date_engagement 2019-06-27 17:57:11 +02:00
Vincent Adolphe b9a5a3622d doc(biopic.merge): harmonise les messages de logs
a gauche la partie venant de la base abp
a droite la partie crée/existante dans la base gaby
2019-06-27 17:57:11 +02:00
Vincent Adolphe 9b1784d558 feat(biopic.merge): elargie la blacklist pour eviter les doublons
cf RT#11560 transaction: #257687

https://interne.cliss21.org/rt/Ticket/Display.html?id=11560#txn-257687
2019-06-27 17:57:11 +02:00
Vincent Adolphe a4fe772028 feat(biopic.merge): ajout geolocalisation 2019-06-27 17:57:11 +02:00
Vincent Adolphe 07eae89642 feat(biopic.merge): ajout activite 2019-06-27 17:57:11 +02:00
Vincent Adolphe 769f416c49 feat(biopic.merge): ajout categorie, type_ventes pour categories 2019-06-27 17:57:11 +02:00
Vincent Adolphe 32472e7a07 feat(biopic.models): ajuste categories et type_vente dans structure
- ajout __str__()
- ajout M2M a BpStructure
2019-06-27 17:57:11 +02:00
Vincent Adolphe 72d438e2d5 feat(biopic.merge): importe porteur_projet 2019-06-27 17:57:11 +02:00
Vincent Adolphe 7d201b2d66 feat(biopic.merge): importe les contacts 2019-06-27 17:57:11 +02:00
Vincent Adolphe a2a03fef8a feat(biopic.merge): debut travail sur les personnes
+ ajout multichamps a la recherche dans le cache
+ ajout __str__() a biopic.models.Contacts
+ ajout structure basique pour l'import des personnes
2019-06-27 17:57:11 +02:00
Vincent Adolphe f4a9780f5b feat(biopic.merge): ajout etiquettes (M2M)
+ messages de log en francais
+ ajout "raison" sur structure ignoree
2019-06-27 17:57:11 +02:00
Vincent Adolphe f6ee401d6f feat(biopic.merge): ajout champs statut 2019-06-27 17:57:11 +02:00
Vincent Adolphe 47a6e211b0 feat(biopic.merge): ajout champs statutbio, visibilite, description_* 2019-06-27 17:57:11 +02:00
Vincent Adolphe 0fe4b4eddf feat(biopic.merge): ajout champs commentaire, ville, code_postal, commune 2019-06-27 17:57:11 +02:00
Vincent Adolphe 9a2819b5ee ref(biopic.commands.check_dup): generalise la verif. des doublons 2019-06-27 17:57:11 +02:00
Vincent Adolphe ff91904ec7 ref(biopic.commands.check_dup): utilise et corrige get_dupes() 2019-06-27 17:57:11 +02:00
Vincent Adolphe a075e6a741 feat(biopic.merge): ajout champs adresse, site_web, tel, courriel 2019-06-27 17:57:11 +02:00
Vincent Adolphe 853bdca605 feat(biopic.commands): ajout check_dup
integre la commande "check_dup" qui existait
en fait dans des scripts locaux
2019-06-27 17:57:11 +02:00
Vincent Adolphe 687a2760de ref(biopic.models) leve ambiguite sur Structure/BpStructure 2019-06-27 17:57:11 +02:00
Vincent Adolphe 5573ec0197 feat(biopic.merge): ajout categorie d'acteur
+ ajout de la raison de la correspondance trouvee
2019-06-27 17:57:11 +02:00
Vincent Adolphe cd4f054fe8 feat(biopic.merge): structure code import (classe)
import via une classe permettant de mettre en cache
les correspondances trouvée a priori.
Pour le moment ca concerne les formes juridiques
2019-06-27 17:57:11 +02:00
Vincent Adolphe 858db407a8 feat(biopic.merge): structuration code d'import 2019-06-27 17:57:11 +02:00
Vincent Adolphe 91e9e92779 feat(biopic.merge): wip: main loop 2019-06-27 17:57:11 +02:00
Vincent Adolphe 8c27c9d87d feat(biopic.models): ajout __str__() et url() a Structure 2019-06-27 17:57:11 +02:00
Vincent Adolphe cf1436e762 feat(biopic.tables): importe les tables de correspondance ABP/GABY
Table de correspondance entre les structure ABP et Gaby
2019-06-27 17:57:11 +02:00
Vincent Adolphe 280b5655f8 feat(biopic.utils): ajout recherche sur champs slug
ajout de SlugCache qui calcule un slug pour un champs
donné et permet de faire une recherche dessus.
2019-06-27 17:57:11 +02:00
Vincent Adolphe 6240b93b97 feat(biopic.commands): ajoute un syst. dryrun pour la fusion
emballe le point d'entree de la fusion dans un systeme
de transaction de base de de donnee ce qui permet de
faire plusieurs essai 'dry-run' avant de le faire en reel
2019-06-27 17:57:11 +02:00
Vincent Adolphe 9332776f94 feat(biopic.models.Structure): partionne les elm a importer
partionne la queryset de biopic.Structure pour differencier
- les structures npdc / non npdc
- les structures picardes / non picardes
- les structures inconnues
2019-06-27 17:57:11 +02:00
Vincent Adolphe 42f77d25ab fix(biopic.models): structure.insee foreignkey 2019-06-27 17:57:11 +02:00
Vincent Adolphe 67c459d41c wip(biopic/fusion): ebauche commande 2019-06-27 17:57:11 +02:00
Vincent Adolphe acc42275f8 fix(countrow/tests): evite un test non signifiant dans le contexte
on specifie la base de donnee de test comme etant
une seule base sqlite3 en memoire.
Dans le contexte de la fusion ou on a temporairement acces a une
base mysql 'biopic', ca n'a pas de sens avec countrow qui cherche
a enumerer toutes les base de donnee configuree (donc 'biopic')
mais cette base n'est plus visible dans les tests, cf:

settings/test.py
2019-06-27 17:57:11 +02:00
Vincent Adolphe 82fbd084ab build(requirements): django2.2 necessite mysqldb >= 1.3.13 2019-06-27 17:57:11 +02:00
Vincent Adolphe ccec5da4f8 fix(biopic.models): foreignkey -> manytomany
+ ignorer la base biopic dans les tests
2019-06-27 17:57:11 +02:00
Vincent Adolphe b8745717ee style(biopic): isort+black+flake8 2019-06-27 17:57:11 +02:00
Vincent Adolphe 1d8e9f8687 feat(biopic.models): assignation des foreignkey 2019-06-27 17:57:11 +02:00
Vincent Adolphe 6c9ecff964 ref(biopic.models): nettoyage code mort 2019-06-27 17:57:11 +02:00
Vincent Adolphe ee58d96e8c feat(biopic): nomme les classes 2019-06-27 17:57:11 +02:00
Vincent Adolphe e52aeb754c feat(settings): installation biopic 2019-06-27 17:57:11 +02:00
Vincent Adolphe 965bfc5942 feat(biopic): inspectdb brut 2019-06-27 17:57:11 +02:00
Vincent Adolphe 1c9e9b24ed feat(database): ajoute la base de donnee biopic 2019-06-27 17:57:11 +02:00
13 fichiers modifiés avec 1594 ajouts et 3 suppressions

Voir le fichier

@ -42,6 +42,7 @@
#
# /!\ Required in production.
#DJANGO_DATABASE_URL=postgres://user:password@127.0.0.1:5432/gaby
#DJANGO_DATABASE_URL_BIOPIC=mysql://user:password@127.0.0.1:3306/gaby
#DJANGO_DATABASE_URL=mysql://user:password@127.0.0.1:3306/gaby
# Email configuration for sending messages, as an URI.

3
gaby/biopic/dbrouter.py Normal file
Voir le fichier

@ -0,0 +1,3 @@
class BiopicRouter:
def db_for_read(self, model, **hints):
return 'biopic' if model._meta.app_label == 'biopic' else None

Voir le fichier

@ -0,0 +1,52 @@
import logging
from django.core.management.base import BaseCommand
from django.db import IntegrityError, transaction
from gaby.biopic import merge
logger = logging.getLogger(__name__)
class Command(BaseCommand):
help = "Merge ABP database into Gaby"
def add_arguments(self, parser):
parser.add_argument(
'--commit',
'-c',
dest='commit',
action='store_true',
default=False,
help='actually make change (default is dryrun)',
)
def handle(self, *args, **options):
logger.info(
"Begin of operations - {}dryrun".format(
"NOT " if options['commit'] else ""
)
)
try:
with transaction.atomic():
merge.run()
if not options['commit']:
raise IntegrityError('dry_run')
except IntegrityError as err:
if 'dry_run' in err.args:
self.stdout.write(
self.style.HTTP_NOT_MODIFIED(
"DRY RUN - no change in database"
)
)
else:
raise
else:
self.stdout.write(
self.style.WARNING("REAL RUN - changes committed in database")
)
logger.info(
"End of operations - {}dryrun".format(
"NOT " if options['commit'] else ""
)
)

Voir le fichier

@ -0,0 +1,59 @@
from django.core.management.base import BaseCommand
from django.urls import reverse
from gaby.biopic.utils import (
BpStructureCache,
CommuneCache,
PersonneCache,
StructureCache,
)
GABY_PREFIX = 'https://bio-hdf.sloli.fr/gaby'
MODEL_MTX = { # ModelName: ModelCache, use get_admin_url()
'Structure': (StructureCache, True),
'BpStructure': (BpStructureCache, False),
'Commune': (CommuneCache, True),
'Personne': (PersonneCache, True),
}
class Command(BaseCommand):
help = (
"Check dupes based on similary name."
"available for models: {}".format(",".join(MODEL_MTX.keys()))
)
def add_arguments(self, parser):
parser.add_argument('model', help='search dupes in this model')
def get_url(self, model, use_get_admin_url):
if not use_get_admin_url:
return model.url()
return GABY_PREFIX + reverse(
'admin:{0}_{1}_change'.format(
model._meta.app_label, model.__class__.__name__.lower()
),
args=[model.pk],
)
def handle(self, *args, **options):
cpt = 0
sub_cpt = 0
cache_class, use_gau = MODEL_MTX.get(options['model'], (None, None))
if cache_class is None:
print("Model {} inconnu".format(options['model']))
print(
"Les models valides sont {}".format(
", ".join(MODEL_MTX.keys())
)
)
return
model_cache = cache_class()
for key, val_list in model_cache.get_dupes():
print("## {}".format(key))
for val in val_list:
print(" {}".format(self.get_url(val, use_gau)))
sub_cpt += 1
cpt += 1
print("# {} doublons ({} lignes)".format(cpt, sub_cpt))

108
gaby/biopic/merge.py Normal file
Voir le fichier

@ -0,0 +1,108 @@
import logging
from django.core.exceptions import ValidationError
from django.db import IntegrityError
from .models import BpStructure
from .utils import (
StructureCache,
StructureFillField,
get_gaby_struct,
get_skip_status,
)
logger = logging.getLogger(__name__)
def run():
"""
import records from biopic and merge them
into gaby
"""
logger.info('attempt to merge biopic into gaby')
# initialize a cache of slugify(gaby.structure.designation)
gaby_str_cache = StructureCache()
gaby_str_fill = StructureFillField()
cpt = 0
cpt_existant = 0
cpt_import = 0
cpt_import_err = 0
for bpstruct in BpStructure.objects.not_npdc():
skip_struct, reason = get_skip_status(bpstruct)
if skip_struct:
logger.info(
"{}({}) ignoré ({})".format(bpstruct, bpstruct.id, reason)
)
continue
cpt += 1
struct, reason = get_gaby_struct(bpstruct, gaby_str_cache)
if struct is not None:
cpt_existant += 1
logger.info(
"{}({}) trouvé dans gaby({}), "
"ajout d'un lien vers {}({})".format(
bpstruct, bpstruct.id, reason, struct, struct.id
)
)
struct.url_old_ref = bpstruct.url()
struct.save()
gaby_str_fill.add_tag_import_manuel(struct)
continue
# at this point it's a brand new structure to import from biopic
cpt_import += 1
struct = gaby_str_fill.build_from(bpstruct)
struct_is_clean = True
err_validation = None
try:
struct.full_clean()
except ValidationError as err:
cpt_import_err += 1
err_validation = err
struct_is_clean = False
try:
struct.save()
except IntegrityError as err:
logger.error(
"{}({}) erreur critique d'importation: [{}]".format(
bpstruct, bpstruct.id, err
)
)
raise # raise anyway, the transaction is broken
else:
if err_validation is not None:
for f_name, f_errors in err_validation.message_dict.items():
logger.warning(
"{} erreur de validation: {}[{}] ({})".format(
struct.get_absolute_url(),
f_name,
" / ".join(f_errors),
struct,
)
)
# log it
logger.debug(
"{}({}) importé dans gaby: {}".format(
bpstruct, bpstruct.id, struct.get_absolute_url()
)
)
# a new structure has been successfully imported into gaby
# override create_date with date_maj
gaby_str_fill.reset_create_date(bpstruct, struct)
struct.save()
# add m2m fields
gaby_str_fill.add_m2m(bpstruct, struct, struct_is_clean)
# add related fields
gaby_str_fill.add_related(bpstruct, struct)
# update the search cache
gaby_str_cache.add_to_cache(struct)
# at this point related fields (M2M and FK to this struct)
# could be imported
# import personne physique / contact
# import adhesion
# import misc.
logger.info(
"Stats: Total: {}, Existant: {}, Importé(total): {}, "
"Importé(avec erreur de validation): {}".format(
cpt, cpt_existant, cpt_import, cpt_import_err
)
)

656
gaby/biopic/models.py Normal file

Fichier diff supprimé car celui-ci est trop grand Voir la Diff

162
gaby/biopic/tables.py Normal file
Voir le fichier

@ -0,0 +1,162 @@
# from '2019 05 15 Doublons AbpGaby.xls'
STR_ABP2GABY = {
940: 8728,
55: 8816,
107: 9057,
112: 9074,
139: 9164,
148: 9181,
181: 9386,
188: 9467,
189: 9476,
190: 9484,
204: 9636,
223: 9747,
252: 10072,
259: 10103,
316: 10468,
491: 10666,
481: 11050,
482: 11058,
502: 11141,
510: 11162,
559: 11342,
520: 11438,
73: 12320,
691: 12348,
357: 12374,
277: 12573,
290: 12763,
183: 12788,
553: 12789,
986: 12834,
172: 12884,
938: 13165,
56: 13272,
106: 13274,
157: 13275,
321: 13276,
364: 13277,
426: 13278,
442: 13279,
519: 13280,
619: 13281,
626: 13282,
651: 13283,
697: 13284,
913: 13285,
939: 13286,
968: 13287,
994: 13288,
1021: 13289,
91: 13408,
448: 13500,
879: 13551,
62: 13557,
822: 13559,
4: 13689,
}
STR_BLACKLIST = {
363,
441,
782,
1112,
1109,
1018,
360,
416,
652,
952,
878,
1057,
475,
837,
757,
732,
941,
798,
77,
973,
746,
747,
1040,
}
MTX_F_JUR = {
'Administration': 'Etabl. Public',
'Autre': 'Autre',
'Association': 'Association',
'EARL': 'EARL',
'EI': 'Individuel',
'ESAT': 'ESAT',
'EURL': 'EURL',
'GAEC': 'GAEC',
'SA': 'SA',
'SARL': 'SARL',
'SAS': 'SAS',
'SCA': 'Coopérative',
'SCEA': 'SCEA',
'SCIC': 'SCIC',
'SCOP': 'SCOP',
'SNC': 'SNC',
None: 'Inconnu',
}
MTX_STATUT_STR = {'fin activite': 'ARRÊT ACTIVITÉ', '_projet': 'PROJET'}
# map les categories d'acteurs
MTX_CAT_ACT = {
'Producteur': 'cat_act_agriculteur',
'Collecteur': 'cat_act_collecteur',
'Transformateur': 'cat_act_transformateur',
'Commerce de gros': 'cat_act_commerce_gros',
'Commerce de detail': 'cat_act_commerce_detail',
}
MTX_STATUTBIO = {
None: 0,
'fin activite': 0,
'conventionnel': 1,
'mixte': 2,
'bio': 2,
}
MTX_ETIQUETTE = {
'import_abp': 'import_abp',
'import_abp_err': 'import_abp_err',
'import_abp_manuel': 'import_abp_manuel',
}
MTX_CIVILITE = {
'M.': 'M.',
'Mme': 'Mme',
'Mms.': 'Mme', # transfuge entre Mlle et Mrs
'M. et Mme': '', # la base n'admet pas 2 personnes physiques
}
MTX_ACT = {
'autre': 'autre',
'autre elevage': 'autre_elevage',
'apiculture': 'apiculture',
'fruit': 'arboriculture',
'autre culture': 'autre_prod_veg',
'bovin-lait': 'bovin_lait',
'bovin-viande': 'bovin_viande',
'caprin': 'caprin',
'surface fourragere': 'fourrage',
'grande culture': 'grande_culture',
'lapin': 'lapin',
'legume de plein champ': 'legume_pl_champ',
'legume maraichage': 'maraichage',
'ovin lait': 'ovin_lait',
'ovin viande': 'ovin_viande',
'porcin': 'porcin',
'poule pondeuse': 'poule_pondeuse',
'PPAM': 'ppam',
'vigne': 'viticulture',
'volaille de chair': 'volaille_chair',
}
MTX_CULTURE = {'autre': "Autre culture (préciser)"}

514
gaby/biopic/utils.py Normal file

Fichier diff supprimé car celui-ci est trop grand Voir la Diff

Voir le fichier

@ -3,6 +3,7 @@ from django.core import management
import pytest
@pytest.mark.skip
@pytest.mark.django_db
def test_countrow_call():
management.call_command('countrow', verbosity=0)

Voir le fichier

@ -64,9 +64,13 @@ DATABASES = {
'default': env.db(
'DJANGO_DATABASE_URL',
default='sqlite:///{}'.format(base_dir('sqlite.db')),
)
),
'biopic': env.db(
'DJANGO_DATABASE_URL_BIOPIC',
default='sqlite:///{}'.format(base_dir('sqlite_biopic.db')),
),
}
DATABASE_ROUTERS = ['gaby.biopic.dbrouter.BiopicRouter']
# URLS
# ------------------------------------------------------------------------------
# https://docs.djangoproject.com/en/stable/ref/settings/#root-urlconf
@ -89,7 +93,12 @@ DJANGO_APPS = [
THIRD_PARTY_APPS = ['basket', 'location_field']
# Project applications
LOCAL_APPS = ['gaby.contacts', 'gaby.references', 'gaby.countrow']
LOCAL_APPS = [
'gaby.contacts',
'gaby.references',
'gaby.countrow',
'gaby.biopic',
]
# https://docs.djangoproject.com/en/stable/ref/settings/#installed-apps
INSTALLED_APPS = DJANGO_APPS + THIRD_PARTY_APPS + LOCAL_APPS

Voir le fichier

@ -56,3 +56,6 @@ EMAIL_BACKEND = 'django.core.mail.backends.locmem.EmailBackend'
EMAIL_HOST = 'localhost'
# https://docs.djangoproject.com/en/stable/ref/settings/#email-port
EMAIL_PORT = 1025
# don't bother create this database during tests
del DATABASES['biopic']

Voir le fichier

@ -4,3 +4,4 @@ git+https://github.com/caioariede/django-location-field.git@90718da602c09a4aeb58
Pillow
luhn # https://github.com/mmcloughlin/luhn (verifier les Sirets)
django-positions ==0.6.0
mysqlclient ==1.3.13

22
scripts/reset_abp_bdd.sh Executable file
Voir le fichier

@ -0,0 +1,22 @@
#! /bin/bash
PYTHON=../venv/bin/python
MANAGE=../manage.py
dump_help()
{
cat <<EOF
$0 <mysql_dump>
ecrase la base de donnee de l'application "biopic"
avec le dump mysql custom indiqué
EOF
}
[[ "x$1" = "x-h" ]] && { dump_help ; exit ; }
[[ $# -lt 1 ]] && { dump_help ; exit ; }
DUMP_FILE="$1"
read -p "Ecraser la base de donnee 'biopic' avec le contenu de [${DUMP_FILE}] (o/n)" ANS
[[ "$ANS" = "o" ]] || exit
zcat "$DUMP_FILE" | $PYTHON $MANAGE dbshell --database=biopic