From a51c3b717c6e7f87eb0490b9d3010c30f69eb359 Mon Sep 17 00:00:00 2001 From: Guillaume Raffy Date: Tue, 15 Oct 2024 17:20:52 +0200 Subject: [PATCH] finalisation de la documentation et nettoyage MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - finalisation du graphe de production - nettoyage des codes python et refactoring pour qu'ils prennent des arguments - ajout d'un makefile qui permet d'automatiser les operations automatisables, mais aussi de documenter la procédure travail lié à [https://bugzilla.ipr.univ-rennes.fr/show_bug.cgi?id=3959] --- achats-ipr/2019/it-cnrs-l1p5.tsv | 85 +++++ achats-ipr/2019/it-ur1-l1p5.tsv | 23 ++ procedures/labo1.5/materiel-info-graph.dot | 79 ++-- procedures/labo1.5/materiel-info-graph.svg | 399 +++++++++++++-------- procedures/labo1.5/materiel-info.md | 139 ++++++- src/Makefile | 41 +++ src/geslabt001_to_itorders.py | 13 +- src/geslabt002_to_itorders.py | 49 ++- src/sifact002_to_itorders.py | 60 ++-- 9 files changed, 663 insertions(+), 225 deletions(-) create mode 100644 achats-ipr/2019/it-cnrs-l1p5.tsv create mode 100644 achats-ipr/2019/it-ur1-l1p5.tsv create mode 100644 src/Makefile diff --git a/achats-ipr/2019/it-cnrs-l1p5.tsv b/achats-ipr/2019/it-cnrs-l1p5.tsv new file mode 100644 index 0000000..45f8602 --- /dev/null +++ b/achats-ipr/2019/it-cnrs-l1p5.tsv @@ -0,0 +1,85 @@ +id Modele Fabricant Type +cnrs_71 macbook pro 13 (2017) apple pc portable +cnrs_79 brilliance 258B6QUEB philips écran +cnrs_89 xps 9365 dell pc portable +cnrs_90 wm126 dell souris +cnrs_210 latitude 5590 dell pc portable +cnrs_212 latitude 5590 dell pc portable +cnrs_214 latitude 7490 dell pc portable +cnrs_216 latitude 7490 dell pc portable +cnrs_275 disque dur +cnrs_313 KB216 dell clavier +cnrs_369 disque dur +cnrs_370 station d'accueil +cnrs_490 latitude 5490 dell pc portable +cnrs_491 KB216 dell clavier +cnrs_525 dell souris +cnrs_525 dell souris +cnrs_525 dell souris +cnrs_525 dell souris +cnrs_526 dell clavier +cnrs_526 dell clavier +cnrs_526 dell clavier +cnrs_526 dell clavier +cnrs_595 moniteur 27 pouces dell écran +cnrs_595 moniteur 27 pouces dell écran +cnrs_602 magic keyboard avec pavé numérique apple clavier +cnrs_623 station d'accueil +cnrs_656 optiplex 7060 dell pc fixe +cnrs_659 my passport western digital disque dur +cnrs_659 my passport western digital disque dur +cnrs_659 my passport western digital disque dur +cnrs_660 latitude 5590 dell pc portable +cnrs_777 optiplex 7060 dell pc fixe +cnrs_778 moniteur 23.8 pouces dell écran +cnrs_805 precision 3630 dell pc fixe +cnrs_828 my passport western digital disque dur +cnrs_828 my passport western digital disque dur +cnrs_828 my passport western digital disque dur +cnrs_829 moniteur 24 pouces panoramique professionnel dell écran +cnrs_1030 station d'accueil +cnrs_1148 disque dur sata/sas dell disque dur +cnrs_1170 hl-l2310d brother imprimante +cnrs_1171 canoscan lide 300 canon scanner +cnrs_1220 moniteur 27 pouces dell écran +cnrs_1268 disque dur interne disque dur +cnrs_1437 moniteur 22 pouces dell écran +cnrs_1919 disque dur hot plug 8 to dell disque dur +cnrs_1919 disque dur hot plug 8 to dell disque dur +cnrs_1919 disque dur hot plug 8 to dell disque dur +cnrs_1919 disque dur hot plug 8 to dell disque dur +cnrs_1919 disque dur hot plug 8 to dell disque dur +cnrs_1956 macbook pro 15 +cnrs_2007 disque dur hot plug 8 to dell disque dur +cnrs_2007 disque dur hot plug 8 to dell disque dur +cnrs_2007 disque dur hot plug 8 to dell disque dur +cnrs_2007 disque dur hot plug 8 to dell disque dur +cnrs_2007 disque dur hot plug 8 to dell disque dur +cnrs_2260 aero 15 oled gigabyte pc portable +cnrs_2297 sandisk extreme portable sandisk disque dur +cnrs_2297 sandisk extreme portable sandisk disque dur +cnrs_2297 sandisk extreme portable sandisk disque dur +cnrs_2297 sandisk extreme portable sandisk disque dur +cnrs_2298 my passport ssd western digital disque dur +cnrs_2305 compact optimal mouse souris +cnrs_2306 b110 logitech souris +cnrs_2306 b110 logitech souris +cnrs_2324 disque dur interne disque dur +cnrs_2534 disque dur hot plug 8 to dell disque dur +cnrs_2535 latitude 7490 dell pc portable +cnrs_2536 KB216 dell clavier +cnrs_2537 Laser USB Mouse Silver & black dell souris +cnrs_2605 U3219Q dell écran +cnrs_2724 precision 7540 dell pc portable +cnrs_2726 optiplex 5070 dell pc fixe +cnrs_2745 disque dur hot plug 8 to dell disque dur +cnrs_2767 860 evo samsung disque dur +cnrs_2800 WD19TB dell station d'accueil +cnrs_2806 precision 7540 dell pc portable +cnrs_2810 WD19 dell station d'accueil +cnrs_2843 latitude 3400 dell pc portable +cnrs_2872 écran panoramique 34 pouces dell écran +cnrs_2873 latitude 5300 dell pc portable +cnrs_2897 kb216 dell clavier +cnrs_2898 dell souris +cnrs_2958 disque dur diff --git a/achats-ipr/2019/it-ur1-l1p5.tsv b/achats-ipr/2019/it-ur1-l1p5.tsv new file mode 100644 index 0000000..7773d2c --- /dev/null +++ b/achats-ipr/2019/it-ur1-l1p5.tsv @@ -0,0 +1,23 @@ +id Modele Fabricant Type +ur1_21 latitude 5590 dell pc portable +ur1_39 1 To disque dur +ur1_233 dell pc portable +ur1_237 latitude 3400 dell pc portable +ur1_238 optiplex 5070 dell pc fixe +ur1_292 disque dur externe disque dur +ur1_292 disque dur externe disque dur +ur1_292 disque dur externe disque dur +ur1_292 disque dur externe disque dur +ur1_321 p2719h dell écran +ur1_323 led brilliance p-line 32" philips écran +ur1_461 écran panormaique 27" dell écran +ur1_509 dell pc portable +ur1_527 latitude 7490 dell pc portable +ur1_527 u2719d dell écran +ur1_530 latitude dell pc portable +ur1_556 latitude 7400 dell pc portable +ur1_578 magic mouse 2 apple souris +ur1_583 optiplex 7070 dell pc fixe +ur1_589 moniteur 27" dell écran +ur1_592 externe 2 To disque dur +ur1_614 moniteur 27" dell écran diff --git a/procedures/labo1.5/materiel-info-graph.dot b/procedures/labo1.5/materiel-info-graph.dot index 4ca2453..256c418 100644 --- a/procedures/labo1.5/materiel-info-graph.dot +++ b/procedures/labo1.5/materiel-info-graph.dot @@ -4,51 +4,70 @@ digraph { node [shape="rectangle", style="filled,rounded", penwidth=0, fillcolor="cyan"] geslab [label="geslab\n(cnrs)"]; cnrs_all_xls [label="cnrs_all_xls\n(commandes-2019-cnrs-t002.xls)"]; - cnrs_all_tsv [label="cnrs_all_tsv\n(commandes-2019-cnrs-t002.tsv)"]; - cnrs_it_orders [label="cnrs_it_orders\n(commandes-it-2019-cnrs-002.tsv)"]; - cnrs_it_orders_labo1p5 [label="cnrs_it_orders_labo1p5\n(it-cnrs-l1p5.tsv)"]; + cnrs_all_tsv [label="cnrs_all_tsv\n(commandes-2019-cnrs-t002.tsv,\n1991 items)"]; + cnrs_it_orders [label="cnrs_it_orders\n(commandes-it-2019-cnrs-002.tsv,\n224 items)"]; + cnrs_it_orders_ann [label="cnrs_it_orders_ann\n(commandes-it-2019-cnrs-002-annotated.tsv,\n224 items)"]; + cnrs_it_orders_labo1p5 [label="cnrs_it_orders_labo1p5\n(it-cnrs-l1p5.tsv, \n84 items)"]; + cnrs_paper_orders [label="cnrs_paper_orders\n(archives papier cnrs)"] sifac [label="sifac\n(ur1)"]; - ur1_all_orders [label="ur1_all_orders\n(2019..xls)"]; - ur1_it_orders [label="ur1_it_orders\n(commandes-it-2019-ur1-002.tsv)"]; + ur1_all_orders [label="ur1_all_orders\n(2019..xls\n610 items)"]; + ur1_it_orders [label="ur1_it_orders\n(commandes-it-2019-ur1-002.tsv,\n33 items))"]; + ur1_it_orders_ann [label="ur1_it_orders_ann\n(commandes-it-2019-ur1-002-annotated.tsv,\n33 items)"]; - ur1_it_orders_labo1p5 [label="ur1_it_orders_labo1p5\n(it-ur1-l1p5.tsv)"]; + ur1_it_orders_labo1p5 [label="ur1_it_orders_labo1p5\n(it-ur1-l1p5.tsv,\n22 items)"]; + ur1_paper_orders [label="ur1_paper_orders\n(archives papier ur1)"] - it_orders_labo1p5 [label="it_orders_labo1p5\n(it-l1p5.tsv)"]; + it_orders_labo1p5 [label="it_orders_labo1p5\n(it-l1p5.tsv,\n106 items)"]; - # actions + # operations node [shape="rectangle", style="filled,rounded", penwidth=0, fillcolor="pink"] - extraction_cnrs [label="extraction ngiquiaux"]; - cnrs_xls_to_tsv [label="export au format tsv\navec libreoffice"]; - it_orders_filter [label="geslabt002_to_itorders.py"]; - concat [label="concaténation"]; - cnrs_manual [label="formatage manuel"]; + op_extra_geslab [label="op_extra_geslab\n(extraction ngiquiaux)"]; + op_cnrs_xls_to_tsv [label="op_cnrs_xls_to_tsv\n(export au format tsv\navec libreoffice)"]; + op_cnrs_it_filter [label="op_cnrs_it_filter\n(geslabt002_to_itorders.py)"]; + op_anno_cnrs_it [label="op_anno_cnrs_it\n(annotations manuelles)"]; + op_cnrs_to_l1p5 [label="op_cnrs_to_l1p5\n(nettoyage et mise au format labo 1.5)"]; - extraction_ur [label="extraction ddemorel"]; - sifac_to_itorders [label="sifact002_to_itorders.py"]; + op_extra_sifac [label="op_extra_sifac\n(extraction ddemorel)"]; + op_ur1_it_filter [label="op_ur1_it_filter\n(sifact002_to_itorders.py)"]; + op_anno_ur1_it [label="op_anno_ur1_it\n(annotations manuelles)"]; + op_ur1_to_l1p5 [label="op_ur1_to_l1p5\n(nettoyage et mise au format labo 1.5)"]; + + op_concat [label="op_concat\n(concaténation)"]; # relations - geslab -> extraction_cnrs; - extraction_cnrs -> cnrs_all_xls; + geslab -> op_extra_geslab; + op_extra_geslab -> cnrs_all_xls; - cnrs_all_xls -> cnrs_xls_to_tsv; - cnrs_xls_to_tsv -> cnrs_all_tsv; + cnrs_all_xls -> op_cnrs_xls_to_tsv; + op_cnrs_xls_to_tsv -> cnrs_all_tsv; - cnrs_all_tsv -> it_orders_filter; - it_orders_filter -> cnrs_it_orders; + cnrs_all_tsv -> op_cnrs_it_filter; + op_cnrs_it_filter -> cnrs_it_orders; - cnrs_it_orders -> cnrs_manual; - cnrs_manual -> cnrs_it_orders_labo1p5; + cnrs_it_orders -> op_anno_cnrs_it; + cnrs_paper_orders -> op_anno_cnrs_it; + op_anno_cnrs_it -> cnrs_it_orders_ann; - sifac -> extraction_ur; - extraction_ur -> ur1_all_orders; + cnrs_it_orders_ann -> op_cnrs_to_l1p5; + op_cnrs_to_l1p5 -> cnrs_it_orders_labo1p5; - ur1_all_orders -> sifac_to_itorders; - sifac_to_itorders -> ur1_it_orders; + sifac -> op_extra_sifac; + op_extra_sifac -> ur1_all_orders; - cnrs_it_orders_labo1p5 -> concat; - ur1_it_orders_labo1p5 -> concat; - concat -> it_orders_labo1p5; + ur1_all_orders -> op_ur1_it_filter; + op_ur1_it_filter -> ur1_it_orders; + + ur1_it_orders -> op_anno_ur1_it; + ur1_paper_orders -> op_anno_ur1_it; + op_anno_ur1_it -> ur1_it_orders_ann; + + ur1_it_orders_ann -> op_ur1_to_l1p5; + op_ur1_to_l1p5 -> ur1_it_orders_labo1p5; + + cnrs_it_orders_labo1p5 -> op_concat; + ur1_it_orders_labo1p5 -> op_concat; + op_concat -> it_orders_labo1p5; } \ No newline at end of file diff --git a/procedures/labo1.5/materiel-info-graph.svg b/procedures/labo1.5/materiel-info-graph.svg index cc0f5a8..61785f2 100644 --- a/procedures/labo1.5/materiel-info-graph.svg +++ b/procedures/labo1.5/materiel-info-graph.svg @@ -4,213 +4,326 @@ - - + + %3 - + geslab - -geslab -(cnrs) + +geslab +(cnrs) - - -extraction_cnrs - -extraction ngiquiaux + + +op_extra_geslab + +op_extra_geslab +(extraction ngiquiaux) - + -geslab->extraction_cnrs - - +geslab->op_extra_geslab + + cnrs_all_xls - -cnrs_all_xls -(commandes-2019-cnrs-t002.xls) + +cnrs_all_xls +(commandes-2019-cnrs-t002.xls) - - -cnrs_xls_to_tsv - -export au format tsv -avec libreoffice + + +op_cnrs_xls_to_tsv + +op_cnrs_xls_to_tsv +(export au format tsv +avec libreoffice) - + -cnrs_all_xls->cnrs_xls_to_tsv - - +cnrs_all_xls->op_cnrs_xls_to_tsv + + cnrs_all_tsv - -cnrs_all_tsv -(commandes-2019-cnrs-t002.tsv) + +cnrs_all_tsv +(commandes-2019-cnrs-t002.tsv, +1991 items) - - -it_orders_filter - -geslabt002_to_itorders.py + + +op_cnrs_it_filter + +op_cnrs_it_filter +(geslabt002_to_itorders.py) - + -cnrs_all_tsv->it_orders_filter - - +cnrs_all_tsv->op_cnrs_it_filter + + cnrs_it_orders - -cnrs_it_orders -(commandes-it-2019-cnrs-002.tsv) + +cnrs_it_orders +(commandes-it-2019-cnrs-002.tsv, +224 items) - - -cnrs_manual - -formatage manuel + + +op_anno_cnrs_it + +op_anno_cnrs_it +(annotations manuelles) - + -cnrs_it_orders->cnrs_manual - - +cnrs_it_orders->op_anno_cnrs_it + + + + + +cnrs_it_orders_ann + +cnrs_it_orders_ann +(commandes-it-2019-cnrs-002-annotated.tsv, +224 items) + + + +op_cnrs_to_l1p5 + +op_cnrs_to_l1p5 +(nettoyage et mise au format labo 1.5) + + + +cnrs_it_orders_ann->op_cnrs_to_l1p5 + + - + cnrs_it_orders_labo1p5 - -cnrs_it_orders_labo1p5 -(it-cnrs-l1p5.tsv) + +cnrs_it_orders_labo1p5 +(it-cnrs-l1p5.tsv, +84 items) - - -concat - -concaténation + + +op_concat + +op_concat +(concaténation) - - -cnrs_it_orders_labo1p5->concat - - + + +cnrs_it_orders_labo1p5->op_concat + + + + + +cnrs_paper_orders + +cnrs_paper_orders +(archives papier cnrs) + + + +cnrs_paper_orders->op_anno_cnrs_it + + - + sifac - -sifac -(ur1) + +sifac +(ur1) - - -extraction_ur - -extraction ddemorel + + +op_extra_sifac + +op_extra_sifac +(extraction ddemorel) - - -sifac->extraction_ur - - + + +sifac->op_extra_sifac + + - + ur1_all_orders - -ur1_all_orders -(2019.<dept-id>.xls) + +ur1_all_orders +(2019.<dept-id>.xls +610 items) - - -sifac_to_itorders - -sifact002_to_itorders.py + + +op_ur1_it_filter + +op_ur1_it_filter +(sifact002_to_itorders.py) - - -ur1_all_orders->sifac_to_itorders - - + + +ur1_all_orders->op_ur1_it_filter + + - + ur1_it_orders - -ur1_it_orders -(commandes-it-2019-ur1-002.tsv) + +ur1_it_orders +(commandes-it-2019-ur1-002.tsv, +33 items)) + + + +op_anno_ur1_it + +op_anno_ur1_it +(annotations manuelles) + + + +ur1_it_orders->op_anno_ur1_it + + + + + +ur1_it_orders_ann + +ur1_it_orders_ann +(commandes-it-2019-ur1-002-annotated.tsv, +33 items) + + + +op_ur1_to_l1p5 + +op_ur1_to_l1p5 +(nettoyage et mise au format labo 1.5) + + + +ur1_it_orders_ann->op_ur1_to_l1p5 + + - + ur1_it_orders_labo1p5 - -ur1_it_orders_labo1p5 -(it-ur1-l1p5.tsv) + +ur1_it_orders_labo1p5 +(it-ur1-l1p5.tsv, +22 items) - - -ur1_it_orders_labo1p5->concat - - + + +ur1_it_orders_labo1p5->op_concat + + + + + +ur1_paper_orders + +ur1_paper_orders +(archives papier ur1) + + + +ur1_paper_orders->op_anno_ur1_it + + - + it_orders_labo1p5 - -it_orders_labo1p5 -(it-l1p5.tsv) + +it_orders_labo1p5 +(it-l1p5.tsv, +106 items) - + -extraction_cnrs->cnrs_all_xls - - +op_extra_geslab->cnrs_all_xls + + - + -cnrs_xls_to_tsv->cnrs_all_tsv - - +op_cnrs_xls_to_tsv->cnrs_all_tsv + + - + -it_orders_filter->cnrs_it_orders - - +op_cnrs_it_filter->cnrs_it_orders + + - + + +op_anno_cnrs_it->cnrs_it_orders_ann + + + + + +op_cnrs_to_l1p5->cnrs_it_orders_labo1p5 + + + + + +op_extra_sifac->ur1_all_orders + + + + -concat->it_orders_labo1p5 - - +op_ur1_it_filter->ur1_it_orders + + - - -cnrs_manual->cnrs_it_orders_labo1p5 - - + + +op_anno_ur1_it->ur1_it_orders_ann + + - - -extraction_ur->ur1_all_orders - - + + +op_ur1_to_l1p5->ur1_it_orders_labo1p5 + + - - -sifac_to_itorders->ur1_it_orders - - + + +op_concat->it_orders_labo1p5 + + diff --git a/procedures/labo1.5/materiel-info.md b/procedures/labo1.5/materiel-info.md index 0994c7e..e184d2e 100644 --- a/procedures/labo1.5/materiel-info.md +++ b/procedures/labo1.5/materiel-info.md @@ -119,14 +119,82 @@ Au lieu de ça, il apparaît ainsi (les colonnes **N° com. GESLAB** et **N° li 1950-4-7 12:00:00 AM 24/01/19 2019-3-19 12:00:00 AM CAT2_Configuration n°3 XPS 9365 DELL SAS S 1 0 1 0.00 1,755.00 0.00 1,755.00 SE9ADO0985 9ADO0985 NANOSC 2100 IM ``` +#### cnrs_it_orders + +Contient uniquement les achats informatiques extraits de [cnrs_all_tsv](####-cnrs_all_tsv). + +- exemple: [commandes-it-2019-cnrs-002.tsv](../../tmp/commandes-it-2019-cnrs-002.tsv), qui contient 224 lignes de données +- colonnes: les mêmes que pour [cnrs_all_tsv](####-cnrs_all_tsv) + +exemple: +```tsv + Date commande Libellé ligne Raison sociale fournisseur Qté com. Reste à const. Qté fac. Cons. ligne antérieur Consommé ligne Réservé ligne Facturé ligne Code EDP Matière Nat. dép. +71 24/01/19 MPXT2FN/A ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 1,195.15 0.00 1,195.15 MECVER 2100 IM +72 24/01/19 MBP13-3PL ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 89.00 0.00 89.00 MECVER 2100 IM +73 24/01/19 ECO-0,30 ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 0.30 0.00 0.30 MECVER 2100 IM +74 24/01/19 CTO-MPXT2-16GB ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 170.00 0.00 170.00 MECVER 2100 IM +... +84 24/01/19 D31591 ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 40.78 0.00 40.78 MECVER 2100 IM +89 24/01/19 CAT2_Configuration n°3 XPS 9365 DELL SAS 1.0 0.0 1.0 0.0 1,755.00 0.00 1,755.00 NANOSC 2100 IM +90 24/01/19 Dell Wireless Mouse WM126 BLACK DELL SAS 1.0 0.0 1.0 0.0 8.00 0.00 8.00 NANOSC 2100 IM +91 24/01/19 Eco contribution DELL SAS 1.0 0.0 1.0 0.0 0.43 0.00 0.43 NANOSC 2100 IM +... +``` + +#### cnrs_it_orders_labo1p5 + +- au format [attendu par labo 1.5](##description-du-fichier-attendu-par-labo1.5) +- par exemple [it-cnrs-l1p5.tsv](../../achats-ipr/2019/it-cnrs-l1p5.tsv) qui contien 84 lignes de données: + +```tsv +id Modele Fabricant Type +cnrs_71 macbook pro 13 (2017) apple pc portable +cnrs_79 brilliance 258B6QUEB philips écran +cnrs_89 xps 9365 dell pc portable +cnrs_90 wm126 dell souris +cnrs_210 latitude 5590 dell pc portable +... +``` ### ur1 +#### ur1_all_orders + +- exemple: [from_ddemorel](../../achats-ipr/2019/ur1/from_ddemorel) (610 items) qui contient: + - [2019.DIRECTION.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.DIRECTION.xls>), (93 items). + - [2019.MAT.NANO.SCIENCES.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.MAT.NANO.SCIENCES.xls>), (85 items). + - [2019.MATERIAUX ET LUMIERE.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.MATERIAUX ET LUMIERE.xls>), (86 items). + - [2019.MATIERE MOLLE.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.MATIERE MOLLE.xls>), (62 items). + - [2019.MECA VERRES.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.MECA VERRES.xls>), (88 items). + - [2019.MILIEU DIVISE.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.MILIEU DIVISE.xls>), (45 items). + - [2019.PHYSIQUE MOLECULAIRE.xls](<../../achats-ipr/2019/ur1/from_ddemorel/2019.PHYSIQUE MOLECULAIRE.xls>), (151 items). +- colonnes: + 1. **Centre financier**: par exemple `991R423` + 2. **Elément d'OTP**: par exemple `17CQ423-S0` + 3. **Document d'achat**: par exemple `4500458349.0` + 4. **Fournisseur/Division fourn.**: par exemple `7976 DELL` + 5. **Date du document**: par exemple `2019-02-14` + 6. **Code TVA**: par exemple `DK` + 7. **Désignation**: par exemple `LATITUDE 5590 - Portable conf.n°2` + 8. **Date livraison**: par exemple `2019-02-25` + 9. **Valeur totale en cours**: par exemple `1616.8` + 10. **Reste à livrer (quantité)**: par exemple `0` + 11. **Livraison finale**: par exemple `X` + 12. **Reste à facturer (quantité)**: par exemple `0` + 13. **Facture finale**: par exemple `126639.0` + 14. **Immobilisation**: par exemple `` + 15. **Groupe marchandises**: par exemple `IA.11` + 16. **Texte Correspondance**: par exemple `Danièle, Le numéro d'ordre n'est pas cor` + 17. **Créateur commande**: par exemple, `DE MOREL DANIELE` + + #### ur1_it_orders -- exemple : [commandes-it-2019-ur1-002\.tsv](../../tmp/commandes-it-2019-ur1-002.tsv), qui contient 33 lignes de données -- colonnes: - 1. ****: identifieur d'achat, par exemple `21` +Contient uniquement les achats informatiques extraits de [ur1_all_orders](####-ur1_all_orders). + +- exemple: [commandes-it-2019-ur1-002\.tsv](../../tmp/commandes-it-2019-ur1-002.tsv), qui contient 33 lignes de données +- colonnes: les mêmes que pour [ur1_all_orders](####-ur1_all_orders) mais avec la première colonne insérée + 1. ****: identifieur de ligne, par exemple `21` 2. **Centre financier**: par exemple `991R423` 3. **Elément d'OTP**: par exemple `17CQ423-S0` 4. **Document d'achat**: par exemple `4500458349.0` @@ -145,6 +213,7 @@ Au lieu de ça, il apparaît ainsi (les colonnes **N° com. GESLAB** et **N° li 17. **Texte Correspondance**: par exemple `Danièle, Le numéro d'ordre n'est pas cor` 18. **Créateur commande**: par exemple, `DE MOREL DANIELE` +exemple: ```tsv 20241011-10:57:24 graffy@graffy-ws2:~/work/ddrs/procedures/labo1.5$ head -3 /home/graffy/work/ddrs/tmp/commandes-it-2019-ur1-002.tsv Centre financier Elément d'OTP Document d'achat Fournisseur/Division fourn. Date du document Code TVA Désignation Date livraison Valeur totale en cours Reste à livrer (quantité) Livraison finale Reste à facturer (quantité) Facture finale Immobilisation Groupe marchandises Texte Correspondance Créateur commande @@ -204,3 +273,67 @@ ur1_237 latitude 3400 dell pc portable ... ``` +## description des opérations + +### `op_extra_geslab`: extraction geslab + +Extraction geslab (effectuée par Nathalie Guicquiaux pour les données 2019) + +### `op_extra_sifac`: extraction sifac + +Extraction sifac (effectuée par Danièle Demorel pour les données 2019) + +### `op_cnrs_it_filter`: filtrage pour ne garder que les achats informatiques + +Opération effectuée automatiquement par [geslabt002_to_itorders.py](../../src/geslabt002_to_itorders.py) via [la recette make](../../src/Makefile) + +Un achat est considéré comme un achat informatique que si le champ `Matière` a l'une des valeurs suivantes (définies dans [cnrs-matieres-001.csv](../../achats-ipr/2019/cnrs/from_ngicquiaux/cnrs-matieres-001.csv)): +- `1100` (PETIT_MATERIEL_INFORMATIQUE) +- `2100` (EQUIPEMENT_INFORMATIQUE) +- `D3--` (INFORMATIQUE_ACHAT) + +### `op_anno_cnrs_it`: annotations + +C'est l'opération manuelle qui consiste à ajouter une colonne `comment` pour y placer des infos supplémentaires concernant les achats, car la colonne `Libellé ligne` est souvent cryptique (il faut alors se référer aux archives papier des commandes cnrs `cnrs_paper_orders`), comme dans l'exemple ci-dessous où: +- le libellé `99MO084201` ne permet pas de savoir acilement qu'il s'agit d'un adaptatateur vga +- le libellé `MBP13-3PL` ne permet pas de savoir facilement qu'il s'agit de la garantie 3 ans du macbook pro +- etc. + +```tsv + Date commande Libellé ligne Raison sociale fournisseur Qté com. Reste à const. Qté fac. Cons. ligne antérieur Consommé ligne Réservé ligne Facturé ligne Code EDP Matière Nat. dép. +... +71 24/01/19 MPXT2FN/A ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 1,195.15 0.00 1,195.15 MECVER 2100 IM macbook pro +72 24/01/19 MBP13-3PL ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 89.00 0.00 89.00 MECVER 2100 IM garantie 3 ans +73 24/01/19 ECO-0,30 ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 0.30 0.00 0.30 MECVER 2100 IM +74 24/01/19 CTO-MPXT2-16GB ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 170.00 0.00 170.00 MECVER 2100 IM passage à 16Go RAM +75 24/01/19 CTO-MPXT2-SSD1To ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 531.25 0.00 531.25 MECVER 2100 IM passage à disque dur 1To +76 24/01/19 MI4-MBP13-5PL ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 106.00 0.00 106.00 MECVER 2100 IM passage à garantie 5 ans +77 24/01/19 99MO084201 ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 23.34 0.00 23.34 MECVER 2100 IM adapter usbc->vga moshi 99MO084201 +78 24/01/19 ECO-0,02 ECONOCOM PRODUCTS & SOLUTIONS 1.0 0.0 1.0 0.0 0.02 0.00 0.02 MECVER 2100 IM +... +``` + +### `op_cnrs_to_l1p5`: nettoyage et mise au format labo 1.5 + +C'est l'opération manuelle qui consiste à: +1. ajouter les colonnes labo 1.5: **id**, **Modèle**, **Fabricant** et **Type** +2. supprimer les lignes qui ne rentrent dans aucun [types supportés par labo 1.5](###-types-supportés-par-labo-1.5), par exemple, adaptateur vga ou extension de garantie +3. remplir les colonnes labo 1.5 (**id** est rempli par l'item number, préfixé par `cnrs_`, de manière à retrouver l'achat correspondant dans les tableaux détaillés, par exemple `ur1_it_orders_ann`) +4. supprimer les colonnes autres que les 4 colonnes labo 1.5 + +### `op_ur1_it_filter`: filtrage pour ne garder que les achats informatiques + +Opération effectuée automatiquement par [sifact002_to_itorders.py](../../src/sifact002_to_itorders.py) via [la recette make](../../src/Makefile) + +Un achat est considéré comme un achat informatique que si le champ `Fournisseur/Division fourn.` a l'une des valeurs suivantes: +- `7976 DELL`: marché pour l'achat de fixe et de portables non Apple +- `16783 ECONOCOM`: marché pour achat de matériel Apple +- `4945 MISCO INMAC WSTORE`: marché pour fournitures informatiques + +### `op_ur1_to_l1p5`: nettoyage et mise au format labo 1.5 + +idem `op_cnrs_to_l1p5` mais côté ur1 + +### `op_concat`: fusion des données cnrs et ur1 + +Opération effectuée automatiquement par [la recette make](../../src/Makefile) \ No newline at end of file diff --git a/src/Makefile b/src/Makefile new file mode 100644 index 0000000..2897093 --- /dev/null +++ b/src/Makefile @@ -0,0 +1,41 @@ +DDRS_ROOT = /home/graffy/work/ddrs +TEMP_DIR = $(DDRS_ROOT)/tmp + +cnrs_all_tsv = $(DDRS_ROOT)/achats-ipr/2019/cnrs/from_ngicquiaux/commandes-2019-cnrs-t002.tsv +cnrs_it_orders = $(TEMP_DIR)/commandes-it-2019-cnrs-002.tsv +cnrs_it_orders_labo1p5 = $(DDRS_ROOT)/achats-ipr/2019/it-cnrs-l1p5.tsv + +ur1_all_orders_dir = $(DDRS_ROOT)/achats-ipr/2019/ur1/from_ddemorel +ur1_all_orders_pattern = $(ur1_all_orders_dir)/2019..xls +ur1_all_orders_files = \ + $(ur1_all_orders_dir)/2019.DIRECTION.xls \ + $(ur1_all_orders_dir)/2019.MAT.NANO.SCIENCES.xls \ + $(ur1_all_orders_dir)/2019.MATERIAUX\ ET\ LUMIERE.xls \ + $(ur1_all_orders_dir)/2019.MATIERE\ MOLLE.xls \ + $(ur1_all_orders_dir)/2019.MECA\ VERRES.xls \ + $(ur1_all_orders_dir)/2019.MILIEU\ DIVISE.xls \ + $(ur1_all_orders_dir)/2019.PHYSIQUE\ MOLECULAIRE.xls +ur1_it_orders = $(TEMP_DIR)/commandes-it-2019-ur1-002.tsv +ur1_it_orders_labo1p5 = $(DDRS_ROOT)/achats-ipr/2019/it-ur1-l1p5.tsv + +it_orders_labo1p5 = $(DDRS_ROOT)/achats-ipr/2019/it-l1p5.tsv + +all: $(it_orders_labo1p5) + +$(it_orders_labo1p5): $(cnrs_it_orders_labo1p5) $(ur1_it_orders_labo1p5) + ( cat $(word 1,$^) && tail +2 $(word 2,$^) )> $@ + +$(cnrs_it_orders_labo1p5): $(cnrs_it_orders) + echo "$@ must be updated manually from $< because $< is newer than $@" && false + +$(cnrs_it_orders): $(cnrs_all_tsv) + $(DDRS_ROOT)/src/geslabt002_to_itorders.py --all-orders-report "$<" --it-orders-sheet "$@" + + +$(ur1_it_orders_labo1p5): $(ur1_it_orders) + echo "$@ must be updated manually from $< because $< is newer than $@" && false + +$(ur1_it_orders): $(ur1_all_orders_files) + $(DDRS_ROOT)/src/sifact002_to_itorders.py --sifac-t002-path "$(ur1_all_orders_pattern)" --it-orders-sheet "$@" + + diff --git a/src/geslabt001_to_itorders.py b/src/geslabt001_to_itorders.py index 206b88c..4fa7972 100755 --- a/src/geslabt001_to_itorders.py +++ b/src/geslabt001_to_itorders.py @@ -6,23 +6,22 @@ import pandas # converts a cnrs geslab type t001 report to a single table def geslabt001_to_sheet(in_tsv_file_path: Path, out_tsv_file_path: Path): - with open(in_tsv_file_path) as inf, open(out_tsv_file_path, 'wt') as outf: + with open(in_tsv_file_path, encoding='utf8') as inf, open(out_tsv_file_path, 'wt', encoding='utf8') as outf: table_header_has_been_written = False for line in inf.readlines(): - ignore_line = False + # the input report file contains groups of data lines sparated by header blocks such as this: # Entité dépensière : AESJULLIEN AES RENNES METROPOLE MC JULLIEN Crédits reçus : 40,000.00 # Disponible : 24,743.14 # # # N° commande Souche Libellé commande Date commande Raison sociale fournisseur Montant consommé sur exercice antérieur Montant consommé sur l'exercice Montant réservé Montant facturé Code origine Nature dépense Statut Cde groupée - if re.match(r'^Entité dépensière', line): - ignore_line = True # noqa - is_table_header = re.match(r'^N° commande', line) is not None - # 19,572.00 19AESMCJ CAMERA ZYLA 5.5 sCMOS 04/11/19 ANDOR TECHNOLOGY LIMITED 0.00 13,681.56 0.00 0.00 635991 IM - if is_table_header and not table_header_has_been_written: + is_column_description = re.match(r'^N° commande', line) is not None + if is_column_description and not table_header_has_been_written: outf.write('# %s' % line) table_header_has_been_written = True if re.match(r'^[0-9,./]+\t', line): + # this line is expected to contain data (ie not be part of the header blocks) + # 19,572.00 19AESMCJ CAMERA ZYLA 5.5 sCMOS 04/11/19 ANDOR TECHNOLOGY LIMITED 0.00 13,681.56 0.00 0.00 635991 IM outf.write(line) diff --git a/src/geslabt002_to_itorders.py b/src/geslabt002_to_itorders.py index 310760d..f8d0bcc 100755 --- a/src/geslabt002_to_itorders.py +++ b/src/geslabt002_to_itorders.py @@ -2,18 +2,32 @@ from pathlib import Path import re import pandas +import argparse +import tempfile +import os + +# a geslab_t002 file is a sheet that contains data in the following form: + +# ``` +# LABORATOIRE : LABO1 IPR - UNIVERSITE DE RENNES Le : 27/01/2023 +# DETAIL DES LIGNES DE COMMANDE Exercice : 2019 +# Page : 1 / 100 +# Etablissement : DR17 Délégation Bretagne et Pays de la Loire +# +# +# N° com. GESLAB Date commande N° ligne Libellé ligne Raison sociale fournisseur S Qté com. Reste à const. Qté fac. Cons. ligne antérieur Consommé ligne Réservé ligne Facturé ligne Code origine Elément analytique Code EDP Matière Nat. dép. +# ... +# 18,313.00 04/01/19 43,427.00 POUSSE SERINGUE PHD ULTRA 4400 I/W HARVARD APPARATUS S 1 0 1 0.00 6,616.00 0.00 6,616.00 59190 591901 ANRASJ 2500 IM +# ``` -# converts a cnrs geslab type t001 report to a single table +# converts a cnrs geslab type t002 report to a single table def geslabt002_to_sheet(in_tsv_file_path: Path, out_tsv_file_path: Path): - with open(in_tsv_file_path) as inf, open(out_tsv_file_path, 'wt') as outf: + + with open(in_tsv_file_path, encoding='utf8') as inf, open(out_tsv_file_path, 'wt', encoding='utf8') as outf: table_header_has_been_written = False for line in inf.readlines(): - # Entité dépensière : AESJULLIEN AES RENNES METROPOLE MC JULLIEN Crédits reçus : 40,000.00 - # Disponible : 24,743.14 - # - # - # N° commande Souche Libellé commande Date commande Raison sociale fournisseur Montant consommé sur exercice antérieur Montant consommé sur l'exercice Montant réservé Montant facturé Code origine Nature dépense Statut Cde groupée + is_table_header = re.match(r'^N° com. GESLAB', line) is not None # for some strange reason, the column 'N° com. GESLAB''s contents are alternatively something like '1952-12-17 12:00:00 AM' and something like '19,855.00' if is_table_header and not table_header_has_been_written: @@ -27,13 +41,15 @@ def geslabt002_to_sheet(in_tsv_file_path: Path, out_tsv_file_path: Path): print('ignoring line : %s' % line) -def geslabt002_to_itorders(geslabt001_file_path: Path, itorders_file_path: Path): - sheet_file_path = Path('./tmp/commandes-2019-cnrs.tsv') - geslabt002_to_sheet(geslabt001_file_path, sheet_file_path) +def geslabt002_to_itorders(geslabt002_file_path: Path, itorders_file_path: Path): - df = pandas.read_csv(sheet_file_path, sep='\t') + all_orders_file_path = tempfile.NamedTemporaryFile(delete=False).name + print(f'all_orders_file_path = {all_orders_file_path}') + geslabt002_to_sheet(geslabt002_file_path, all_orders_file_path) - # delete the colums for which the labve is of the form 'Unnamed: '. They come from the csv export of libre office + df = pandas.read_csv(all_orders_file_path, sep='\t') + + # delete the colums for which the label is of the form 'Unnamed: '. They come from the csv export of libre office unnamed_columns = [column_label for column_label in df.keys() if re.match(r'^Unnamed', column_label) is not None] print(unnamed_columns) df = df.drop(columns=unnamed_columns) @@ -56,11 +72,18 @@ def geslabt002_to_itorders(geslabt001_file_path: Path, itorders_file_path: Path) it_df = it_df.drop(columns=['S']) # I don't know the meaning of this column print(it_df[['Facturé ligne', 'Raison sociale fournisseur', 'Libellé ligne']]) + os.makedirs(itorders_file_path.parent, exist_ok=True) it_df.to_csv(itorders_file_path, sep='\t') def main(): - geslabt002_to_itorders(Path('./achats-ipr/2019/cnrs/from_ngicquiaux_20230127/commandes-2019-cnrs-t002.tsv'), Path('./tmp/commandes-it-2019-cnrs-002.tsv')) + arg_parser = argparse.ArgumentParser(description='extracts the orders related to information technology hardware purchases from a report (in format geslab_t002) containing all the orders') + arg_parser.add_argument('--all-orders-report', type=Path, required=True, help='the input report file (in format geslab_t002) containing all the orders') + arg_parser.add_argument('--it-orders-sheet', type=Path, required=True, help='the output sheet containing only it orders') + args = arg_parser.parse_args() + all_orders_report_path = args.all_orders_report + it_orders_sheet_path = args.it_orders_sheet + geslabt002_to_itorders(all_orders_report_path, it_orders_sheet_path) main() diff --git a/src/sifact002_to_itorders.py b/src/sifact002_to_itorders.py index 81bde0b..bc0fd8c 100755 --- a/src/sifact002_to_itorders.py +++ b/src/sifact002_to_itorders.py @@ -2,10 +2,20 @@ from pathlib import Path import re import pandas +import argparse +import tempfile +import logging + +# example of sifac_t002 file +# ``` +# Centre financier Elément d'OTP Document d'achat Fournisseur/Division fourn. Date du document Code TVA Désignation Date livraison Valeur totale en cours Reste à livrer (quantité) Livraison finale Reste à facturer (quantité) Facture finale Immobilisation Groupe marchandises Texte Correspondance Créateur commande +# 0 991R423 17CQ423-A0 4500454464.0 4692 AIR LIQUIDE FRANCE INDUSTRIE 2019-01-21 DJ REGUL 2018GAZ HORS MARCHE ALPHAGAZ 2 AIR 2019-01-21 130.27 0 0 GA.21 Rejet à la demande de Magali MARCAULT MAGALI +# ... +# ``` -# converts a cnrs geslab type t001 report to a single table -def sifact002_to_sheet(sifact002_dir: Path, out_tsv_file_path: Path): +# converts a cnrs sifac type t002 report to a single table +def sifact002_to_sheet(sifac_t002_path: str, out_tsv_file_path: Path): dept_names = [ 'DIRECTION', @@ -17,15 +27,16 @@ def sifact002_to_sheet(sifact002_dir: Path, out_tsv_file_path: Path): 'PHYSIQUE MOLECULAIRE' ] - with open(out_tsv_file_path, 'wt') as outf: + with open(out_tsv_file_path, 'wt', encoding='utf8') as outf: out_header_has_been_written = False for dept_name in dept_names: - src_file_path = sifact002_dir / ('2019.' + dept_name + '.xls') - tmp_file_path = Path('./tmp') / ('2019.' + dept_name + '.tsv') + src_file_path = Path(sifac_t002_path.replace('', dept_name)) + tmp_file_path = Path(tempfile.NamedTemporaryFile(delete=False).name).with_suffix('.tsv') + logging.debug('tmp_file_path for department %s : %s', dept_name, tmp_file_path) df = pandas.read_excel(src_file_path) df.to_csv(tmp_file_path, sep='\t') - with open(tmp_file_path) as inf: + with open(tmp_file_path, encoding='utf8') as inf: in_header_has_been_read = False for line in inf.readlines(): if in_header_has_been_read: @@ -45,31 +56,14 @@ def sifact002_to_sheet(sifact002_dir: Path, out_tsv_file_path: Path): # df = df[-1:] + df[:-1] # put the id column in the first column df.to_csv(out_tsv_file_path, sep='\t') - # with open(in_tsv_file_path) as inf, open(out_tsv_file_path, 'wt') as outf: - # table_header_has_been_written = False - # for line in inf.readlines(): - # ignore_line = False - # # Entité dépensière : AESJULLIEN AES RENNES METROPOLE MC JULLIEN Crédits reçus : 40,000.00 - # # Disponible : 24,743.14 - # # - # # - # # N° commande Souche Libellé commande Date commande Raison sociale fournisseur Montant consommé sur exercice antérieur Montant consommé sur l'exercice Montant réservé Montant facturé Code origine Nature dépense Statut Cde groupée - # if re.match(r'^Entité dépensière', line): - # ignore_line = True # noqa - # is_table_header = re.match(r'^N° commande', line) is not None - # # 19,572.00 19AESMCJ CAMERA ZYLA 5.5 sCMOS 04/11/19 ANDOR TECHNOLOGY LIMITED 0.00 13,681.56 0.00 0.00 635991 IM - # if is_table_header and not table_header_has_been_written: - # outf.write('# %s' % line) - # table_header_has_been_written = True - # if re.match(r'^[0-9,./]+\t', line): - # outf.write(line) +def sifact002_to_itorders(sifac_t002_path: str, itorders_file_path: Path): + all_orders_file_path = tempfile.NamedTemporaryFile(delete=False).name + logging.debug('all_orders_file_path = %s', all_orders_file_path) -def sifact002_to_itorders(sifact002_dir: Path, itorders_file_path: Path): - sheet_file_path = Path('./tmp/commandes-2019-ur1.tsv') - sifact002_to_sheet(sifact002_dir, sheet_file_path) + sifact002_to_sheet(sifac_t002_path, all_orders_file_path) - df = pandas.read_csv(sheet_file_path, sep='\t') + df = pandas.read_csv(all_orders_file_path, sep='\t') # delete the colums for which the label is of the form 'Unnamed: '. They come from the csv export of libre office unnamed_columns = [column_label for column_label in df.keys() if re.match(r'^Unnamed', column_label) is not None] @@ -95,7 +89,15 @@ def sifact002_to_itorders(sifact002_dir: Path, itorders_file_path: Path): def main(): - sifact002_to_itorders(Path('./achats-ipr/2019/ur1/from_ddemorel'), Path('./tmp/commandes-it-2019-ur1-002.tsv')) + logging.basicConfig(level=logging.DEBUG) + + arg_parser = argparse.ArgumentParser(description='extracts the orders related to information technology hardware purchases from excel sheets (one per department) containing all the orders') + arg_parser.add_argument('--sifac-t002-path', type=str, required=True, help='the path to the input files, where the department is represented by the tag (eg ./achats-ipr/2019/ur1/from_ddemorel/2019..xls)') + arg_parser.add_argument('--it-orders-sheet', type=Path, required=True, help='the output sheet containing only it orders') + args = arg_parser.parse_args() + sifac_t002_path = args.sifac_t002_path + it_orders_sheet_path = args.it_orders_sheet + sifact002_to_itorders(sifac_t002_path, it_orders_sheet_path) main()