====== Quickstart API Python ====== ===== Base de données ===== ==== Module db_common ==== Le module db_common propose des fonction utilitaires pour effectuer des requêtes sur la base de données. === Lire plusieurs lignes === Nous allons utiliser la fonction ''dbgenericgetrows()'' dont la signature est la suivante: def dbgenericgetrows(usession, itbl, icond=None, ifldorder=None, ifldordersens="A", limit=None, limistart = 0) """ Return rows from a table. Select all the fields. :type usession: session :param usession: NCHP Session :type itbl: string :param itbl: table to fetch :type icond : list :param icond: list of conditions :rtype: list :return: A list of row, each row described by a dictionnary. """ Exemple d'utilisation pour sélectionner toutes les lignes de la table ''test'' rows = db_common.dbgenericgetrows( usession = gses, itbl = "factfour", ) pprint.pprint(rows) >>> [{ 'FACTFOUR_CPPID': 0L, 'FACTFOUR_DATE': datetime.datetime(2022, 6, 10, 11, 59, 55), 'FACTFOUR_DATEDEPOTSAE': None, 'FACTFOUR_DATEFACT': datetime.datetime(2016, 9, 29, 0, 0), 'FACTFOUR_DEPOTSAE': 0, 'FACTFOUR_FOURNISSEURID': 36L, 'FACTFOUR_HT': 1350.0, 'FACTFOUR_ID': 13L, 'FACTFOUR_NUMFACTURE': 'QUAL_00000000003821', 'FACTFOUR_TTC': 1620.0, 'FACTFOUR_TVA': 270.0 }, { 'FACTFOUR_CPPID': 0L, 'FACTFOUR_DATE': datetime.datetime(2022, 6, 10, 14, 36, 39), 'FACTFOUR_DATEDEPOTSAE': datetime.datetime(2022, 6, 10, 14, 45, 14), 'FACTFOUR_DATEFACT': datetime.datetime(2016, 9, 29, 0, 0), 'FACTFOUR_DEPOTSAE': 1, 'FACTFOUR_FOURNISSEURID': 36L, 'FACTFOUR_HT': 1350.0, 'FACTFOUR_ID': 14L, 'FACTFOUR_NUMFACTURE': 'QUAL_00000000003821', 'FACTFOUR_TTC': 1620.0, 'FACTFOUR_TVA': 270.0 }, { 'FACTFOUR_CPPID': 380066452L, 'FACTFOUR_DATE': None, 'FACTFOUR_DATEDEPOTSAE': None, 'FACTFOUR_DATEFACT': None, 'FACTFOUR_DEPOTSAE': 0, 'FACTFOUR_FOURNISSEURID': 0L, 'FACTFOUR_HT': 0.0, 'FACTFOUR_ID': 15L, 'FACTFOUR_NUMFACTURE': '0', 'FACTFOUR_TTC': 0.0, 'FACTFOUR_TVA': 0.0 } ] Un exemple maintenant en ajoutant des conditions rows = db_common.dbgenericgetrows( usession = gses, itbl = "factfour", icond = db_common.buildcondandor( tbl = "factfour", fields = ["FACTFOUR_CPPID", "FACTFOUR_DEPOTSAE"], values = ["0", "1"] ) ) pprint.pprint(rows) >>> [{ 'FACTFOUR_CPPID': 0L, 'FACTFOUR_DATE': datetime.datetime(2022, 6, 10, 11, 59, 55), 'FACTFOUR_DATEDEPOTSAE': None, 'FACTFOUR_DATEFACT': datetime.datetime(2016, 9, 29, 0, 0), 'FACTFOUR_DEPOTSAE': 0, 'FACTFOUR_FOURNISSEURID': 36L, 'FACTFOUR_HT': 1350.0, 'FACTFOUR_ID': 13L, 'FACTFOUR_NUMFACTURE': 'QUAL_00000000003821', 'FACTFOUR_TTC': 1620.0, 'FACTFOUR_TVA': 270.0 } ] La fonction ''db_common.buildcondandor(...)'' qui est utilisée pour construire les conditions ne gère que des conditions utilisant le même opérateur qui par défaut est l'opérateur ''=''. === Insérer une ligne === On utilise la fonction ''dbgenericinsert()'' dont la signature est la suivante: def dbgenericinsert(usession, itbl, iflds, ivalues, dbtype = None): """ Generic function to insert a record in a system table and get its primary key. > ret = db_common.dbgenericinsert(session, "test", ["fld1", "fld2", "fldx"], [1, 2, 'foo']) Execute query : insert into test (fld1,fld2,fldx) values (1,2,'foo'); ret contains new generated ID :type usession: session :param usession: NCHP Session :type itbl: string :param itbl: table to fetch :type iflds: list :param iflds: fields to put values in :type ivalues: list :param ivalues: Values to put in fields :type dbtype: string :param dbtype: database type :rtype: long :return: new ID of record, or 0 if insert failed. """ Voici un exemple: new_rsid = db_common.dbgenericinsert( usession = gses, itbl = "client", iflds = ["CLIENT_NUMERO", "CLIENT_NOM"], ivalues = ["123456", "Client 123456"] ) if new_rsid <= 0: print("Error code :{}, error msg: {}".format(gses.db.db_errorcode, gses.db.db_errormsg)) Il est important de tester le retour afin de s'assurer que l'insertion a bien été faite et sinon on peut récupérer le code d'erreur et le message retourné par la base de données via ''gses.db.db_errorcode'' et ''gses.db.db_errormsg'' ==== Classe sql_db ==== Une autre façon de faire des requêtes est d'utiliser directement la classe ''sql_db'' qui est implémentée spécifiquement par chaque module dédié à un SGBD donné. Par exemple pour MySQL l'API EzGED propose le module ''db_mysql'' En général vous n'avez pas besoin d'instancier directement la classe ''sql_db'' car une instance est attachée à la session EzGED que vous aurez ouverte. >>> import common >>> gses = common.dbses() >>> gses.db Pour exécuter une requête on peut alors procéder ainsi import common gses = common.dbses() result = gses.db.query("SELECT * FROM societycache;") if result is not None: with result: for row in result: print(row) L'utilisation de with et l'itération sur l'objet result ne sont possibles qu'à partir de la version **3.4.23127**\\ Pour les versions antérieures voir [[docs:dev:api:python:db]] qui présente d'autres manières de procéder. Ce qui nous affichera quelque chose comme ça: {'SOCIETYCACHE_SIREN': '552ZZ081317', 'SOCIETYCACHE_SOCIETYNAME': 'ELECTRICITE DE FRANCE', 'SOCIETYCACHE_ID': 5L} {'SOCIETYCACHE_SIREN': '515180115', 'SOCIETYCACHE_SOCIETYNAME': 'EZDEV', 'SOCIETYCACHE_ID': 24L} ... ===== Logging ===== EzGED utilise le module python standard ''logging'' pour la journalisation de messages. Les loggers suivants peuvent être utilisés: * ezged => toute journalisation concernant EzGED. * jobd => journalisation concernant le serveur de travaux * convd => journalisation dans le cadre du serveur de conversion * eztest => journalisation pour les scripts de test Le logger a utiliser dépend donc du contexte dans lequel votre code est susceptible de s'exécuter. Donc pour obtenir le logger ''ezged'' il suffirait de faire import logging ezged_logger = logging.getLogger("ezged") Mais vous n'êtes pas obligé de le connaitre et le plus simple reste d'utiliser notre fonction ''_common.get_logger()'' afin de récupérer le logger correspondant au contexte d'exécution. import _common app_logger = _common.get_logger() ''_common'' est un module python EzGED qui contient de nombreuses fonctions utiles et globalement utilisées dans toute l'application. Dont notamment la fonction ''get_logger()'' ===== Journaliser les activités ===== Dans EzGED un certain nombre d'entités tels que les fiches descriptives ou les fiches sont l'objet d'activités ou d'évènements. Pour ajouter une activité à une fiche descriptive on peut par exemple utiliser la fonction ''dblog.dblogaddindexifnotexist''. Exemple: import dblog dblog.dblogaddindexifnotexist( usession = gses, tbl = "facture", rsid = 12, secusrid = 1, action = "C", text = log_msg, tstamp = _common.tsatamp() ) L'appel ci-dessus va créer une nouvelle "activité" pour la facture d'identifiant 12. Il s'agit d'une activité de type "Création" indiqué par le paramètre ''action = "C"''. ===== Travaux ===== ==== Créer un travail EzGED ==== === Script d'étape === La logique d'exécution des étapes d'un travail dans EzGED sont implémentées via des scripts pythons. Le plus simple est de partir d'un [[docs:dev:python:templates|template de script]]. === Progression du script === On peut mettre à jour l'avancement de l'exécution de l'étape en utilisant la fonction ''libjobdext.jobstateupdate_percent'': libjobdext.jobstateupdate_percent(gses, jobqueueid, jobstepnumber, jobstatepercent) ''jobstepnumber'' est le numéro de l'étape. On peut passer ''0'' et laisser la fonction le déterminer. ''value'' est la valeur d'avancement du job où une valeur de ''1'' représente une progression de 100%. Exemple pour positionner une progression de 30% sur le travail 1234 libjobdext.jobstateupdate_percent(gses, jobqueueid=1234, jobstepnumber=0, jobstatepercent=0.3) === Lecture/Ecriture des fichiers de travail === Les fichiers de travail sont les fichiers qu'utilisent les scripts pour écrire ou lire des informations nécessaires à la réalisation du script et donc de son travail. Parmi les principaux on retrouve ''indexes'', ''fssto'' et ''docpak'' Ces fichiers sont des fichiers textes contenant des données structurées en colonnes de longueur fixe. Pour faciliter leur manipulation on utilise le module ''scriptfiles'' ==== Instancier un travail ==== import libjobdext jobid, activated = libjobdext.jobcreatefromtpl( usession = usession, id = "MYJOBCODE", secusrid = usession.userid, params = ["param1","param2"], paramvalues = ["value1","value2"], active = 0 ) ''MYJOBCODE'' est le code du travail à instancier. Le code peut être retrouvé en allant consulter la liste des Travaux de référence. La fonction retourne l'identifiant du travail et indique si le travail a été activé ou non. ==== Activer un travail ==== Dans l'exemple précédent nous avons instancier un travail en passant le paramètre ''active'' à 0 donc le travail a été créé (on peut le voir dans la liste des travaux depuis l'interface web par exemple) mais il n'est pas actif. Ceci permet par exemple de copier des fichiers dans le répertoire du travail (qui aura été créé au moment de son instanciation). Une fois que la mise en place est terminée on peut finalement l'activer. libjobdext.job_activate(usession, jobid) ===== Fichiers ===== ==== Attacher un fichier à une fiche ==== Nous avons besoins d'importer les modules suivants import fs import docpak La première consiste à stocker le fichier new_fsfileid = fs.fsfilesto(gses, filepath, ifssaid = 0) Si le fichier a bien été stocké alors ''new_fsfileid'' est un entier strictement positif. Nous pouvons ensuite attacher le fichier stocké à l'enregistrement (la fiche). docpakid = docpaknew(gses, itbl="matable", irsid=1234 , ifiles=[new_fsfileid]) ==== Obtenir les fichiers d'une fiche ==== Nous avons besoin d'importer le module suivant import docpak Nous avons ensuite besoin de deux informations: * Le nom de la table documentaire. * L'identifiant d'enregistrement de la fiche. fichiers = docpak.getfilesforrsid(gses, "contratsm", 81) print(fichiers) [ ('D:\\nchp\\var\\nchp\\instance\\EMDOM\\DEFTSA\\00000013\\ed\\4d\\4RGETML2.pdf','contrat_4201.pdf') ] Le même appel avec l'option moreinfo=True fichiers = docpak.getfilesforrsid(gses, "contratsm", 81) print(fichiers) [('D:\\nchp\\var\\nchp\\instance\\EMDOM\\DEFTSA\\00000013\\ed\\4d\\4RGETML2.pdf', 'contrat_4201.pdf', 22864L, #Identifiant du fichier 'ed4d2b8b04b3b1861a450b35210114c75ebae4dc', #Empreinte md160 du fichier 'application/pdf', #Type mime 1L #Rang du fichier ) ] ===== Scripts COLD ===== ==== Lire un fichier d'état (scriptfile) ====