add migration script for cr-reunion (#76605)
gitea/misc-cazino/pipeline/head This commit looks good Details

This commit is contained in:
Emmanuel Cazenave 2023-07-26 17:48:34 +02:00
parent bb3dcd4a5f
commit 8fdad44fcf
1 changed files with 613 additions and 0 deletions

613
cr-reunion/run.py Normal file
View File

@ -0,0 +1,613 @@
'''
Usage :
wcs-manage runscript -d wcs.dev.publik.love cr-reunion/run.py import --filepath ~/notes/clients/cr-reunion/aide-voyage/demande.csv --api-url=https://wcs.dev.publik.love/api/ --key=cr-reunion-voyage --passwd=29a7182f-e3f0-4044-b6d4-163d16bbb86e
wcs-manage runscript -d wcs.dev.publik.love cr-reunion/run.py reset
'''
import argparse
import base64
import collections
import csv
import datetime
import hashlib
import hmac
import random
import time
import urllib.parse
from pprint import pprint
import requests
from requests.auth import HTTPBasicAuth
from wcs.carddef import CardDef
import wcs.sql_criterias as st
CARD_BENEFICIAIRE_SLUG = 'beneficiaire-ct'
CARD_BON_SLUG = 'bon-ct'
CARD_COMPAGNIE_AERIENNE_SLUG = 'referentiel-compagnies-aeriennes'
CARD_DEROGATION_SLUG = 'referentiel-beneficiaires-de-derogation'
CARD_TYPE_AIDE_SLUG = 'referentiel-type-d-aide'
COMPAGNIES_AERIENNES = {}
DEROGATIONS = {}
TYPE_AIDES = {}
def build_cache(slug, cache):
cardef = CardDef.get_by_urlname(slug)
libelle_field = get_field_by_varname(cardef, 'libelle')
for card in cardef.data_class().select():
cache[card.data[libelle_field.id].upper()] = str(card.id)
def get_field_by_varname(cardef, varname):
for field in cardef.fields:
if field.varname == varname:
return field
raise ValueError('Missing field: %s' % varname)
def get_type_aide_cardddata(label):
if not TYPE_AIDES:
build_cache(CARD_TYPE_AIDE_SLUG, TYPE_AIDES)
return TYPE_AIDES[label.upper()]
def get_derogation_cardddata(label):
if not DEROGATIONS:
build_cache(CARD_DEROGATION_SLUG, DEROGATIONS)
return DEROGATIONS[label.upper()]
def get_compagnie_aerienne(label):
if not COMPAGNIES_AERIENNES:
build_cache(CARD_COMPAGNIE_AERIENNE_SLUG, COMPAGNIES_AERIENNES)
return COMPAGNIES_AERIENNES[label.upper()]
def parse_date(date_str, date_format='%Y-%m-%d'):
if not date_str or date_str == 'NULL':
return ''
return datetime.datetime.strptime(date_str, date_format).date().strftime('%Y-%m-%d')
def api_call(args, path, data=None, user_email=None, method='post'):
basic = HTTPBasicAuth(args.key, args.passwd)
url = args.api_url + path
if method == 'post':
post_data = {'data': data}
if user_email:
post_data['user'] = {'email': user_email}
resp = requests.post(url, json=post_data, auth=basic)
elif method == 'get':
resp = requests.get(url, auth=basic)
resp.raise_for_status()
return resp
def get_rows(args):
with open(args.filepath) as csvfile:
reader = csv.DictReader(csvfile, delimiter=',', quotechar='"')
numline = 0
for i, row in enumerate(reader):
if i < args.start_line:
continue
if args.mode != 'full' and numline > args.sample_numlines:
break
numline += 1
yield i, row
def import_data(args):
benef_path = 'cards/%s/submit' % CARD_BENEFICIAIRE_SLUG
bon_path = 'cards/%s/submit' % CARD_BON_SLUG
# list of (criteria, result) tuples
aide_derogation_mapping = [
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'CONTINUITE FUNERAIRE',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Continuité Territoriale Funéraire'
)
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'Accompagnateur femme enceinte',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata(
"Accompagnateur d'une femme enceinte"
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'Accompagnateur personne âgée',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata(
"Accompagnateur d'une personne âgée"
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': "Accompagnateur personne porteuse d'un handicap",
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata(
"Accompagnateur d'une personne en situation de handicap"
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': "Enfants nés après la déclaration fiscale et n'apparaissant par sur l'avis fiscal de référence",
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': '', # TO COMPLETE
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'Femme enceinte',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata('Femme enceinte'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'Personne âgée',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata('Personne âgée'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': "Personne porteuse d'un handicap",
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': get_derogation_cardddata(
'Personne en situation de handicap'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'Personnes ne pouvant justifier de leur état civil à La Réunion',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
'bon_type_derogation': '', # TO COMPLETE
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': "Pupilles de la nation ou enfants faisant l'objet d'un placement auprès des structures spécifiques",
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Pupille de la nation'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'GRAND PUBLIC',
'derogation': 'NULL',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Grand Public'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Accompagnateur acteurs culturels',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Voyage artistique (accompagnateur)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': "Accompagnateur d'un patient lors d'un rapatriement sanitaire pris en charge à 65% maximum par la CGSS après réponse négative des organismes sollicités",
},
{
'bon_type_aide': get_type_aide_cardddata(
"Accompagnateur d'un patient en transfert sanitaire"
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Accompagnateur de sportif(s) de haut niveau',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Compétition sportive (accompagnateur)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': "Accompagnateur majeur d'un jeune de moins de 26 ans pour un premier départ de La Réunion pour les études, ou lycéen ou apprenti.",
},
{
'bon_type_aide': get_type_aide_cardddata(
"Accompagnateur d'un jeune de moins de 26 ans pour un premier départ de La Réunion"
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Accompagnateur voyage pédagogique pour les publics scolaires mineurs.',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Voyage pédagogique (accompagnateur)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Acteurs culturels',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Voyage artistique (artistes et acteurs culturels)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Cas particulier du deuil en Métropole',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Deuil et raisons funéraires (hors CTF et remboursement)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Doctorant et post-doctorant pour des travaux de recherche',
},
{
'bon_type_aide': get_type_aide_cardddata('Doctorant ou post-doctorant'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Lycéens, apprenti, étudiant en France métropolitaine',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Lycéen, apprenti, étudiant en France métropolitaine'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': "Patient lors d'un rapatriement sanitaire pris en charge à 65% maximum par la CGSS après réponse négative des organismes sollicités",
},
{
'bon_type_aide': get_type_aide_cardddata(
'Patient en transfert sanitaire'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': "Salarié non fonctionnaire ou demandeur d'emploi non aidé par d'autres organismes",
},
{
'bon_type_aide': '', # TO COMPLETE
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Sportif de haut niveau national ou régional',
},
{
'bon_type_aide': get_type_aide_cardddata(
'Compétition sportive (sportif)'
),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'BON',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Voyage pédagogique pour les publics scolaires',
},
{
'bon_type_aide': get_type_aide_cardddata('Voyage pédagogique (élève)'),
},
),
(
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'REMBOURSEMENT',
'type aide': 'AIDE REGIONALE POUR UN DEUIL A LA REUNION',
'derogation': 'NULL',
'mesure specifique': 'Cas particulier du deuil en Métropole',
},
{
'bon_type_aide': get_type_aide_cardddata('Remboursement (deuil)'),
},
),
(
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'BON',
'type aide': 'AIDE RESSOURCEMENT ETUDIANT',
'derogation': "Personne porteuse d'un handicap",
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Ressourcement étudiant'),
'bon_type_derogation': get_derogation_cardddata(
'Personne en situation de handicap'
),
},
),
(
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'BON',
'type aide': 'AIDE RESSOURCEMENT ETUDIANT',
'derogation': 'NULL',
'mesure specifique': 'NULL',
},
{
'bon_type_aide': get_type_aide_cardddata('Ressourcement étudiant'),
},
),
(
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'BON',
'type aide': 'AIDE ETUDIANT SPECIAL COVID',
'derogation': 'NULL',
'mesure specifique': 'NULL',
},
'continue',
),
(
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'REMBOURSEMENT',
'type aide': 'RESSOURCEMENT ETUDIANT',
'derogation': 'NULL',
'mesure specifique': 'NULL',
},
'continue',
),
( # check me with Marie
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'BON',
'type aide': 'RESSOURCEMENT ETUDIANT',
'derogation': 'NULL',
'mesure specifique': 'NULL',
},
'continue',
),
( # check me with Marie
{
'volet': 'VOLET A - Réunion / Métropole',
'type demande': 'REMBOURSEMENT',
'type aide': 'MESURES SPECIFIQUES',
'derogation': 'NULL',
'mesure specifique': 'Cas particulier du deuil en Métropole',
},
'continue',
),
( # check me with Marie
{
'volet': 'VOLET B - Métropole / Réunion',
'type demande': 'BON',
'type aide': 'RESSOURCEMENT ETUDIANT',
'derogation': "Personne porteuse d'un handicap",
'mesure specifique': 'NULL',
},
'continue',
),
]
def get_aide_derogation(row_data):
for criteria, extra_data in aide_derogation_mapping:
for key, value in criteria.items():
if row_data[key] != value:
break
else:
return extra_data
return None
for i, row in get_rows(args):
aide_derogation = get_aide_derogation(row)
if aide_derogation is None:
print('No matching criteria for row num %s.' % i)
pprint(row)
continue
if aide_derogation == 'continue':
continue
email = ''
if row['email'] != 'NULL':
email = row['email'].lower()
data = {
'courriel_demandeur': email,
'date_import': datetime.datetime.now().date().strftime('%Y-%m-%d'),
'date_naissance': parse_date(row['date naissance']),
'nom_naissance': row['nom naissance'].upper(),
'nom_usage': row['nom'].upper(),
'numero_fiscal': row['numero fiscal'],
'prenom': row['prenom'].upper(),
}
resp = api_call(args, path=benef_path, data=data)
benef_id = str(resp.json()['data']['id'])
data = {
'annee_demande': row['campagne'],
'beneficiaire': benef_id,
'beneficiaire_courriel': email,
'beneficiaire_numero_cni': row['numero CI/passeport'],
'bon_numero': row['numero bon'],
'bon_montant': row['montant region'],
'bon_validite': row['date validite'],
'commentaires_import': 'Trajet : %s.' % row['trajet'],
'date_import': datetime.datetime.now().date().strftime('%Y-%m-%d'),
'voyage_date_aller': parse_date(row['date aller'], '%Y-%m-%d %H:%M:%S'),
'voyage_date_retour': parse_date(row['date retour'], '%Y-%m-%d %H:%M:%S'),
}
if row['compagnie'] and row['compagnie'] != 'NULL':
data['billet_compagnie'] = get_compagnie_aerienne(row['compagnie'])
aide_derogation = get_aide_derogation(row)
data.update(aide_derogation)
resp = api_call(args, path=bon_path, data=data)
def reset(args):
for slug in (CARD_BENEFICIAIRE_SLUG, CARD_BON_SLUG):
cardef = CardDef.get_by_urlname(slug)
date_timport_field = get_field_by_varname(cardef, 'date_import')
for carddata in cardef.data_class().select(
[st.NotNull(st.get_field_id(date_timport_field))]
):
carddata.remove_self()
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers()
parser_import = subparsers.add_parser('import')
parser_import.set_defaults(func=import_data)
parser_import.add_argument('--filepath')
parser_import.add_argument('--mode', default='sample', choices=('sample', 'full'))
parser_import.add_argument('--sample-numlines', default=100, type=int)
parser_import.add_argument('--start-line', default=0, type=int)
parser_import.add_argument('--api-url')
parser_import.add_argument('--email')
parser_import.add_argument('--key')
parser_import.add_argument('--passwd')
parser_reset = subparsers.add_parser('reset')
parser_reset.set_defaults(func=reset)
args = parser.parse_args()
args.func(args)