south
django-admin-tools
auf.django.skin
+ simplejson
+ reportlab
+ html5lib
+ pisa
[versions]
django = 1.2.3
wsgi=false
settings=development
eggs = ${buildout:eggs}
- django-debug-toolbar
--- /dev/null
+# DÉPLOIEMENT
+# config
+Pour déploiement, créer sur la racine :
+conf.py
+
+...sur la base du fichier :
+conf.py.edit
+
+# DOCUMENTS
+Les documents uploadés par les candidats sont servis par l'application et ne sont pas suivis dans Git.
+Les déployer dans
+/formwcs/docs/
+
+problèmes JSON :
+json/0333 modifier manuellement ses caractères accentués
+ex. : é --> %|% puis %|% --> é
+
+json/0295 champ particip_prog_auf_dernier
+caract. invisible entre mot "distant" et double-quote json : supprimer
+
+# IMPORT WCS
+> cd sigmawcs
+> python manage.py shell
+> cd formwcs
+> run views.py
+
+# MISES À JOUR
+git pull
+
+reloader apache
+
+# WCS2JSON
+Fichiers pour générer
+- les JSON,
+- le form en PDF et
+- les zip (form + 3 pj.)
--- /dev/null
+# -*- encoding: utf-8 -*-
+DEBUG = True
+TEMPLATE_DEBUG = DEBUG
+AUTH_PASSWORD_REQUIRED = False
+
+# DEV
+DATABASE_ENGINE = 'mysql'
+DATABASE_NAME = 'sigmawcs'
+DATABASE_USER = ''
+DATABASE_PASSWORD = ''
+DATABASE_HOST = 'new-dev.auf'
+DATABASE_PORT = ''
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from project.settings import *
+DEBUG=True
+TEMPLATE_DEBUG=DEBUG
+
+# Décommentez ces lignes pour activer la debugtoolbar
+#INTERNAL_IPS = ('127.0.0.1',)
+#INSTALLED_APPS += ('debug_toolbar',)
+#MIDDLEWARE_CLASSES += ('debug_toolbar.middleware.DebugToolbarMiddleware',)
+
+AUTH_PASSWORD_REQUIRED = False
--- /dev/null
+import os
+import sys
+
+sys.path.append('/srv/www/rh-eval-test.auf')
+sys.path.append('/srv/www/rh-eval-test.auf/rh-eval-test/')
+
+os.environ['DJANGO_SETTINGS_MODULE'] = 'rh-eval-test.settings'
+
+import django.core.handlers.wsgi
+application = django.core.handlers.wsgi.WSGIHandler()
--- /dev/null
+# -=- encoding: utf-8 -=-
+import os.path
+import unicodedata
+from simplejson import loads
+
+
+# HELPERS
+def jsonCleanUp(json):
+ for k,v in json.iteritems():
+ if type(v) is unicode :
+ # encodage : correction caractères
+ v = replaceUnicodeNotIso(v)
+ # strip espaces
+ v = v.lstrip()
+ v = v.rstrip()
+ json[k] = v
+ if type(v) is str :
+ print ('%s %s a str : %s') % (json['num_dossier'], k, v)
+ return json
+
+def replaceUnicodeNotIso(string):
+ """Remplace caractère Unicode (scripts latin) n'ayant pas d'équivalent ISO-8859-1
+ par un caractère visuellement similaire.
+ """
+ result = ''
+
+# nkfd_form = unicodedata.normalize('NFKD', unicode(string))
+# string = u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
+
+ # Latin Extended-A
+ avant = u'ĂŞşŢţν'
+ apres = u'ASsTtv'
+
+ for char in string:
+ i = avant.find(char)
+ if i >= 0:
+ char = apres[i]
+ result += char
+
+ return result
+
+
+# MAIN
+if __name__ == "__main__":
+
+ rootDocsJson = 'docs/json/'
+ listjson = []
+
+ if os.path.exists(rootDocsJson):
+ listjson = os.listdir(rootDocsJson)
+
+ extensions = set()
+ erreurs = set()
+ tests = {}
+ i = 0
+ for candidature in listjson :
+ fichier = "%s%s" % (rootDocsJson, candidature)
+
+ f = open(fichier, 'r')
+ data = f.read()
+ f.close()
+
+ data = loads(data, encoding='utf-8')
+ data = jsonCleanUp(data)
+
+ extension_dt = data['descriptif_these'].rsplit('.', 1)[1]
+ extension_pr = data['protocole_recherche'].rsplit('.', 1)[1]
+ extension_cv = data['curriculum_vitae'].rsplit('.', 1)[1]
+
+ if len(extension_dt) < 5 :
+ if extension_dt not in extensions :
+ tests[extension_dt] = data['num_dossier']
+ extensions.add(extension_dt)
+ else :
+ erreurs.add(data['num_dossier'])
+
+ if len(extension_pr) < 5 :
+ if extension_pr not in extensions :
+ tests[extension_pr] = data['num_dossier']
+ extensions.add(extension_pr)
+ else :
+ erreurs.add(data['num_dossier'])
+
+ if len(extension_cv) < 5 :
+ if extension_cv not in extensions :
+ tests[extension_cv] = data['num_dossier']
+ extensions.add(extension_cv)
+ else :
+ erreurs.add(data['num_dossier'])
+
+ i = i + 1
+
+ print '%d - %s, %s, %s' % (i, extension_dt, extension_pr, extension_cv)
+ print 'Total = %d' % (i)
+ print 'Extensions ='
+ print ', '.join(extensions)
+ print 'Erreurs (num_dossier WCS) ='
+ print ', '.join([str(e) for e in erreurs])
+ print 'Tests : cas a tester pour chaque extension :'
+ print tests
--- /dev/null
+# -=- encoding: utf-8 -=-
+import os.path
+import unicodedata
+from datetime import datetime
+from datetime import date
+from simplejson import loads
+
+from sigma_v1.models import Dossier, DossierPieces
+
+from settings import USER, STATUT_DOSSIER, MOBILITE
+
+def createDossierPieces(d):
+### DOSSIER PIÈCES
+ pieces_created = []
+
+ pieces_WCS = [
+ 45, # etabl origine = membre
+ 46, # etabl accueil = membre
+ 55, # date naissance
+ 56, # etabl orig et acc = pays diff
+ ]
+
+ for piece in pieces_WCS:
+ dp = DossierPieces()
+ #dp.id =
+ dp.dossier = d
+ dp.presente = False
+ dp.piece = piece
+ #dp.conforme =
+ #dp.commentaire = u"Pièce chargée par candidat via formulaire électronique."
+ dp.save()
+ pieces_created.append(dp)
+
+ return pieces_created
+
+# MAIN
+if __name__ == "__main__":
+
+ candidatures = range(8017, 9776) # réel [8017, 9775], 2e param range = exclu
+
+ nombre = len(candidatures)
+
+ print 'AJOUT PIECES CANDIDATURES'
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nombre)
+ print '--------------------------------------------------'
+
+ i = 0
+ for candidature in candidatures:
+ d = Dossier(id=candidature)
+ pieces = createDossierPieces(d)
+
+ print candidature
+
+ i = i + 1
+
+ print '--------------------------------------------------'
+ print 'Total traité = %d' % (i)
+ print '--------------------------------------------------'
--- /dev/null
+# -=- encoding: utf-8 -=-
+import os.path
+import unicodedata
+from datetime import datetime
+from datetime import date
+from simplejson import loads
+
+from sigma_v1.models import Personne, Dossier, DossierOrigine, DossierAccueil, DossierMobilite, DossierPieces
+from sigma_v1.models import Etablissement, Implantation, Bureau
+
+from settings import USER, STATUT_DOSSIER, MOBILITE
+
+def createPersonne(data):
+### PERSONNE
+ p = Personne()
+
+ #p.id
+ p.utilisateur_creation = USER
+ #p.utilisateur_maj =
+ #p.date_creation =
+ #p.date_maj =
+
+ if data['nom'] is not None :
+ p.nom = majSansAccent(data['nom'].upper())[0:100]
+ p.nom_index = p.nom
+ if data['nom_jeune_fille'] is not None :
+ p.nom_jeune_fille = majSansAccent(data['nom_jeune_fille'].upper())[0:100]
+ p.nom_jeune_fille_index = p.nom_jeune_fille
+ if data['prenom'] is not None :
+ p.prenom = majSansAccent(data['prenom'].title())[0:100]
+ p.prenom_index = p.prenom.upper()
+ p.pays_nationalite = data['pays_nationalite']
+ #p.sexe =
+
+ p.civilite = str2civilite(data['civilite'])
+
+ p.pays_naissance = data['pays_naissance'] or u""
+ p.date_naissance = str2date(data['date_naissance'])
+ p.ville_naissance = majSansAccent(data['ville_naissance'].title()) or u""
+
+ p.adresse = data['adresse'] or u""
+ p.ville = majSansAccent(data['ville'].title()) or u""
+ p.region = data['region'] or u""
+ if data['code_postal'] is not None :
+ p.code_postal = data['code_postal'][0:10]
+ p.pays_residence = data['pays_residence'] or u""
+ if data['tel'] is not None :
+ p.tel = data['tel'][0:25]
+ #p.fax
+ if data['tel_pro'] is not None :
+ p.tel_pro = data['tel_pro'][0:25]
+ #p.fax_pro
+ if data['email'] is not None :
+ p.email = data['email'][0:100] or u""
+
+ p.save()
+
+ return p
+
+def createDossier(data, p):
+### DOSSIER
+ d = Dossier()
+
+ #d.id
+ d.statut = STATUT_DOSSIER
+ d.mobilite = MOBILITE
+ d.personne = p
+ d.statut_personne = str2statutPersonne(data['statut_personne'])
+ if data['fonction'] is not None :
+ d.fonction = data['fonction'][0:100]
+
+ # bureau rattachement via établissement d'origine
+ try:
+ id_etablissement = data['o_etablissement'].lstrip('0')
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+ d.bureau_rattachement = etablissement.implantation_sigma.bureau.id_num
+ except Etablissement.DoesNotExist:
+ pass
+
+ if data['intitule_d_diplome'] is not None :
+ d.intitule_d_diplome = data['intitule_d_diplome'][0:100]
+ d.date_d_diplome = str2date(data['date_d_diplome'])
+ if data['nom_etb'] is not None :
+ d.nom_etb = data['nom_etb'][0:100]
+ d.pays_etb = data['pays_etb'] or u""
+ d.niveau = str2niveauEtude(data['niveau'])
+
+ #data['particip_prog_auf']
+ if data['particip_prog_auf_dernier'] is not None :
+ d.programme = data['particip_prog_auf_dernier'][0:255]
+ d.annee_programme = data['particip_prog_auf_annee'] or 0
+ #data['boursier_auf']
+ if data['boursier_auf_type'] is not None :
+ d.categorie_bourse = data['boursier_auf_type'][0:12]
+ d.annee_bourse = data['boursier_auf_annee'] or 0
+
+ #d.etat
+ #d.dd_activation
+ #d.df_activation
+ d.utilisateur_creation = USER
+ d.utilisateur_maj = USER
+ #d.date_maj
+
+ #d.classement_1
+ #d.classement_2
+ #d.classement_3
+ #d.opp_regionale
+ #d.coche_selection
+ #d.reponse_notification
+ #d.commentaire_notification
+ #d.moyenne_academique
+ #d.autres_criteres
+ #d.erreurs_recevabilite
+ #d.repechage
+ #d.rendu_irrecevable
+
+ d.save()
+
+ return d
+
+def createDossierOrigine(data, d):
+### DOSSIER ORIGINE
+ do = DossierOrigine()
+
+ #do.id
+ do.dossier = d
+
+ # établissement
+ id_etablissement = data['o_etablissement'].lstrip('0')
+ try:
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+
+ # id
+ do.etablissement = etablissement.id # PAS etablissement.id_gde
+
+ # coordonnées
+ do.pays = etablissement.pays
+ do.adresse = etablissement.adresse
+ if etablissement.code_postal is not None :
+ do.code_postal = etablissement.code_postal[0:10]
+ if etablissement.ville is not None :
+ do.ville = etablissement.ville[0:50]
+ if etablissement.province is not None :
+ do.region = etablissement.province[0:50]
+ #do.url_site
+ except Etablissement.DoesNotExist:
+ pass
+
+ if data['o_etablissement_unite'] is not None :
+ do.sc_faculte = data['o_etablissement_unite'][0:150]
+
+ #do.erreur_recevabilite_etbt_origine =
+ #do.autre_etb =
+
+ # accord scientifique
+ do.sc_civilite = str2civilite(data['o_sc_civilite'])
+ if data['o_sc_nom'] is not None :
+ do.sc_nom = majSansAccent(data['o_sc_nom'].upper())[0:100]
+ if data['o_sc_prenom'] is not None :
+ do.sc_prenom = majSansAccent(data['o_sc_prenom'].title())[0:100]
+ if data['o_sc_fonction'] is not None :
+ do.sc_fonction = data['o_sc_fonction'][0:100]
+ #do.sc_adresse =
+ #do.sc_code_postal =
+ if data['o_sc_ville'] is not None :
+ do.sc_ville = majSansAccent(data['o_sc_ville'].title())[0:50]
+ if data['o_sc_email'] is not None :
+ do.sc_email = data['o_sc_email'][0:100]
+ if data['o_sc_tel_pro'] is not None :
+ do.sc_tel_pro = data['o_sc_tel_pro'][0:25]
+ #do.sc_fax_pro =
+
+ # accord institutionnel
+ #do.inst_civilite =
+ #do.inst_nom =
+ #do.inst_prenom =
+ #do.inst_fonction =
+
+ do.save()
+
+ return do
+
+def createDossierAccueil(data, d):
+### DOSSIER ACCUEIL
+ da = DossierAccueil()
+
+ #da.id =
+ da.dossier = d
+
+ # établissement
+ id_etablissement = data['a_etablissement'].lstrip('0')
+ try:
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+
+ # id
+ da.etablissement = etablissement.id # PAS etablissement.id_gde
+
+ # coordonnées
+ da.pays = etablissement.pays
+ da.adresse = etablissement.adresse
+ if etablissement.code_postal is not None :
+ da.code_postal = etablissement.code_postal[0:10]
+ if etablissement.ville is not None :
+ da.ville = etablissement.ville[0:50]
+ if etablissement.province is not None :
+ da.region = etablissement.province[0:50]
+ #da.url_site
+ except Etablissement.DoesNotExist:
+ pass
+
+ if data['a_etablissement_unite'] is not None :
+ da.sc_faculte = data['a_etablissement_unite'][0:150]
+
+ #da.erreur_recevabilite_etbt_accueil =
+ #da.autre_etb =
+
+ # accord scientifique
+ da.sc_civilite = str2civilite(data['a_sc_civilite'])
+ if data['a_sc_nom'] is not None :
+ da.sc_nom = majSansAccent(data['a_sc_nom'].upper())[0:100]
+ if data['a_sc_prenom'] is not None :
+ da.sc_prenom = majSansAccent(data['a_sc_prenom'].title())[0:100]
+ if data['a_sc_fonction'] is not None :
+ da.sc_fonction = data['a_sc_fonction'][0:100]
+ #da.sc_adresse =
+ #da.sc_code_postal =
+ if data['a_sc_ville'] is not None :
+ da.sc_ville = majSansAccent(data['a_sc_ville'].title())[0:50]
+ if data['a_sc_email'] is not None :
+ da.sc_email = data['a_sc_email'][0:100]
+ if data['a_sc_tel_pro'] is not None :
+ da.sc_tel_pro = data['a_sc_tel_pro'][0:25]
+ #da.sc_fax_pro =
+
+ # accord institutionnel
+ #da.inst_civilite =
+ #da.inst_nom =
+ #da.inst_prenom =
+ #da.inst_fonction =
+ #da.inst_email =
+ #da.inst_tel_pro =
+ #da.inst_fax_pro =
+
+ da.save()
+
+ return da
+
+def createDossierMobilite(data, d):
+### DOSSIER MOBILITÉ
+ dm = DossierMobilite()
+
+ #dm.id =
+ dm.dossier = d
+
+ # calcul dates
+# o_date_debut = str2date(data['o_date_debut_mobilite'])
+# a_date_debut = str2date(data['a_date_debut_mobilite'])
+
+# if (o_date_debut < a_date_debut):
+# date_debut = o_date_debut
+# else :
+# date_debut = a_date_debut
+
+# o_date_fin = str2date(data['o_date_fin_mobilite'])
+# a_date_fin = str2date(data['a_date_fin_mobilite'])
+
+# if (o_date_fin < a_date_fin):
+# date_fin = o_date_fin
+# else :
+# date_fin = a_date_fin
+
+# dm.dd_mobilite = date_debut
+# dm.df_mobilite = date_fin
+# dm.total_mobilite = # intervalle dd_mobilite, df_mobilite
+
+ dm.alt_mois_origine = str2nbMois(data['o_nb_mois'])
+ dm.alt_mois_accueil = str2nbMois(data['a_nb_mois'])
+
+ dm.intitule_projet = premiereMaj(data['intitule_projet']) or u""
+ # ajout point à la fin...
+ if dm.intitule_projet != u"" and dm.intitule_projet[-1] != u"." :
+ dm.intitule_projet = dm.intitule_projet + u"."
+
+ if data['mot_clef1'] is not None :
+ dm.mot_clef1 = majSansAccent(data['mot_clef1'].upper())[0:50]
+ if data['mot_clef2'] is not None :
+ dm.mot_clef2 = majSansAccent(data['mot_clef2'].upper())[0:50]
+ if data['mot_clef3'] is not None :
+ dm.mot_clef3 = majSansAccent(data['mot_clef3'].upper())[0:50]
+
+ dm.intitule_diplome = data['programme'] or u""
+ if dm.intitule_diplome == u"" and data['programme_autre'] is not None :
+ dm.intitule_diplome = data['programme_autre']
+
+ dm.niveau_encours = str2niveauEtude(data['annee_programme'])
+
+ #dm.type_intervention =
+ #dm.public_vise =
+ #dm.autres_publics =
+
+ dm.discipline = data['discipline'] or u""
+ #dm.sous_discipline =
+
+ #dm.mobilite_accueil = # debut mobilité à l'accueil?
+ #dm.intitule_diplome_demande =
+ #dm.niveau_demande =
+ #dm.obtention_prevu =
+
+ dm.date_inscription_these = str2date(data['date_inscription_these'])
+ dm.pays_soutenance = data['pays_soutenance'] or u""
+ dm.date_soutenance_these = str2date(data['date_soutenance_these'])
+ dm.type_these = str2typeThese(data['type_these'])
+ # workaround : champ dm.date_soutenance_these pas affiché in SIGMA :
+ dm.type_these_autre = u"Date soutenance prévue : %s" % (dm.date_soutenance_these)
+ dm.type_these_autre = dm.type_these_autre[0:255]
+
+ dm.dir_ori_civilite = str2civilite(data['o_inst_civilite'])
+ if data['o_inst_nom'] is not None :
+ dm.dir_ori_nom = majSansAccent(data['o_inst_nom'].upper())[0:100]
+ if data['o_inst_prenom'] is not None :
+ dm.dir_ori_prenom = majSansAccent(data['o_inst_prenom'].title())[0:100]
+ # email absent in SIGMA... sale workaround
+ if data['o_inst_email'] is not None :
+ dm.dir_ori_prenom = u"%s [%s]" % (dm.dir_ori_prenom, data['o_inst_email'])
+ dm.dir_ori_prenom = dm.dir_ori_prenom[0:100]
+
+ dm.dir_acc_civilite = str2civilite(data['a_inst_civilite'])
+ if data['a_inst_nom'] is not None :
+ dm.dir_acc_nom = majSansAccent(data['a_inst_nom'].upper())[0:100]
+ if data['a_inst_prenom'] is not None :
+ dm.dir_acc_prenom = majSansAccent(data['a_inst_prenom'].title())[0:100]
+ # email absent in SIGMA... sale workaround
+ if data['a_inst_email'] is not None :
+ dm.dir_acc_prenom = u"%s [%s]" % (dm.dir_acc_prenom, data['a_inst_email'])
+ dm.dir_acc_prenom = dm.dir_acc_prenom[0:100]
+
+ dm.save()
+
+ return dm
+
+def createDossierPieces(data, d):
+### DOSSIER PIÈCES
+ pieces_created = []
+
+ #data['descriptif_these']
+ #data['protocole_recherche']
+ #data['curriculum_vitae']
+ pieces_WCS = [
+ 19, # formulaire
+ 17, # descriptif thèse
+ 27, # protocole de recherche
+ 16, # curriculum_vitae
+ ]
+
+ for piece in pieces_WCS:
+ dp = DossierPieces()
+ #dp.id =
+ dp.dossier = d
+ dp.presente = True
+ dp.piece = piece
+ #dp.conforme =
+ #dp.commentaire = u"Pièce chargée par candidat via formulaire électronique."
+ dp.save()
+ pieces_created.append(dp)
+
+ # Autres pièces in SIGMA
+ pieces_SIGMA = [1,4,5,8,10,12,47]
+
+ for piece in pieces_SIGMA:
+ dp = DossierPieces()
+ dp.dossier = d
+ dp.piece = piece
+ dp.save()
+ pieces_created.append(dp)
+
+ return pieces_created
+
+### AUTRE
+ #data['num_dossier']
+
+ #data['engagement_nom']
+ #data['engagement_prenom']
+ #data['engagement_respect_reglement']
+
+# HELPERS
+def jsonCleanUp(json):
+ for k,v in json.iteritems():
+ if type(v) is unicode :
+ # encodage : correction caractères
+ v = replaceUnicodeNotIso(v)
+ # strip espaces
+ v = v.lstrip()
+ v = v.rstrip()
+ json[k] = v
+ if type(v) is str :
+ print ('%s %s a str : %s') % (json['num_dossier'], k, v)
+ return json
+
+def replaceUnicodeNotIso(string):
+ """Remplace caractère Unicode (scripts latin) n'ayant pas d'équivalent ISO-8859-1
+ par un caractère visuellement similaire.
+ """
+ result = ''
+
+# nkfd_form = unicodedata.normalize('NFKD', unicode(string))
+# string = u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
+
+ # Latin Extended-A
+ avant = u'ĂŞşŢţνγδệịạỄợụĐốữẦươȘβğПΣăúµÁẾ'
+ apres = u'ASsTtvgdêiaEouDouAuoSBgPEaumAE'
+
+ for char in string:
+ i = avant.find(char)
+ if i >= 0:
+ char = apres[i]
+ result += char
+
+ return result
+
+def premiereMaj(s):
+ """Met le premier caractère en majuscule et reste minuscule"""
+ premiere = s[0]
+ reste = s[1:]
+
+ return premiere.upper() + reste.lower()
+
+def majSansAccent(s):
+ result = ''
+ avant = u'ÇÁÀÂÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÝỲŶŸ'
+ apres = u'CAAAEEEEIIIIOOOOUUUUYYYY'
+
+ for char in s:
+ i = avant.find(char)
+ if i >= 0:
+ char = apres[i]
+ result += char
+
+ return result
+
+def str2date(s):
+ d = datetime.strptime(s, '%Y-%m-%d')
+ return date(d.year, d.month, d.day)
+
+def str2civilite(s):
+ output = ''
+ if s == 'M.':
+ output = 'MR'
+ elif s == 'Mme':
+ output = 'MM'
+ elif s == 'Mlle':
+ output = 'ME'
+ return output
+
+def str2typeThese(s):
+ output = ''
+ if s == 'Co-tutelle':
+ output = 'CT'
+ elif s == 'Co-direction':
+ output = 'CD'
+ elif s == 'Autre':
+ output = 'AU'
+ return output
+
+def str2statutPersonne(s):
+ output = 0
+ try :
+ # id du statut = permière lettre
+ output = int(s[0])
+ except ValueError :
+ pass
+ return output
+
+def str2nbMois(s):
+ output = 0
+ try :
+ # permière lettre = nb de mois
+ output = int(s[0])
+ except ValueError :
+ pass
+ return output
+
+def str2niveauEtude(s):
+ output = 0
+ try :
+ # années études = permière lettre
+ annees = int(s[0])
+ # sauf 10 ans = 2 premières lettres...
+ if annees == 1:
+ annees = 10
+
+ #C_NIVEAU L_INTITULE_NIVEAU L_NIVEAU (annees)
+ #6 ... 0
+ #1 Licence 2 2
+ #2 Licence 3 3
+ #3 Master 1 4
+ #4 Master 2 5
+ #7 Master 2 + 6
+ #5 Doctorat 8
+ #8 Bac + 7 7
+ #9 Doctorat 9
+
+ if annees == 4 : output = 3
+ elif annees == 5 : output = 4
+ elif annees == 6 : output = 7
+ elif annees == 7 : output = 8
+ elif annees == 8 : output = 5
+ elif annees == 9 : output = 9
+ elif annees == 10 : output = 9
+
+ except ValueError :
+ pass
+ return output
+
+# MAIN
+if __name__ == "__main__":
+
+ rootDocsJson = 'docs/json/'
+ listjson = []
+
+ if os.path.exists(rootDocsJson):
+ listjson = os.listdir(rootDocsJson)
+ nombre = len(listjson)
+
+ print 'IMPORT CANDIDATURES : WCS -> json -> SIGMA'
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nombre)
+ print '--------------------------------------------------'
+
+ i = 0
+ for candidature in listjson :
+ fichier = "%s%s" % (rootDocsJson, candidature)
+
+ f = open(fichier, 'r')
+ data = f.read()
+ f.close()
+
+ data = loads(data, encoding='utf-8')
+ data = jsonCleanUp(data)
+
+ p = createPersonne(data)
+ d = createDossier(data, p)
+ do = createDossierOrigine(data, d)
+ da = createDossierAccueil(data, d)
+ dm = createDossierMobilite(data, d)
+ pieces = createDossierPieces(data, d)
+
+ i = i + 1
+
+ print '%d - %s' % (i, p)
+ print '--------------------------------------------------'
+ print 'Total traité = %d' % (i)
+ print '--------------------------------------------------'
--- /dev/null
+WCS2JSON
+
+
+Note: wcs n'est apparemment pas compatible avec python-2.6,
+ il ne fonctionne qu'avec 2.5.
+Note: Il manque surement d'autres dependances
+
+
+1. Dependances
+=====================================================================
+
+1.1. Packages Debian
+
+$ sudo apt-get install python-html5lib python-lxml python-quixote wcs
+
+
+1.2. Easy install
+
+$ sudo easy_install-2.5 pisa
+
+
+
+2. Organisation
+=====================================================================
+
+
+2.1. wcs2json
+
+2.1.1. Fichiers
+
+wcs2json.py : Extracte les donnees, les ecrit en json, peut etre
+ execute directement.
+wcs2json.sh : Wrapper au script python, verifie des permissions et
+ fork l'execution du script.
+
+
+2.2. Generation de PDF
+
+2.2.1. Fichiers
+
+jsontopdf.py : Classe qui definit le convertisseur
+template.html : Template django initial incomplet, le convertisseur va aller
+ le chercher dans le dossier courant.
+settings.py : Pour faire croire a l'engine de template de django qu'on
+ est dans un projet django
+
+2.2.2. Exemple
+
+ from jsontopdf import JsonToPdf
+ converter = JsonToPdf ("/path/to/template") #param facultatif
+ pdf = converter.convertFromFile (jsonFile) #jsonFile est le path
+
+
+3. Utilisation
+=====================================================================
+
+1. Copier le dossier /var/lib/wcs/formulaire.auf.org du serveur de prod
+ en local. Ce path est a priori invariable.
+
+2. Editer wcs2json.py:
+ - Ligne 10; Mettre le nom du formulaire a traiter.
+ - Ligne 12/13: Specifier le dossier ou on peut que les fichiers
+ json et zip soient places.
+
+3. L'executer et attendre
--- /dev/null
+5:civilite
+6:nom
+7:nom_jeune_fille
+8:prenom
+9:pays_nationalite
+10:pays_naissance
+11:date_naissance
+12:ville_naissance
+14:adresse
+15:ville
+16:region
+17:code_postal
+18:pays_residence
+19:tel
+20:tel_pro
+21:email
+23:statut_personne
+24:fonction
+26:intitule_d_diplome
+27:date_d_diplome
+28:nom_etb
+29:pays_etb
+30:niveau
+32:particip_prog_auf
+33:particip_prog_auf_dernier
+34:particip_prog_auf_annee
+35:boursier_auf
+36:boursier_auf_type
+37:boursier_auf_annee
+39:programme
+40:programme_autre
+41:annee_programme
+44:o_etablissement_unite
+45:o_sc_civilite
+46:o_sc_nom
+47:o_sc_prenom
+48:o_sc_fonction
+49:o_sc_ville
+50:o_sc_tel_pro
+51:o_sc_email
+53:o_inst_civilite
+54:o_inst_nom
+55:o_inst_prenom
+56:o_inst_email
+59:a_etablissement_unite
+60:a_sc_civilite
+61:a_sc_nom
+62:a_sc_prenom
+63:a_sc_fonction
+64:a_sc_ville
+65:a_sc_tel_pro
+66:a_sc_email
+68:a_inst_civilite
+69:a_inst_nom
+70:a_inst_prenom
+71:a_inst_email
+75:o_date_debut_mobilite
+76:o_date_fin_mobilite
+77:o_nb_mois
+79:a_date_debut_mobilite
+80:a_date_fin_mobilite
+81:a_nb_mois
+83:date_inscription_these
+84:date_soutenance_these
+85:pays_soutenance
+86:type_these
+87:discipline
+88:intitule_projet
+90:mot_clef1
+91:mot_clef2
+92:mot_clef3
+95:engagement_nom
+96:engagement_prenom
+98:engagement_respect_reglement
+101:descriptif_these
+102:protocole_recherche
+103:curriculum_vitae
+108:a_etablissement
+109:o_etablissement
--- /dev/null
+#!/usr/bin/python
+
+import os, sys, simplejson, StringIO
+from ho import pisa
+
+from django.template import Context, Template
+from django.conf import settings
+
+
+class JsonToPdf:
+ "Convertit un fichier json de candidature en pdf."
+ inputBuffer = ""
+ templateFile = ""
+
+ def __init__ (self,
+ templateFileName = "template.html"):
+ self.templateFile = templateFileName
+
+ def readFile (self, fileName):
+ """Lire le fichier fileName et retourne son contenu.
+ Vide si le fichier n'existe pas
+ """
+ buffer = ""
+
+ try:
+ inFile = open (fileName, 'r')
+ except:
+ print "Fichier", fileName, "illisible"
+ else:
+ buffer = inFile.read ()
+
+ return buffer
+
+ def asJson (self, jsonBuffer):
+ """Convertit le buffer json en objet,
+ retourne None si l'evaluation echoue"""
+ object = None
+
+ try:
+ object = simplejson.loads (jsonBuffer)
+ except:
+ print "Format json invalide"
+
+ return object
+
+ def convert (self):
+ "Effectue la conversion"
+
+ if len (self.inputBuffer) > 0:
+ object = self.asJson (self.inputBuffer)
+ if object is not None:
+ # Render
+ template = Template (self.readFile (self.templateFile))
+ context = Context (object)
+ # As HTML
+ html = template.render (context)
+ # Write PDF
+ pdf = StringIO.StringIO ()
+ pisa.CreatePDF(html, pdf)
+ return pdf
+
+ def convertFromFile (self, inputFile):
+ self.inputBuffer = self.readFile (inputFile)
+ return self.convert ()
+
+ def convertBuffer (self, buffer):
+ self.inputBuffer = buffer
+ return self.convert ()
+
+
+
+if __name__ == "__main__":
+ if len (sys.argv) > 1:
+ settings.configure ()
+ for inputFile in sys.argv[1:]:
+ tmp = JsonToPdf ()
+ tmp.convertFromFile (inputFile)
+ #tmp.convertFromBuffer ("blabla", "out.pdf")
--- /dev/null
+# Bogus Django settings
+
+import os
+
+
+DEBUG = True
+
--- /dev/null
+h1 { color:#c60 ; margin:0px; padding:0px; }
+h2 { padding:5px; background-color:#ccc; }
+h3 { margin:0px; padding:0px; }
+p { margin:0px; padding:0px; }
+
+div.spacer { line-height:0.25cm; }
+
+table { width:100%; padding:0px; }
+table.titre { margin:10px 0px 10px 0px; }
+table.data { margin-top:5px; }
+
+td { width:49%; padding:2px; vertical-align:top; }
+table.titre td { padding:0px; }
+
+.bloc { border: solid 1px black; padding:5px; }
+.gutter { width:2%; }
+
+td.w15 { width:15%; padding:0px; vertical-align:top; }
+td.w25 { width:25%; padding:0px; vertical-align:top; }
+td.w30 { width:30%; padding:0px; vertical-align:top; }
+td.w35 { width:35%; padding:0px; vertical-align:top; }
+td.w50 { width:50%; padding:0px; vertical-align:top; }
+
+td.w20 { width:20%; padding:0px; vertical-align:top; }
+td.w80 { width:80%; padding:0px; vertical-align:top; }
+
+td.w40 { width:40%; padding:0px; vertical-align:top; }
+td.w60 { width:60%; padding:0px; vertical-align:top; }
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\r
+ <title>{{nom.upper}}, {{prenom.title}} : Bourses de doctorat - 2010-2011</title>\r
+ <link href="style.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+
+<h1>{{civilite}} {{prenom.title}} {{nom.upper}}</h1>
+
+<h2>Renseignements personnels</h2>
+
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Identification</h3>
+ <p>
+ {{civilite}} {{prenom.title}} {{nom.upper}}
+ {% if nom_jeune_fille %}<br />Nom de jeune fille : {{nom_jeune_fille.upper}}{% endif %}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Nationalité : </i></td><td class="w60">{{pays_nationalite_orig}}</td></tr>
+ <tr>
+ <td class="w40"><i>Date de naissance : </i></td>
+ <td class="w60">
+ {% with date_naissance as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Ville de naissance : </i></td><td class="w60">{{ville_naissance.title|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Pays de naissance : </i></td><td class="w60">{{pays_naissance_orig|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Adresse de correspondance</h3>
+ <p>
+ {{adresse}}
+ <br />
+ {% if ville %}{{ville.title}}{% endif %}
+ {% if region %}, {{region}}{% endif %}
+ {% if code_postal %} {{code_postal}} {% endif %}
+ {% if pays_residence_orig %}<br />{{pays_residence_orig}}{% endif %}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Téléphone personnel : </i></td><td class="w60">{{tel|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionel : </i></td><td class="w60">{{tel_pro|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{email|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Situation universitaire</h3>
+ <table>
+ <tr><td class="w20"><i>Statut : </i></td><td class="w80">{{statut_personne|slice:"4:"|default:"n/d"}}</td></tr>
+ <tr><td class="w20"><i>Fonction : </i></td><td class="w80">{{fonction|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Dernier diplôme obtenu</h3>
+ <table>
+ <tr><td class="w40"><i>Intitulé : </i></td><td class="w60">{{intitule_d_diplome|default:"n/d"}}</td></tr>
+ <tr>
+ <td class="w40"><i>Date d'obtention : </i></td>
+ <td class="w60">
+ {% with date_d_diplome as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Établissement : </i></td><td class="w60">{{nom_etb|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Pays : </i></td><td class="w60">{{pays_etb_orig|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Niveau (nb. années univ.) : </i></td><td class="w60">{{niveau|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc" colspan="3">
+ <h3>Lien avec l'AUF</h3>
+ <table>
+ <tr>
+ <td class="w35"><i>Candidat a déjà participé à un programme de l'AUF : </i></td><td class="w15">{{particip_prog_auf|default:"n/d"}}</td>
+ <td class="w35" style="padding-left:5px;"><i>Candidat a déjà bénéficié d'une bourse AUF : </i></td><td class="w15">{{boursier_auf|default:"n/d"}}</td>
+ </tr>
+ <tr>
+ <td class="w35"><i>Dernier programme participé : </i></td><td class="w15">{{particip_prog_auf_dernier|default:"n/d"}}</td>
+ <td class="w35" style="padding-left:5px;"><i>Type de bourse : </i></td><td class="w15">{{boursier_auf_type_orig|default:"n/d"}}</td>
+ </tr>
+ <tr>
+ <td class="w35"><i>Année : </i></td><td class="w15">{{particip_prog_auf_annee|default:"n/d"}}</td>
+ <td class="w35" style="padding-left:5px;"><i>Année : </i></td><td class="w15">{{boursier_auf_annee|default:"n/d"}}</td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+
+<div class="spacer"> </div>
+<table class="titre">
+<tr>
+ <td>
+ <h2>Origine</h2>
+ </td>
+ <td class="gutter"></td>
+ <td>
+ <h2>Accueil</h2>
+ </td>
+</tr>
+</table>
+
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Établissement d'origine</h3>
+ <p>
+ {{o_etablissement_orig|default:"n/d"}}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Faculté, départ. ou labo : </i></td><td class="w60">{{o_etablissement_unite|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Ville : </i></td><td class="w60">{{o_sc_ville.title|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Établissement d'accueil</h3>
+ <p>
+ {{a_etablissement_orig|default:"n/d"}}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Faculté, départ. ou labo : </i></td><td class="w60">{{a_etablissement_unite|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Ville : </i></td><td class="w60">{{a_sc_ville.title|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Accord scientifique</h3></td>
+ <td class="w60">
+ {% if o_sc_civilite %}{{o_sc_civilite}} {% endif %}
+ {% if o_sc_prenom %}{{o_sc_prenom.title}} {% endif %}
+ {% if o_sc_nom %}{{o_sc_nom.upper}}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Fonction : </i></td><td class="w60">{{o_sc_fonction|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionnel : </i></td><td class="w60">{{o_sc_tel_pro|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{o_sc_email|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Accord scientifique</h3></td>
+ <td class="w60">
+ {% if a_sc_civilite %}{{a_sc_civilite}} {% endif %}
+ {% if a_sc_prenom %}{{a_sc_prenom.title}} {% endif %}
+ {% if a_sc_nom %}{{a_sc_nom.upper}}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Fonction : </i></td><td class="w60">{{a_sc_fonction|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionnel : </i></td><td class="w60">{{a_sc_tel_pro|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{a_sc_email|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+
+ <table>
+ <tr>
+ <td class="w40"><h3>Directeur de thèse</h3></td>
+ <td class="w60">
+ {% if o_inst_civilite %}{{o_inst_civilite}} {% endif %}
+ {% if o_inst_prenom %}{{o_inst_prenom.title}} {% endif %}
+ {% if o_inst_nom %}{{o_inst_nom.upper}}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{o_inst_email|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Directeur de thèse</h3></td>
+ <td class="w60">
+ {% if a_inst_civilite %}{{a_inst_civilite}} {% endif %}
+ {% if a_inst_prenom %}{{a_inst_prenom.title}} {% endif %}
+ {% if a_inst_nom %}{{a_inst_nom.upper}}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{a_inst_email|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+
+<div class="spacer"> </div>
+<h2>Mobilité</h2>
+
+<table>
+<tr>
+ <td class="bloc">
+ <h3>Période de mobilité - Origine</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date de début : </i></td>
+ <td class="w60">
+ {% with o_date_debut_mobilite as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de fin : </i></td>
+ <td class="w60">
+ {% with o_date_fin_mobilite as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Nombre de mois : </i></td><td class="w60">{{o_nb_mois|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Période de mobilité - Accueil</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date de début : </i></td>
+ <td class="w60">
+ {% with a_date_debut_mobilite as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de fin : </i></td>
+ <td class="w60">
+ {% with a_date_fin_mobilite as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Nombre de mois : </i></td><td class="w60">{{a_nb_mois|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Thèse</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date d'inscription en thèse : </i></td>
+ <td class="w60">
+ {% with date_inscription_these as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de soutenance prévue : </i></td>
+ <td class="w60">
+ {% with date_soutenance_these as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Pays de soutenance prévu : </i></td><td class="w60">{{pays_soutenance_orig|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Type de thèse : </i></td><td class="w60">{{type_these|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Formation en cours</h3>
+ <table>
+ <tr><td class="w40"><i>Diplôme préparé : </i></td><td class="w60">{{programme|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Si autre : </i></td><td class="w60">{{programme_autre|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Niveau (nb. années univ.) : </i></td><td class="w60">{{annee_programme|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Dossier scientifique</h3>
+ <table>
+ <tr><td class="w40"><i>Intitulé du sujet de thèse : </i></td><td class="w60">{{intitule_projet|default:"n/d"}}</td></tr>
+ <tr><td class="w40"><i>Mots-clés : </i></td>
+ <td class="w60">
+ {% if mot_clef1 %}{{mot_clef1.upper}}{% endif %}
+ {% if mot_clef2 %}, {{mot_clef2.upper}}{% endif %}
+ {% if mot_clef3 %}, {{mot_clef3.upper}}{% endif %}
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Discipline</h3>
+ <p>
+ {{discipline_orig|default:"n/d"}}
+ </p>
+ </td>
+</tr>
+</table>
+
+</body>
+</html>
--- /dev/null
+#!/usr/bin/python2.5
+
+from django.template import Context, Template
+
+from jsontopdf import JsonToPdf
+from django.conf import settings
+
+if __name__ == "__main__":
+ converter = JsonToPdf()
+ pdf = converter.convertFromFile('../docs/template_test/test.json')
+
+ file = open('test.pdf', 'w')
+ file.write(pdf.getvalue())
+ file.close()
--- /dev/null
+#!/bin/sh
+export DJANGO_SETTINGS_MODULE=settings
+python2.5 template.py
--- /dev/null
+#!/usr/bin/env python
+# -*- coding: utf-8 -*-
+
+####
+# Constantes
+
+# le nom d'hote hébergeant wcs
+VHOST = "formulaires.auf.org"
+# nom du formulaire à explorer
+FORM_NAME = "demande-de-bourse-de-doctorat-2010-2011"
+# nom des fichiers à générer (un par formulaire)
+OUTPUT_DIRECTORY = "/srv/www/wcs/%s/%s" % (VHOST, FORM_NAME)
+OUTPUT_DIRECTORY = "/home/cyril/docs"
+
+URL_BASE = "http://%s/backoffice/%s" % (VHOST, FORM_NAME)
+URL_DOWNLOAD = "%s/%s" % (URL_BASE, "%s/download?f=%s")
+#TIME_FORMAT = "%Y-%m-%d %H:%M:%S"
+TIME_FORMAT = "%Y-%m-%d"
+
+
+###
+# Imports
+
+# Quixote se cache
+import sys
+sys.path += ['/usr/share/python-support/python-quixote']
+
+import os, zipfile, time, re, simplejson, shutil
+from wcs import publisher
+from wcs.formdef import FormDef
+from wcs.fields import TitleField, CommentField, TextField, \
+ StringField, ItemField, EmailField, \
+ DateField, FileField, BoolField
+
+from jsontopdf import JsonToPdf
+
+
+###
+# Methodes
+
+# Supprime les accents des caracteres accentues,
+# et remplace les caracteres non alphabetiques par '-'
+def cleanup(string):
+ result = ''
+ avec_accent = u'çÇáàâÁÀÂéèêëÉÈÊËíìîïÍÌÎÏóòôöÓÒÔÖúùûüÚÙÛÜýỳyÿÝỲYŸ'
+ sans_accent = u'cCaaaAAAeeeeEEEEiiiiIIIIooooOOOOuuuuUUUUyyyyYYYY'
+
+ if type(string) is not unicode:
+ string = unicode(string, 'utf-8')
+ wasUnicode = False
+
+ for char in string:
+ i = avec_accent.find (char)
+ if i >= 0:
+ char = sans_accent[i]
+ elif char != '-' and not ('a' <= char.lower() <= 'z'):
+ char = '-'
+ result += char
+
+ if not wasUnicode:
+ result = result.encode('utf-8')
+
+ return result
+
+
+###
+# Main
+
+# Cherche les "noms" des champs
+f = open(FORM_NAME + '_field-names.txt', 'r')
+field_names = dict([l.strip().split(':') for l in f.readlines()])
+f.close()
+
+# Cree un publisher pour app_dir
+pub = publisher.WcsPublisher.create_publisher()
+pub.app_dir = os.path.join(pub.app_dir, VHOST)
+
+# Ouvre la definition du form, et va parcourir les entites
+formdef = FormDef.get_by_urlname(FORM_NAME)
+for entity in formdef.data_class().select():
+ result = { 'num_dossier': entity.id }
+ qfiles = { }
+ jsonFile = ""
+ attachments = []
+ # Parcours des champs de l'entite
+ for field in formdef.fields:
+ field_id = str(field.id)
+
+ # Champs a ignorer
+ if not field_id in entity.data:
+ continue
+ if isinstance(field, TitleField) or isinstance(field, CommentField):
+ continue
+
+ # Recupere le nom et la valeur
+ field_name = field_names.get(field_id, field.label)
+ data = entity.data.get(field_id)
+
+ if isinstance(field, StringField) or isinstance(field, TextField) \
+ or isinstance(field, EmailField):
+ result[field_name] = data
+
+ elif isinstance(field, ItemField):
+ # Suppression des informations non necessaires
+ if field_name in ("o_etablissement", "a_etablissement"):
+ result[field_name + '_orig'] = data
+ matches = re.search ("\((\d+).*\)$", data)
+ if matches:
+ groups = matches.groups ()
+ if len (groups) > 0:
+ data = groups[0]
+ elif field_name.startswith ("pays"):
+ result[field_name + '_orig'] = data
+ matches = re.search ("\(([a-zA-Z]{2}).*\)$", data)
+ if matches:
+ groups = matches.groups ()
+ if len (groups) > 0:
+ data = groups[0]
+ elif field_name == "boursier_auf_type" and data is not None:
+ result[field_name + '_orig'] = data
+ matches = re.search ("\(([a-zA-Z]{2}).*\)$", data)
+ if matches:
+ groups = matches.groups ()
+ if len (groups) > 0:
+ data = groups[0]
+ elif field_name == 'discipline':
+ result[field_name + '_orig'] = data
+ m = re
+ index = data.rfind('(')
+ if index >= 0:
+ end = data.find(')', index+1)
+ data = data[index+1:end]
+ result[field_name] = data
+
+ elif isinstance(field, BoolField):
+ result[field_name] = (data == 'True')
+
+ elif isinstance(field, FileField):
+ extension = data.orig_filename.rpartition('.')[2].lower()
+ result[field_name] = "%s.%s" % (field_name, extension)
+ qfiles[field_name] = data.qfilename
+
+ elif isinstance(field, DateField):
+ data = time.strftime(TIME_FORMAT, entity.data.get(field_id))
+ result[field_name] = data
+
+ else:
+ data = entity.data.get(field_id)
+ print "WARNING: unknown field type '%s' for '%s'" % \
+ (field.__class__.__name__, field.label)
+ raise RuntimeError
+
+ # Prepare le nom de fichier json
+ num_dossier = result['num_dossier']
+ nom = cleanup('-'.join(result['nom'].split()).upper())
+ prenom = cleanup('-'.join(result['prenom'].split()).upper())
+ email = result['email'].replace('@','-').lower()
+
+ baseFile = "%04d-%s-%s-%s" % (num_dossier, nom, prenom, email)
+
+ jsonFile = "%s/json/%s.json" % (OUTPUT_DIRECTORY, baseFile)
+
+ # Ecriture json
+ f = open(jsonFile, 'w')
+ f.write(simplejson.dumps(result, ensure_ascii=False))
+ f.close()
+
+ # Prepare la copie dans le script shell
+ for f in qfiles:
+ currentFileName = "%s/uploads/%s" % (pub.app_dir, qfiles[f])
+ newFileName = "%s/docs/%s_%s" % (OUTPUT_DIRECTORY, baseFile, result[f])
+ attachments.append ((currentFileName, newFileName))
+
+ # Generation du pdf
+ pdfFile = "%s/docs/%s.pdf" % (OUTPUT_DIRECTORY, baseFile)
+ converter = JsonToPdf ()
+ pdf = converter.convertFromFile (jsonFile)
+ f = open (pdfFile, 'w')
+ f.write (pdf.getvalue ())
+ f.close ()
+
+ # Creation de l'archive
+ zipFile = "%s/docs/%s.zip" % (OUTPUT_DIRECTORY, baseFile)
+ archive = zipfile.ZipFile(zipFile, "w", zipfile.ZIP_STORED)
+
+ # PDF
+ archive.write (pdfFile, os.path.basename (pdfFile))
+
+ # Autres fichiers, avec noms reels
+ for (attachment, displayName) in attachments:
+ shutil.copy (attachment, displayName)
+ archive.write (displayName, os.path.basename (displayName))
+
+ archive.close ()
+
--- /dev/null
+#!/bin/sh
+#sudo chmod -R g+rX /var/lib/wcs/
+export DJANGO_SETTINGS_MODULE=settings
+python2.5 wcs2json.py >& wcs2json.log
+tail wcs2json.log
--- /dev/null
+h1 { color:#c60 ; margin:0px; padding:0px; }
+h2 { padding:5px; background-color:#ccc; }
+h3 { margin:0px; padding:0px; }
+p { margin:0px; padding:0px; }
+
+div.spacer { line-height:0.25cm; }
+
+table { width:100%; padding:0px; }
+table.titre { margin:10px 0px 10px 0px; }
+table.data { margin-top:5px; }
+
+td { width:49%; padding:2px; vertical-align:top; }
+table.titre td { padding:0px; }
+
+.bloc { border: solid 1px black; padding:5px; }
+.gutter { width:2%; }
+
+td.w15 { width:15%; padding:0px; vertical-align:top; }
+td.w25 { width:25%; padding:0px; vertical-align:top; }
+td.w30 { width:30%; padding:0px; vertical-align:top; }
+td.w35 { width:35%; padding:0px; vertical-align:top; }
+td.w50 { width:50%; padding:0px; vertical-align:top; }
+
+td.w20 { width:20%; padding:0px; vertical-align:top; }
+td.w80 { width:80%; padding:0px; vertical-align:top; }
+
+td.w40 { width:40%; padding:0px; vertical-align:top; }
+td.w60 { width:60%; padding:0px; vertical-align:top; }
--- /dev/null
+# Django settings for sigmawcs project.
+
+import os.path
+
+from conf import *
+
+ADMINS = (
+ # ('Your Name', 'your_email@domain.com'),
+)
+
+MANAGERS = ADMINS
+
+# Local time zone for this installation. Choices can be found here:
+# http://en.wikipedia.org/wiki/List_of_tz_zones_by_name
+# although not all choices may be available on all operating systems.
+# If running in a Windows environment this must be set to the same as your
+# system time zone.
+TIME_ZONE = 'America/Montreal'
+
+# Language code for this installation. All choices can be found here:
+# http://www.i18nguy.com/unicode/language-identifiers.html
+LANGUAGE_CODE = 'fr-ca'
+
+SITE_ID = 1
+
+# If you set this to False, Django will make some optimizations so as not
+# to load the internationalization machinery.
+USE_I18N = True
+
+# Absolute path to the directory that holds media.
+# Example: "/home/media/media.lawrence.com/"
+MEDIA_ROOT = ''
+
+# URL that handles the media served from MEDIA_ROOT. Make sure to use a
+# trailing slash if there is a path component (optional in other cases).
+# Examples: "http://media.lawrence.com", "http://example.com/media/"
+MEDIA_URL = '/media/'
+STATIC_DOC_ROOT = os.path.join(os.path.dirname(__file__), 'media').replace('\\','/')
+
+# URL prefix for admin media -- CSS, JavaScript and images. Make sure to use a
+# trailing slash.
+# Examples: "http://foo.com/media/", "/media/".
+ADMIN_MEDIA_PREFIX = '/admin/media/'
+
+# Make this unique, and don't share it with anybody.
+SECRET_KEY = 'b+w^)l4s6feh+*r(k2i-%a#a+zhir-xfidz#9bou%(f8ma$'
+
+# List of callables that know how to import templates from various sources.
+TEMPLATE_LOADERS = (
+ 'django.template.loaders.filesystem.load_template_source',
+ 'django.template.loaders.app_directories.load_template_source',
+# 'django.template.loaders.eggs.load_template_source',
+)
+
+MIDDLEWARE_CLASSES = (
+ 'django.middleware.common.CommonMiddleware',
+ 'django.contrib.sessions.middleware.SessionMiddleware',
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
+)
+
+ROOT_URLCONF = 'sigmawcs.urls'
+
+TEMPLATE_DIRS = (
+ # Put strings here, like "/home/html/django_templates" or "C:/www/django/templates".
+ # Always use forward slashes, even on Windows.
+ # Don't forget to use absolute paths, not relative paths.
+ os.path.join(os.path.dirname(__file__), 'templates').replace('\\','/'),
+)
+
+INSTALLED_APPS = (
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.sites',
+ 'wcs',
+)
--- /dev/null
+# -*- encoding: utf-8 -*-
+from datetime import date
+
+from django.db import models
+
+GENRE = (
+ ('M', "Masculin"),
+ ('F', "Féminin"),
+)
+CIVILITE = (
+ ('MR', "Monsieur"),
+ ('MM', "Madame"),
+ ('ME', "Mademoiselle"),
+)
+
+
+class Personne(models.Model):
+ """Informations personnelles de chaque candidat.
+ """
+
+ id = models.AutoField(primary_key=True, db_column='C_PERSONNE')
+ sexe = models.CharField(max_length=3, db_column='Y_SEXE', blank=True, default=None)
+ civilite = models.CharField(max_length=6, db_column='Y_CIVILITE', blank=True, choices=CIVILITE)
+ nom = models.CharField(max_length=100, db_column='L_NOM')
+ nom_index = models.CharField(max_length=100, db_column='L_NOM_INDEX')
+ prenom = models.CharField(max_length=100, db_column='L_PRENOM', default="")
+ prenom_index = models.CharField(max_length=100, db_column='L_PRENOM_INDEX', default="")
+ nom_jeune_fille = models.CharField(max_length=100, db_column='L_NOM_JEUNE_FILLE', default="")
+ nom_jeune_fille_index = models.CharField(max_length=100, db_column='L_NOM_JEUNE_FILLE_INDEX', default="")
+ pays_nationalite = models.CharField(max_length=10, db_column='F_PAYS_NATIONALITE') # foreign
+
+ # naissance
+ ville_naissance = models.CharField(max_length=50, db_column='L_VILLE_NAISSANCE')
+ date_naissance = models.DateField(db_column='D_NAISSANCE')
+ pays_naissance = models.CharField(max_length=10, db_column='F_PAYS_NAISSANCE') # foreign
+
+ # coordonnées
+ pays_residence = models.CharField(max_length=10, db_column='F_PAYS_RESIDENCE') # foreign
+ adresse = models.TextField(db_column='L_ADRESSE')
+ code_postal = models.CharField(max_length=10, db_column='L_CODE_POSTAL', default="")
+ ville = models.CharField(max_length=50, db_column='L_VILLE')
+ region = models.CharField(max_length=50, db_column='L_REGION', default="")
+ tel = models.CharField(max_length=25, db_column='N_TEL', default="")
+ fax = models.CharField(max_length=25, db_column='N_FAX')
+ tel_pro = models.CharField(max_length=25, db_column='N_TEL_PRO', default="")
+ fax_pro = models.CharField(max_length=25, db_column='N_FAX_PRO', default="")
+ email = models.CharField(max_length=100, db_column='L_EMAIL', default="")
+
+ # meta
+ utilisateur_creation = models.IntegerField(db_column='F_UTILISATEUR_CREATION', default=0) #foreign
+ utilisateur_maj = models.IntegerField(null=True, db_column='F_UTILISATEUR_MAJ', blank=True, default=None) # foreign
+ date_creation = models.DateField(auto_now_add=True, db_column='D_CREATION_PERSONNE')
+ date_maj = models.DateField(null=True, db_column='D_MAJ_PERSONNE', blank=True)
+
+ class Meta:
+ db_table = u'GM_PERSONNE'
+
+ def __unicode__(self):
+ return u"%s, %s [%d]" % (self.nom, self.prenom, self.id)
+
+
+class Dossier(models.Model):
+ """Informations générales du dossier de candidature.
+ """
+ REPONSE = (
+ ('sr', "sr"),
+ ('a', "a"),
+ ('r', "r"),
+ )
+
+ id = models.AutoField(primary_key=True, db_column='C_DOSSIER')
+ statut = models.IntegerField(db_column='F_STATUT', default=1) # foreign
+ mobilite = models.IntegerField(unique=True, db_column='F_MOBILITE', default=0) # foreign
+ personne = models.OneToOneField('Personne', db_column='F_PERSONNE')
+ statut_personne = models.IntegerField(db_column='F_STATUT_PERSONNE', default=0) # foreign
+ bureau_rattachement = models.IntegerField(null=True, db_column='F_BUREAU_RATTACHEMENT', blank=True) # foreign Bureau.id_num
+ fonction = models.CharField(max_length=100, db_column='L_FONCTION', default="")
+ intitule_d_diplome = models.CharField(max_length=100, db_column='L_INTITULE_D_DIPLOME', default="")
+ date_d_diplome = models.DateField(db_column='D_D_DIPLOME')
+ nom_etb = models.CharField(max_length=100, db_column='L_NOM_ETB', default="")
+ pays_etb = models.CharField(max_length=10, db_column='F_PAYS_ETB') # foreign
+ niveau = models.IntegerField(db_column='F_NIVEAU', default=0) # foreign
+ programme = models.CharField(max_length=255, db_column='L_PROGRAMME', default="")
+ annee_programme = models.IntegerField(db_column='N_ANNEE_PROGRAMME', default=0)
+ categorie_bourse = models.CharField(max_length=12, db_column='F_CATEGORIE_BOURSE', default="") # foreign
+ annee_bourse = models.IntegerField(db_column='N_ANNEE_BOURSE', default=0)
+
+ # traitement
+ classement_1 = models.IntegerField(null=True, db_column='N_CLASSEMENT_1', blank=True)
+ classement_2 = models.IntegerField(null=True, db_column='N_CLASSEMENT_2', blank=True)
+ classement_3 = models.IntegerField(null=True, db_column='N_CLASSEMENT_3', blank=True)
+ opp_regionale = models.CharField(max_length=9, db_column='L_OPP_REGIONALE')
+ coche_selection = models.BooleanField(db_column='I_COCHE_SELECTION', default=False)
+ reponse_notification = models.CharField(max_length=6, db_column='Y_REPONSE_NOTIFICATION', choices=REPONSE, default='sr')
+ commentaire_notification = models.CharField(max_length=255, db_column='L_COMMENTAIRE_NOTIFICATION')
+ moyenne_academique = models.FloatField(null=True, db_column='N_MOYENNE_ACADEMIQUE', blank=True)
+ autres_criteres = models.CharField(max_length=255, db_column='L_AUTRES_CRITERES')
+ erreurs_recevabilite = models.TextField(db_column='L_ERREURS_RECEVABILITE')
+ repechage = models.BooleanField(db_column='I_REPECHAGE', default=False)
+ rendu_irrecevable = models.BooleanField(db_column='I_RENDU_IRRECEVABLE', default=False)
+
+ # meta
+ etat = models.BooleanField(db_column='I_ETAT', default=False)
+ date_maj = models.CharField(max_length=10, db_column='D_MAJ_DOSSIER', default='0000-00-00')
+ dd_activation = models.CharField(max_length=10, db_column='DD_ACTIVATION', default='0000-00-00')
+ df_activation = models.CharField(max_length=10, db_column='DF_ACTIVATION', default='0000-00-00')
+ utilisateur_creation = models.IntegerField(db_column='F_UTILISATEUR_CREATION', default=0) # foreign
+ utilisateur_maj = models.IntegerField(db_column='F_UTILISATEUR_MAJ') # foreign
+
+ class Meta:
+ db_table = u'GM_DOSSIER'
+
+ def __unicode__(self):
+ return u"%s - appel %d - dossier [%d]" % (self.personne, self.mobilite, self.id)
+
+
+class DossierOrigine(models.Model):
+ """Informations sur le contexte d'origine du candidat.
+ """
+
+ dossier = models.OneToOneField('Dossier', db_column='F_DOSSIER')
+ id = models.AutoField(primary_key=True, db_column='ID_DOSSIER_ORIGINE')
+ pays = models.CharField(max_length=10, db_column='F_PAYS_ORIGINE', default="") # foreign
+ etablissement = models.CharField(max_length=10, db_column='F_ETABLISSEMENT', blank=True) # foreign, PAS id de GDE = PAS C_N_ETABLISSEMENT
+ erreur_recevabilite_etbt_origine = models.BooleanField(db_column='ERREUR_RECEVABILITE_ETBT_ORIGINE', default=False)
+ autre_etb = models.CharField(max_length=100, db_column='L_AUTRE_ETB', default="")
+ adresse = models.TextField(db_column='L_ADRESSE', default="")
+ code_postal = models.CharField(max_length=10, db_column='L_CODE_POSTAL', default="")
+ ville = models.CharField(max_length=50, db_column='L_VILLE', default="")
+ region = models.CharField(max_length=50, db_column='L_REGION', default="")
+ url_site = models.CharField(max_length=150, db_column='L_URL_SITE', default="")
+ inst_civilite = models.CharField(max_length=6, db_column='Y_INST_CIVILITE', choices=CIVILITE, default='MR')
+ inst_nom = models.CharField(max_length=100, db_column='L_INST_NOM', default="s/o")
+ inst_prenom = models.CharField(max_length=100, db_column='L_INST_PRENOM', default="s/o")
+ inst_fonction = models.CharField(max_length=100, db_column='L_INST_FONCTION', default="s/o")
+ sc_civilite = models.CharField(max_length=6, db_column='Y_SC_CIVILITE', choices=CIVILITE, default='MR')
+ sc_nom = models.CharField(max_length=100, db_column='L_SC_NOM', default="")
+ sc_prenom = models.CharField(max_length=100, db_column='L_SC_PRENOM', default="")
+ sc_fonction = models.CharField(max_length=100, db_column='L_SC_FONCTION', default="")
+ sc_faculte = models.CharField(max_length=150, db_column='L_SC_FACULTE', default="")
+ sc_adresse = models.TextField(db_column='L_SC_ADRESSE')
+ sc_code_postal = models.CharField(max_length=10, db_column='L_SC_CODE_POSTAL')
+ sc_ville = models.CharField(max_length=50, db_column='L_SC_VILLE', default="")
+ sc_email = models.CharField(max_length=100, db_column='L_SC_EMAIL', default="")
+ sc_tel_pro = models.CharField(max_length=25, db_column='L_SC_TEL_PRO', default="")
+ sc_fax_pro = models.CharField(max_length=25, db_column='L_SC_FAX_PRO')
+
+ class Meta:
+ db_table = u'GM_DOSSIER_ORIGINE'
+
+ def __unicode__(self):
+ return u"%s - origine [%d]" % (self.dossier.personne, self.id)
+
+
+class DossierAccueil(models.Model):
+ """Informations sur le contexte d'accueil du candidat.
+ """
+
+ dossier = models.OneToOneField('Dossier', db_column='F_DOSSIER', default=0)
+ id = models.AutoField(primary_key=True, db_column='ID_DOSSIER_ACCUEIL')
+ pays = models.CharField(max_length=10, db_column='F_PAYS_ACCUEIL', default="") # foreign
+ etablissement = models.CharField(max_length=10, db_column='F_ETABLISSEMENT', blank=True) # foreign, PAS id de GDE = PAS C_N_ETABLISSEMENT
+ erreur_recevabilite_etbt_accueil = models.BooleanField(db_column='ERREUR_RECEVABILITE_ETBT_ACCUEIL', default=False)
+ autre_etb = models.CharField(max_length=100, db_column='L_AUTRE_ETB', default="")
+ adresse = models.TextField(db_column='L_ADRESSE', default="")
+ code_postal = models.CharField(max_length=10, db_column='L_CODE_POSTAL', default="")
+ ville = models.CharField(max_length=50, db_column='L_VILLE', default="")
+ region = models.CharField(max_length=50, db_column='L_REGION', default="")
+ url_site = models.CharField(max_length=150, db_column='L_URL_SITE', default="")
+ inst_civilite = models.CharField(max_length=6, db_column='Y_INST_CIVILITE', choices=CIVILITE, default='MR')
+ inst_nom = models.CharField(max_length=100, db_column='L_INST_NOM')
+ inst_prenom = models.CharField(max_length=100, db_column='L_INST_PRENOM')
+ inst_fonction = models.CharField(max_length=100, db_column='L_INST_FONCTION')
+ inst_email = models.CharField(max_length=100, db_column='L_INST_EMAIL')
+ inst_tel_pro = models.CharField(max_length=25, db_column='L_INST_TEL_PRO')
+ inst_fax_pro = models.CharField(max_length=25, db_column='L_INST_FAX_PRO')
+ sc_civilite = models.CharField(max_length=6, db_column='Y_SC_CIVILITE', choices=CIVILITE, default='MR')
+ sc_nom = models.CharField(max_length=100, db_column='L_SC_NOM', default="")
+ sc_prenom = models.CharField(max_length=100, db_column='L_SC_PRENOM', default="")
+ sc_fonction = models.CharField(max_length=100, db_column='L_SC_FONCTION', default="")
+ sc_faculte = models.CharField(max_length=150, db_column='L_SC_FACULTE', default="")
+ sc_adresse = models.TextField(db_column='L_SC_ADRESSE')
+ sc_code_postal = models.CharField(max_length=10, db_column='L_SC_CODE_POSTAL')
+ sc_ville = models.CharField(max_length=50, db_column='L_SC_VILLE', default="")
+ sc_email = models.CharField(max_length=100, db_column='L_SC_EMAIL', default="")
+ sc_tel_pro = models.CharField(max_length=25, db_column='L_SC_TEL_PRO', default="")
+ sc_fax_pro = models.CharField(max_length=25, db_column='L_SC_FAX_PRO')
+
+ class Meta:
+ db_table = u'GM_DOSSIER_ACCUEIL'
+
+ def __unicode__(self):
+ return u"%s - accueil [%d]" % (self.dossier.personne, self.id)
+
+
+class DossierMobilite(models.Model):
+ """Informations sur la mobilité demandée par le candidat.
+ """
+ TYPE_THESE = (
+ ('CT', "Co-Tutelle"),
+ ('CD', "Co-Direction"),
+ ('AU', "Autre"),
+ )
+
+ id = models.AutoField(primary_key=True, db_column='ID_DOSSIER_MOBILITE')
+ dossier = models.OneToOneField('Dossier', db_column='F_DOSSIER', default=0)
+ dd_mobilite = models.DateField(db_column='DD_MOBILITE')
+ df_mobilite = models.DateField(db_column='DF_MOBILITE')
+ total_mobilite = models.IntegerField(db_column='N_TOTAL_MOBILITE', default=0, verbose_name="Durée totale mobilité souhaitée")
+ intitule_projet = models.TextField(db_column='L_INTITULE_PROJET')
+ mot_clef1 = models.CharField(max_length=50, db_column='L_MOT_CLEF1', default="")
+ mot_clef2 = models.CharField(max_length=50, db_column='L_MOT_CLEF2', default="")
+ mot_clef3 = models.CharField(max_length=50, db_column='L_MOT_CLEF3', default="")
+ intitule_diplome = models.CharField(max_length=100, db_column='L_INTITULE_DIPLOME')
+ niveau_encours = models.IntegerField(db_column='F_NIVEAU_ENCOURS', default=0) # foreign
+ type_intervention = models.IntegerField(db_column='F_TYPE_INTERVENTION', default=0) # foreign
+ public_vise = models.IntegerField(db_column='F_PUBLIC_VISE', default=0) # foreign
+ autres_publics = models.CharField(max_length=50, db_column='L_AUTRES_PUBLICS')
+ discipline = models.CharField(max_length=10, db_column='F_DISCIPLINE', default=0) # foreign
+ sous_discipline = models.CharField(max_length=50, db_column='L_SOUS_DISCIPLINE', default="")
+ alt_mois_accueil = models.IntegerField(db_column='N_ALT_MOIS_ACCUEIL', default=0)
+ alt_mois_origine = models.IntegerField(db_column='N_ALT_MOIS_ORIGINE', default=0)
+ mobilite_accueil = models.BooleanField(db_column='I_MOBILITE_ACCUEIL', default=False)
+ intitule_diplome_demande = models.CharField(max_length=100, db_column='L_INTITULE_DIPLOME_DEMANDE', default="")
+ niveau_demande = models.IntegerField(db_column='F_NIVEAU_DEMANDE', default=0) # foreign
+ obtention_prevu = models.CharField(max_length=10, db_column='D_OBTENTION_PREVU', default='0000-00-00')
+ date_inscription_these = models.DateField(db_column='D_INSCRIPTION_THESE')
+ pays_soutenance = models.CharField(max_length=10, db_column='F_PAYS_SOUTENANCE', default=0) # foreign
+ date_soutenance_these = models.DateField(db_column='D_SOUTENANCE_THESE')
+ type_these = models.CharField(max_length=6, db_column='Y_TYPE_THESE', choices=TYPE_THESE, default='CT')
+ type_these_autre = models.CharField(max_length=255, db_column='L_TYPE_THESE_AUTRE')
+ dir_acc_civilite = models.CharField(max_length=6, db_column='Y_DIR_ACC_CIVILITE', choices=CIVILITE, default='MR')
+ dir_ori_civilite = models.CharField(max_length=6, db_column='Y_DIR_ORI_CIVILITE', choices=CIVILITE, default='MR')
+ dir_acc_nom = models.CharField(max_length=100, db_column='L_DIR_ACC_NOM', default="")
+ dir_acc_prenom = models.CharField(max_length=100, db_column='L_DIR_ACC_PRENOM', default="")
+ dir_ori_nom = models.CharField(max_length=100, db_column='L_DIR_ORI_NOM', default="")
+ dir_ori_prenom = models.CharField(max_length=100, db_column='L_DIR_ORI_PRENOM', default="")
+
+ class Meta:
+ db_table = u'GM_DOSSIER_MOBILITE'
+
+ def __unicode__(self):
+ return u"%s - mobilite [%d]" % (self.dossier.personne, self.id)
+
+
+class DossierPieces(models.Model):
+ """Informations sur les pièces administratives jointes au dossier de candidature.
+ """
+
+ id = models.AutoField(primary_key=True, db_column='ID_DOSSIER_PIECE')
+ dossier = models.OneToOneField('Dossier', db_column='F_DOSSIER', default=0)
+ presente = models.BooleanField(db_column='I_PIECE', default=False)
+ piece = models.IntegerField(db_column='F_PIECE', default=0) # foreign
+ conforme = models.BooleanField(db_column='I_CONFORME', default=False)
+ commentaire = models.CharField(max_length=255, db_column='L_PIECE_COMMENTAIRE', default="")
+
+ class Meta:
+ db_table = u'GM_DOSSIER_PIECES'
+
+ def __unicode__(self):
+ return u"%s - piece %d [%d]" % (self.dossier.personne, self.piece, self.id)
+
+class Mobilite(object): # Appel
+ id = 0 #c_mobilite = models.IntegerField(primary_key=True, db_column='C_MOBILITE')
+# id_mobilite = models.IntegerField(db_column='ID_MOBILITE')
+ code_budgetaire = '' #f_projet = models.CharField(max_length=36, db_column='F_PROJET')
+ wcs_form_name = ''
+# f_commutateur = models.IntegerField(db_column='F_COMMUTATEUR')
+# f_id_categorie_bourse = models.IntegerField(db_column='F_ID_CATEGORIE_BOURSE')
+# f_statut_mobilite = models.IntegerField(db_column='F_STATUT_MOBILITE')
+ nom = models.CharField(max_length=150, db_column='L_MOBILITE', blank=True)
+# i_coda = models.IntegerField(db_column='I_CODA')
+# i_ao = models.IntegerField(db_column='I_AO')
+# y_periode_mobilite = models.CharField(max_length=30, db_column='Y_PERIODE_MOBILITE')
+# y_selection = models.CharField(max_length=15, db_column='Y_SELECTION')
+# n_validite_diplome = models.IntegerField(db_column='N_VALIDITE_DIPLOME')
+# i_nb_ex = models.IntegerField(db_column='I_NB_EX')
+ dd_mobilite = models.DateField(db_column='DD_MOBILITE')
+ df_mobilite = models.DateField(db_column='DF_MOBILITE')
+# y_except_expertise = models.CharField(max_length=3, db_column='Y_EXCEPT_EXPERTISE', blank=True)
+# y_except_bareme = models.CharField(max_length=3, db_column='Y_EXCEPT_BAREME', blank=True)
+# n_except_min_mobilite = models.IntegerField(null=True, db_column='N_EXCEPT_MIN_MOBILITE', blank=True)
+# n_except_total_mobilite = models.IntegerField(null=True, db_column='N_EXCEPT_TOTAL_MOBILITE', blank=True)
+# m_except_inter_s_b = models.FloatField(null=True, db_column='M_EXCEPT_INTER_S_B', blank=True)
+# m_except_inter_s_f = models.FloatField(null=True, db_column='M_EXCEPT_INTER_S_F', blank=True)
+# m_except_inter_n_b = models.FloatField(null=True, db_column='M_EXCEPT_INTER_N_B', blank=True)
+# m_except_inter_n_f = models.FloatField(null=True, db_column='M_EXCEPT_INTER_N_F', blank=True)
+# m_except_intra_s_b = models.FloatField(null=True, db_column='M_EXCEPT_INTRA_S_B', blank=True)
+# m_except_intra_s_f = models.FloatField(null=True, db_column='M_EXCEPT_INTRA_S_F', blank=True)
+# m_except_intra_n_b = models.FloatField(null=True, db_column='M_EXCEPT_INTRA_N_B', blank=True)
+# m_except_intra_n_f = models.FloatField(null=True, db_column='M_EXCEPT_INTRA_N_F', blank=True)
+# i_mobilite_active = models.IntegerField(db_column='I_MOBILITE_ACTIVE')
+ dd_activation_mobilite = models.DateField(db_column='DD_ACTIVATION_MOBILITE')
+ df_activation_mobilite = models.DateField(null=True, db_column='DF_ACTIVATION_MOBILITE', blank=True)
+# i_accueil_origine = models.IntegerField(db_column='I_ACCUEIL_ORIGINE')
+# i_institut_auf = models.IntegerField(db_column='I_INSTITUT_AUF')
+# i_candidature_en_ligne = models.IntegerField(db_column='I_CANDIDATURE_EN_LIGNE')
+# class Meta:
+# db_table = u'GM_MOBILITES'
+
+ def __init__(self, id, code_budgetaire, wcs_form_name):
+ self.id = id
+ self.code_budgetaire = code_budgetaire
+ self.wcs_form_name = wcs_form_name
+
+class MobilitePiece(models.Model):
+ mobilite = models.IntegerField(primary_key=True, db_column='F_MOBILITE') # Field name made lowercase.
+ piece = models.IntegerField(primary_key=True, db_column='F_PIECE') # Field name made lowercase.
+ commentaire = models.CharField(max_length=765, db_column='L_COMMENTAIRE', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_PIECE_MOBILITE'
+
+### REFERENCES
+class Etablissement(models.Model):
+ id = models.CharField(max_length=10, primary_key=True, db_column='C_ETABLISSEMENT')
+ id_gde = models.IntegerField(null=True, db_column='C_N_ETABLISSEMENT', blank=True) # unique
+ cgrm = models.CharField(max_length=12, db_column='C_CGRM') # unique
+ pays = models.CharField(max_length=10, db_column='F_PAYS') # foreign
+ implantation_sigma = models.ForeignKey('Implantation', db_column='F_IMPLANTATION_SIGMA')
+ implantation_inst = models.CharField(max_length=10, db_column='F_IMPLANTATION_INST') # foreign
+ zone_etablissement = models.CharField(max_length=4, db_column='Y_ZONE_ETABLISSEMENT')
+ nom = models.CharField(max_length=200, db_column='L_ETABLISSEMENT')
+ statut = models.CharField(max_length=15, db_column='Y_STATUT_ETABLISSEMENT', default="")
+ actif = models.IntegerField(null=True, db_column='I_ETABLISSEMENT_ACTIF', blank=True) # Boolean
+ institut = models.IntegerField(db_column='I_INSTITUT') # Boolean
+ dd_activation = models.DateField(null=True, db_column='DD_ACTIVATION_ETABLISSEMENT', blank=True)
+ df_activation = models.DateField(null=True, db_column='DF_ACTIVATION_ETABLISSEMENT', blank=True)
+ bureau_geographique = models.CharField(max_length=12, db_column='F_BUREAU_GEOGRAPHIQUE') # foreign
+ bureau_gestion = models.CharField(max_length=12, db_column='F_BUREAU_GESTION', blank=True) # foreign
+ president_universite = models.CharField(max_length=255, db_column='L_PRESIDENT_UNIVERSITE', blank=True)
+ sexe_responsable_etablissement = models.CharField(max_length=1, db_column='I_SEXE_RESPONSABLE_ETABLISSEMENT')
+ nom_responsable_etablissement = models.CharField(max_length=100, db_column='L_NOM_RESPONSABLE_ETABLISSEMENT')
+ prenom_responsable_etablissement = models.CharField(max_length=100, db_column='L_PRENOM_RESPONSABLE_ETABLISSEMENT')
+ adresse = models.CharField(max_length=255, db_column='L_ADRESSE', blank=True)
+ code_postal = models.CharField(max_length=12, db_column='L_CODE_POSTAL', blank=True)
+ cedex = models.CharField(max_length=12, db_column='L_CEDEX', blank=True)
+ ville = models.CharField(max_length=64, db_column='L_VILLE', blank=True)
+ province = models.CharField(max_length=64, db_column='L_PROVINCE', blank=True)
+ tel = models.CharField(max_length=32, db_column='N_TEL', blank=True)
+ fax = models.CharField(max_length=32, db_column='N_FAX', blank=True)
+
+ class Meta:
+ db_table = u'RE_ETABLISSEMENT'
+
+ def __unicode__(self):
+ return u"%s [%s]" % (self.nom, unicode(self.id_gde))
+
+
+class Implantation(models.Model):
+ id_implantus = models.IntegerField(unique=True, db_column='C_N_IMPLANTATION')
+ id = models.CharField(max_length=10, primary_key=True, db_column='C_IMPLANTATION')
+ bureau = models.ForeignKey('Bureau', db_column='F_BUREAU')
+ nom = models.CharField(max_length=255, db_column='L_IMPLANTATION')
+ nom_court = models.CharField(max_length=20, db_column='L_IMPLANTATION_COURT')
+ actif = models.IntegerField(null=True, db_column='I_IMPLANTATION_ACTIVE', blank=True) # Boolean
+ dd_activation = models.DateField(null=True, db_column='DD_ACTIVATION_IMPLANTATION', blank=True)
+ df_activation = models.DateField(null=True, db_column='DF_ACTIVATION_IMPLANTATION', blank=True)
+
+ class Meta:
+ db_table = u'RE_IMPLANTATION'
+
+ def __unicode__(self):
+ return u"%s [%s]" % (self.nom, self.id)
+
+
+class Bureau(models.Model):
+ id_num = models.IntegerField(unique=True, db_column='C_N_BUREAU')
+ id = models.CharField(max_length=12, primary_key=True, db_column='C_BUREAU')
+ nom = models.CharField(max_length=100, db_column='L_BUREAU')
+ type = models.CharField(max_length=20, db_column='Y_BUREAU')
+ actif = models.IntegerField(null=True, db_column='I_BUREAU_ACTIF', blank=True) # Boolean
+ dd_activation = models.DateField(null=True, db_column='DD_ACTIVATION', blank=True)
+ df_activation = models.DateField(null=True, db_column='DF_ACTIVATION', blank=True)
+ pays = models.CharField(max_length=10, db_column='F_PAYS_GEOGRAPHIQUE', blank=True) # foreign
+ adresse1 = models.CharField(max_length=128, db_column='L_LIGNE_ADRESSE1', blank=True)
+ adresse2 = models.CharField(max_length=128, db_column='L_LIGNE_ADRESSE2', blank=True)
+ adresse3 = models.CharField(max_length=128, db_column='L_LIGNE_ADRESSE3', blank=True)
+ code_postal = models.CharField(max_length=12, db_column='L_CODE_POSTAL', blank=True)
+ ville = models.CharField(max_length=64, db_column='L_VILLE', blank=True)
+ province = models.CharField(max_length=64, db_column='L_PROVINCE', blank=True)
+ tel = models.CharField(max_length=32, db_column='N_TEL', blank=True)
+ tel2 = models.CharField(max_length=32, db_column='N_TEL2', blank=True)
+ fax = models.CharField(max_length=32, db_column='N_FAX', blank=True)
+
+ class Meta:
+ db_table = u'RE_BUREAU'
+
+ def __unicode__(self):
+ return u"%s - %s" % (self.id, self.nom)
--- /dev/null
+# This is an auto-generated Django model module.
+# You'll have to do the following manually to clean this up:
+# * Rearrange models' order
+# * Make sure each model has one field with primary_key=True
+# Feel free to rename the models, but don't rename db_table values or field names.
+#
+# Also note: You'll have to insert the output of 'django-admin.py sqlcustom [appname]'
+# into your database.
+
+from django.db import models
+
+class GmBlocsChamps(models.Model):
+ c_bloc = models.IntegerField(primary_key=True, db_column='C_BLOC') # Field name made lowercase.
+ l_bloc = models.CharField(max_length=300, db_column='L_BLOC') # Field name made lowercase.
+ i_bloc_actif = models.IntegerField(db_column='I_BLOC_ACTIF') # Field name made lowercase.
+ dd_activation = models.DateField(db_column='DD_ACTIVATION') # Field name made lowercase.
+ df_activation = models.DateField(db_column='DF_ACTIVATION') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_BLOCS_CHAMPS'
+
+class GmCategoriesBlocs(models.Model):
+ c_categorie_bloc = models.IntegerField(primary_key=True, db_column='C_CATEGORIE_BLOC') # Field name made lowercase.
+ c_bloc = models.IntegerField(unique=True, db_column='C_BLOC') # Field name made lowercase.
+ c_categorie_bourse = models.CharField(unique=True, max_length=36, db_column='C_CATEGORIE_BOURSE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_CATEGORIES_BLOCS'
+
+class GmChamps(models.Model):
+ c_champ = models.IntegerField(primary_key=True, db_column='C_CHAMP') # Field name made lowercase.
+ l_bdd_table = models.CharField(max_length=60, db_column='L_BDD_TABLE') # Field name made lowercase.
+ l_bdd_champ = models.CharField(max_length=120, db_column='L_BDD_CHAMP') # Field name made lowercase.
+ l_champ = models.CharField(max_length=450, db_column='L_CHAMP') # Field name made lowercase.
+ f_bloc = models.IntegerField(db_column='F_BLOC') # Field name made lowercase.
+ m_version = models.FloatField(db_column='M_VERSION') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_CHAMPS'
+
+class GmChampMobilite(models.Model):
+ f_champ = models.IntegerField(primary_key=True, db_column='F_CHAMP') # Field name made lowercase.
+ f_mobilite = models.CharField(max_length=36, primary_key=True, db_column='F_MOBILITE') # Field name made lowercase.
+ l_commentaire = models.TextField(db_column='L_COMMENTAIRE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_CHAMP_MOBILITE'
+
+class GmCommutateur(models.Model):
+ c_commutateur = models.IntegerField(primary_key=True, db_column='C_COMMUTATEUR') # Field name made lowercase.
+ i_actif = models.IntegerField(db_column='I_ACTIF') # Field name made lowercase.
+ y_etat = models.CharField(max_length=18, db_column='Y_ETAT') # Field name made lowercase.
+ dd_activation = models.DateField(db_column='DD_ACTIVATION') # Field name made lowercase.
+ df_activation = models.DateField(db_column='DF_ACTIVATION') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_COMMUTATEUR'
+
+class GmConvention(models.Model):
+ c_convention_technique = models.IntegerField(primary_key=True, db_column='C_CONVENTION_TECHNIQUE') # Field name made lowercase.
+ f_premier_etablissement = models.CharField(max_length=30, db_column='F_PREMIER_ETABLISSEMENT') # Field name made lowercase.
+ f_second_etablissement = models.CharField(max_length=30, db_column='F_SECOND_ETABLISSEMENT') # Field name made lowercase.
+ c_convention = models.CharField(max_length=36, db_column='C_CONVENTION') # Field name made lowercase.
+ i_convention_active = models.IntegerField(db_column='I_CONVENTION_ACTIVE') # Field name made lowercase.
+ dd_activation_convention = models.DateField(db_column='DD_ACTIVATION_CONVENTION') # Field name made lowercase.
+ df_activation_convention = models.DateField(null=True, db_column='DF_ACTIVATION_CONVENTION', blank=True) # Field name made lowercase.
+ l_commentaire = models.CharField(max_length=765, db_column='L_COMMENTAIRE') # Field name made lowercase.
+ l_collection = models.CharField(max_length=60, db_column='L_COLLECTION') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_CONVENTION'
+
+class GmCourriers(models.Model):
+ c_courrier = models.IntegerField(primary_key=True, db_column='C_COURRIER') # Field name made lowercase.
+ l_libelle = models.CharField(max_length=765, db_column='L_LIBELLE', blank=True) # Field name made lowercase.
+ l_modele = models.CharField(max_length=765, db_column='L_MODELE', blank=True) # Field name made lowercase.
+ f_mobilite = models.IntegerField(db_column='F_MOBILITE') # Field name made lowercase.
+ f_courrier_reference = models.IntegerField(db_column='F_COURRIER_REFERENCE') # Field name made lowercase.
+ d_template = models.DateTimeField(db_column='D_TEMPLATE') # Field name made lowercase.
+ d_modele = models.DateTimeField(db_column='D_MODELE') # Field name made lowercase.
+ l_nom_template = models.CharField(max_length=150, db_column='L_NOM_TEMPLATE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_COURRIERS'
+
+class GmCourriersReferences(models.Model):
+ c_courrier_reference = models.IntegerField(primary_key=True, db_column='C_COURRIER_REFERENCE') # Field name made lowercase.
+ l_libelle = models.CharField(max_length=765, db_column='L_LIBELLE', blank=True) # Field name made lowercase.
+ l_modele = models.CharField(max_length=765, db_column='L_MODELE', blank=True) # Field name made lowercase.
+ f_type_courrier = models.IntegerField(db_column='F_TYPE_COURRIER') # Field name made lowercase.
+ d_template = models.DateTimeField(db_column='D_TEMPLATE') # Field name made lowercase.
+ d_modele = models.DateTimeField(db_column='D_MODELE') # Field name made lowercase.
+ l_nom_template = models.CharField(max_length=150, db_column='L_NOM_TEMPLATE') # Field name made lowercase.
+ f_categorie_bourse = models.CharField(max_length=36, db_column='F_CATEGORIE_BOURSE') # Field name made lowercase.
+ i_generique = models.IntegerField(db_column='I_GENERIQUE') # Field name made lowercase.
+ i_accessible = models.IntegerField(db_column='I_ACCESSIBLE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_COURRIERS_REFERENCES'
+
+class GmCritereRecevabilite(models.Model):
+ c_critere_recevabilite = models.IntegerField(primary_key=True, db_column='C_CRITERE_RECEVABILITE') # Field name made lowercase.
+ f_mobilite = models.IntegerField(unique=True, db_column='F_MOBILITE') # Field name made lowercase.
+ f_niveau = models.IntegerField(unique=True, db_column='F_NIVEAU') # Field name made lowercase.
+ n_age_max = models.IntegerField(db_column='N_AGE_MAX') # Field name made lowercase.
+ i_flux_nord = models.IntegerField(db_column='I_FLUX_NORD') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_CRITERE_RECEVABILITE'
+
+
+class GmDossierExpert(models.Model):
+ c_dossier_expert = models.IntegerField(primary_key=True, db_column='C_DOSSIER_EXPERT') # Field name made lowercase.
+ f_dossier = models.IntegerField(db_column='F_DOSSIER') # Field name made lowercase.
+ f_expert = models.IntegerField(db_column='F_EXPERT') # Field name made lowercase.
+ n_numero = models.IntegerField(db_column='N_NUMERO') # Field name made lowercase.
+ n_note_1 = models.FloatField(null=True, db_column='N_NOTE_1', blank=True) # Field name made lowercase.
+ n_note_2 = models.FloatField(null=True, db_column='N_NOTE_2', blank=True) # Field name made lowercase.
+ n_note_3 = models.FloatField(null=True, db_column='N_NOTE_3', blank=True) # Field name made lowercase.
+ n_note_4 = models.FloatField(null=True, db_column='N_NOTE_4', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_DOSSIER_EXPERT'
+
+class GmExpert(models.Model):
+ c_expert = models.IntegerField(primary_key=True, db_column='C_EXPERT') # Field name made lowercase.
+ f_utilisateur_creation = models.IntegerField(null=True, db_column='F_UTILISATEUR_CREATION', blank=True) # Field name made lowercase.
+ f_utilisateur_maj = models.IntegerField(null=True, db_column='F_UTILISATEUR_MAJ', blank=True) # Field name made lowercase.
+ f_bureau_gestion = models.IntegerField(db_column='F_BUREAU_GESTION') # Field name made lowercase.
+ dd_activation = models.DateField(null=True, db_column='DD_ACTIVATION', blank=True) # Field name made lowercase.
+ df_activation = models.DateField(null=True, db_column='DF_ACTIVATION', blank=True) # Field name made lowercase.
+ f_pays_nationalite = models.CharField(max_length=30, db_column='F_PAYS_NATIONALITE') # Field name made lowercase.
+ y_civilite = models.CharField(max_length=6, db_column='Y_CIVILITE', blank=True) # Field name made lowercase.
+ l_nom = models.CharField(max_length=300, db_column='L_NOM', blank=True) # Field name made lowercase.
+ l_prenom = models.CharField(max_length=300, db_column='L_PRENOM', blank=True) # Field name made lowercase.
+ l_nom_index = models.CharField(max_length=300, db_column='L_NOM_INDEX', blank=True) # Field name made lowercase.
+ y_sexe = models.CharField(max_length=3, db_column='Y_SEXE', blank=True) # Field name made lowercase.
+ f_etablissement = models.CharField(max_length=30, db_column='F_ETABLISSEMENT', blank=True) # Field name made lowercase.
+ l_autre_etablissement = models.CharField(max_length=300, db_column='L_AUTRE_ETABLISSEMENT', blank=True) # Field name made lowercase.
+ f_pays_autre_etablissement = models.CharField(max_length=30, db_column='F_PAYS_AUTRE_ETABLISSEMENT') # Field name made lowercase.
+ l_titre_et_fonction = models.CharField(max_length=300, db_column='L_TITRE_ET_FONCTION', blank=True) # Field name made lowercase.
+ l_adresse = models.TextField(db_column='L_ADRESSE', blank=True) # Field name made lowercase.
+ l_code_postal = models.CharField(max_length=30, db_column='L_CODE_POSTAL', blank=True) # Field name made lowercase.
+ l_ville = models.CharField(max_length=150, db_column='L_VILLE', blank=True) # Field name made lowercase.
+ l_region = models.CharField(max_length=150, db_column='L_REGION', blank=True) # Field name made lowercase.
+ f_pays_correspondance = models.CharField(max_length=30, db_column='F_PAYS_CORRESPONDANCE') # Field name made lowercase.
+ n_tel = models.CharField(max_length=75, db_column='N_TEL', blank=True) # Field name made lowercase.
+ n_fax = models.CharField(max_length=75, db_column='N_FAX', blank=True) # Field name made lowercase.
+ n_tel_pro = models.CharField(max_length=75, db_column='N_TEL_PRO', blank=True) # Field name made lowercase.
+ n_fax_pro = models.CharField(max_length=75, db_column='N_FAX_PRO', blank=True) # Field name made lowercase.
+ l_email = models.CharField(max_length=300, db_column='L_EMAIL', blank=True) # Field name made lowercase.
+ l_commentaire = models.TextField(db_column='L_COMMENTAIRE', blank=True) # Field name made lowercase.
+ i_actif = models.IntegerField(null=True, db_column='I_ACTIF', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_EXPERT'
+
+class GmExpertsDisciplines(models.Model):
+ c_expert_disc = models.IntegerField(primary_key=True, db_column='C_EXPERT_DISC') # Field name made lowercase.
+ f_expert = models.IntegerField(null=True, db_column='F_EXPERT', blank=True) # Field name made lowercase.
+ f_discipline = models.CharField(max_length=30, db_column='F_DISCIPLINE') # Field name made lowercase.
+ l_sous_discipline = models.CharField(max_length=300, db_column='L_SOUS_DISCIPLINE', blank=True) # Field name made lowercase.
+ n_ordre_discipline = models.IntegerField(db_column='N_ORDRE_DISCIPLINE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_EXPERTS_DISCIPLINES'
+
+class GmHabilitations(models.Model):
+ c_habilitation = models.IntegerField(primary_key=True, db_column='C_HABILITATION') # Field name made lowercase.
+ f_matricule = models.IntegerField(db_column='F_MATRICULE') # Field name made lowercase.
+ l_habilitation = models.CharField(max_length=45, db_column='L_HABILITATION') # Field name made lowercase.
+ dd_activ = models.DateField(null=True, db_column='DD_ACTIV', blank=True) # Field name made lowercase.
+ df_activ = models.DateField(null=True, db_column='DF_ACTIV', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_HABILITATIONS'
+
+class GmInterventions(models.Model):
+ c_intervention = models.IntegerField(primary_key=True, db_column='C_INTERVENTION') # Field name made lowercase.
+ l_intervention = models.CharField(max_length=300, db_column='L_INTERVENTION') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_INTERVENTIONS'
+
+class GmMobiliteRegionStatut(models.Model):
+ c_statut_mobilite_bsc = models.IntegerField(primary_key=True, db_column='C_STATUT_MOBILITE_BSC') # Field name made lowercase.
+ f_statut_bureau = models.IntegerField(unique=True, db_column='F_STATUT_BUREAU') # Field name made lowercase.
+ f_statut_mobilite = models.IntegerField(unique=True, db_column='F_STATUT_MOBILITE') # Field name made lowercase.
+ f_statut_bsc = models.IntegerField(db_column='F_STATUT_BSC') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_MOBILITE_REGION_STATUT'
+
+class GmNiveauxEtudes(models.Model):
+ c_niveau = models.IntegerField(primary_key=True, db_column='C_NIVEAU') # Field name made lowercase.
+ l_intitule_niveau = models.CharField(max_length=90, db_column='L_INTITULE_NIVEAU') # Field name made lowercase.
+ l_niveau = models.CharField(max_length=150, db_column='L_NIVEAU') # Field name made lowercase.
+ l_cycle = models.CharField(max_length=150, db_column='L_CYCLE', blank=True) # Field name made lowercase.
+ i_niveau_actif = models.IntegerField(null=True, db_column='I_NIVEAU_ACTIF', blank=True) # Field name made lowercase.
+ dd_activation = models.DateField(db_column='DD_ACTIVATION') # Field name made lowercase.
+ df_activation = models.DateField(null=True, db_column='DF_ACTIVATION', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_NIVEAUX_ETUDES'
+
+class GmPieceAdministrative(models.Model):
+ c_piece = models.IntegerField(primary_key=True, db_column='C_PIECE') # Field name made lowercase.
+ l_piece = models.CharField(max_length=765, db_column='L_PIECE') # Field name made lowercase.
+ i_piece_active = models.IntegerField(db_column='I_PIECE_ACTIVE') # Field name made lowercase.
+ dd_activation_piece = models.DateField(db_column='DD_ACTIVATION_PIECE') # Field name made lowercase.
+ df_activation_piece = models.DateField(null=True, db_column='DF_ACTIVATION_PIECE', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_PIECE_ADMINISTRATIVE'
+
+class GmPublicsVises(models.Model):
+ c_public = models.IntegerField(primary_key=True, db_column='C_PUBLIC') # Field name made lowercase.
+ l_public = models.CharField(max_length=300, db_column='L_PUBLIC') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_PUBLICS_VISES'
+
+class GmStatutDossier(models.Model):
+ y_niveau_traitement = models.CharField(max_length=3, db_column='Y_NIVEAU_TRAITEMENT') # Field name made lowercase.
+ l_niveau_traitement = models.CharField(max_length=300, db_column='L_NIVEAU_TRAITEMENT') # Field name made lowercase.
+ l_droit = models.CharField(max_length=60, db_column='L_DROIT') # Field name made lowercase.
+ c_statut = models.IntegerField(primary_key=True, db_column='C_STATUT') # Field name made lowercase.
+ l_libelle_statut = models.CharField(max_length=300, db_column='L_LIBELLE_STATUT') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_STATUT_DOSSIER'
+
+class GmStatutMobilite(models.Model):
+ c_statut_mobilite = models.IntegerField(primary_key=True, db_column='C_STATUT_MOBILITE') # Field name made lowercase.
+ l_statut_mobilite = models.CharField(max_length=90, db_column='L_STATUT_MOBILITE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_STATUT_MOBILITE'
+
+class GmStatutPersonne(models.Model):
+ c_statut_personne = models.IntegerField(primary_key=True, db_column='C_STATUT_PERSONNE') # Field name made lowercase.
+ l_statut_personne = models.CharField(max_length=150, db_column='L_STATUT_PERSONNE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_STATUT_PERSONNE'
+
+class GmTypeCourrier(models.Model):
+ c_type_courrier = models.IntegerField(primary_key=True, db_column='C_TYPE_COURRIER') # Field name made lowercase.
+ l_type_courrier = models.CharField(max_length=150, db_column='L_TYPE_COURRIER') # Field name made lowercase.
+ l_nom_requete = models.CharField(max_length=150, db_column='L_NOM_REQUETE') # Field name made lowercase.
+ class Meta:
+ db_table = u'GM_TYPE_COURRIER'
+
+class ReCategorieBourse(models.Model):
+ c_categorie_bourse = models.CharField(max_length=36, db_column='C_CATEGORIE_BOURSE') # Field name made lowercase.
+ id_categorie_bourse = models.IntegerField(primary_key=True, db_column='ID_CATEGORIE_BOURSE') # Field name made lowercase.
+ l_categorie_bourse = models.CharField(max_length=300, db_column='L_CATEGORIE_BOURSE') # Field name made lowercase.
+ i_bourse_active = models.IntegerField(db_column='I_BOURSE_ACTIVE') # Field name made lowercase.
+ dd_activation_bourse = models.DateField(db_column='DD_ACTIVATION_BOURSE') # Field name made lowercase.
+ df_activation_bourse = models.DateField(null=True, db_column='DF_ACTIVATION_BOURSE', blank=True) # Field name made lowercase.
+ y_expertise = models.CharField(max_length=3, db_column='Y_EXPERTISE') # Field name made lowercase.
+ y_bareme = models.CharField(max_length=3, db_column='Y_BAREME') # Field name made lowercase.
+ n_min_mobilite = models.IntegerField(db_column='N_MIN_MOBILITE') # Field name made lowercase.
+ n_total_mobilite = models.IntegerField(db_column='N_TOTAL_MOBILITE') # Field name made lowercase.
+ i_exception = models.IntegerField(db_column='I_EXCEPTION') # Field name made lowercase.
+ i_statut_etudiant = models.IntegerField(db_column='I_STATUT_ETUDIANT') # Field name made lowercase.
+ i_origine = models.IntegerField(db_column='I_ORIGINE') # Field name made lowercase.
+ i_accueil = models.IntegerField(db_column='I_ACCUEIL') # Field name made lowercase.
+ i_age = models.IntegerField(db_column='I_AGE') # Field name made lowercase.
+ i_validite_exigee = models.IntegerField(db_column='I_VALIDITE_EXIGEE') # Field name made lowercase.
+ i_rnvt = models.IntegerField(db_column='I_RNVT') # Field name made lowercase.
+ n_rnvt = models.IntegerField(db_column='N_RNVT') # Field name made lowercase.
+ i_alternance = models.IntegerField(db_column='I_ALTERNANCE') # Field name made lowercase.
+ n_mois_min = models.IntegerField(db_column='N_MOIS_MIN') # Field name made lowercase.
+ m_inter_s_b = models.FloatField(db_column='M_INTER_S_B') # Field name made lowercase.
+ m_inter_s_f = models.FloatField(db_column='M_INTER_S_F') # Field name made lowercase.
+ m_inter_n_b = models.FloatField(db_column='M_INTER_N_B') # Field name made lowercase.
+ m_inter_n_f = models.FloatField(db_column='M_INTER_N_F') # Field name made lowercase.
+ m_intra_s_b = models.FloatField(db_column='M_INTRA_S_B') # Field name made lowercase.
+ m_intra_s_f = models.FloatField(db_column='M_INTRA_S_F') # Field name made lowercase.
+ m_intra_n_b = models.FloatField(db_column='M_INTRA_N_B') # Field name made lowercase.
+ m_intra_n_f = models.FloatField(db_column='M_INTRA_N_F') # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_CATEGORIE_BOURSE'
+
+class ReDiscipline(models.Model):
+ c_discipline = models.CharField(max_length=30, primary_key=True, db_column='C_DISCIPLINE') # Field name made lowercase.
+ lc_discipline = models.CharField(max_length=765, db_column='LC_DISCIPLINE') # Field name made lowercase.
+ ll_discipline = models.CharField(max_length=765, db_column='LL_DISCIPLINE') # Field name made lowercase.
+ i_discipline_active = models.IntegerField(db_column='I_DISCIPLINE_ACTIVE') # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_DISCIPLINE'
+
+class RePays(models.Model):
+ c_pays = models.CharField(max_length=30, primary_key=True, db_column='C_PAYS') # Field name made lowercase.
+ f_bureau = models.CharField(max_length=36, db_column='F_BUREAU') # Field name made lowercase.
+ l_nom_pays = models.CharField(max_length=300, db_column='L_NOM_PAYS') # Field name made lowercase.
+ y_zone = models.CharField(max_length=12, db_column='Y_ZONE') # Field name made lowercase.
+ l_nationalite = models.CharField(max_length=300, db_column='L_NATIONALITE') # Field name made lowercase.
+ i_pays_actif = models.IntegerField(db_column='I_PAYS_ACTIF') # Field name made lowercase.
+ dd_activation_pays = models.DateField(db_column='DD_ACTIVATION_PAYS') # Field name made lowercase.
+ df_activation_pays = models.DateField(db_column='DF_ACTIVATION_PAYS') # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_PAYS'
+
+class ReProgramme(models.Model):
+ c_programme = models.CharField(max_length=36, primary_key=True, db_column='C_PROGRAMME') # Field name made lowercase.
+ l_programme = models.CharField(max_length=765, db_column='L_PROGRAMME') # Field name made lowercase.
+ i_programme_actif = models.IntegerField(null=True, db_column='I_PROGRAMME_ACTIF', blank=True) # Field name made lowercase.
+ dd_activation_programme = models.DateField(null=True, db_column='DD_ACTIVATION_PROGRAMME', blank=True) # Field name made lowercase.
+ df_activation_programme = models.DateField(null=True, db_column='DF_ACTIVATION_PROGRAMME', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_PROGRAMME'
+
+class ReProjet(models.Model):
+ c_code_projet = models.CharField(max_length=36, primary_key=True, db_column='C_CODE_PROJET') # Field name made lowercase.
+ l_projet_intitule = models.CharField(max_length=765, db_column='L_PROJET_INTITULE') # Field name made lowercase.
+ f_bureau = models.CharField(max_length=36, db_column='F_BUREAU') # Field name made lowercase.
+ f_programme = models.CharField(max_length=36, db_column='F_PROGRAMME') # Field name made lowercase.
+ i_projet_actif = models.IntegerField(db_column='I_PROJET_ACTIF') # Field name made lowercase.
+ dd_projet = models.DateField(db_column='DD_PROJET') # Field name made lowercase.
+ df_projet = models.DateField(db_column='DF_PROJET') # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_PROJET'
+
+class ReProjetPoste(models.Model):
+ c_projet_poste = models.CharField(max_length=36, primary_key=True, db_column='C_PROJET_POSTE') # Field name made lowercase.
+ f_projet_ref = models.CharField(max_length=36, db_column='F_PROJET_REF') # Field name made lowercase.
+ f_bureau = models.CharField(max_length=36, db_column='F_BUREAU') # Field name made lowercase.
+ f_programme = models.CharField(max_length=36, db_column='F_PROGRAMME') # Field name made lowercase.
+ l_projet = models.CharField(max_length=765, db_column='L_PROJET') # Field name made lowercase.
+ f_categorie_bourse = models.IntegerField(db_column='F_CATEGORIE_BOURSE') # Field name made lowercase.
+ i_projet_actif = models.IntegerField(db_column='I_PROJET_ACTIF') # Field name made lowercase.
+ dd_activation_projet = models.DateField(db_column='DD_ACTIVATION_PROJET') # Field name made lowercase.
+ df_activation_projet = models.DateField(null=True, db_column='DF_ACTIVATION_PROJET', blank=True) # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_PROJET_POSTE'
+
+class ReUtilisateurSigma(models.Model):
+ c_matricule = models.IntegerField(primary_key=True, db_column='C_MATRICULE') # Field name made lowercase.
+ c_matricule_sigma = models.CharField(unique=True, max_length=36, db_column='C_MATRICULE_SIGMA') # Field name made lowercase.
+ f_bureau_gestion = models.CharField(max_length=36, db_column='F_BUREAU_GESTION', blank=True) # Field name made lowercase.
+ f_bureau_geographique = models.CharField(max_length=36, db_column='F_BUREAU_GEOGRAPHIQUE', blank=True) # Field name made lowercase.
+ c_implantation_dpp = models.CharField(max_length=30, db_column='C_IMPLANTATION_DPP') # Field name made lowercase.
+ l_email = models.CharField(max_length=300, db_column='L_EMAIL') # Field name made lowercase.
+ c_utilisateur = models.CharField(max_length=180, db_column='C_UTILISATEUR') # Field name made lowercase.
+ i_sexe_utilisateur = models.IntegerField(null=True, db_column='I_SEXE_UTILISATEUR', blank=True) # Field name made lowercase.
+ l_nom_utilisateur = models.CharField(max_length=300, db_column='L_NOM_UTILISATEUR') # Field name made lowercase.
+ l_prenom_utilisateur = models.CharField(max_length=300, db_column='L_PRENOM_UTILISATEUR') # Field name made lowercase.
+ l_fonction_utilisateur = models.CharField(max_length=765, db_column='L_FONCTION_UTILISATEUR') # Field name made lowercase.
+ c_mot_passe = models.CharField(max_length=96, db_column='C_MOT_PASSE') # Field name made lowercase.
+ i_utilisateur_actif = models.IntegerField(null=True, db_column='I_UTILISATEUR_ACTIF', blank=True) # Field name made lowercase.
+ dd_activation_utilisateur = models.DateField(null=True, db_column='DD_ACTIVATION_UTILISATEUR', blank=True) # Field name made lowercase.
+ df_activation_utilisateur = models.DateField(null=True, db_column='DF_ACTIVATION_UTILISATEUR', blank=True) # Field name made lowercase.
+ n_compteur_connexion = models.IntegerField(null=True, db_column='N_COMPTEUR_CONNEXION', blank=True) # Field name made lowercase.
+ i_correpondant_bourse = models.IntegerField(null=True, db_column='I_CORREPONDANT_BOURSE', blank=True) # Field name made lowercase.
+ i_assistant_programme = models.IntegerField(db_column='I_ASSISTANT_PROGRAMME') # Field name made lowercase.
+ class Meta:
+ db_table = u'RE_UTILISATEUR_SIGMA'
+
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+# Pièces nom requis pour apparaître dans interface SIGMA
+PIECES_SUFFIXE = {
+ # id_sigma: 'nom_fichier_sigma' # Nom affichage SIGMA
+ #1:'', # Attestation d’accord du(des) directeur(s) de thèse justifiant l'alternance proposée
+ 2:'attestation_o_dir', # Attestation d'accord - Établissement d'accueil
+ 3:'attestation_a_dir', # Attestation d'accord - Établissement d'origine
+ #4:'attestation_a_sc', # Attestation d'accord à l'accueil - Responsable
+ #5:'attestation_o_sc', # Attestation d'accord à l'origine - Responsable
+ #6:'', # Attestation d'admission - Établissement d'accueil
+ #7:'', # Demande d'inscription pour l'année de mobilité
+ #8:'', # Attestation d'inscription pour l'année en cours
+ #9:'', # Budget prévisionnel détaillé
+ #10:'', # Calendrier de l'alternance (dates conforme au règlement)
+ #11:'', # Convention de stage
+ #12:'', # Copie du dernier diplôme obtenu
+ #13:'', # Copie du dernier relevé de notes
+ #14:'', # Copie du diplôme de doctorat et du rapport de soutenance de thèse
+ #15:'', # Copie du dossier de scolarité universitaire
+ 16:'curriculum_vitae', # Curriculum vitae actualisé
+ 17:'descriptif_these', # Description détaillée
+ #18:'', # Fiche de renseignements personnels dûment complétée et signée
+ # formulaire (PDF) : pas de suffixe, seulement extension .pdf
+ 19:'', # Formulaire de demande dûment complété et signé
+ #20:'', # Lettre de motivation
+ #21:'', # Liste des activités pédagogiques
+ #22:'', # Liste des membres du comité scientifique de la manifestation
+ #23:'', # Liste détaillée des publications
+ #24:'', # Liste détaillée des publications, communications et recherches non publiées
+ #25:'', # Photocopie du passeport (no et date d’expiration)
+ #26:'', # Profil de l'établissement d'accueil
+ 27:'protocole_recherche', # Protocole de recherche
+ #28:'', # Calendrier
+ #29:'', # Justificatif d'inscription deux années consécutives dans un même établissement durant les trois dernières années
+ #30:'', # Composition du comité scientifique de la manifestation
+ #31:'', # Opportunité pour les Universités partenaires au Sud et au Nord et retombées
+ #32:'', # Classement de l'établissement des dossiers par ordre de priorité
+ #33:'', # Attestation d'accord supplémentaire - Établissement d'origine
+ #34:'', # Dossier reçu avant le
+ #45:'', # Etablissement d'origine membre AUF
+ #46:'', # Etablissement d'accueil membre AUF
+ #47:'', # Année académique de 1ère inscription en thèse
+ #49:'', # Année d'interruption après l'obtention du doctorat
+ #50:'', # Programme de la formation demandée durant la période de mobilité
+ #51:'', # Copie convention liant les établissements d’accueil et d’origine pour la formation visée
+ #52:'', # Justificatif du statut de retraité(e)
+ #53:'', # Attestation d'accord de l'enseignant pour dispenser le cours (séminaire, travaux dirigés/pratiques)
+ #54:'', # Description détaillée des enseignements / cours à dispenser
+ #55:'', # Date de naissance
+ #56:'', # Etablissements Origine et Accueil situés dans 2 pays différents (Nord/Sud - Sud/Nord - Sud/Sud)
+ #57:'', # Date de première inscription en thèse
+ 58:'etat_travaux', # Etat des travaux réalisés
+ }
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from django.conf.urls.defaults import *
+
+from wcs.settings import WCS_URL_NAMESPACE
+
+urlpatterns = patterns('',
+ (r'^' + WCS_URL_NAMESPACE + r'/', include('wcs.urls')),
+)
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from sigma_v1.models import Personne as P
+from sigma_v1.models import Dossier as D
+from sigma_v1.models import DossierOrigine as DO
+from sigma_v1.models import DossierAccueil as DA
+from sigma_v1.models import DossierMobilite as DM
+from sigma_v1.models import DossierPieces as DP
+
+from conf import DATABASE_HOST
+from wcs.conf import MOBILITE, CODE_BUDGETAIRE, FORMNAME
+
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run delete.py
+ """
+
+ # Dossiers de l'appel
+ ds = D.objects.filter(mobilite=MOBILITE)
+ ds_ids = [d.id for d in ds]
+ nb_ds = len(ds_ids)
+
+ # rapport : header
+ print '--------------------------------------------------'
+ print 'SUPPRESSION CANDIDATURES SIGMA'
+ print '**** SERVEUR : %s ****' % DATABASE_HOST
+ print 'Formulaire : %s' % FORMNAME
+ print 'Mobilité : %d' % MOBILITE
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nb_ds)
+ print '--------------------------------------------------'
+
+ # Suppression des pièces jointes
+ dps = DP.objects.filter(dossier__in=ds_ids)
+ nb_dps = len(dps)
+ dps.delete()
+ print 'Pièces jointes supprimées = %d' % (nb_dps)
+
+ # Suppression des dossiers mobilité
+ dms = DM.objects.filter(dossier__in=ds_ids)
+ nb_dms = len(dms)
+ dms.delete()
+ print 'Dossiers mobilité supprimés = %d' % (nb_dms)
+
+ # Suppression des dossiers accueil
+ das = DA.objects.filter(dossier__in=ds_ids)
+ nb_das = len(das)
+ das.delete()
+ print 'Dossiers accueil supprimés = %d' % (nb_das)
+
+ # Suppression des dossiers origine
+ dos = DO.objects.filter(dossier__in=ds_ids)
+ nb_dos = len(dos)
+ dos.delete()
+ print 'Dossiers origine supprimés = %d' % (nb_dos)
+
+ # Suppression des personnes
+ ps_ids = [d.personne_id for d in ds]
+ ps = P.objects.filter(id__in=ps_ids)
+ nb_ps = len(ps)
+ ps.delete()
+ print 'Personnes supprimées = %d' % (nb_ps)
+
+ # Suppression des dossiers
+ ds.delete()
+ print 'Dossiers supprimés = %d' % (nb_ds)
+
+ # rapport : footer
+ print '--------------------------------------------------'
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+import os
+from simplejson import loads
+import urllib2
+import zipfile
+
+from wcs.settings import FORMNAME
+
+from lib import getCandidaturesJson, createPdf, createZip
+from models import JsonWcs2JsonSigma
+
+# MAIN
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run views.py
+ """
+
+ # json WCS
+ candidatures = getCandidaturesJson()
+ nombre = len(candidatures)
+ spams = 0
+ traites = 0
+ traitesPdf = 0
+ traitesZip = 0
+
+ # rapport : header
+ print 'CRÉATION DES DOCUMENTS : PDF ET ZIP'
+ print 'Formulaire : %s' % FORMNAME
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nombre)
+ print '--------------------------------------------------'
+
+ # IMPORT
+ jj = JsonWcs2JsonSigma()
+ for candidature in candidatures :
+ if candidature['wcs_workflow_status'] == 'SPAM':
+ spams = spams + 1
+ else :
+ candidature = jj.mapper(candidature)
+ traites = traites + 1
+ print '%d - %s' % (traites, candidature['wcs_num_dossier'])
+ # pdf
+ createPdf(candidature)
+ traitesPdf = traitesPdf + 1
+ print '* PDF : %s' % (candidature['wcs_num_dossier'])
+ # zip
+ createZip(candidature)
+ traitesZip = traitesZip + 1
+ print '* ZIP : %s' % (candidature['wcs_num_dossier'])
+ print ''
+
+ # rapport : footer
+ print '--------------------------------------------------'
+ print 'Total spams = %d sur %d' % (spams, nombre)
+ print 'Total traités = %d sur %d' % (traites, nombre)
+ print 'Total = %d sur %d' % (spams + traites, nombre)
+ print 'Total PDF = %d sur %d' % (traitesPdf, traites)
+ print 'Total ZIP = %d sur %d' % (traitesZip, traites)
+ print '--------------------------------------------------'
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from sigma_v1.models import Mobilite
+
+from wcs.conf import MOBILITE, CODE_BUDGETAIRE, FORMNAME
+from views import exportSigmaFiles
+
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run export.py
+ """
+
+ # Appel en cours
+ appel = Mobilite(id=MOBILITE, code_budgetaire=CODE_BUDGETAIRE, wcs_form_name=FORMNAME)
+ exportSigmaFiles(appel)
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from sigma_v1.models import Mobilite
+
+from wcs.conf import MOBILITE, CODE_BUDGETAIRE, FORMNAME
+from views import importDossiersCandidaturesWcs
+
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run import.py
+ """
+
+ # Appel en cours
+ appel = Mobilite(id=MOBILITE, code_budgetaire=CODE_BUDGETAIRE, wcs_form_name=FORMNAME)
+ importDossiersCandidaturesWcs(appel)
--- /dev/null
+#!/usr/bin/python
+# -=- encoding: utf-8 -=-
+
+import os, sys, simplejson, StringIO
+from ho import pisa
+
+from django.template import Context, Template
+from wcs.settings import FORMNAME
+
+class JsonToPdf:
+ "Convertit un fichier json de candidature en pdf."
+ inputBuffer = ""
+ templateFile = ""
+
+ def __init__ (self,
+ templateFileName = "templates/candidature.html"):
+ self.templateFile = templateFileName
+
+ def readFile (self, fileName):
+ """Lire le fichier fileName et retourne son contenu.
+ Vide si le fichier n'existe pas
+ """
+ buffer = ""
+
+ try:
+ inFile = open (fileName, 'r')
+ except:
+ print "Fichier", fileName, "illisible"
+ else:
+ buffer = inFile.read ()
+
+ return buffer
+
+ def convert (self):
+ "Effectue la conversion"
+
+ if len (self.inputBuffer) > 0:
+ object = self.inputBuffer
+ if object is not None:
+ # Render
+ template = Template (self.readFile (self.templateFile))
+ object['formname'] = unicode(FORMNAME)
+ context = Context (object)
+ # As HTML
+ html = template.render (context)
+ # Write PDF
+ pdf = StringIO.StringIO ()
+ pisa.CreatePDF(html, pdf)
+ return pdf
+
+ def convertFromFile (self, inputFile):
+ self.inputBuffer = inputFile
+ return self.convert ()
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+import os.path
+from simplejson import loads
+import zipfile
+
+from jsontopdf import JsonToPdf
+from wcs.settings import DATA_DIR
+
+def getCandidaturesJson(source='local'):
+ candidatures = []
+ if source == 'local':
+ # Fichiers WCS importés en local : .json et pièces jointes
+ if os.path.exists(DATA_DIR):
+ listjson = [f for f in os.listdir(DATA_DIR) if f.endswith('.json')]
+ for candidature in listjson :
+ fichier = "%s%s" % (DATA_DIR, candidature)
+
+ f = open(fichier, 'r')
+ data = f.read()
+ f.close()
+
+ data = loads(data, encoding='utf-8')
+ data['wcs_json_filename'] = unicode(candidature)
+ candidatures.append(data)
+ else:
+ pass
+ return candidatures
+
+def createPdf(candidature):
+ """Créer un fichier PDF représentant la candidature WCS avec toutes ses données reçues.
+ PDF basé sur la structure de données de WCS (pas SIGMA) :
+ ingérable à court terme sauf si créé côté serveur.
+
+ À terme, le PDF doit être généré à partir de la page HTML du formulaire WCS
+ tel qu'il peut être vu par le candidat.
+ -> Construction des PDF serveur side.
+ """
+ baseName = candidature['wcs_json_filename'].rstrip('.json')
+ pdfFilePath = "%s%s.pdf" % (DATA_DIR, baseName)
+
+ converter = JsonToPdf()
+ pdf = converter.convertFromFile(candidature)
+ f = open(pdfFilePath, 'w')
+ f.write(pdf.getvalue())
+ f.close()
+
+def createZip(candidature):
+ """Constitue une dossier ZIP comprenant :
+ * le formulaire en PDF
+ * les pièces jointes soumises par candidat
+ """
+ baseName = candidature['wcs_json_filename'].rstrip('.json')
+ zipFilePath = "%s%s.zip" % (DATA_DIR, baseName)
+ archive = zipfile.ZipFile(zipFilePath, "w", zipfile.ZIP_STORED)
+
+ if os.path.exists(DATA_DIR):
+ files = [f for f in os.listdir(DATA_DIR) \
+ if f.startswith(baseName) and not f.endswith('.json') and not f.endswith('.zip')]
+ for f in files:
+ filePath = DATA_DIR + f
+ archive.write(filePath, f)
+ archive.close()
+
+def premiereMaj(s):
+ """Met le premier caractère en majuscule et reste minuscule"""
+ premiere = s[0]
+ reste = s[1:]
+
+ return premiere.upper() + reste.lower()
+
+def majSansAccent(s):
+ result = ''
+ avant = u'ÇÁÀÂÉÈÊËÍÌÎÏÓÒÔÖÚÙÛÜÝỲŶŸ'
+ apres = u'CAAAEEEEIIIIOOOOUUUUYYYY'
+
+ for char in s:
+ i = avant.find(char)
+ if i >= 0:
+ char = apres[i]
+ result += char
+
+ return result
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from datetime import datetime, date as datetime_date
+import os
+import re
+#import unicodedata
+
+from sigma_v1.models import Personne, Dossier, DossierOrigine, DossierAccueil, DossierMobilite, DossierPieces
+from sigma_v1.models import Etablissement, Implantation, Bureau
+
+from wcs.settings import USER, STATUT_DOSSIER, MOBILITE, BUREAU, MAPPING, DATA_DIR
+from wcs.settings import SIGMA_DOSSIER_M_ALT_MOIS_ORIGINE, SIGMA_DOSSIER_M_MOBILITE_ACCUEIL
+from wcs.settings import PATTERN_STATUT_PERSONNE, PATTERN_ETABL
+from wcs.settings import PIECES_SUFFIXE, PIECES_WCS, PIECES_SIGMA
+from lib import majSansAccent, premiereMaj
+
+#class Formulaire(object):
+# Formulaire WCS (associé à un appel SIGMA)
+
+#class Candidature(object):
+# Candidature WCS (associé à un formulaire WCS)
+# init = via une candidature au format json
+#
+# def createPdf(request, candidature):
+# crée le PDF à partir d'un template local (futur : à partir du form wcs)
+#
+# def createZip(request, candidature):
+# crée le dossier zip contenant PDF et toutes les pièces jointes
+
+class JsonSigma2ObjectSigma(object):
+ # TEST : en cas d'échec, erreur levée en console
+ creation_django_ok = True
+ creation_db_ok = True
+
+ def createPersonne(self, data, save=True):
+ """
+ Créer Personne SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ p = Personne()
+
+ #p.id
+ p.utilisateur_creation = USER
+ #p.utilisateur_maj =
+ #p.date_creation =
+ #p.date_maj =
+
+ p.civilite = data['sigma_personne_civilite']
+ p.nom = majSansAccent(data['sigma_personne_nom'].upper())[0:100]
+ p.nom_index = p.nom
+ p.nom_jeune_fille = majSansAccent(data['sigma_personne_nom_jeune_fille'].upper())[0:100]
+ p.nom_jeune_fille_index = p.nom_jeune_fille
+ p.prenom = majSansAccent(data['sigma_personne_prenom'].title())[0:100]
+ p.prenom_index = p.prenom.upper()
+ p.pays_nationalite = data['sigma_personne_pays_nationalite']
+ #p.sexe =
+
+ p.pays_naissance = data['sigma_personne_pays_naissance']
+ p.date_naissance = data['sigma_personne_date_naissance']
+ p.ville_naissance = majSansAccent(data['sigma_personne_ville_naissance'].title())[0:50]
+
+ p.adresse = data['sigma_personne_adresse']
+ p.ville = majSansAccent(data['sigma_personne_ville'].title())[0:50]
+ p.region = data['sigma_personne_region'][0:50]
+ p.code_postal = data['sigma_personne_code_postal'][0:10]
+ p.pays_residence = data['sigma_personne_pays_residence']
+ p.tel = data['sigma_personne_tel'][0:25]
+ #p.fax
+ p.tel_pro = data['sigma_personne_tel_pro'][0:25]
+ #p.fax_pro
+ p.email = data['sigma_personne_email'][0:100]
+
+ if save:
+ p.save()
+
+ return p
+
+ def createDossier(self, data, p, save=True):
+ """
+ Créer Dossier SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ d = Dossier()
+
+ #d.id
+ d.statut = STATUT_DOSSIER
+ d.mobilite = MOBILITE
+ d.personne = p
+
+ d.statut_personne = data['sigma_dossier_statut_personne']
+ d.fonction = data['sigma_dossier_fonction'][0:100]
+
+ if BUREAU is not None :
+ d.bureau_rattachement = BUREAU
+ else:
+ # bureau rattachement via établissement d'origine
+ try:
+ id_etablissement = data['sigma_dossier_o_etablissement'].lstrip('0')
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+ d.bureau_rattachement = etablissement.implantation_sigma.bureau.id_num
+ except Etablissement.DoesNotExist:
+ pass
+
+ d.intitule_d_diplome = data['sigma_dossier_intitule_d_diplome'][0:100]
+ d.date_d_diplome = data['sigma_dossier_date_d_diplome']
+ d.nom_etb = data['sigma_dossier_nom_etabl'][0:100]
+ d.pays_etb = data['sigma_dossier_pays_etabl']
+ d.niveau = data['sigma_dossier_niveau']
+
+ #data['sigma_dossier_particip_prog_auf']
+ d.programme = data['sigma_dossier_programme'][0:255]
+ d.annee_programme = data['sigma_dossier_annee_programme'] or 0
+ #data['sigma_dossier_boursier_auf']
+ d.categorie_bourse = data['sigma_dossier_categorie_bourse'][0:12]
+ d.annee_bourse = data['sigma_dossier_annee_bourse'] or 0
+
+ #d.etat
+ #d.dd_activation
+ #d.df_activation
+ d.utilisateur_creation = USER
+ d.utilisateur_maj = USER
+ #d.date_maj
+
+ #d.classement_1
+ #d.classement_2
+ #d.classement_3
+ #d.opp_regionale
+ #d.coche_selection
+ #d.reponse_notification
+ #d.commentaire_notification
+ #d.moyenne_academique
+ nl = u'\n\n'
+ d.autres_criteres = nl.join(data['sigma_dossier_autres_criteres'])[0:255]
+ #d.erreurs_recevabilite
+ #d.repechage
+ #d.rendu_irrecevable
+
+ if save:
+ d.save()
+
+ return d
+
+ def createDossierOrigine(self, data, d, save=True):
+ """
+ Créer DossierOrigine SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ do = DossierOrigine()
+
+ #do.id
+ do.dossier = d
+
+ # établissement
+ id_etablissement = data['sigma_dossier_o_etablissement'].lstrip('0')
+ try:
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+
+ # id
+ do.etablissement = etablissement.id # PAS etablissement.id_gde
+
+ # coordonnées
+ do.pays = etablissement.pays
+ do.adresse = etablissement.adresse
+ if etablissement.code_postal is not None :
+ do.code_postal = etablissement.code_postal[0:10]
+ if etablissement.ville is not None :
+ do.ville = etablissement.ville[0:50]
+ if etablissement.province is not None :
+ do.region = etablissement.province[0:50]
+ #do.url_site
+ except Etablissement.DoesNotExist:
+ pass
+ do.sc_faculte = data['sigma_dossier_o_sc_faculte'][0:150]
+
+ #do.erreur_recevabilite_etbt_origine =
+ #do.autre_etb =
+
+ # accord scientifique
+ do.sc_civilite = data['sigma_dossier_o_sc_civilite']
+ do.sc_nom = majSansAccent(data['sigma_dossier_o_sc_nom'].upper())[0:100]
+ do.sc_prenom = majSansAccent(data['sigma_dossier_o_sc_prenom'].title())[0:100]
+ do.sc_fonction = data['sigma_dossier_o_sc_fonction'][0:100]
+ #do.sc_adresse =
+ #do.sc_code_postal =
+ do.sc_ville = majSansAccent(data['sigma_dossier_o_sc_ville'].title())[0:50]
+ do.sc_tel_pro = data['sigma_dossier_o_sc_tel_pro'][0:25]
+ do.sc_email = data['sigma_dossier_o_sc_email'][0:100]
+ #do.sc_fax_pro =
+
+ # accord institutionnel
+ #do.inst_civilite =
+ #do.inst_nom =
+ #do.inst_prenom =
+ #do.inst_fonction =
+
+ if save:
+ do.save()
+
+ return do
+
+ def createDossierAccueil(self, data, d, save=True):
+ """
+ Créer DossierAccueil SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ da = DossierAccueil()
+
+ #da.id =
+ da.dossier = d
+
+ # établissement
+ id_etablissement = data['sigma_dossier_a_etablissement'].lstrip('0')
+ try:
+ etablissement = Etablissement.objects.get(id_gde=id_etablissement)
+
+ # id
+ da.etablissement = etablissement.id # PAS etablissement.id_gde
+
+ # coordonnées
+ da.pays = etablissement.pays
+ da.adresse = etablissement.adresse
+ if etablissement.code_postal is not None :
+ da.code_postal = etablissement.code_postal[0:10]
+ if etablissement.ville is not None :
+ da.ville = etablissement.ville[0:50]
+ if etablissement.province is not None :
+ da.region = etablissement.province[0:50]
+ #da.url_site
+ except Etablissement.DoesNotExist:
+ pass
+ da.sc_faculte = data['sigma_dossier_a_sc_faculte'][0:150]
+
+ #da.erreur_recevabilite_etbt_accueil =
+ #da.autre_etb =
+
+ # accord scientifique
+ da.sc_civilite = data['sigma_dossier_a_sc_civilite']
+ da.sc_nom = majSansAccent(data['sigma_dossier_a_sc_nom'].upper())[0:100]
+ da.sc_prenom = majSansAccent(data['sigma_dossier_a_sc_prenom'].title())[0:100]
+ da.sc_fonction = data['sigma_dossier_a_sc_fonction'][0:100]
+ #da.sc_adresse =
+ #da.sc_code_postal =
+ da.sc_ville = majSansAccent(data['sigma_dossier_a_sc_ville'].title())[0:50]
+ da.sc_tel_pro = data['sigma_dossier_a_sc_tel_pro'][0:25]
+ da.sc_email = data['sigma_dossier_a_sc_email'][0:100]
+ #da.sc_fax_pro =
+
+ # accord institutionnel
+ #da.inst_civilite =
+ #da.inst_nom =
+ #da.inst_prenom =
+ #da.inst_fonction =
+ #da.inst_email =
+ #da.inst_tel_pro =
+ #da.inst_fax_pro =
+
+ if save:
+ da.save()
+
+ return da
+
+ def createDossierMobilite(self, data, d, save=True):
+ """
+ Créer DossierMobilite SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ dm = DossierMobilite()
+
+ #dm.id =
+ dm.dossier = d
+
+ dm.intitule_diplome = data['sigma_dossier_m_intitule_diplome'][0:100]
+ if not dm.intitule_diplome and data['sigma_dossier_m_intitule_diplome_autre'] :
+ dm.intitule_diplome = data['sigma_dossier_m_intitule_diplome_autre'][0:100]
+
+ dm.niveau_encours = data['sigma_dossier_m_niveau_encours']
+
+ # calculs : ce qu'on peut dériver des data
+ mobilite_accueil = None
+ dd_mobilite = None
+ df_mobilite = None
+
+ o_dd = data['sigmawcs_dossier_o_dd']
+ o_df = data['sigmawcs_dossier_o_df']
+ a_dd = data['sigmawcs_dossier_a_dd']
+ a_df = data['sigmawcs_dossier_a_df']
+
+ # origine et accueil
+ if o_dd is not None and a_dd is not None:
+ if (o_dd < a_dd):
+ # commence mobilité à origine
+ mobilite_accueil = False
+ dd_mobilite = o_dd
+ df_mobilite = a_df
+ else :
+ # commence mobilité à accueil
+ mobilite_accueil = True
+ dd_mobilite = a_dd
+ df_mobilite = o_df
+ # origine seul
+ elif o_dd is not None and a_dd is None:
+ if (o_dd < a_dd):
+ # commence mobilité à origine
+ mobilite_accueil = False
+ dd_mobilite = o_dd
+ df_mobilite = o_df
+ # accueil seul
+ elif o_dd is None and a_dd is not None:
+ # commence mobilité à accueil
+ mobilite_accueil = True
+ dd_mobilite = a_dd
+ df_mobilite = a_df
+
+ if data.has_key('sigma_dossier_m_dd_mobilite') and data.has_key('sigma_dossier_m_df_mobilite'):
+ dd_mobilite = data['sigma_dossier_m_dd_mobilite']
+ df_mobilite = data['sigma_dossier_m_df_mobilite']
+ # 1. data WCS
+ if data.has_key('sigma_dossier_m_mobilite_accueil'):
+ mobilite_accueil = data['sigma_dossier_m_mobilite_accueil']
+ # 2. conf de l'appel
+ elif SIGMA_DOSSIER_M_MOBILITE_ACCUEIL is not None:
+ mobilite_accueil = SIGMA_DOSSIER_M_MOBILITE_ACCUEIL
+
+ dm.dd_mobilite = dd_mobilite
+ dm.df_mobilite = df_mobilite
+ #dm.total_mobilite = total_mobilite # intervalle dd_mobilite, df_mobilite # computé par SIGMA?
+
+ # 1. default
+ alt_mois_origine = 0
+ # 2. data WCS
+ if data.has_key('sigma_dossier_m_alt_mois_origine'):
+ alt_mois_origine = data['sigma_dossier_m_alt_mois_origine']
+ # 3. conf de l'appel
+ elif SIGMA_DOSSIER_M_ALT_MOIS_ORIGINE is not None:
+ alt_mois_origine = SIGMA_DOSSIER_M_ALT_MOIS_ORIGINE
+ dm.alt_mois_origine = alt_mois_origine
+ dm.alt_mois_accueil = data['sigma_dossier_m_alt_mois_accueil']
+ dm.mobilite_accueil = mobilite_accueil
+
+ dm.date_inscription_these = data['sigma_dossier_m_date_inscription_these']
+ dm.date_soutenance_these = data['sigma_dossier_m_date_soutenance_these']
+ dm.pays_soutenance = data['sigma_dossier_m_pays_soutenance']
+ dm.type_these = data['sigma_dossier_m_type_these']
+ # workaround : champ dm.date_soutenance_these pas affiché in SIGMA :
+ dm.type_these_autre = u"Date soutenance prévue : %s" % (dm.date_soutenance_these)
+ dm.type_these_autre = dm.type_these_autre[0:255]
+
+ dm.discipline = data['sigma_dossier_m_discipline'] or u""
+ #dm.sous_discipline =
+
+ dm.intitule_projet = premiereMaj(data['sigma_dossier_m_intitule_projet'])
+ # ajout point à la fin...
+ if dm.intitule_projet != u"" and dm.intitule_projet[-1] != u"." :
+ dm.intitule_projet = dm.intitule_projet + u"."
+
+ dm.mot_clef1 = majSansAccent(data['sigma_dossier_m_mot_clef1'].upper())[0:50]
+ dm.mot_clef2 = majSansAccent(data['sigma_dossier_m_mot_clef2'].upper())[0:50]
+ dm.mot_clef3 = majSansAccent(data['sigma_dossier_m_mot_clef3'].upper())[0:50]
+
+ #dm.type_intervention =
+ #dm.public_vise =
+ #dm.autres_publics =
+
+ #dm.mobilite_accueil = # debut mobilité à l'accueil?
+ #dm.intitule_diplome_demande =
+ #dm.niveau_demande =
+ #dm.obtention_prevu =
+
+ dm.dir_ori_civilite = data['sigma_dossier_m_dir_ori_civilite']
+ dm.dir_ori_nom = majSansAccent(data['sigma_dossier_m_dir_ori_nom'].upper())[0:100]
+ dm.dir_ori_prenom = majSansAccent(data['sigma_dossier_m_dir_ori_prenom'].title())[0:100]
+ # email absent in SIGMA... sale workaround
+ dm.dir_ori_prenom = u"%s [%s]" % (dm.dir_ori_prenom, data['sigma_dossier_m_dir_ori_email'])
+ dm.dir_ori_prenom = dm.dir_ori_prenom[0:100]
+
+ dm.dir_acc_civilite = data['sigma_dossier_m_dir_acc_civilite']
+ dm.dir_acc_nom = majSansAccent(data['sigma_dossier_m_dir_acc_nom'].upper())[0:100]
+ dm.dir_acc_prenom = majSansAccent(data['sigma_dossier_m_dir_acc_prenom'].title())[0:100]
+ # email absent in SIGMA... sale workaround
+ dm.dir_acc_prenom = u"%s [%s]" % (dm.dir_acc_prenom, data['sigma_dossier_m_dir_acc_email'])
+ dm.dir_acc_prenom = dm.dir_acc_prenom[0:100]
+
+ if save:
+ dm.save()
+
+ return dm
+
+ def createDossierPieces(self, data, d, save=True):
+ """
+ Créer DossierPieces SIGMA à partir du json reçu, nettoyé, mappé et converti.
+ """
+ pieces_created = []
+
+ #data['sigma_dossier_p_*']
+ mapping_reverse = {}
+ for k,v in MAPPING.items():
+ mapping_reverse[v] = k
+
+ for piece in PIECES_WCS:
+ # pièce présente? accès fichier réel
+ presente = False
+ if piece == 19:
+ # formulaire
+ presente = True
+ else :
+ # autres pièces
+ wcs_suffixe = PIECES_SUFFIXE[piece]
+ sigma_key = mapping_reverse[wcs_suffixe]
+ filename = data[sigma_key]
+ if os.path.exists(filename):
+ presente = True
+
+ dp = DossierPieces()
+ #dp.id =
+ dp.dossier = d
+ dp.presente = presente
+ dp.piece = piece
+ #dp.conforme =
+ #dp.commentaire = u"Pièce chargée par candidat via formulaire électronique."
+ if save:
+ dp.save()
+ pieces_created.append(dp)
+
+ # Autres pièces in SIGMA
+
+ for piece in PIECES_SIGMA:
+ dp = DossierPieces()
+ dp.dossier = d
+ dp.piece = piece
+ if save:
+ dp.save()
+ pieces_created.append(dp)
+
+ return pieces_created
+
+ ### AUTRE
+ #data['wcs_num_dossier']
+
+ #data['sigma_confirmation_nom']
+ #data['sigma_confirmation_prenom']
+ #data['sigma_confirmation']
+
+class JsonWcs2JsonSigma(object):
+ """
+ Converti les données de formulaires WCS, notamment les <option> des <select>
+ en données exploitables par SIGMA.
+ Ex.:
+ input : Algérie - Centre de recherche en anthropologie sociale et culturelle (Sud/BEOM/547)
+ output : 547
+ """
+
+ ### types SIGMA
+ # champs WCS = liste
+ civilite = []
+ statut = []
+ niveau = []
+ diplome = []
+ mois = []
+ these = []
+ bourse = []
+ pays = []
+ etablissement = []
+ discipline = []
+ # champs WCS = date
+ date = []
+
+ # civilite
+ civilite.append('sigma_personne_civilite')
+ civilite.append('sigma_dossier_o_sc_civilite')
+ civilite.append('sigma_dossier_m_dir_ori_civilite')
+ civilite.append('sigma_dossier_a_sc_civilite')
+ civilite.append('sigma_dossier_m_dir_acc_civilite')
+ # statut
+ statut.append('sigma_dossier_statut_personne')
+ # niveau
+ niveau.append('sigma_dossier_niveau')
+ niveau.append('sigma_dossier_m_niveau_encours')
+ # diplome
+ diplome.append('sigma_dossier_m_intitule_diplome')
+ # mois
+ mois.append('sigma_dossier_m_alt_mois_origine')
+ mois.append('sigma_dossier_m_alt_mois_accueil')
+ # these
+ these.append('sigma_dossier_m_type_these')
+ # bourse
+ bourse.append('sigma_dossier_categorie_bourse')
+ # pays
+ pays.append('sigma_personne_pays_nationalite')
+ pays.append('sigma_personne_pays_naissance')
+ pays.append('sigma_personne_pays_residence')
+ pays.append('sigma_dossier_pays_etabl')
+ pays.append('sigma_dossier_m_pays_soutenance')
+ # etablissement
+ etablissement.append('sigma_dossier_o_etablissement')
+ etablissement.append('sigma_dossier_a_etablissement')
+ # discipline
+ discipline.append('sigma_dossier_m_discipline')
+ # date
+ date.append('sigma_personne_date_naissance')
+ date.append('sigma_dossier_date_d_diplome')
+ date.append('sigmawcs_dossier_o_dd')
+ date.append('sigmawcs_dossier_o_df')
+ date.append('sigmawcs_dossier_a_dd')
+ date.append('sigmawcs_dossier_a_df')
+ date.append('sigma_dossier_m_date_inscription_these')
+ date.append('sigma_dossier_m_date_soutenance_these')
+
+ ### TEST (utilisé par test.py) : résultats conversion globale de tous les .json
+ convert_ok = True
+ convert_errors = []
+
+ ### NETTOYAGE unicode -> ISO
+ def cleanup(self, json):
+ for k,v in json.iteritems():
+ if type(v) is unicode :
+ # encodage : correction caractères
+ v = self.replaceUnicodeNotIso(v)
+ # strip espaces
+ v = v.lstrip()
+ v = v.rstrip()
+ json[k] = v
+ if type(v) is str :
+ print ('%s : %s a str = %s') % (json['wcs_num_dossier'], k, v)
+ return json
+
+ def replaceUnicodeNotIso(self, string):
+ """
+ Remplace caractère Unicode (scripts latin) n'ayant pas d'équivalent ISO-8859-1
+ par un caractère visuellement similaire.
+ """
+ result = ''
+
+ #nkfd_form = unicodedata.normalize('NFKD', unicode(string))
+ #string = u"".join([c for c in nkfd_form if not unicodedata.combining(c)])
+
+ # Latin Extended-A
+ avant = u'ĂŞşŢţνγδệịạỄợụĐốữẦươȘβğПΣăúµÁẾ◦õễọạươộảỨũửỆỘƯƠ'
+ apres = u'ASsTtvgdêiaEouDouAuoSBgPEaumAE*oeoauooaUuuEOUO'
+
+ for char in string:
+ i = avant.find(char)
+ if i >= 0:
+ char = apres[i]
+ result += char
+
+ return result
+
+ ### MAPPAGE pour formulaire en cours
+ mapping = MAPPING
+
+ def mapper(self, json):
+ """
+ Traitement sur les champs reçus : mapper pour associer à SIGMA.
+ """
+ newJson = {}
+ mapping_reverse = {}
+ for k,v in self.mapping.items():
+ mapping_reverse[v] = k
+ # renomme champ avec nom SIGMA si mappé sinon conserve nom
+ for k,v in json.items():
+ if k in self.mapping.values():
+ new_k = mapping_reverse[k]
+ newJson[new_k] = v
+ else:
+ newJson[k] = v
+ # ajouter tous les champs SIGMA qui ne serait pas dans le formulaire reçu
+ for k,v in self.mapping.items():
+ if not newJson.has_key(k):
+ newJson[k] = None
+ return newJson
+
+ ### CONVERSION (de string s pour key k)
+ def convert(self, json):
+ """
+ Traitement sur les valeurs reçues : convertir pour rencontre conforme SIGMA.
+ """
+ for k,s in json.iteritems():
+ if s is None:
+ s = u''
+ json[k] = s
+ if k in self.civilite :
+ s2 = self.str2civilite(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.statut :
+ json[k] = self.str2statutPersonne(s)
+ # no log_error
+ elif k in self.niveau :
+ json[k] = self.str2niveauEtude(s)
+ # no log_error
+ elif k in self.diplome :
+ json[k] = self.str2diplome(s)
+ # no log_error
+ elif k in self.mois :
+ json[k] = self.str2nbMois(s)
+ # no log_error
+ elif k in self.these :
+ s2 = self.str2typeThese(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.bourse :
+ s2 = self.str2bourse(s)
+ json[k] = s2
+ if s != u'' and s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.pays:
+ s2 = self.str2pays(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.etablissement :
+ s2 = self.str2etablissement(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.discipline :
+ s2 = self.str2discipline(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ elif k in self.date :
+ s2 = self.str2date(s)
+ json[k] = s2
+ if s2 == s:
+ self.log_error(json, k, s)
+ return json
+
+ def log_error(self, json, k, s):
+ self.convert_ok = False
+ error = '%s : %s = %s' % (json['wcs_num_dossier'], k, s)
+ self.convert_errors.append(error)
+
+ def str2civilite(self, s):
+ output = s
+ if s == 'M.':
+ output = 'MR'
+ elif s == 'Mme':
+ output = 'MM'
+ elif s == 'Mlle':
+ output = 'ME'
+ return output
+
+ def str2statutPersonne(self, s):
+ """
+ Exemple :
+ pattern 1 (SIGMA) :
+ 1 Étudiant
+ 2 Chercheur
+ 3 Enseignant
+ 4 Enseignant-chercheur
+ 5 Post-Doc
+
+ pattern 2:
+ 1 Chercheur
+ 2 Enseignant-chercheur
+ 3 Étudiant
+ """
+ output = 0
+ try :
+ # id du statut = permière lettre
+ input = int(s[0])
+ # WCS : valeurs différentes de SIGMA... :(
+ if PATTERN_STATUT_PERSONNE is not None:
+ if PATTERN_STATUT_PERSONNE == 1:
+ output = input
+ elif PATTERN_STATUT_PERSONNE == 2:
+ if input == 1:
+ output = 2
+ elif input == 2:
+ output = 4
+ elif input == 3:
+ output = 1
+ except ValueError :
+ pass
+ return output
+
+ def str2niveauEtude(self, s):
+ """
+ C_NIVEAU L_INTITULE_NIVEAU L_NIVEAU (annees)
+ 6 ... 0
+ 1 Licence 2 2
+ 2 Licence 3 3
+ 3 Master 1 4
+ 4 Master 2 5
+ 7 Master 2 + 6
+ 5 Doctorat 8
+ 8 Bac + 7 7
+ 9 Doctorat 9
+ """
+ output = 0
+ try :
+ # années études = permière lettre
+ annees = int(s[0])
+ # sauf 10 ans = 2 premières lettres...
+ if annees == 1:
+ annees = 10
+
+ if annees == 4 : output = 3
+ elif annees == 5 : output = 4
+ elif annees == 6 : output = 7
+ elif annees == 7 : output = 8
+ elif annees == 8 : output = 5
+ elif annees == 9 : output = 9
+ elif annees == 10 : output = 9
+
+ except ValueError :
+ pass
+ return output
+
+ def str2diplome(self, s):
+ output = s
+ if s.lower().startswith('autre'):
+ output = '' # retourne vide car traitement teste si vide pour prendre valeur autre champ
+ return output
+
+ def str2nbMois(self, s):
+ output = 0
+ try :
+ # permière lettre = nb de mois
+ output = int(s[0])
+ except (ValueError, IndexError) :
+ pass
+ return output
+
+ def str2typeThese(self, s):
+ output = s
+ if s == 'Co-tutelle':
+ output = 'CT'
+ elif s == 'Co-direction':
+ output = 'CD'
+ elif s == 'Autre':
+ output = 'AU'
+ return output
+
+ def str2bourse(self, s):
+ """
+ Exemple :
+ input = Bourse de doctorat (Formation à la Recherche - FR)
+ output = FR
+ """
+ pattern = r'.*(?P<code>\w{2})\)$'
+ return self.code_from_pattern(pattern, s)
+
+ def str2pays(self, s):
+ """
+ Exemple :
+ input = Arménie (AM - Europe centrale et orientale)
+ output = AM
+ """
+ pattern = r'.*\((?P<code>\w{2}).*\)$'
+ return self.code_from_pattern(pattern, s)
+
+ def str2etablissement(self, s):
+ """
+ Exemple :
+ pattern 1 :
+ input = Algérie - Centre universitaire d'El Oued (Sud/BEOM/1120)
+ output = 1120
+
+ pattern 2 :
+ input = Cameroun - Université de Ngaoundéré (265 - Sud)
+ output = 265
+ """
+ patterns = {
+ 1: r'.*\(.*/(?P<code>\d*)\)$',
+ 2: r'.*\((?P<code>\d*) .*\)$',
+ }
+ pattern = patterns[PATTERN_ETABL]
+ return self.code_from_pattern(pattern, s)
+
+ def str2discipline(self, s):
+ """
+ Exemple :
+ input = Anthropologie (D104)
+ output = D104
+ """
+ pattern = r'.*\((?P<code>\w*)\)$'
+ return self.code_from_pattern(pattern, s)
+
+ def str2date(self, s):
+ date = None
+ try:
+ d = datetime.strptime(s, '%Y-%m-%d')
+ date = datetime_date(d.year, d.month, d.day)
+ except ValueError:
+ pass
+ return date
+
+ def code_from_pattern(self, pattern=r'^$', s=u''):
+ if s is None:
+ s = u''
+ output = s
+ if s :
+ m = re.match(pattern, s)
+ if m and m.group('code'):
+ output = m.group('code')
+ return output
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from wcs.conf import *
+
+# WCS
+WCS_SIGMA_URL = 'https://formulaires.auf.org/sigma'
+
+# SIGMA
+# statut SIGMA des dossiers importés de WCS
+STATUT_DOSSIER = 3 # En cours
+# Pièces : nom du champ WCS attendu (sinon passer par conf.MAPPING)
+PIECES_FIELDNAME = {
+ 2:'sigma_dossier_p_attestation_a_dir',
+ 3:'sigma_dossier_p_attestation_o_dir',
+ 16:'sigma_dossier_p_cv',
+ 17:'sigma_dossier_p_descriptif_these',
+ 19:'', # formulaire (PDF) : pas encore fourni par WCS, généré localement par sigmawcs.wcs.docs
+ 27:'sigma_dossier_p_protocole_recherche',
+ 58:'sigma_dossier_p_etat_travaux',
+ }
+
+# SIGMAWCS
+WCS_URL_NAMESPACE = 'wcs'
+DATA_DIR = 'docs/%s/data/' % FORMNAME
+
--- /dev/null
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />\r
+ <title>{{ sigma_personne_nom.upper }}, {{ sigma_personne_prenom.title }} : {{ formname }}</title>\r
+ {% comment %}\r
+ <link href="{{ MEDIA_URL }}pdf.css" rel="stylesheet" type="text/css" />
+ {% endcomment %}
+ <style type="text/css">
+h1 { color:#c60 ; margin:0px; padding:0px; }
+h2 { padding:5px; background-color:#ccc; }
+h3 { margin:0px; padding:0px; }
+p { margin:0px; padding:0px; }
+
+div.spacer { line-height:0.25cm; }
+
+table { width:100%; padding:0px; }
+table.titre { margin:10px 0px 10px 0px; }
+table.data { margin-top:5px; }
+
+td { width:49%; padding:2px; vertical-align:top; }
+table.titre td { padding:0px; }
+
+.bloc { border: solid 1px black; padding:5px; }
+.gutter { width:2%; }
+
+td.w15 { width:15%; padding:0px; vertical-align:top; }
+td.w25 { width:25%; padding:0px; vertical-align:top; }
+td.w30 { width:30%; padding:0px; vertical-align:top; }
+td.w35 { width:35%; padding:0px; vertical-align:top; }
+td.w50 { width:50%; padding:0px; vertical-align:top; }
+
+td.w20 { width:20%; padding:0px; vertical-align:top; }
+td.w80 { width:80%; padding:0px; vertical-align:top; }
+
+td.w40 { width:40%; padding:0px; vertical-align:top; }
+td.w60 { width:60%; padding:0px; vertical-align:top; }
+ </style>
+</head>
+<body>
+
+<h1>{{ sigma_personne_civilite }} {{ sigma_personne_prenom.title }} {{ sigma_personne_nom.upper }}</h1>
+
+<h2>Renseignements personnels</h2>
+
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Identification</h3>
+ <p>
+ {{ sigma_personne_civilite }} {{ sigma_personne_prenom.title }} {{ sigma_personne_nom.upper }}
+ {% if sigma_personne_nom_jeune_fille %}<br />Nom de jeune fille : {{ sigma_personne_nom_jeune_fille.upper }}{% endif %}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Nationalité : </i></td><td class="w60">{{ sigma_personne_pays_nationalite }}</td></tr>
+ <tr>
+ <td class="w40"><i>Date de naissance : </i></td>
+ <td class="w60">
+ {% with sigma_personne_date_naissance as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Ville de naissance : </i></td><td class="w60">{{ sigma_personne_ville_naissance.title|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Pays de naissance : </i></td><td class="w60">{{ sigma_personne_pays_naissance|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Adresse de correspondance</h3>
+ <p>
+ {{ sigma_personne_adresse }}
+ <br />
+ {% if sigma_personne_ville %}{{ sigma_personne_ville.title }}{% endif %}
+ {% if sigma_personne_region %}, {{ sigma_personne_region }}{% endif %}
+ {% if sigma_personne_code_postal %} {{ sigma_personne_code_postal }} {% endif %}
+ {% if sigma_personne_pays_residence %}<br />{{ sigma_personne_pays_residence }}{% endif %}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Téléphone personnel : </i></td><td class="w60">{{ sigma_personne_tel|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionel : </i></td><td class="w60">{{ sigma_personne_tel_pro|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{ sigma_personne_email|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Situation universitaire</h3>
+ <table>
+ <tr><td class="w20"><i>Statut : </i></td><td class="w80">{{ sigma_dossier_statut_personne|slice:"4:"|default:"n/d" }}</td></tr>
+ <tr><td class="w20"><i>Fonction : </i></td><td class="w80">{{ sigma_dossier_fonction|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Dernier diplôme obtenu</h3>
+ <table>
+ <tr><td class="w40"><i>Intitulé : </i></td><td class="w60">{{ sigma_dossier_intitule_d_diplome|default:"n/d" }}</td></tr>
+ <tr>
+ <td class="w40"><i>Date d'obtention : </i></td>
+ <td class="w60">
+ {% with sigma_dossier_date_d_diplome as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Établissement : </i></td><td class="w60">{{ sigma_dossier_nom_etabl|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Pays : </i></td><td class="w60">{{ sigma_dossier_pays_etabl|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Niveau (nb. années univ.) : </i></td><td class="w60">{{ sigma_dossier_niveau|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc" colspan="3">
+ <h3>Lien avec l'AUF</h3>
+ <table>
+ <tr>
+ <td class="w35"><i>Candidat a déjà participé à un programme de l'AUF : </i></td><td class="w15">{{ sigma_dossier_particip_prog_auf|default:"n/d" }}</td>
+ <td class="w35" style="padding-left:5px;"><i>Candidat a déjà bénéficié d'une bourse AUF : </i></td><td class="w15">{{ sigma_dossier_boursier_auf|default:"n/d" }}</td>
+ </tr>
+ <tr>
+ <td class="w35"><i>Dernier programme participé : </i></td><td class="w15">{{ sigma_dossier_programme|default:"n/d" }}</td>
+ <td class="w35" style="padding-left:5px;"><i>Type de bourse : </i></td><td class="w15">{{ sigma_dossier_categorie_bourse|default:"n/d" }}</td>
+ </tr>
+ <tr>
+ <td class="w35"><i>Année : </i></td><td class="w15">{{ sigma_dossier_annee_programme|default:"n/d" }}</td>
+ <td class="w35" style="padding-left:5px;"><i>Année : </i></td><td class="w15">{{ sigma_dossier_annee_bourse|default:"n/d" }}</td>
+ </tr>
+ </table>
+ </td>
+</tr>
+</table>
+
+<div class="spacer"> </div>
+<table class="titre">
+<tr>
+ <td>
+ <h2>Origine</h2>
+ </td>
+ <td class="gutter"></td>
+ <td>
+ <h2>Accueil</h2>
+ </td>
+</tr>
+</table>
+
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Établissement d'origine</h3>
+ <p>
+ {{ sigma_dossier_o_etablissement|default:"n/d" }}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Faculté, départ. ou labo : </i></td><td class="w60">{{ sigma_dossier_o_sc_faculte|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Ville : </i></td><td class="w60">{{ sigma_dossier_o_sc_ville.title|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Établissement d'accueil</h3>
+ <p>
+ {{ sigma_dossier_a_etablissement|default:"n/d" }}
+ </p>
+ <table>
+ <tr><td class="w40"><i>Faculté, départ. ou labo : </i></td><td class="w60">{{ sigma_dossier_a_sc_faculte|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Ville : </i></td><td class="w60">{{ sigma_dossier_a_sc_ville.title|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Accord scientifique</h3></td>
+ <td class="w60">
+ {% if sigma_dossier_o_sc_civilite %}{{ sigma_dossier_o_sc_civilite }} {% endif %}
+ {% if sigma_dossier_o_sc_prenom %}{{ sigma_dossier_o_sc_prenom.title }} {% endif %}
+ {% if sigma_dossier_o_sc_nom %}{{ sigma_dossier_o_sc_nom.upper }}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Fonction : </i></td><td class="w60">{{ sigma_dossier_o_sc_fonction|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionnel : </i></td><td class="w60">{{ sigma_dossier_o_sc_tel_pro|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{ sigma_dossier_o_sc_email|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Accord scientifique</h3></td>
+ <td class="w60">
+ {% if sigma_dossier_a_sc_civilite %}{{ sigma_dossier_a_sc_civilite }} {% endif %}
+ {% if sigma_dossier_a_sc_prenom %}{{ sigma_dossier_a_sc_prenom.title }} {% endif %}
+ {% if sigma_dossier_a_sc_nom %}{{ sigma_dossier_a_sc_nom.upper }}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Fonction : </i></td><td class="w60">{{ sigma_dossier_a_sc_fonction|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Téléphone professionnel : </i></td><td class="w60">{{ sigma_dossier_a_sc_tel_pro|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{ sigma_dossier_a_sc_email|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+
+ <table>
+ <tr>
+ <td class="w40"><h3>Directeur de thèse</h3></td>
+ <td class="w60">
+ {% if sigma_dossier_m_dir_ori_civilite %}{{ sigma_dossier_m_dir_ori_civilite }} {% endif %}
+ {% if sigma_dossier_m_dir_ori_prenom %}{{ sigma_dossier_m_dir_ori_prenom.title }} {% endif %}
+ {% if sigma_dossier_m_dir_ori_nom %}{{ sigma_dossier_m_dir_ori_nom.upper }}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{ sigma_dossier_m_dir_ori_email|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <table>
+ <tr>
+ <td class="w40"><h3>Directeur de thèse</h3></td>
+ <td class="w60">
+ {% if sigma_dossier_m_dir_acc_civilite %}{{ sigma_dossier_m_dir_acc_civilite }} {% endif %}
+ {% if sigma_dossier_m_dir_acc_prenom %}{{ sigma_dossier_m_dir_acc_prenom.title }} {% endif %}
+ {% if sigma_dossier_m_dir_acc_nom %}{{ sigma_dossier_m_dir_acc_nom.upper }}{% endif %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Adresse électronique : </i></td><td class="w60">{{ sigma_dossier_m_dir_acc_email|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+
+<div class="spacer"> </div>
+<h2>Mobilité</h2>
+
+<table>
+<tr>
+ <td class="bloc">
+ <h3>Période de mobilité - Origine</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date de début : </i></td>
+ <td class="w60">
+ {% with sigmawcs_dossier_o_dd as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de fin : </i></td>
+ <td class="w60">
+ {% with sigmawcs_dossier_o_df as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Nombre de mois : </i></td><td class="w60">{{sigma_dossier_m_alt_mois_origine|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Période de mobilité - Accueil</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date de début : </i></td>
+ <td class="w60">
+ {% with sigmawcs_dossier_a_dd as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de fin : </i></td>
+ <td class="w60">
+ {% with sigmawcs_dossier_a_df as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Nombre de mois : </i></td><td class="w60">{{sigma_dossier_m_alt_mois_accueil|default:"n/d"}}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Thèse</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Date d'inscription en thèse : </i></td>
+ <td class="w60">
+ {% with sigma_dossier_m_date_inscription_these as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr>
+ <td class="w40"><i>Date de soutenance prévue : </i></td>
+ <td class="w60">
+ {% with sigma_dossier_m_date_soutenance_these as date %}
+ {% if date %}
+ {{date|slice:"8:"}}-{{date|slice:"5:7"}}-{{date|slice:"0:4"}}
+ {% else %}
+ n/d
+ {% endif %}
+ {% endwith %}
+ </td>
+ </tr>
+ <tr><td class="w40"><i>Pays de soutenance prévu : </i></td><td class="w60">{{ sigma_dossier_m_pays_soutenance|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Type de thèse : </i></td><td class="w60">{{ sigma_dossier_m_type_these|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Formation en cours</h3>
+ <table>
+ <tr>
+ <td class="w40"><i>Diplôme préparé : </i></td><td class="w60">{{ sigma_dossier_m_intitule_diplome|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Si autre : </i></td><td class="w60">{{ sigma_dossier_m_intitule_diplome_autre|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Niveau (nb. années univ.) : </i></td><td class="w60">{{ sigma_dossier_m_niveau_encours|default:"n/d" }}</td></tr>
+ </table>
+ </td>
+</tr>
+</table>
+<table class="data">
+<tr>
+ <td class="bloc">
+ <h3>Dossier scientifique</h3>
+ <table>
+ <tr><td class="w40"><i>Intitulé du sujet de thèse : </i></td><td class="w60">{{ sigma_dossier_m_intitule_projet|default:"n/d" }}</td></tr>
+ <tr><td class="w40"><i>Mots-clés : </i></td>
+ <td class="w60">
+ {% if sigma_dossier_m_mot_clef1 %}{{ sigma_dossier_m_mot_clef1.upper }}{% endif %}
+ {% if sigma_dossier_m_mot_clef2 %}, {{ sigma_dossier_m_mot_clef2.upper }}{% endif %}
+ {% if sigma_dossier_m_mot_clef3 %}, {{ sigma_dossier_m_mot_clef3.upper }}{% endif %}
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td class="gutter"></td>
+ <td class="bloc">
+ <h3>Discipline</h3>
+ <p>
+ {{ sigma_dossier_m_discipline|default:"n/d" }}
+ </p>
+ </td>
+</tr>
+</table>
+
+</body>
+</html>
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+from wcs.settings import FORMNAME
+
+from lib import getCandidaturesJson, createPdf, createZip
+from models import JsonWcs2JsonSigma, JsonSigma2ObjectSigma
+
+# MAIN
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run tests.py
+ """
+
+ # json WCS
+ candidatures = getCandidaturesJson()
+ nombre = len(candidatures)
+ spams = 0
+ traites = 0
+
+ # rapport : header
+ print 'IMPORT CANDIDATURES : WCS => json => SIGMA'
+ print 'Formulaire : %s' % FORMNAME
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nombre)
+ print '--------------------------------------------------'
+
+ # TESTS
+ jj = JsonWcs2JsonSigma()
+ jo = JsonSigma2ObjectSigma()
+# candidature = candidatures[3]
+ for candidature in candidatures :
+ if candidature['wcs_workflow_status'] == 'SPAM':
+ spams = spams + 1
+ else:
+ candidature = jj.mapper(candidature)
+ # json
+ candidature = jj.cleanup(candidature)
+ candidature = jj.convert(candidature)
+ # objets SIGMA
+ save = False
+ p = jo.createPersonne(candidature, save)
+ d = jo.createDossier(candidature, p, save)
+ do = jo.createDossierOrigine(candidature, d, save)
+ da = jo.createDossierAccueil(candidature, d, save)
+ dm = jo.createDossierMobilite(candidature, d, save)
+ pieces = jo.createDossierPieces(candidature, d, save)
+ save = True
+ p = jo.createPersonne(candidature, save)
+ d = jo.createDossier(candidature, p, save)
+ do = jo.createDossierOrigine(candidature, d, save)
+ da = jo.createDossierAccueil(candidature, d, save)
+ dm = jo.createDossierMobilite(candidature, d, save)
+ pieces = jo.createDossierPieces(candidature, d, save)
+ traites = traites + 1
+
+ # RÉSULTATS
+ if jj.convert_ok:
+ print 'OK : Test de conversion passé avec succès.'
+ else:
+ print 'ERREUR : Tests de conversion ont échoué pour les cas suivants :'
+ jj.convert_errors.sort()
+ for error in jj.convert_errors:
+ print error
+ print '--------------------------------------------------'
+ print 'ERREUR : %d erreurs lors de traitement' % len(jj.convert_errors)
+ if jo.creation_django_ok:
+ print 'Ok : Test de création des objets Django passé avec succès.'
+ if jo.creation_db_ok:
+ print 'Ok : Test de sauvegarde dans DB passé avec succès.'
+
+ # rapport : footer
+ print '--------------------------------------------------'
+ print 'Total spams = %d sur %d' % (spams, nombre)
+ print 'Total traités = %d sur %d' % (traites, nombre)
+ print 'Total = %d sur %d' % (spams + traites, nombre)
+ print '--------------------------------------------------'
--- /dev/null
+# -*- encoding: utf-8 -*-
+
+from django.conf.urls.defaults import *
+
+urlpatterns = patterns('',
+ url(r'^import/$', 'wcs.views.importDossiersCandidaturesWcs', name='import'),
+)
--- /dev/null
+# -=- encoding: utf-8 -=-
+
+import os
+from simplejson import loads
+import urllib2
+import zipfile
+
+from sigma_v1.models import Dossier
+from sigma_v1.settings import PIECES_SUFFIXE as PIECES_SIGMA_SUFFIXE
+from wcs.settings import PIECES_FIELDNAME, PIECES_SUFFIXE as PIECES_WCS_SUFFIXE
+from wcs.settings import MOBILITE, FORMNAME, WCS_SIGMA_URL, WCS_SIGMA_USER, WCS_SIGMA_PASS
+
+from lib import getCandidaturesJson
+from models import JsonWcs2JsonSigma, JsonSigma2ObjectSigma
+
+def importDossiersCandidaturesWcs(appel):
+ """Appel distant sur WCS et copie locale de tout le répertoire d'un appel
+ """
+ def retrieve(url, filename, force=True):
+ written = False
+ if not os.path.exists(filename) or force:
+ pagehandle = urllib2.urlopen(url)
+ f = file(filename, 'wb')
+ f.write(pagehandle.read())
+ f.close()
+ pagehandle.close()
+ written = True
+ return written
+
+ # conf
+ src = '%s/%s' % (WCS_SIGMA_URL, appel.wcs_form_name)
+ dst = 'docs/%s' % (appel.wcs_form_name)
+ dossierDir = 'data'
+ meta = [
+ 'field-names.json',
+ 'field-names.txt',
+ 'last-run.log',
+ 'liste-dossiers.json',
+ ]
+ erreurs = []
+
+ # local
+ if not os.path.exists(dst):
+ dstData = '%s/%s' % (dst, dossierDir)
+ os.makedirs(dstData) # mode 0777 ?
+
+ # accès WCS
+ passman = urllib2.HTTPPasswordMgrWithDefaultRealm()
+ passman.add_password(None, WCS_SIGMA_URL, WCS_SIGMA_USER, WCS_SIGMA_PASS)
+ authhandler = urllib2.HTTPBasicAuthHandler(passman)
+ opener = urllib2.build_opener(authhandler)
+ urllib2.install_opener(opener)
+
+ # rapport : header
+ print '--------------------------------------------------'
+ print 'IMPORT WCS'
+ print 'Formulaire : %s' % (appel.wcs_form_name)
+ print '--------------------------------------------------'
+
+ # import meta
+ print 'Import des fichiers de méta-données sur le formulaire :'
+ os.chdir(dst)
+
+ nb_meta = len(meta)
+ nb_meta_done = 0
+ for filename in meta:
+ url = '%s/%s' % (src, filename)
+ rapport = '%s : %s' % ('meta', filename)
+ try:
+ retrieve(url, filename)
+ print rapport
+ nb_meta_done = nb_meta_done + 1
+ except urllib2.HTTPError:
+ erreurs.append(rapport)
+ print '--------------------------------------------------'
+
+ # import data
+ print 'Import des dossiers de candidature (json et pièces jointes) :'
+ f = open('liste-dossiers.json', 'r')
+ data = f.read()
+ f.close()
+ listjson = loads(data, encoding='utf-8')
+ listjson.sort()
+ os.chdir(dossierDir)
+
+ nb_json = len(listjson)
+ nb_json_done = 0
+ nb_json_imported = 0
+ nb_pieces = 0
+ for id, piece in PIECES_WCS_SUFFIXE.items():
+ if piece:
+ nb_pieces = nb_pieces + 1
+ nb_pieces = nb_pieces * nb_json
+ nb_pieces_done = 0
+ for filename in listjson:
+ # json
+ url = '%s/%s/%s' % (src, dossierDir, filename)
+ rapport = '%s : %s' % ('json', filename)
+ try:
+ imported = retrieve(url, filename, force=False)
+ if imported :
+ print rapport
+ nb_json_imported = nb_json_imported + 1
+ nb_json_done = nb_json_done + 1
+ except urllib2.HTTPError:
+ erreurs.append(rapport)
+
+ # pièces jointes
+ f = open(filename, 'r')
+ data = f.read()
+ f.close()
+ json = loads(data, encoding='utf-8')
+ for id, piece in PIECES_WCS_SUFFIXE.items():
+ if piece:
+ try:
+ pieceName = json[piece]
+ url = '%s/%s/%s' % (src, dossierDir, pieceName)
+ rapport = '* %s : %s' % (piece, pieceName)
+ except KeyError:
+ erreurs.append(rapport)
+ try:
+ retrieve(url, pieceName)
+ print rapport
+ nb_pieces_done = nb_pieces_done + 1
+ except urllib2.HTTPError:
+ erreurs.append(rapport)
+ print ''
+ print '--------------------------------------------------'
+
+ if erreurs:
+ print '%d ERREURS' % (len(erreurs))
+ for erreur in erreurs:
+ print erreur
+ print '--------------------------------------------------'
+
+ # rapport : footer
+ print 'FIN IMPORT WCS'
+ print 'Méta traités : %d sur %d' % (nb_meta_done, nb_meta)
+ print 'Json traités : %d sur %d' % (nb_json_done, nb_json)
+ print 'Json importés : %d sur %d' % (nb_json_imported, nb_json)
+ print 'Pièces traitées : %d sur %d' % (nb_pieces_done, nb_pieces)
+ print '--------------------------------------------------'
+
+
+#def getCandidaturesJsonWcs(request, appel):
+# retourne la liste locale des json importés de WCS
+
+#def exportSigmaData(request, appel):
+# exporte dans la base de données SIGMA les données des candidatures json de WCS
+
+def exportSigmaFiles(appel):
+ """Déplace les fichiers ZIP et PDF de la candidature à leur emplacement final sigma.
+ """
+
+ # conf
+ dossierDir = 'data'
+ src = 'docs/%s/%s' % (appel.wcs_form_name, dossierDir)
+ dst = 'docs/%s/export' % (appel.wcs_form_name)
+ dstZip = "docs/%s/candidatures" % (appel.wcs_form_name)
+ erreurs = []
+
+ if not os.path.exists(dst):
+ os.makedirs(dst) # mode 0777 ?
+ if not os.path.exists(dstZip):
+ os.mkdir(dstZip) # mode 0777 ?
+
+ mappingPiecesSuffixes = {}
+ for id, suffixe_wcs in PIECES_WCS_SUFFIXE.items():
+ if suffixe_wcs:
+ # nom champ json normalisé pour cette pièce
+ field = PIECES_FIELDNAME[id]
+ # suffixe SIGMA
+ suffixe_sigma = PIECES_SIGMA_SUFFIXE[id]
+ # mapping
+ mappingPiecesSuffixes[field] = (suffixe_wcs, suffixe_sigma)
+
+ # rapport : header
+ print '--------------------------------------------------'
+ print 'EXPORT DOSSIERS DE CANDIDATURE (FICHIERS) : SIGMAWCS => SIGMA'
+ print 'Formulaire : %s' % (appel.wcs_form_name)
+ print '--------------------------------------------------'
+
+ # création du répertoire local pour rsync
+ print "Création du répertoire locale des dossiers de candidature (fichiers renommés) :"
+ exportCandidaturesPath = "%s/%d.zip" % (dstZip, MOBILITE)
+ archive = zipfile.ZipFile(exportCandidaturesPath, "w", zipfile.ZIP_STORED)
+
+ candidatures = getCandidaturesJson()
+ nb_cand = len(candidatures)
+ nb_spam = 0
+ nb_cand_done = 0
+
+ jj = JsonWcs2JsonSigma()
+ for candidature in candidatures :
+ if candidature['wcs_workflow_status'] == 'SPAM':
+ nb_spam = nb_spam + 1
+ else:
+ candidature = jj.mapper(candidature)
+ candidature = jj.cleanup(candidature)
+ candidature = jj.convert(candidature)
+ filename = candidature['wcs_json_filename']
+ basename = filename.rstrip('.json')
+ nb_cand_done = nb_cand_done + 1
+ print '%d : %s' % (nb_cand_done, basename)
+ # pièces jointes : renommage et copie
+ for field, mapping in mappingPiecesSuffixes.items():
+ nom_src = candidature[field]
+ nom_dst = nom_src.replace(mapping[0], mapping[1])
+ # pièces peuvent être facultatives
+ if nom_src:
+ path_src = '%s/%s' % (src, nom_src)
+ path_dst = '%s/%s' % (dst, nom_dst)
+ fsrc = open(path_src, 'r')
+ fdst = file(path_dst, 'wb')
+ fdst.write(fsrc.read())
+ fdst.close()
+ fsrc.close()
+ # formulaire (.pdf) et dossier complet (.zip) : copie
+ extensions = ('.pdf', '.zip')
+ for ext in extensions:
+ nom_src = basename + ext
+ nom_dst = nom_src
+ path_src = '%s/%s' % (src, nom_src)
+ path_dst = '%s/%s' % (dst, nom_dst)
+ rapport = '* %s' % (path_src)
+ if os.path.exists(path_src):
+ fsrc = open(path_src, 'r')
+ fdst = file(path_dst, 'wb')
+ fdst.write(fsrc.read())
+ fdst.close()
+ fsrc.close()
+ # zip de tous les dossiers de candidature (zip des zips)
+ if ext == '.zip':
+ zipname = '%s-%s-%s.zip' % (candidature['sigma_personne_nom'].upper(), \
+ candidature['sigma_personne_prenom'].lower().title(), \
+ candidature['sigma_dossier_m_discipline'])
+ archive.write(path_src, zipname)
+ print rapport
+ else:
+ erreurs.append(rapport)
+ print ''
+ print '--------------------------------------------------'
+ archive.close()
+
+ # déplacement de l'archive sur le serveur
+ # attention : archive plus créée (répertoire rsyncé)
+ # todo : avec fabric
+
+ # extraction de l'archive dans les sources SIGMA
+ # attention : archive plus créée (répertoire rsyncé)
+ # todo :
+ # from wcs.conf import MOBILITE
+ # project/modules/candidatures/docs/%s/ % (MOBILITE)
+
+ # rapport : erreurs
+ if erreurs:
+ print '%d ERREURS' % (len(erreurs))
+ for erreur in erreurs:
+ print erreur
+ print '--------------------------------------------------'
+
+ # rapport : footer
+ print 'FIN EXPORT DOSSIERS'
+ print 'Candidatures : %d' % (nb_cand)
+ print 'Spams : %d sur %d' % (nb_spam, nb_cand)
+ print 'Json traités : %d sur %d' % (nb_cand_done, nb_cand)
+# print 'PDF traités : %d sur %d' % (nb_pdf_done, nb_cand_done)
+# print 'ZIP traités : %d sur %d' % (nb_zip_done, nb_cand_done)
+ print '--------------------------------------------------'
+
+# MAIN
+if __name__ == "__main__":
+ """
+ bin/django shell # python manage.py shell
+ >>> cd wcs
+ >>> run views.py
+ """
+ # candidats déjà dans SIGMA pour cet appel
+ existants = set()
+ try:
+ dossiers = Dossier.objects.filter(mobilite=MOBILITE)
+ except:
+ dossiers = Dossier.objects.none()
+ for dossier in dossiers:
+ existants.add(dossier.personne.email)
+ nb_existants = len(existants)
+
+ # json WCS
+ candidatures = getCandidaturesJson()
+ nombre = len(candidatures)
+ spams = 0
+ traites = 0
+
+ # rapport : header
+ print 'IMPORT CANDIDATURES : WCS => json => SIGMA'
+ print 'Formulaire : %s' % FORMNAME
+ print '--------------------------------------------------'
+ print 'Nombre à traiter = %d' % (nombre)
+ print '--------------------------------------------------'
+ # IMPORT
+ jj = JsonWcs2JsonSigma()
+ jo = JsonSigma2ObjectSigma()
+ for candidature in candidatures :
+ candidature = jj.mapper(candidature)
+ print 'WCS %s : en cours...' % candidature['wcs_num_dossier']
+ if candidature['wcs_workflow_status'] == 'SPAM':
+ spams = spams + 1
+ elif candidature['sigma_personne_email'] in existants:
+ print 'existant : %s' % (candidature['sigma_personne_email'])
+ else :
+ # json
+ candidature = jj.cleanup(candidature)
+ candidature = jj.convert(candidature)
+ # objets SIGMA
+ p = jo.createPersonne(candidature)
+ d = jo.createDossier(candidature, p)
+ do = jo.createDossierOrigine(candidature, d)
+ da = jo.createDossierAccueil(candidature, d)
+ dm = jo.createDossierMobilite(candidature, d)
+ pieces = jo.createDossierPieces(candidature, d)
+ traites = traites + 1
+ print '%d - %s' % (traites, p)
+
+ # rapport : footer
+ print '--------------------------------------------------'
+ print 'Total existants = %d sur %d' % (nb_existants, nombre)
+ print 'Total spams = %d sur %d' % (spams, nombre)
+ print 'Total traités = %d sur %d' % (traites, nombre)
+ print 'Total = %d sur %d' % (nb_existants + spams + traites, nombre)
+ print '--------------------------------------------------'